@@ -39,7 +39,7 @@ import {
39
39
HttpErrorContent ,
40
40
} from '@/components' ;
41
41
import { LoginToContinueModal , BadgeModal } from '@/components/Modal' ;
42
- import { changeTheme , Storage } from '@/utils' ;
42
+ import { changeTheme , Storage , scrollToElementTop } from '@/utils' ;
43
43
import { useQueryNotificationStatus } from '@/services' ;
44
44
import { useExternalToast } from '@/hooks' ;
45
45
import { EXTERNAL_CONTENT_DISPLAY_MODE } from '@/common/constants' ;
@@ -58,6 +58,74 @@ const Layout: FC = () => {
58
58
const { show : showLoginToContinueModal } = loginToContinueStore ( ) ;
59
59
const { data : notificationData } = useQueryNotificationStatus ( ) ;
60
60
61
+ useEffect ( ( ) => {
62
+ // handle footnote links
63
+ const fixFootnoteLinks = ( ) => {
64
+ const footnoteLinks = document . querySelectorAll (
65
+ 'a[href^="#"]:not([data-footnote-fixed])' ,
66
+ ) ;
67
+
68
+ footnoteLinks . forEach ( ( link ) => {
69
+ link . setAttribute ( 'data-footnote-fixed' , 'true' ) ;
70
+ const href = link . getAttribute ( 'href' ) ;
71
+ link . addEventListener ( 'click' , ( e ) => {
72
+ e . preventDefault ( ) ;
73
+ const targetId = href ?. substring ( 1 ) || '' ;
74
+ const targetElement = document . getElementById ( targetId ) ;
75
+
76
+ if ( targetElement ) {
77
+ window . history . pushState ( null , '' , `${ location . pathname } ${ href } ` ) ;
78
+
79
+ scrollToElementTop ( targetElement ) ;
80
+ }
81
+ } ) ;
82
+ } ) ;
83
+
84
+ if ( window . location . hash ) {
85
+ const { hash } = window . location ;
86
+ const targetElement = document . getElementById ( hash . substring ( 1 ) ) ;
87
+
88
+ if ( targetElement ) {
89
+ setTimeout ( ( ) => {
90
+ scrollToElementTop ( targetElement ) ;
91
+ } , 100 ) ;
92
+ }
93
+ }
94
+ } ;
95
+ fixFootnoteLinks ( ) ;
96
+
97
+ const observer = new MutationObserver ( ( ) => {
98
+ fixFootnoteLinks ( ) ;
99
+ } ) ;
100
+
101
+ observer . observe ( document . body , {
102
+ childList : true ,
103
+ subtree : true ,
104
+ attributes : true ,
105
+ attributeFilter : [ 'id' , 'href' ] ,
106
+ } ) ;
107
+
108
+ const handleHashChange = ( ) => {
109
+ if ( window . location . hash ) {
110
+ const { hash } = window . location ;
111
+ const targetElement = document . getElementById ( hash . substring ( 1 ) ) ;
112
+
113
+ if ( targetElement ) {
114
+ setTimeout ( ( ) => {
115
+ scrollToElementTop ( targetElement ) ;
116
+ } , 100 ) ;
117
+ }
118
+ }
119
+ } ;
120
+
121
+ window . addEventListener ( 'hashchange' , handleHashChange ) ;
122
+
123
+ return ( ) => {
124
+ observer . disconnect ( ) ;
125
+ window . removeEventListener ( 'hashchange' , handleHashChange ) ;
126
+ } ;
127
+ } , [ location . pathname ] ) ;
128
+
61
129
useEffect ( ( ) => {
62
130
httpStatusReset ( ) ;
63
131
} , [ location ] ) ;
0 commit comments