blog.z0x.ca/src/components/TableOfContents.astro
2024-09-10 17:51:46 -07:00

47 lines
1.2 KiB
Text

---
import TableOfContentsHeading from './TableOfContentsHeading.astro'
// https://kld.dev/building-table-of-contents/
const { headings } = Astro.props
const toc = buildToc(headings)
export interface Heading {
depth: number
slug: string
text: string
}
function buildToc(headings: Heading[]) {
const toc: Heading[] = []
const parentHeadings = new Map()
headings.forEach((h) => {
const heading = { ...h, subheadings: [] }
parentHeadings.set(heading.depth, heading)
if (heading.depth === 2) {
toc.push(heading)
} else {
parentHeadings.get(heading.depth - 1).subheadings.push(heading)
}
})
return toc
}
---
<details open class="mb-8 block rounded-lg border p-3 xl:hidden">
<summary class="cursor-pointer text-xl font-semibold"
>Table of Contents</summary
>
<nav>
<ul class="py-3">
{toc.map((heading) => <TableOfContentsHeading heading={heading} />)}
</ul>
</nav>
</details>
<nav
class="overflow-wrap-break-word sticky top-16 hidden h-0 w-[calc(50vw-50%-4rem)] translate-x-[calc(-100%-2em)] text-xs leading-4 xl:block"
>
<h2 class="mb-4 text-xl font-semibold">Table of Contents</h2>
<ul class="space-y-2">
{toc.map((heading) => <TableOfContentsHeading heading={heading} />)}
</ul>
</nav>