gallery.badmanners.xyz/src/components/TocMdx.astro

45 lines
1 KiB
Text

---
import TocMdxHeading from "./TocMdxHeading.astro";
type Props = {
headings: { depth: number; slug: string; text: string }[];
};
interface NestedHeading {
depth: number;
slug: string;
text: string;
children?: NestedHeading[];
}
const { headings } = Astro.props;
const nestedHeadings = headings.reduce((acc, heading) => {
if (acc.length === 0) {
acc.push({ ...heading });
} else {
let parent: NestedHeading | null = null;
let nextParent: NestedHeading = acc[acc.length - 1];
while (nextParent.depth < heading.depth) {
parent = nextParent;
if (!nextParent.children) {
nextParent.children = [];
break;
}
nextParent = nextParent.children[nextParent.children.length - 1];
}
if (parent === null) {
acc.push({ ...heading });
} else {
parent.children!.push({ ...heading });
}
}
return acc;
}, [] as NestedHeading[]);
---
<h2 id="table-of-contents">Table of contents</h2>
<nav>
<ul>
{nestedHeadings.map((heading) => <TocMdxHeading {...heading} />)}
</ul>
</nav>