(function () {
var overlay, inputEl, resultsEl;
var indexLoaded = false;
var pages = [];
function ensureElements() {
if (!overlay) {
overlay = document.querySelector("[data-search-overlay]");
}
if (!inputEl && overlay) {
inputEl = overlay.querySelector("[data-search-input]");
}
if (!resultsEl && overlay) {
resultsEl = overlay.querySelector("[data-search-results]");
}
}
function loadIndex() {
if (indexLoaded) return;
indexLoaded = true;
fetch("/index.json")
.then(function (r) {
if (!r.ok) throw new Error("index.json not found");
return r.json();
})
.then(function (data) {
pages = (data && data.pages) || [];
})
.catch(function () {
pages = [];
});
}
function openOverlay() {
ensureElements();
if (!overlay) return;
overlay.classList.remove("search-overlay");
overlay.classList.add("search-overlay--open");
loadIndex();
if (inputEl) {
setTimeout(function () {
inputEl.focus();
}, 20);
}
}
function closeOverlay() {
ensureElements();
if (!overlay) return;
if (overlay.classList.contains("search-overlay--closing")) return;
overlay.classList.add("search-overlay--closing");
setTimeout(function () {
overlay.classList.remove("search-overlay--open");
overlay.classList.remove("search-overlay--closing");
overlay.classList.add("search-overlay");
if (inputEl) inputEl.value = "";
if (resultsEl) {
resultsEl.innerHTML =
'
' +
'
' +
'
Start searching
' +
'
Enter keywords to search articles.
' +
"
";
}
}, 180);
}
function filterPages(query) {
if (!pages.length) return [];
var q = (query || "").toLowerCase().trim();
if (!q) return [];
return pages
.filter(function (p) {
var t = (p.title || "").toLowerCase();
var s = (p.summary || "").toLowerCase();
return t.indexOf(q) !== -1 || s.indexOf(q) !== -1;
})
.slice(0, 20);
}
function highlightText(text, query) {
if (!query) return text;
var regex = new RegExp("(" + query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + ")", "gi");
return text.replace(regex, '$1');
}
function getSectionIcon(section) {
var icons = {
blog: "fa-regular fa-note-sticky",
projects: "fa-regular fa-folder-open",
posts: "fa-regular fa-note-sticky",
};
return icons[section.toLowerCase()] || "fa-regular fa-file";
}
function truncateText(text, maxLength) {
if (!text || text.length <= maxLength) return text;
return text.substring(0, maxLength) + "...";
}
function renderResults(query) {
ensureElements();
if (!resultsEl) return;
var q = (query || "").trim();
if (!q) {
resultsEl.innerHTML =
'' +
'
' +
'
Start searching
' +
'
Enter keywords to search articles.
' +
"
";
return;
}
var matches = filterPages(q);
if (!matches.length) {
resultsEl.innerHTML =
'' +
'
' +
'
No results found
' +
'
Try different keywords or check your spelling.
' +
"
";
return;
}
var html = matches
.map(function (p, index) {
var title = highlightText(p.title || "Untitled", q);
var section = p.section || "";
var summary = truncateText(p.summary || "", 120);
var highlightedSummary = highlightText(summary, q);
var icon = getSectionIcon(section);
var date = p.date ? new Date(p.date).toLocaleDateString("en-US", {
year: "numeric",
month: "short",
day: "numeric"
}) : "";
return (
'' +
'" +
(highlightedSummary ? '' + highlightedSummary + "
" : "") +
""
);
})
.join("");
resultsEl.innerHTML = html;
// Add keyboard navigation
addKeyboardNavigation();
}
var selectedIndex = -1;
function addKeyboardNavigation() {
ensureElements();
if (!inputEl) return;
var items = resultsEl.querySelectorAll(".search-result-item");
inputEl.addEventListener("keydown", function(e) {
if (e.key === "ArrowDown") {
e.preventDefault();
selectedIndex = Math.min(selectedIndex + 1, items.length - 1);
updateSelection(items);
} else if (e.key === "ArrowUp") {
e.preventDefault();
selectedIndex = Math.max(selectedIndex - 1, -1);
updateSelection(items);
} else if (e.key === "Enter" && selectedIndex >= 0) {
e.preventDefault();
items[selectedIndex].click();
}
});
}
function updateSelection(items) {
items.forEach(function(item, index) {
if (index === selectedIndex) {
item.classList.add("search-result-item--selected");
item.scrollIntoView({ block: "nearest", behavior: "smooth" });
} else {
item.classList.remove("search-result-item--selected");
}
});
}
function initSearch() {
ensureElements();
if (!overlay) return;
// Close and ESC
overlay.querySelectorAll("[data-search-close]").forEach(function (el) {
el.addEventListener("click", closeOverlay);
});
document.addEventListener("keydown", function (e) {
if (e.key === "Escape") closeOverlay();
});
// Typing
if (inputEl) {
inputEl.addEventListener("input", function (e) {
renderResults(e.target.value || "");
});
}
// Ctrl/Cmd + K to open
document.addEventListener("keydown", function (e) {
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "k") {
e.preventDefault();
openOverlay();
}
});
// Expose global API for inline onclick
window.MinimalSearch = {
open: openOverlay,
close: closeOverlay,
};
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initSearch);
} else {
initSearch();
}
})();