This commit is contained in:
cupcakearmy 2020-12-06 17:46:18 +01:00
parent 079caec774
commit 5f556187c3
No known key found for this signature in database
GPG Key ID: D28129AE5654D9D9
6 changed files with 155 additions and 0 deletions

5
package-lock.json generated
View File

@ -642,6 +642,11 @@
"integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=",
"dev": true
},
"lunr": {
"version": "2.3.9",
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow=="
},
"magic-string": {
"version": "0.25.7",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",

View File

@ -9,6 +9,7 @@
"compression": "^1.7.1",
"dayjs": "^1.9.7",
"highlight.js": "^10.4.1",
"lunr": "^2.3.9",
"polka": "next",
"sirv": "^1.0.9",
"svelte-cloudinary": "^0.2"

View File

@ -101,6 +101,11 @@
<h1 class:active={segment === undefined}>NB</h1>
</a>
<ul>
<li>
<a href="/search">
<ion-icon name="search-outline" />
</a>
</li>
{#each routes as { name, href }}
<li>
<a {href}>

View File

@ -0,0 +1,50 @@
<script>
export let result
const [type, slug] = result.ref.split('/')
let href = '/'
$: {
console.log(type, slug)
switch (type) {
case 'works':
case 'projects':
href = `${type}`
break
case 'post':
href = `/blog/${slug}`
break
case 'page':
href = `/${slug}`
break
}
}
</script>
<style>
h3 {
margin: 0;
margin-top: 2em;
text-transform: capitalize;
}
span {
display: inline-block;
padding: 0.1em 0.15em;
background-color: var(--clr-primary);
margin: 0;
line-height: 90%;
height: 1.25em;
}
code {
margin-left: 1em;
}
</style>
<li>
<a {href}>
<h3>{slug.replace(/-/g, ' ')}</h3>
<span>{type}</span>
<code>Score: {result.score.toFixed(1)}</code>
</a>
</li>

36
src/routes/search.json.js Normal file
View File

@ -0,0 +1,36 @@
import lunr from 'lunr'
import { getAll } from '../lib/wp'
function removeHTML(s) {
return s.replace(/<.*?>|\s+|&#\d+;/g, ' ').trim()
}
async function convertForIdx(type, fields = []) {
const items = await getAll(type)
const defaults = ['title', 'content', 'slug']
return items.map((item) => ({
url: `${item.type}/${item.slug}`,
data: [...defaults, ...fields].map((field) => removeHTML(item[field])).join(' '),
}))
}
export async function get(req, res) {
const all = await Promise.all([
convertForIdx('projects', ['description']),
convertForIdx('pages'),
convertForIdx('posts'),
convertForIdx('works', ['role']),
])
const idx = lunr(function () {
this.ref('url')
this.field('data')
all.flat().forEach((doc) => {
this.add(doc)
})
})
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify(idx))
}

58
src/routes/search.svelte Normal file
View File

@ -0,0 +1,58 @@
<script context="module">
export async function preload() {
const prebuilt = await this.fetch(`/search.json`).then((res) => res.json())
return { prebuilt }
}
</script>
<script>
import lunr from 'lunr'
import SearchResult from '../components/SearchResult.svelte'
import SimplePage from '../components/SimplePage.svelte'
export let prebuilt
let needle
let results = []
async function search(needle) {
if (!needle || !idx) {
results = []
} else {
let found = idx.search(needle + '~1')
if (!found.length) found = idx.search(needle + '*')
results = found.slice(0, 20)
}
}
$: idx = lunr.Index.load(prebuilt)
$: search(needle)
</script>
<style>
input {
appearance: none;
margin: 0;
padding: 0.5rem;
font-size: 1em;
width: 100%;
outline: none;
border: 1px solid var(--clr-dark);
}
ul {
margin-top: 2em;
list-style: none;
padding: 0;
}
</style>
<SimplePage title="Search" expanded={false}>
<input bind:value={needle} placeholder="needle" />
<ul>
{#each results as result (result.ref)}
<SearchResult {result} />
{/each}
</ul>
</SimplePage>