@@ -50,6 +50,16 @@ function useActiveTocItem(ids: string[]) {
5050export function TableOfContents ( { toc, className } : { toc : TocItem [ ] ; className ?: string } ) {
5151 const ids = toc . map ( ( item ) => item . url )
5252 const activeId = useActiveTocItem ( ids )
53+ const tocItemRefs = useRef < Map < string , HTMLLIElement > > ( new Map ( ) )
54+
55+ useEffect ( ( ) => {
56+ if ( ! activeId ) return
57+
58+ tocItemRefs . current . get ( `#${ activeId } ` ) ?. scrollIntoView ( {
59+ block : 'nearest' ,
60+ inline : 'nearest' ,
61+ } )
62+ } , [ activeId ] )
5363
5464 return (
5565 < details className = { clsx ( 'space-y-4 [&_.chevron-right]:open:rotate-90' , className ) } open >
@@ -61,17 +71,25 @@ export function TableOfContents({ toc, className }: { toc: TocItem[]; className?
6171 />
6272 < span className = "text-lg font-medium" > On this page</ span >
6373 </ summary >
64- < ul className = "flex flex-col space-y-2" >
74+ < ul className = "no-scrollbar flex flex-col space-y-2 lg:max-h-[calc(100vh-16rem)] lg:overflow-y-auto lg:pr -2" >
6575 { toc . map ( ( { value, depth, url } ) => (
6676 < li
6777 key = { url }
78+ ref = { ( node ) => {
79+ if ( node ) {
80+ tocItemRefs . current . set ( url , node )
81+ return
82+ }
83+
84+ tocItemRefs . current . delete ( url )
85+ } }
6886 className = { clsx ( [
69- 'font-medium' ,
87+ 'font-medium transition-colors duration-200 ' ,
7088 url === `#${ activeId } `
7189 ? 'text-gray-700 dark:text-gray-200'
7290 : 'text-gray-400 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-200' ,
7391 ] ) }
74- style = { { paddingLeft : ( depth - 2 ) * 16 } }
92+ style = { { paddingLeft : Math . max ( 0 , depth - 2 ) * 16 } }
7593 >
7694 < Link href = { url } > { value } </ Link >
7795 </ li >
0 commit comments