11import { untrack } from "svelte" ;
2- import { page } from "$app/stores" ;
3- import { fromStore } from "svelte/store" ;
2+ import { page } from "$app/state" ;
43import { addEventListener } from "svelte-toolbelt" ;
54
65export type TocItem = {
@@ -16,14 +15,53 @@ export type TableOfContents = {
1615export function useToc ( getItemIds : ( ) => string [ ] ) {
1716 const itemIds = $derived ( getItemIds ( ) ) ;
1817 let activeId = $state < string | null > ( null ) ;
19- const pageState = fromStore ( page ) ;
20- const urlHash = $derived ( pageState . current . url . hash ) ;
18+ const urlHash = $derived ( page . url . hash ) ;
2119 const isAtBottom = useIsAtBottom ( ) ;
2220
23- const activeIndex = $derived ( itemIds . findIndex ( ( id ) => id === activeId ) ) ;
24- const markerTopStyle = $derived . by ( ( ) => {
25- if ( activeIndex === - 1 ) return "0px" ;
26- return activeIndex * 28 + "px" ;
21+ let markerTopStyle = $state ( "0px" ) ;
22+ let markerHeightStyle = $state ( "20px" ) ;
23+
24+ $effect ( ( ) => {
25+ if ( ! activeId ) {
26+ markerTopStyle = "0px" ;
27+ return ;
28+ }
29+
30+ requestAnimationFrame ( ( ) => {
31+ const tocContainer = document . querySelector ( "[data-toc-container]" ) ;
32+ if ( ! tocContainer ) return ;
33+
34+ const tocLinks = Array . from ( tocContainer . querySelectorAll ( "a[href]" ) ) ;
35+
36+ let targetIndex = - 1 ;
37+ let targetElement : Element | null = null ;
38+ for ( let i = 0 ; i < tocLinks . length ; i ++ ) {
39+ const href = tocLinks [ i ] . getAttribute ( "href" ) ;
40+ if ( href && href . includes ( `#${ activeId } ` ) ) {
41+ targetIndex = i ;
42+ targetElement = tocLinks [ i ] ;
43+ break ;
44+ }
45+ }
46+
47+ if ( targetIndex === - 1 || ! targetElement ) {
48+ const oldIndex = itemIds . findIndex ( ( id ) => id === activeId ) ;
49+ markerTopStyle = oldIndex * 28 + "px" ;
50+ markerHeightStyle = "20px" ;
51+ return ;
52+ }
53+
54+ let totalHeight = 0 ;
55+ for ( let i = 0 ; i < targetIndex ; i ++ ) {
56+ totalHeight += tocLinks [ i ] . getBoundingClientRect ( ) . height ;
57+ }
58+
59+ const activeElementHeight = targetElement . getBoundingClientRect ( ) . height ;
60+
61+ markerTopStyle = totalHeight + "px" ;
62+ const isLastItem = targetIndex === tocLinks . length - 1 ;
63+ markerHeightStyle = activeElementHeight - ( isLastItem ? 0 : 8 ) + "px" ;
64+ } ) ;
2765 } ) ;
2866
2967 function isActive ( item : TocItem ) {
@@ -91,6 +129,9 @@ export function useToc(getItemIds: () => string[]) {
91129 get markerTopStyle ( ) {
92130 return markerTopStyle ;
93131 } ,
132+ get markerHeightStyle ( ) {
133+ return markerHeightStyle ;
134+ } ,
94135 isActive,
95136 isLastItem,
96137 } ;
0 commit comments