'use client'; import { useEffect, useState } from 'react'; interface TocItem { id: string; text: string; depth: number; } export function PostToc() { const [items, setItems] = useState([]); const [activeId, setActiveId] = useState(null); useEffect(() => { const headings = Array.from( document.querySelectorAll('article h2, article h3') ); const mapped = headings .filter((el) => el.id) .map((el) => ({ id: el.id, text: el.innerText, depth: el.tagName === 'H3' ? 3 : 2 })); setItems(mapped); const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { const id = (entry.target as HTMLElement).id; if (id) { setActiveId(id); } } }); }, { // Trigger when heading is in upper 40% of viewport rootMargin: '0px 0px -60% 0px', threshold: 0.1 } ); headings.forEach((el) => observer.observe(el)); return () => observer.disconnect(); }, []); if (items.length === 0) return null; return ( ); }