Add clickable breadcrumbs that focus and expand corresponding sidebar paths with vault panel auto-expansion and improved collapsed state styling

This commit is contained in:
Bruno Charest 2026-03-22 00:06:30 -04:00
parent fe30703a0d
commit 05dc436cea
2 changed files with 80 additions and 3 deletions

View File

@ -369,6 +369,61 @@
} }
} }
async function focusPathInSidebar(vaultName, targetPath, options) {
setPanelExpanded("vault", true);
const vaultItem = document.querySelector(`.vault-item[data-vault="${CSS.escape(vaultName)}"]`);
if (!vaultItem) return;
document.querySelectorAll(".vault-item.focused").forEach((el) => el.classList.remove("focused"));
vaultItem.classList.add("focused");
const vaultContainer = document.getElementById(`vault-children-${vaultName}`);
if (!vaultContainer) return;
if (vaultContainer.classList.contains("collapsed")) {
await toggleVault(vaultItem, vaultName, true);
}
if (!targetPath) {
scrollTreeItemIntoView(vaultItem, options && options.alignToTop);
return;
}
const segments = targetPath.split("/").filter(Boolean);
let currentContainer = vaultContainer;
let cumulativePath = "";
for (let index = 0; index < segments.length; index++) {
cumulativePath += (cumulativePath ? "/" : "") + segments[index];
let targetItem = null;
try {
targetItem = currentContainer.querySelector(`.tree-item[data-vault="${CSS.escape(vaultName)}"][data-path="${CSS.escape(cumulativePath)}"]`);
} catch (e) {
targetItem = null;
}
if (!targetItem) {
return;
}
const isLastSegment = index === segments.length - 1;
if (!isLastSegment) {
const nextContainer = document.getElementById(`dir-${vaultName}-${cumulativePath}`);
if (nextContainer && nextContainer.classList.contains("collapsed")) {
targetItem.click();
await new Promise((resolve) => setTimeout(resolve, 0));
}
if (nextContainer) {
currentContainer = nextContainer;
}
}
scrollTreeItemIntoView(targetItem, Boolean(options && options.alignToTop && isLastSegment));
}
}
async function loadDirectory(vaultName, dirPath, container) { async function loadDirectory(vaultName, dirPath, container) {
const url = `/api/browse/${encodeURIComponent(vaultName)}?path=${encodeURIComponent(dirPath)}`; const url = `/api/browse/${encodeURIComponent(vaultName)}?path=${encodeURIComponent(dirPath)}`;
const data = await api(url); const data = await api(url);
@ -613,16 +668,22 @@
// Breadcrumb // Breadcrumb
const parts = data.path.split("/"); const parts = data.path.split("/");
const breadcrumbEls = []; const breadcrumbEls = [];
breadcrumbEls.push(makeBreadcrumbSpan(data.vault, () => {})); breadcrumbEls.push(makeBreadcrumbSpan(data.vault, () => {
focusPathInSidebar(data.vault, "", { alignToTop: true });
}));
let accumulated = ""; let accumulated = "";
parts.forEach((part, i) => { parts.forEach((part, i) => {
breadcrumbEls.push(el("span", { class: "sep" }, [document.createTextNode(" / ")])); breadcrumbEls.push(el("span", { class: "sep" }, [document.createTextNode(" / ")]));
accumulated += (accumulated ? "/" : "") + part; accumulated += (accumulated ? "/" : "") + part;
const p = accumulated; const p = accumulated;
if (i < parts.length - 1) { if (i < parts.length - 1) {
breadcrumbEls.push(makeBreadcrumbSpan(part, () => {})); breadcrumbEls.push(makeBreadcrumbSpan(part, () => {
focusPathInSidebar(data.vault, p, { alignToTop: true });
}));
} else { } else {
breadcrumbEls.push(el("span", {}, [document.createTextNode(part.replace(/\.md$/i, ""))])); breadcrumbEls.push(makeBreadcrumbSpan(part.replace(/\.md$/i, ""), () => {
focusPathInSidebar(data.vault, data.path, { alignToTop: false });
}));
} }
}); });

View File

@ -318,6 +318,18 @@ a:hover {
flex: 1 1 auto; flex: 1 1 auto;
min-height: 0; min-height: 0;
max-height: none; max-height: none;
padding-top: 0;
}
.sidebar.vault-collapsed .sidebar-tree {
flex: 0 0 auto;
min-height: 0;
padding-bottom: 0;
}
.sidebar.vault-collapsed .tag-resize-handle {
border-top: none;
height: 0;
} }
.sidebar.tag-collapsed .sidebar-tree { .sidebar.tag-collapsed .sidebar-tree {
@ -577,6 +589,10 @@ a:hover {
display: none; display: none;
} }
.sidebar.vault-collapsed .tag-panel-toggle {
border-top: 1px solid var(--border);
}
/* --- Sidebar resize handle (horizontal) --- */ /* --- Sidebar resize handle (horizontal) --- */
.sidebar-resize-handle { .sidebar-resize-handle {
width: 5px; width: 5px;