@@ -564,17 +564,53 @@ export function TableOfContentMarkdown({
564564 markdown : string ;
565565 depth ?: number ;
566566} ) {
567+ // Add state to track the active section
568+ const [ activeSection , setActiveSection ] = useState < string | null > ( null ) ;
569+
570+ // Set up intersection observer to track which section is in view
571+ useEffect ( ( ) => {
572+ const headings = document . querySelectorAll ( 'h1, h2, h3, h4' ) ;
573+
574+ const observer = new IntersectionObserver (
575+ ( entries ) => {
576+ entries . forEach ( ( entry ) => {
577+ if ( entry . isIntersecting ) {
578+ setActiveSection ( entry . target . id ) ;
579+ }
580+ } ) ;
581+ } ,
582+ {
583+ rootMargin : '-100px 0px -80% 0px' ,
584+ threshold : 0
585+ }
586+ ) ;
587+
588+ headings . forEach ( ( heading ) => {
589+ observer . observe ( heading ) ;
590+ } ) ;
591+
592+ return ( ) => {
593+ headings . forEach ( ( heading ) => {
594+ observer . unobserve ( heading ) ;
595+ } ) ;
596+ } ;
597+ } , [ ] ) ;
598+
567599 return (
568600 < Markdown
569601 options = { {
570602 overrides : {
571603 h1 : {
572604 component : ( { children } ) => {
573605 const slug = slugifyMarkdownHeadline ( children ) ;
606+ const isActive = activeSection === slug ;
574607 return (
575608 < a
576609 href = { `#${ slug } ` }
577- className = 'flex cursor-pointer mb-3 max-sm:text-sm text-slate-600 dark:text-slate-300 leading-6 font-medium'
610+ className = { `flex cursor-pointer mb-3 max-sm:text-sm leading-6 font-medium ${ isActive
611+ ? 'text-blue-600 dark:text-blue-400 font-semibold bg-blue-50 dark:bg-slate-700 px-2 py-1 -ml-2 rounded'
612+ : 'text-slate-600 dark:text-slate-300'
613+ } `}
578614 >
579615 { children }
580616 </ a >
@@ -586,91 +622,107 @@ export function TableOfContentMarkdown({
586622 h2 :
587623 depth === 0
588624 ? {
625+ component : ( { children } ) => {
626+ const slug = slugifyMarkdownHeadline ( children ) ;
627+ const isActive = activeSection === slug ;
628+ return (
629+ < a
630+ href = { `#${ slug } ` }
631+ className = { `block cursor-pointer mb-3 leading-5 font-medium ml-4 ${ isActive
632+ ? 'text-blue-600 dark:text-blue-400 font-semibold bg-blue-50 dark:bg-slate-700 px-2 py-1 -ml-2 rounded'
633+ : 'text-slate-600 dark:text-slate-300'
634+ } `}
635+ >
636+ { children }
637+ </ a >
638+ ) ;
639+ } ,
640+ }
641+ : depth >= 2
642+ ? {
589643 component : ( { children } ) => {
590644 const slug = slugifyMarkdownHeadline ( children ) ;
645+ const [ isChrome , setIsChrome ] = useState ( false ) ;
646+ const isActive = activeSection === slug ;
647+
648+ useEffect ( ( ) => {
649+ const chromeCheck =
650+ / C h r o m e / . test ( navigator . userAgent ) &&
651+ / G o o g l e I n c / . test ( navigator . vendor ) ;
652+ setIsChrome ( chromeCheck ) ;
653+ } , [ ] ) ;
654+
591655 return (
656+ // chromeClass
592657 < a
593658 href = { `#${ slug } ` }
594- className = 'block cursor-pointer mb-3 text-slate-600 dark:text-slate-300 leading-5 font-medium ml-4'
659+ className = { `block cursor-pointer mb-3 max-sm:text-sm leading-4 max-sm:-ml-[6px] font-medium ${ isActive
660+ ? 'text-blue-600 dark:text-blue-400 font-semibold bg-blue-50 dark:bg-slate-700 px-2 py-1 rounded'
661+ : 'text-slate-600 dark:text-slate-300'
662+ } ${ isChrome ? '-ml-[4.8px]' : '-ml-[6.5px]' } `}
595663 >
664+ < span className = { `mr-1 text-[0.7em] ${ isActive ? 'text-blue-600 dark:text-blue-400' : 'text-blue-400' } ` } >
665+ ●
666+ </ span >
596667 { children }
597668 </ a >
598669 ) ;
599670 } ,
600671 }
601- : depth >= 2
602- ? {
603- component : ( { children } ) => {
604- const slug = slugifyMarkdownHeadline ( children ) ;
605- const [ isChrome , setIsChrome ] = useState ( false ) ;
606-
607- useEffect ( ( ) => {
608- const chromeCheck =
609- / C h r o m e / . test ( navigator . userAgent ) &&
610- / G o o g l e I n c / . test ( navigator . vendor ) ;
611- setIsChrome ( chromeCheck ) ;
612- } , [ ] ) ;
613-
614- return (
615- // chromeClass
616- < a
617- href = { `#${ slug } ` }
618- className = { `block cursor-pointer mb-3 max-sm:text-sm text-slate-600 dark:text-slate-300 leading-4 ] max-sm:-ml-[6px] font-medium ${ isChrome ? '-ml-[4.8px]' : '-ml-[6.5px]' } ` }
619- >
620- < span className = 'mr-1 text-blue-400 text-[0.7em]' >
621- ●
622- </ span >
623- { children }
624- </ a >
625- ) ;
626- } ,
627- }
628672 : { component : ( ) => null } ,
629673 h3 :
630674 depth >= 3
631675 ? {
632- component : ( { children } ) => {
633- const slug = slugifyMarkdownHeadline ( children ) ;
634- return (
635- < a
636- href = { `#${ slug } ` }
637- className = 'flex flex-row items-center cursor-pointer mb-3 max-sm:text-sm text-slate-600 dark:text-slate-300 leading-4 ml-[-0.25rem]'
638- >
639- < span className = 'text-blue-400/40 font-extrabold text-[0.8em] max-sm:text-[1.2em] ml-1' >
640- ——
641- </ span >
642- < span className = 'mr-1 text-blue-400/90 text-[0.7em] flex justify-center items-center' >
643- ●
644- </ span >
676+ component : ( { children } ) => {
677+ const slug = slugifyMarkdownHeadline ( children ) ;
678+ const isActive = activeSection === slug ;
679+ return (
680+ < a
681+ href = { `#${ slug } ` }
682+ className = { `flex flex-row items-center cursor-pointer mb-3 max-sm:text-sm leading-4 ml-[-0.25rem] ${ isActive
683+ ? 'text-blue-600 dark:text-blue-400 font-semibold bg-blue-50 dark:bg-slate-700 px-2 py-1 rounded'
684+ : 'text-slate-600 dark:text-slate-300'
685+ } `}
686+ >
687+ < span className = 'text-blue-400/40 font-extrabold text-[0.8em] max-sm:text-[1.2em] ml-1' >
688+ ——
689+ </ span >
690+ < span className = { `mr-1 text-[0.7em] flex justify-center items-center ${ isActive ? 'text-blue-600 dark:text-blue-400' : 'text-blue-400/90' } ` } >
691+ ●
692+ </ span >
645693
646- { children }
647- </ a >
648- ) ;
649- } ,
650- }
694+ { children }
695+ </ a >
696+ ) ;
697+ } ,
698+ }
651699 : { component : ( ) => null } ,
652700 h4 :
653701 depth >= 4
654702 ? {
655- component : ( { children } ) => {
656- const slug = slugifyMarkdownHeadline ( children ) ;
657- return (
658- < a
659- href = { `#${ slug } ` }
660- className = 'flex flex-row items-center cursor-pointer mb-3 max-sm:text-sm text-slate-600 dark:text-slate-300 leading-4 ml-[-0.25rem] '
661- >
662- < span className = 'text-blue-400/40 font-extrabold text-[0.8em] ml-1 max-sm:text-[1.2em]' >
663- ————
664- </ span >
665- < span className = 'mr-1 text-blue-400/90 text-[0.7em] flex justify-center items-center' >
666- ●
667- </ span >
703+ component : ( { children } ) => {
704+ const slug = slugifyMarkdownHeadline ( children ) ;
705+ const isActive = activeSection === slug ;
706+ return (
707+ < a
708+ href = { `#${ slug } ` }
709+ className = { `flex flex-row items-center cursor-pointer mb-3 max-sm:text-sm leading-4 ml-[-0.25rem] ${ isActive
710+ ? 'text-blue-600 dark:text-blue-400 font-semibold bg-blue-50 dark:bg-slate-700 px-2 py-1 rounded'
711+ : 'text-slate-600 dark:text-slate-300'
712+ } `}
713+ >
714+ < span className = 'text-blue-400/40 font-extrabold text-[0.8em] ml-1 max-sm:text-[1.2em]' >
715+ ————
716+ </ span >
717+ < span className = { `mr-1 text-[0.7em] flex justify-center items-center ${ isActive ? 'text-blue-600 dark:text-blue-400' : 'text-blue-400/90' } ` } >
718+ ●
719+ </ span >
668720
669- { children }
670- </ a >
671- ) ;
672- } ,
673- } /* eslint-enable */
721+ { children }
722+ </ a >
723+ ) ;
724+ } ,
725+ } /* eslint-enable */
674726 : { component : ( ) => null } ,
675727 ...hiddenElements (
676728 'strong' ,
0 commit comments