1
- import { useState , useRef , useEffect } from 'react' ;
1
+ import { useState , useRef , useEffect , useLayoutEffect } from 'react' ;
2
2
import Link from 'next/link' ;
3
+ import { useRouter } from 'next/router' ;
3
4
import TableOfContents from '../components/TableOfContents' ;
4
5
import { Container } from '../components/Container' ;
5
6
import { Footer } from '../components/Footer' ;
@@ -20,6 +21,8 @@ export default function WithSidebar(props) {
20
21
const sidebarEl = useRef ( null ) ;
21
22
const [ prevLink , setPrevLink ] = useState ( null ) ;
22
23
const [ nextLink , setNextLink ] = useState ( null ) ;
24
+ const [ isScrollRestored , setIsScrollRestored ] = useState ( false ) ;
25
+ const router = useRouter ( ) ;
23
26
const Sidebar =
24
27
meta . section && sidebars [ meta . section ] ? sidebars [ meta . section ] : null ;
25
28
let childrenWithTOC ;
@@ -63,18 +66,81 @@ export default function WithSidebar(props) {
63
66
}
64
67
} ;
65
68
69
+ const saveSidebarScrollPosition = ( ) => {
70
+ if ( sidebarEl . current && meta . section ) {
71
+ const scrollTop = sidebarEl . current . scrollTop ;
72
+ sessionStorage . setItem ( `sidebar-scroll-${ meta . section } ` , scrollTop . toString ( ) ) ;
73
+ }
74
+ } ;
75
+
76
+ const restoreSidebarScrollPosition = ( ) => {
77
+ if ( sidebarEl . current && meta . section && ! isScrollRestored ) {
78
+ const savedScrollTop = sessionStorage . getItem ( `sidebar-scroll-${ meta . section } ` ) ;
79
+ if ( savedScrollTop ) {
80
+ const scrollValue = parseInt ( savedScrollTop , 10 ) ;
81
+ sidebarEl . current . style . scrollBehavior = 'auto' ;
82
+ sidebarEl . current . scrollTop = scrollValue ;
83
+ setIsScrollRestored ( true ) ;
84
+ requestAnimationFrame ( ( ) => {
85
+ if ( sidebarEl . current ) {
86
+ sidebarEl . current . style . scrollBehavior = '' ;
87
+ }
88
+ } ) ;
89
+ } else {
90
+ setIsScrollRestored ( true ) ;
91
+ }
92
+ }
93
+ } ;
94
+
66
95
useEffect ( ( ) => {
67
96
setPrevNextLinks ( ) ;
68
97
} , [ ] ) ;
69
98
99
+ useEffect ( ( ) => {
100
+ setIsScrollRestored ( false ) ;
101
+ } , [ meta . section ] ) ;
102
+
103
+ useLayoutEffect ( ( ) => {
104
+ if ( sidebarEl . current && meta . section ) {
105
+ restoreSidebarScrollPosition ( ) ;
106
+ }
107
+ } , [ meta . section , isScrollRestored ] ) ;
108
+
109
+ useEffect ( ( ) => {
110
+ const sidebarElement = sidebarEl . current ;
111
+ if ( ! sidebarElement ) return ;
112
+
113
+ const handleScroll = ( ) => {
114
+ saveSidebarScrollPosition ( ) ;
115
+ } ;
116
+
117
+ const handleBeforeUnload = ( ) => {
118
+ saveSidebarScrollPosition ( ) ;
119
+ } ;
120
+
121
+ sidebarElement . addEventListener ( 'scroll' , handleScroll ) ;
122
+ window . addEventListener ( 'beforeunload' , handleBeforeUnload ) ;
123
+
124
+ const handleRouteChangeStart = ( ) => {
125
+ saveSidebarScrollPosition ( ) ;
126
+ } ;
127
+
128
+ router . events . on ( 'routeChangeStart' , handleRouteChangeStart ) ;
129
+
130
+ return ( ) => {
131
+ sidebarElement . removeEventListener ( 'scroll' , handleScroll ) ;
132
+ window . removeEventListener ( 'beforeunload' , handleBeforeUnload ) ;
133
+ router . events . off ( 'routeChangeStart' , handleRouteChangeStart ) ;
134
+ } ;
135
+ } , [ router . events , meta . section ] ) ;
136
+
70
137
return (
71
138
< >
72
139
< Header />
73
140
< Container className = "flex" >
74
141
< div
75
- className = { `${
76
- opened ? '' : 'hidden'
77
- } dark:bg-dark fixed top-16 left-0 z-20 mr-4 w-64 flex-none bg-white text-sm shadow-lg sm:mr-6 lg:relative lg:top-0 lg:mr-8 lg:block lg:shadow-none xl:mr-10`}
142
+ className = { `${ opened ? '' : 'hidden'
143
+ } dark:bg-dark fixed top-16 left-0 z-20 mr-4 w-64 flex-none bg-white text-sm shadow-lg sm:mr-6 lg:relative lg:top-0 lg:mr-8 lg:block lg:shadow-none xl:mr-10`}
78
144
>
79
145
< div
80
146
className = "sticky top-0 max-h-[calc(100vh-64px)] overflow-y-auto overscroll-contain px-4 py-10 pt-26 lg:px-0 lg:pt-10"
0 commit comments