style: final consistency pass — theme, responsive, animations

This commit is contained in:
2026-06-01 20:36:42 -05:00
parent 533c166f3b
commit 274217c77f
4 changed files with 19 additions and 7 deletions

View File

@@ -8,10 +8,8 @@ interface TOCItem {
level: number;
}
export function TableOfContents() {
function useHeadings(): TOCItem[] {
const [headings, setHeadings] = useState<TOCItem[]>([]);
const [activeId, setActiveId] = useState("");
const observerRef = useRef<IntersectionObserver | null>(null);
useEffect(() => {
const elements = Array.from(
@@ -24,8 +22,19 @@ export function TableOfContents() {
level: el.tagName === "H2" ? 2 : 3,
}));
// eslint-disable-next-line react-hooks/set-state-in-effect
setHeadings(parsed);
}, []);
return headings;
}
export function TableOfContents() {
const [activeId, setActiveId] = useState("");
const observerRef = useRef<IntersectionObserver | null>(null);
const headings = useHeadings();
useEffect(() => {
observerRef.current = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
@@ -37,6 +46,10 @@ export function TableOfContents() {
{ rootMargin: "-20% 0px -70% 0px", threshold: 0 }
);
const elements = Array.from(
document.querySelectorAll("article h2, article h3")
) as HTMLElement[];
elements.forEach((el) => observerRef.current?.observe(el));
return () => observerRef.current?.disconnect();