Something went wrong. Try again.
very fast at protocol indexer with flexible filtering, xrpc queries, cursor-backed event stream, and more, built on fjall
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455// the list beside the paper: selection, and folding. a section opens when the selection moves// into it and closes again when it leaves, unless you opened it by hand with its triangle.
export interface Tree { /** select the entry linking to #key ("" is the top of the page) */ select(key: string): void; /** entries in list order that aren't folded away, for ↑↓ */ visible(): string[];}
/** `side` is Tree.astro's column: the title and the list */export function tree(side: HTMLElement): Tree { const list = side.querySelector<HTMLElement>(".tree")!; const links = new Map([...side.querySelectorAll<HTMLAnchorElement>("[data-to]")].map((a) => [a.dataset.to!, a])); const open = new Set<string>(); let auto: string | null = null;
const fold = () => list.querySelectorAll<HTMLElement>("[data-grp]").forEach((g) => { const isOpen = open.has(g.dataset.grp!); g.classList.toggle("open", isOpen); g.querySelector("[data-fold]")?.setAttribute("aria-expanded", String(isOpen)); });
list.addEventListener("click", (e) => { const btn = (e.target as HTMLElement).closest<HTMLElement>("[data-fold]"); if (!btn) return; const g = btn.dataset.fold!; open.has(g) ? open.delete(g) : open.add(g); if (auto === g) auto = null; fold(); });
return { select(key) { const link = links.get(key); links.forEach((a, k) => a.classList.toggle("sel", k === key)); const group = link?.closest<HTMLElement>("[data-grp]")?.dataset.grp ?? null; if (auto && auto !== group) open.delete(auto); if (group && !open.has(group)) { open.add(group); auto = group; } fold(); // scroll the list only, never the page around it if (link) { const r = link.getBoundingClientRect(), box = list.getBoundingClientRect(); if (r.top < box.top) list.scrollTop -= box.top - r.top; else if (r.bottom > box.bottom) list.scrollTop += r.bottom - box.bottom; } }, visible: () => [...links].filter(([, a]) => a.offsetParent).map(([k]) => k), };}