1
- import React , { useState , useEffect } from 'react' ;
1
+ import React , { useState , useEffect , useRef } from 'react' ;
2
2
import Hamburger from "./Hamburger" ;
3
3
import MobileSideBarMenuContents from './Content' ;
4
4
import styles from './styles.module.scss' ;
5
+ import { useLocation , useHistory } from '@docusaurus/router' ;
5
6
6
7
const MobileSideBarMenu = ( { sidebar, menu} ) => {
7
- const [ currentMenuState , setMenuState ] = useState ( false ) ;
8
+ const [ currentMenuState , setMenuState ] = useState ( ( ) => {
9
+ // Try to restore menu state from sessionStorage on mount
10
+ const savedMenuState = sessionStorage . getItem ( 'mobilemenu_open' ) ;
11
+ return savedMenuState === 'true' ;
12
+ } ) ;
13
+ const location = useLocation ( ) ;
14
+ const history = useHistory ( ) ;
15
+ const previousLocationRef = useRef ( null ) ;
16
+ const isLanguageChangeRef = useRef ( false ) ;
17
+ const languageChangeTimeoutRef = useRef ( null ) ;
18
+
19
+ // Save menu state to sessionStorage whenever it changes
20
+ useEffect ( ( ) => {
21
+ sessionStorage . setItem ( 'mobilemenu_open' , currentMenuState . toString ( ) ) ;
22
+ } , [ currentMenuState ] ) ;
8
23
9
24
// Define the breakpoint where mobile menu should be hidden (laptop breakpoint)
10
25
const LAPTOP_BREAKPOINT = 1330 ;
11
26
27
+ // Initialize the previous location ref on first render and monitor location changes
28
+ useEffect ( ( ) => {
29
+ const currentPath = location . pathname ;
30
+ const previousPath = previousLocationRef . current ;
31
+
32
+ // On first render, check if we can get previous path from sessionStorage
33
+ if ( previousPath === null ) {
34
+ const storedPreviousPath = sessionStorage . getItem ( 'mobilemenu_previous_path' ) ;
35
+
36
+ if ( storedPreviousPath && storedPreviousPath !== currentPath ) {
37
+ // We have a stored previous path that's different from current
38
+ previousLocationRef . current = storedPreviousPath ;
39
+ // Continue with path change detection below
40
+ } else {
41
+ // No stored path or it's the same - initialize and skip detection
42
+ previousLocationRef . current = currentPath ;
43
+ sessionStorage . setItem ( 'mobilemenu_previous_path' , currentPath ) ;
44
+ return ; // Skip path change detection on first render
45
+ }
46
+ }
47
+
48
+ // Check if this is a language change (same base path, different locale)
49
+ const isLanguageChange = ( ) => {
50
+ // More comprehensive language change detection
51
+ const normalizePathForComparison = ( path ) => {
52
+ // Handle docs root cases first
53
+ if ( path === '/docs' || path === '/docs/' ) {
54
+ return '/docs/' ;
55
+ }
56
+ if ( path . match ( / ^ \/ d o c s \/ ( j p | j a | r u | z h | z h - C N ) \/ ? $ / ) ) {
57
+ return '/docs/' ;
58
+ }
59
+
60
+ // Handle other docs paths
61
+ if ( path . startsWith ( '/docs/' ) ) {
62
+ const normalized = path
63
+ . replace ( / ^ \/ d o c s \/ ( j p | j a | r u | z h | z h - C N ) \/ / , '/docs/' ) // Remove /docs/locale/
64
+ . replace ( / ^ \/ d o c s \/ ( j p | j a | r u | z h | z h - C N ) $ / , '/docs/' ) ; // Remove /docs/locale
65
+ return normalized ;
66
+ }
67
+
68
+ // Handle non-docs paths
69
+ const normalized = path
70
+ . replace ( / ^ \/ ( j p | j a | r u | z h | z h - C N ) \/ / , '/' ) // Remove /locale/
71
+ . replace ( / ^ \/ ( j p | j a | r u | z h | z h - C N ) $ / , '/' ) ; // Remove /locale
72
+ return normalized ;
73
+ } ;
74
+
75
+ const normalizedCurrent = normalizePathForComparison ( currentPath ) ;
76
+ const normalizedPrevious = normalizePathForComparison ( previousLocationRef . current ) ;
77
+
78
+ // It's a language change if:
79
+ // 1. The language change flag is set, OR
80
+ // 2. The normalized paths are the same (same content, different locale)
81
+ return isLanguageChangeRef . current || normalizedCurrent === normalizedPrevious ;
82
+ } ;
83
+
84
+ // If the path changed, decide whether to close the menu
85
+ if ( currentPath !== previousLocationRef . current ) {
86
+ const langChange = isLanguageChange ( ) ;
87
+
88
+ if ( ! langChange ) {
89
+ setMenuState ( false ) ;
90
+ } else {
91
+ // Reset the language change flag after navigation is complete
92
+ if ( languageChangeTimeoutRef . current ) {
93
+ clearTimeout ( languageChangeTimeoutRef . current ) ;
94
+ }
95
+ languageChangeTimeoutRef . current = setTimeout ( ( ) => {
96
+ isLanguageChangeRef . current = false ;
97
+ } , 300 ) ;
98
+ }
99
+ }
100
+
101
+ // Update the previous path reference and store it
102
+ previousLocationRef . current = currentPath ;
103
+ sessionStorage . setItem ( 'mobilemenu_previous_path' , currentPath ) ;
104
+ } , [ location . pathname ] ) ;
105
+
12
106
// Prevent body scroll when menu is open
13
107
useEffect ( ( ) => {
14
108
if ( currentMenuState ) {
@@ -52,13 +146,38 @@ const MobileSideBarMenu = ({sidebar, menu}) => {
52
146
} ;
53
147
} , [ currentMenuState , LAPTOP_BREAKPOINT ] ) ;
54
148
149
+ // Handle language change
150
+ const handleLanguageChange = ( locale , href ) => {
151
+ // Set the flag BEFORE navigation
152
+ isLanguageChangeRef . current = true ;
153
+
154
+ // Clear any existing timeout
155
+ if ( languageChangeTimeoutRef . current ) {
156
+ clearTimeout ( languageChangeTimeoutRef . current ) ;
157
+ }
158
+
159
+ // Set a backup timeout to reset the flag (in case something goes wrong)
160
+ languageChangeTimeoutRef . current = setTimeout ( ( ) => {
161
+ isLanguageChangeRef . current = false ;
162
+ } , 1000 ) ;
163
+ } ;
164
+
165
+ // Cleanup timeout on unmount
166
+ useEffect ( ( ) => {
167
+ return ( ) => {
168
+ if ( languageChangeTimeoutRef . current ) {
169
+ clearTimeout ( languageChangeTimeoutRef . current ) ;
170
+ }
171
+ } ;
172
+ } , [ ] ) ;
173
+
55
174
// Function to handle menu close
56
175
const handleMenuClose = ( ) => {
57
176
setMenuState ( false ) ;
58
177
} ;
59
178
60
179
const handleItemClick = ( item ) => {
61
- // Safely check if item exists and is not collapsible
180
+ // Close menu for non- collapsible items
62
181
if ( item && ! item . collapsible ) {
63
182
handleMenuClose ( ) ;
64
183
}
@@ -77,6 +196,7 @@ const MobileSideBarMenu = ({sidebar, menu}) => {
77
196
}
78
197
} }
79
198
onClose = { handleMenuClose }
199
+ onLanguageChange = { handleLanguageChange }
80
200
sidebar = { sidebar } // Left sidebar items
81
201
menu = { menu } // Top level menu items
82
202
isVisible = { currentMenuState } // Pass menu visibility state
@@ -89,4 +209,4 @@ const MobileSideBarMenu = ({sidebar, menu}) => {
89
209
90
210
}
91
211
92
- export default MobileSideBarMenu ;
212
+ export default MobileSideBarMenu ;
0 commit comments