45 lines
1 KiB
Text
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>
|