'use client'; import { useState, useEffect } from 'react'; interface TableOfContentsProps { className?: string; } interface Section { id: string; title: string; level: number; } export function TableOfContents({ className = '' }: TableOfContentsProps) { const [activeSection, setActiveSection] = useState(''); const [sections, setSections] = useState([]); useEffect(() => { const extractSections = () => { const sectionsWithId = document.querySelectorAll('section[id]'); const extractedSections: Section[] = Array.from(sectionsWithId).map((section) => { const h2 = section.querySelector('h2'); return { id: section.id, title: h2?.textContent || section.id, level: 2 }; }); setSections(extractedSections); return sectionsWithId; }; // Fonction pour configurer l'intersection observer const setupIntersectionObserver = (sections: NodeListOf) => { const intersectionObserver = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { setActiveSection(entry.target.id); } }); }, { rootMargin: '-20% 0px -70% 0px', threshold: 0 } ); sections.forEach((section) => intersectionObserver.observe(section)); return intersectionObserver; }; // Essayer immédiatement let sectionsElements = extractSections(); let intersectionObserver: IntersectionObserver | null = null; if (sectionsElements.length > 0) { intersectionObserver = setupIntersectionObserver(sectionsElements); } else { // Utiliser MutationObserver pour surveiller les changements const mutationObserver = new MutationObserver((mutations) => { let shouldCheck = false; mutations.forEach((mutation) => { if (mutation.type === 'childList') { // Vérifier si des sections ont été ajoutées mutation.addedNodes.forEach((node) => { if (node.nodeType === Node.ELEMENT_NODE) { const element = node as Element; if (element.tagName === 'SECTION' || element.querySelector('section[id]')) { shouldCheck = true; } } }); } }); if (shouldCheck) { sectionsElements = extractSections(); if (sectionsElements.length > 0 && !intersectionObserver) { intersectionObserver = setupIntersectionObserver(sectionsElements); mutationObserver.disconnect(); } } }); // Surveiller le contenu principal const mainContent = document.querySelector('.lg\\:col-span-3') || document.body; mutationObserver.observe(mainContent, { childList: true, subtree: true }); // Fallback avec des tentatives périodiques const intervalId = setInterval(() => { sectionsElements = extractSections(); if (sectionsElements.length > 0) { if (!intersectionObserver) { intersectionObserver = setupIntersectionObserver(sectionsElements); } mutationObserver.disconnect(); clearInterval(intervalId); } }, 1000); return () => { mutationObserver.disconnect(); clearInterval(intervalId); if (intersectionObserver) { sectionsElements.forEach((section) => intersectionObserver!.unobserve(section)); } }; } return () => { if (intersectionObserver) { sectionsElements.forEach((section) => intersectionObserver!.unobserve(section)); } }; }, []); const scrollToSection = (sectionId: string) => { const element = document.getElementById(sectionId); if (element) { element.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }; return ( ); }