mirror of
https://github.com/hyzendust/hyzendust.github.io.git
synced 2026-09-19 02:23:17 +02:00
Add: Search bar
This commit is contained in:
129
static/js/search.js
Normal file
129
static/js/search.js
Normal file
@@ -0,0 +1,129 @@
|
||||
(function () {
|
||||
var listEl = document.querySelector('[data-search-list]');
|
||||
var statusEl = document.querySelector('[data-search-status]');
|
||||
var queryEl = document.querySelector('[data-search-query]');
|
||||
if (!listEl || !statusEl) return;
|
||||
|
||||
function getQueryParam(name) {
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
return params.get(name) || '';
|
||||
}
|
||||
|
||||
function escapeHtml(str) {
|
||||
return str.replace(/[&<>"']/g, function (c) {
|
||||
return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c];
|
||||
});
|
||||
}
|
||||
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
function buildSnippet(content, term) {
|
||||
var radius = 90;
|
||||
var start = 0;
|
||||
var end = Math.min(content.length, radius * 2);
|
||||
|
||||
if (term) {
|
||||
var idx = content.toLowerCase().indexOf(term.toLowerCase());
|
||||
if (idx !== -1) {
|
||||
start = Math.max(0, idx - radius);
|
||||
end = Math.min(content.length, idx + term.length + radius);
|
||||
}
|
||||
}
|
||||
|
||||
var snippet = content.slice(start, end);
|
||||
if (start > 0) snippet = '\u2026' + snippet;
|
||||
if (end < content.length) snippet = snippet + '\u2026';
|
||||
|
||||
var escaped = escapeHtml(snippet);
|
||||
if (term) {
|
||||
var re = new RegExp('(' + escapeRegExp(term) + ')', 'ig');
|
||||
escaped = escaped.replace(re, '<mark>$1</mark>');
|
||||
}
|
||||
return escaped;
|
||||
}
|
||||
|
||||
function sectionLabel(section) {
|
||||
if (section === 'blog') return 'Blog';
|
||||
if (section === 'services') return 'Service';
|
||||
return section;
|
||||
}
|
||||
|
||||
var query = getQueryParam('q').trim();
|
||||
if (queryEl) queryEl.textContent = query ? 'for "' + query + '"' : '';
|
||||
|
||||
if (!query) {
|
||||
statusEl.textContent = 'Enter a search term above.';
|
||||
return;
|
||||
}
|
||||
|
||||
statusEl.textContent = 'Searching\u2026';
|
||||
|
||||
fetch('/index.json')
|
||||
.then(function (res) {
|
||||
if (!res.ok) throw new Error('Failed to load search index');
|
||||
return res.json();
|
||||
})
|
||||
.then(function (items) {
|
||||
var terms = query.toLowerCase().split(/\s+/).filter(Boolean);
|
||||
|
||||
var matches = items
|
||||
.map(function (item) {
|
||||
var titleLower = (item.title || '').toLowerCase();
|
||||
var contentLower = (item.content || '').toLowerCase();
|
||||
var score = 0;
|
||||
terms.forEach(function (term) {
|
||||
if (titleLower.indexOf(term) !== -1) score += 10;
|
||||
if (contentLower.indexOf(term) !== -1) score += 1;
|
||||
});
|
||||
return { item: item, score: score };
|
||||
})
|
||||
.filter(function (m) {
|
||||
return m.score > 0;
|
||||
})
|
||||
.sort(function (a, b) {
|
||||
return b.score - a.score;
|
||||
});
|
||||
|
||||
listEl.innerHTML = '';
|
||||
|
||||
if (matches.length === 0) {
|
||||
statusEl.textContent = 'No results found for "' + query + '".';
|
||||
return;
|
||||
}
|
||||
|
||||
statusEl.textContent =
|
||||
matches.length + ' result' + (matches.length === 1 ? '' : 's') + ' found.';
|
||||
|
||||
matches.forEach(function (m) {
|
||||
var item = m.item;
|
||||
|
||||
var li = document.createElement('li');
|
||||
li.className = 'search-results__item';
|
||||
|
||||
var meta = document.createElement('span');
|
||||
meta.className = 'search-results__item-meta';
|
||||
meta.textContent = sectionLabel(item.section);
|
||||
|
||||
var h2 = document.createElement('h2');
|
||||
h2.className = 'search-results__item-title';
|
||||
var a = document.createElement('a');
|
||||
a.href = item.url;
|
||||
a.textContent = item.title;
|
||||
h2.appendChild(a);
|
||||
|
||||
var p = document.createElement('p');
|
||||
p.className = 'search-results__item-snippet';
|
||||
p.innerHTML = buildSnippet(item.content || '', terms[0] || query);
|
||||
|
||||
li.appendChild(meta);
|
||||
li.appendChild(h2);
|
||||
li.appendChild(p);
|
||||
listEl.appendChild(li);
|
||||
});
|
||||
})
|
||||
.catch(function () {
|
||||
statusEl.textContent = 'Something went wrong loading search results.';
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user