-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTableOfContents.tsx
More file actions
53 lines (46 loc) · 1.26 KB
/
Copy pathTableOfContents.tsx
File metadata and controls
53 lines (46 loc) · 1.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
"use client";
import { useEffect, useState } from "react";
import type { Heading } from "@/types";
export function TableOfContents({ headings }: { headings: Heading[] }) {
const [activeId, setActiveId] = useState<string>("");
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
setActiveId(entry.target.id);
}
}
},
{ rootMargin: "-80px 0px -70% 0px" }
);
for (const heading of headings) {
const el = document.getElementById(heading.id);
if (el) observer.observe(el);
}
return () => observer.disconnect();
}, [headings]);
if (headings.length === 0) return null;
return (
<aside className="layout-toc hidden xl:block">
<h4
className="text-xs font-semibold mb-3"
style={{ color: "var(--text-500)" }}
>
On this page
</h4>
<nav className="space-y-0.5">
{headings.map((h) => (
<a
key={h.id}
href={`#${h.id}`}
data-level={h.level}
className={`toc-link ${activeId === h.id ? "active" : ""}`}
>
{h.text}
</a>
))}
</nav>
</aside>
);
}