'use client'; /** * Table of Contents - Variant C: Modern & Visual (Shopify-inspired) * * Design Philosophy: Floating card with colorful visual indicators * * Features: * - Wrapped in large gradient-bordered card * - Colorful dot indicators (alternating purple/cyan/amber) * - Large text sizes (text-base for items) * - Generous spacing (p-6, gap-4) * - Floating shadow effect with colored glow * - NO section numbers (more visual/playful) * - Active state with gradient background * - Smooth hover animations with scale * - Fun, engaging design with emoji header * * Visual Elements: * - Large colored dots instead of numbers * - Gradient progress bar with rainbow colors * - Active item with gradient highlight * - Hover effects with shadow and scale * * Behavior: * - Extracts H2 and H3 headings (no numbers) * - Shows reading progress with colorful bar * - Click to smooth scroll to section * - Visual feedback with animations */ import { useEffect, useState } from 'react'; interface TocItem { id: string; text: string; level: number; } interface DocsTOCCProps { items: TocItem[]; } const getColorForIndex = (index: number): string => { const colors = ['purple', 'cyan', 'amber']; return colors[index % colors.length]; }; const getDotClasses = (color: string, isActive: boolean): string => { const baseClasses = 'w-2.5 h-2.5 rounded-full flex-shrink-0 transition-all duration-300'; if (isActive) { return `${baseClasses} shadow-lg ${ color === 'purple' ? 'bg-purple-500 shadow-purple-500/50' : color === 'cyan' ? 'bg-cyan-500 shadow-cyan-500/50' : 'bg-amber-500 shadow-amber-500/50' }`; } return `${baseClasses} ${ color === 'purple' ? 'bg-purple-500/40' : color === 'cyan' ? 'bg-cyan-500/40' : 'bg-amber-500/40' }`; }; export const DocsTOCC = ({ items }: DocsTOCCProps) => { const [activeId, setActiveId] = useState(''); const [scrollProgress, setScrollProgress] = useState(0); useEffect(() => { const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { setActiveId(entry.target.id); } }); }, { rootMargin: '-20% 0px -35% 0px' } ); items.forEach((item) => { const element = document.getElementById(item.id); if (element) observer.observe(element); }); const handleScroll = () => { const windowHeight = window.innerHeight; const documentHeight = document.documentElement.scrollHeight; const scrollTop = window.scrollY; const progress = (scrollTop / (documentHeight - windowHeight)) * 100; setScrollProgress(Math.min(progress, 100)); }; window.addEventListener('scroll', handleScroll); return () => { observer.disconnect(); window.removeEventListener('scroll', handleScroll); }; }, [items]); const scrollToSection = (id: string) => { const element = document.getElementById(id); if (element) { element.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }; if (items.length === 0) { return null; } return ( ); };