(function () {
var prefix = window.__PREFIX__ || ".";
var input = document.getElementById("search-input");
var results = document.getElementById("search-results");
if (!input || !results) return;
var indexPromise = null;
var selectedIndex = -1;
function loadIndex() {
if (indexPromise) return indexPromise;
indexPromise = new Promise(function (resolve) {
var script = document.createElement("script");
script.src = prefix + "/static/search-index.js";
script.onload = function () {
if (!window.__SEARCH_INDEX__) {
console.error("search-index loaded but set no index: " + script.src);
}
resolve(window.__SEARCH_INDEX__ || []);
};
script.onerror = function () {
console.error("search-index failed to load: " + script.src);
resolve([]);
};
document.head.appendChild(script);
});
return indexPromise;
}
function score(entry, q) {
var ql = q.toLowerCase();
if (entry.title.toLowerCase().indexOf(ql) !== -1) return 3;
if (entry.tags.some(function (t) { return t.toLowerCase().indexOf(ql) !== -1; })) return 2;
if (entry.ingredients.some(function (i) { return i.toLowerCase().indexOf(ql) !== -1; })) return 1;
return 0;
}
function escapeHtml(s) {
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
}
function render(matches) {
if (matches.length === 0) {
results.innerHTML = '<div class="p-4 text-muted text-center">No recipes found</div>';
} else {
results.innerHTML = matches.map(function (m) {
var href = prefix + "/" + m.path;
return '<a href="' + escapeHtml(href) + '" class="search-result block px-4 py-3 hover:bg-sunk border-b border-line last:border-b-0">' +
'<div class="font-medium text-text">' + escapeHtml(m.title) + '</div>' +
'</a>';
}).join("");
}
results.classList.remove("hidden");
}
function updateSearchSelection() {
var items = results.querySelectorAll("a");
items.forEach(function (item, i) {
if (i === selectedIndex) {
item.classList.add("search-selected");
item.scrollIntoView({ block: "nearest" });
} else {
item.classList.remove("search-selected");
}
});
}
var timeout;
input.addEventListener("input", function () {
clearTimeout(timeout);
var q = this.value.trim();
selectedIndex = -1;
if (q.length < 2) {
results.classList.add("hidden");
return;
}
timeout = setTimeout(function () {
loadIndex().then(function (idx) {
var matches = idx
.map(function (e) { return { e: e, s: score(e, q) }; })
.filter(function (x) { return x.s > 0; })
.sort(function (a, b) { return b.s - a.s; })
.slice(0, 20)
.map(function (x) { return x.e; });
render(matches);
});
}, 150);
});
input.addEventListener("keydown", function (e) {
var items = results.querySelectorAll("a");
if (items.length === 0 || results.classList.contains("hidden")) return;
if (e.key === "ArrowDown") {
e.preventDefault();
selectedIndex = Math.min(selectedIndex + 1, items.length - 1);
updateSearchSelection();
} else if (e.key === "ArrowUp") {
e.preventDefault();
selectedIndex = Math.max(selectedIndex - 1, -1);
updateSearchSelection();
} else if (e.key === "Enter") {
if (selectedIndex >= 0 && selectedIndex < items.length) {
e.preventDefault();
items[selectedIndex].click();
}
}
});
document.addEventListener("click", function (e) {
if (!input.contains(e.target) && !results.contains(e.target)) {
results.classList.add("hidden");
selectedIndex = -1;
}
});
})();