"use client" import { useState, useEffect } from "react" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Badge } from "@/components/ui/badge" import { List, ChevronRight, Hash } from "lucide-react" interface TOCItem { id: string title: string level: number } interface TableOfContentsProps { items: TOCItem[] className?: string } export default function TableOfContents({ items, className = "" }: TableOfContentsProps) { const [activeId, setActiveId] = useState("") const [isVisible, setIsVisible] = useState(false) // Read initial hash from URL on mount useEffect(() => { const hash = window.location.hash.slice(1) // Remove the # symbol if (hash && items.some(item => item.id === hash)) { setActiveId(hash) } }, [items]) // Listen for hash changes useEffect(() => { const handleHashChange = () => { const hash = window.location.hash.slice(1) // Remove the # symbol if (hash && items.some(item => item.id === hash)) { setActiveId(hash) } } window.addEventListener('hashchange', handleHashChange) return () => window.removeEventListener('hashchange', handleHashChange) }, [items]) useEffect(() => { if (items.length === 0) return // Calculate header height dynamically const header = document.querySelector('header') const headerHeight = header ? header.offsetHeight + 20 : 100 // 20px buffer const rootMargin = `-${headerHeight}px 0% -35% 0%` const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { setActiveId(entry.target.id) // Update URL hash when scrolling to a section if (window.location.hash !== `#${entry.target.id}`) { window.history.replaceState(null, '', `#${entry.target.id}`) } } }) }, { rootMargin, threshold: 0.1, } ) // Observe all TOC items items.forEach((item) => { const element = document.getElementById(item.id) if (element) { observer.observe(element) } }) return () => { items.forEach((item) => { const element = document.getElementById(item.id) if (element) { observer.unobserve(element) } }) } }, [items]) useEffect(() => { // Show TOC if there are items setIsVisible(items.length > 0) }, [items]) const scrollToSection = (id: string) => { const element = document.getElementById(id) if (element) { // Update URL hash immediately window.history.pushState(null, '', `#${id}`) setActiveId(id) // Get the actual header height dynamically const header = document.querySelector('header') const headerHeight = header ? header.offsetHeight + 20 : 100 // 20px buffer const elementPosition = element.offsetTop - headerHeight // Add a small delay to ensure smooth scrolling setTimeout(() => { window.scrollTo({ top: Math.max(0, elementPosition), // Ensure we don't scroll to negative position behavior: "smooth" }) }, 10) } } if (!isVisible) return null return ( ) }