Sidebar nav: full garden tree on every page
- buildNavTree: every non-draft page nested by vault folder; folders link to their (real or synthetic) index page and take its title when set - NavTree component: recursive details/summary tree, no JS — folders on the current path render open, current page gets aria-current styling - layout: sticky left sidebar >=72rem, flows after the footer as a site index on narrow screens Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
// Sidebar navigation tree: every non-draft page in the garden, nested by
|
||||
// vault folder. Folders link to their index page (real or synthetic).
|
||||
import { urlForId, slugForId } from './quartz-compat.mjs';
|
||||
|
||||
export function buildNavTree(entries) {
|
||||
const root = { children: new Map() };
|
||||
|
||||
const dirNode = (parts) => {
|
||||
let node = root;
|
||||
let acc = '';
|
||||
for (const seg of parts) {
|
||||
acc = acc ? `${acc}/${seg}` : seg;
|
||||
if (!node.children.has(seg)) {
|
||||
node.children.set(seg, {
|
||||
name: seg,
|
||||
url: '/' + slugForId(acc) + '/',
|
||||
children: new Map(),
|
||||
});
|
||||
}
|
||||
node = node.children.get(seg);
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
for (const e of entries) {
|
||||
if (e.data.draft || e.id === 'index') continue;
|
||||
const parts = e.id.split('/');
|
||||
const base = parts.pop();
|
||||
const folder = dirNode(parts);
|
||||
if (base === 'index') {
|
||||
// folder's own page: use its title for the folder label if set
|
||||
if (e.data.title) folder.name = e.data.title;
|
||||
continue;
|
||||
}
|
||||
folder.children.set(base, {
|
||||
name: e.data.title ?? base,
|
||||
url: urlForId(e.id),
|
||||
children: null,
|
||||
});
|
||||
}
|
||||
|
||||
const finalize = (node) => {
|
||||
const kids = [...node.children.values()].map((k) =>
|
||||
k.children ? finalize(k) : k,
|
||||
);
|
||||
kids.sort((a, b) => {
|
||||
const af = a.children ? 0 : 1;
|
||||
const bf = b.children ? 0 : 1;
|
||||
return af - bf || a.name.localeCompare(b.name, 'en', { sensitivity: 'base' });
|
||||
});
|
||||
return { ...node, children: kids };
|
||||
};
|
||||
|
||||
return finalize(root).children;
|
||||
}
|
||||
Reference in New Issue
Block a user