mirror of
https://github.com/imfing/hextra.git
synced 2025-06-20 00:51:18 -04:00
feat: basic flexsearch implementation
This commit is contained in:
86
assets/js/flexsearch.js
Normal file
86
assets/js/flexsearch.js
Normal file
@ -0,0 +1,86 @@
|
||||
// {{ $searchDataFile := printf "%s.search-data.json" .Language.Lang }}
|
||||
// {{ $searchData := resources.Get "json/search-data.json" | resources.ExecuteAsTemplate $searchDataFile . | resources.Minify | resources.Fingerprint }}
|
||||
|
||||
(function () {
|
||||
const searchDataURL = '{{ $searchData.Permalink }}';
|
||||
console.log('searchDataURL', searchDataURL);
|
||||
|
||||
const indexConfig = {
|
||||
tokenize: "full",
|
||||
cache: 100,
|
||||
document: {
|
||||
id: 'id',
|
||||
store: ['title', 'href', 'section'],
|
||||
index: ["title", "content"]
|
||||
},
|
||||
context: {
|
||||
resolution: 9,
|
||||
depth: 2,
|
||||
bidirectional: true
|
||||
}
|
||||
}
|
||||
window.flexSearchIndex = new FlexSearch.Document(indexConfig);
|
||||
|
||||
const input = document.getElementById('search-input');
|
||||
const results = document.getElementById('search-results');
|
||||
|
||||
input.addEventListener('focus', init);
|
||||
input.addEventListener('keyup', search);
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the search functionality by adding the necessary event listeners and fetching the search data.
|
||||
*/
|
||||
function init() {
|
||||
input.removeEventListener('focus', init); // init once
|
||||
|
||||
fetch(searchDataURL).then(resp => resp.json()).then(pages => {
|
||||
pages.forEach(page => {
|
||||
window.flexSearchIndex.add(page);
|
||||
});
|
||||
}).then(search);
|
||||
}
|
||||
|
||||
function search() {
|
||||
console.log('search', input.value);
|
||||
while (results.firstChild) {
|
||||
results.removeChild(results.firstChild);
|
||||
}
|
||||
|
||||
if (!input.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const searchHits = window.flexSearchIndex.search(input.value, { limit: 5, enrich: true });
|
||||
showResults(searchHits);
|
||||
}
|
||||
|
||||
function showResults(hits) {
|
||||
console.log('showResults', hits);
|
||||
const flatResults = new Map(); // keyed by href to dedupe hits
|
||||
for (const result of hits.flatMap(r => r.result)) {
|
||||
if (flatResults.has(result.doc.href)) continue;
|
||||
flatResults.set(result.doc.href, result.doc);
|
||||
}
|
||||
console.log('flatResults', flatResults);
|
||||
const create = (str) => {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = str.trim();
|
||||
return div.firstChild;
|
||||
}
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
console.log(fragment)
|
||||
|
||||
for (const result of flatResults.values()) {
|
||||
const li = create(`
|
||||
<li class="mx-2.5 break-words rounded-md contrast-more:border text-gray-800 contrast-more:border-transparent dark:text-gray-300">
|
||||
<a class="block scroll-m-12 px-2.5 py-2" data-index="0" href="${result.href}">
|
||||
<div class="text-base font-semibold leading-5">${result.title}</div>
|
||||
</a>
|
||||
</li>`);
|
||||
fragment.appendChild(li);
|
||||
}
|
||||
results.appendChild(fragment);
|
||||
}
|
||||
})();
|
19
assets/json/search-data.json
Normal file
19
assets/json/search-data.json
Normal file
@ -0,0 +1,19 @@
|
||||
{{- $pages := where .Site.Pages "Kind" "in" (slice "page" "section") -}}
|
||||
{{- $pages = where $pages "Params.excludeSearch" "!=" true -}}
|
||||
{{- $pages = where $pages "Content" "!=" "" -}}
|
||||
|
||||
[
|
||||
{{ range $index, $page := $pages }}
|
||||
{{ $pageTitle := $page.LinkTitle | default $page.File.BaseFileName }}
|
||||
{{ $pageContent := $page.Plain }}
|
||||
{{ $pageSection := $page.Parent.LinkTitle }}
|
||||
|
||||
{{ if gt $index 0}},{{end}} {
|
||||
"id": {{ $index }},
|
||||
"href": "{{ $page.Permalink }}",
|
||||
"title": {{ $pageTitle | jsonify }},
|
||||
"section": {{ $pageSection | jsonify }},
|
||||
"content": {{ $page.Plain | jsonify }}
|
||||
}
|
||||
{{- end -}}
|
||||
]
|
Reference in New Issue
Block a user