Add desktop sidebar toggle with persistent state, search result highlighting, and improved filter icon positioning

This commit is contained in:
2026-03-22 23:37:53 -04:00
parent 8e1ae4be26
commit 6f694148db
3 changed files with 134 additions and 6 deletions
+79 -2
View File
@@ -368,6 +368,32 @@
return res.json();
}
// ---------------------------------------------------------------------------
// Sidebar toggle (desktop)
// ---------------------------------------------------------------------------
function initSidebarToggle() {
const toggleBtn = document.getElementById("sidebar-toggle-btn");
const sidebar = document.getElementById("sidebar");
const resizeHandle = document.getElementById("sidebar-resize-handle");
if (!toggleBtn || !sidebar || !resizeHandle) return;
// Restore saved state
const savedState = localStorage.getItem("obsigate-sidebar-hidden");
if (savedState === "true") {
sidebar.classList.add("hidden");
resizeHandle.classList.add("hidden");
toggleBtn.classList.add("active");
}
toggleBtn.addEventListener("click", () => {
const isHidden = sidebar.classList.toggle("hidden");
resizeHandle.classList.toggle("hidden", isHidden);
toggleBtn.classList.toggle("active", isHidden);
localStorage.setItem("obsigate-sidebar-hidden", isHidden ? "true" : "false");
});
}
// ---------------------------------------------------------------------------
// Mobile sidebar
// ---------------------------------------------------------------------------
@@ -1580,10 +1606,26 @@
const container = el("div", { class: "search-results" });
data.results.forEach((r) => {
// Create title with highlighting
const titleDiv = el("div", { class: "search-result-title" });
if (query && query.trim()) {
highlightSearchText(titleDiv, r.title, query, searchCaseSensitive);
} else {
titleDiv.textContent = r.title;
}
// Create snippet with highlighting
const snippetDiv = el("div", { class: "search-result-snippet" });
if (query && query.trim() && r.snippet) {
highlightSearchText(snippetDiv, r.snippet, query, searchCaseSensitive);
} else {
snippetDiv.textContent = r.snippet || "";
}
const item = el("div", { class: "search-result-item" }, [
el("div", { class: "search-result-title" }, [document.createTextNode(r.title)]),
titleDiv,
el("div", { class: "search-result-vault" }, [document.createTextNode(r.vault + " / " + r.path)]),
el("div", { class: "search-result-snippet" }, [document.createTextNode(r.snippet || "")]),
snippetDiv,
]);
if (r.tags && r.tags.length > 0) {
@@ -1764,6 +1806,40 @@
}
}
function highlightSearchText(container, text, query, caseSensitive) {
container.textContent = "";
if (!query || !text) {
container.appendChild(document.createTextNode(text || ""));
return;
}
const source = caseSensitive ? text : text.toLowerCase();
const needle = caseSensitive ? query : query.toLowerCase();
let start = 0;
let index = source.indexOf(needle, start);
if (index === -1) {
container.appendChild(document.createTextNode(text));
return;
}
while (index !== -1) {
if (index > start) {
container.appendChild(document.createTextNode(text.slice(start, index)));
}
const mark = el("mark", { class: "search-highlight" }, [
document.createTextNode(text.slice(index, index + query.length)),
]);
container.appendChild(mark);
start = index + query.length;
index = source.indexOf(needle, start);
}
if (start < text.length) {
container.appendChild(document.createTextNode(text.slice(start)));
}
}
function showWelcome() {
const area = document.getElementById("content-area");
area.innerHTML = `
@@ -2015,6 +2091,7 @@
document.getElementById("theme-toggle").addEventListener("click", toggleTheme);
document.getElementById("header-logo").addEventListener("click", goHome);
initSearch();
initSidebarToggle();
initMobile();
initVaultContext();
initSidebarTabs();