fix(blog): collapse inactive toc branches
Some checks failed
Frontend CI/CD / build (push) Has been cancelled
Frontend CI/CD / deploy (push) Has been cancelled

This commit is contained in:
2026-06-12 11:21:19 +03:30
parent e06a4b1cf8
commit bced5dceb1

View File

@@ -8,9 +8,37 @@ type Props = {
headings: MarkdownHeading[]; headings: MarkdownHeading[];
}; };
function getParentHeading(headings: MarkdownHeading[], index: number) {
const heading = headings[index];
for (let cursor = index - 1; cursor >= 0; cursor -= 1) {
if (headings[cursor].level < heading.level) {
return headings[cursor];
}
}
return null;
}
export default function BlogTableOfContents({ headings }: Props) { export default function BlogTableOfContents({ headings }: Props) {
const [activeId, setActiveId] = useState(headings[0]?.id ?? ""); const [activeId, setActiveId] = useState(headings[0]?.id ?? "");
const parentById = new Map<string, string | null>();
headings.forEach((heading, index) => {
parentById.set(heading.id, getParentHeading(headings, index)?.id ?? null);
});
const activeBranch = new Set<string>();
let cursor = activeId;
while (cursor) {
activeBranch.add(cursor);
cursor = parentById.get(cursor) ?? "";
}
const visibleHeadings = headings.filter((heading) => {
const parentId = parentById.get(heading.id);
if (!parentId) return true;
return activeBranch.has(parentId);
});
useEffect(() => { useEffect(() => {
if (!headings.length) return; if (!headings.length) return;
@@ -51,7 +79,7 @@ export default function BlogTableOfContents({ headings }: Props) {
return ( return (
<nav className="space-y-1 text-sm"> <nav className="space-y-1 text-sm">
{headings.map((heading) => { {visibleHeadings.map((heading) => {
const active = activeId === heading.id; const active = activeId === heading.id;
return ( return (
<button <button