chore: embed search index; one less network call
This commit is contained in:
parent
34e4b69723
commit
bca02f1511
4 changed files with 46 additions and 59 deletions
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "coryd.dev",
|
"name": "coryd.dev",
|
||||||
"version": "9.1.0",
|
"version": "9.2.0",
|
||||||
"description": "The source for my personal site. Built using 11ty.",
|
"description": "The source for my personal site. Built using 11ty.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
---
|
|
||||||
layout: null
|
|
||||||
eleventyExcludeFromCollections: true
|
|
||||||
permalink: /api/search
|
|
||||||
---
|
|
||||||
{{ collections.searchIndex | json }}
|
|
|
@ -1,48 +0,0 @@
|
||||||
(() => {
|
|
||||||
const miniSearch = new MiniSearch({
|
|
||||||
fields: ['title', 'text', 'tags']
|
|
||||||
})
|
|
||||||
|
|
||||||
const $form = document.querySelector('.search__form')
|
|
||||||
const $input = document.querySelector('.search__form--input')
|
|
||||||
const $fallback = document.querySelector('.search__form--fallback')
|
|
||||||
const $results = document.querySelector('.search__results')
|
|
||||||
|
|
||||||
// remove noscript fallbacks
|
|
||||||
$form.removeAttribute('action')
|
|
||||||
$form.removeAttribute('method')
|
|
||||||
$fallback.remove()
|
|
||||||
|
|
||||||
let resultsById = {}
|
|
||||||
|
|
||||||
// fetch index
|
|
||||||
fetch('/api/search').then(response => response.json())
|
|
||||||
.then((results) => {
|
|
||||||
resultsById = results.reduce((byId, result) => {
|
|
||||||
byId[result.id] = result
|
|
||||||
return byId
|
|
||||||
}, {})
|
|
||||||
return miniSearch.addAll(results)
|
|
||||||
})
|
|
||||||
|
|
||||||
$input.addEventListener('input', () => {
|
|
||||||
const query = $input.value
|
|
||||||
const results = (query.length > 1) ? getSearchResults(query) : []
|
|
||||||
if (query === '') renderSearchResults([])
|
|
||||||
if (results && window.fathom) fathom?.trackEvent(`Search query: ${query}`)
|
|
||||||
renderSearchResults(results)
|
|
||||||
})
|
|
||||||
|
|
||||||
const getSearchResults = (query) => miniSearch.search(query, { prefix: true, fuzzy: 0.2, boost: { title: 2 } }).map(({ id }) => resultsById[id])
|
|
||||||
const renderSearchResults = (results) => {
|
|
||||||
$results.innerHTML = results.map(({ title, url }) => {
|
|
||||||
return `<li class="search__results--result"><a href="${url}">${title}</a></li>`
|
|
||||||
}).join('\n')
|
|
||||||
|
|
||||||
if (results.length > 0) {
|
|
||||||
$results.classList.remove('hidden')
|
|
||||||
} else {
|
|
||||||
$results.classList.add('hidden')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
|
@ -9,10 +9,51 @@ permalink: /search.html
|
||||||
{% endcapture %}
|
{% endcapture %}
|
||||||
<style>{{ css }}</style>
|
<style>{{ css }}</style>
|
||||||
<script src="/assets/scripts/components/minisearch.js"></script>
|
<script src="/assets/scripts/components/minisearch.js"></script>
|
||||||
{% capture js %}
|
<script type="module">
|
||||||
{% render "../assets/scripts/search.js" %}
|
(() => {
|
||||||
{% endcapture %}
|
const miniSearch = new MiniSearch({
|
||||||
<script type="module">{{ js }}</script>
|
fields: ['title', 'text', 'tags']
|
||||||
|
})
|
||||||
|
|
||||||
|
const $form = document.querySelector('.search__form')
|
||||||
|
const $input = document.querySelector('.search__form--input')
|
||||||
|
const $fallback = document.querySelector('.search__form--fallback')
|
||||||
|
const $results = document.querySelector('.search__results')
|
||||||
|
|
||||||
|
// remove noscript fallbacks
|
||||||
|
$form.removeAttribute('action')
|
||||||
|
$form.removeAttribute('method')
|
||||||
|
$fallback.remove()
|
||||||
|
|
||||||
|
const index = {{ collections.searchIndex | json }}
|
||||||
|
const resultsById = index.reduce((byId, result) => {
|
||||||
|
byId[result.id] = result
|
||||||
|
return byId
|
||||||
|
}, {})
|
||||||
|
miniSearch.addAll(index)
|
||||||
|
|
||||||
|
$input.addEventListener('input', () => {
|
||||||
|
const query = $input.value
|
||||||
|
const results = (query.length > 1) ? getSearchResults(query) : []
|
||||||
|
if (query === '') renderSearchResults([])
|
||||||
|
if (results && window.fathom) fathom?.trackEvent(`Search query: ${query}`)
|
||||||
|
renderSearchResults(results)
|
||||||
|
})
|
||||||
|
|
||||||
|
const getSearchResults = (query) => miniSearch.search(query, { prefix: true, fuzzy: 0.2, boost: { title: 2 } }).map(({ id }) => resultsById[id])
|
||||||
|
const renderSearchResults = (results) => {
|
||||||
|
$results.innerHTML = results.map(({ title, url }) => {
|
||||||
|
return `<li class="search__results--result"><a href="${url}">${title}</a></li>`
|
||||||
|
}).join('\n')
|
||||||
|
|
||||||
|
if (results.length > 0) {
|
||||||
|
$results.classList.remove('hidden')
|
||||||
|
} else {
|
||||||
|
$results.classList.add('hidden')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
<form class="search__form" action="https://duckduckgo.com" method="get">
|
<form class="search__form" action="https://duckduckgo.com" method="get">
|
||||||
<input class="search__form--input" placeholder="Search" type="search" name="q" autocomplete="off" autofocus>
|
<input class="search__form--input" placeholder="Search" type="search" name="q" autocomplete="off" autofocus>
|
||||||
<input class="search__form--fallback" type="hidden" placeholder="Search" name="sites" value="coryd.dev">
|
<input class="search__form--fallback" type="hidden" placeholder="Search" name="sites" value="coryd.dev">
|
||||||
|
|
Reference in a new issue