Skip to content

Commit bacf47d

Browse files
committed
fix up some subtle bugs around invalid paths
1 parent fc574e0 commit bacf47d

File tree

1 file changed

+86
-10
lines changed

1 file changed

+86
-10
lines changed

src/components/MobileSideBarMenu/Content.jsx

Lines changed: 86 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ import NavbarLogo from '@theme/Navbar/Logo';
1010
import ColorModeToggle from "../../components/ColorModeToggler";
1111
import Translate from "@docusaurus/Translate";
1212
import { useLocation } from '@docusaurus/router';
13+
import { useHistory } from '@docusaurus/router';
1314
import MobileLanguagePicker from "./MobileLanguagePicker";
15+
1416
const MobileSideBarMenuContents = ({ className, onClick, onClose, sidebar, path, menu, isVisible = true }) => {
1517
const [showTopLevel, setShowTopLevel] = useState(false);
1618
const location = useLocation();
19+
const history = useHistory();
1720

1821
// Reset to sidebar view (showTopLevel = false) whenever the mobile menu becomes visible
1922
useEffect(() => {
@@ -22,12 +25,60 @@ const MobileSideBarMenuContents = ({ className, onClick, onClose, sidebar, path,
2225
}
2326
}, [isVisible]);
2427

28+
// Get current locale from URL
29+
const getCurrentLocale = () => {
30+
const pathname = location.pathname;
31+
const docsLocaleMatch = pathname.match(/^\/docs\/(jp|ja|ru|zh|zh-CN)(?=\/|$)/);
32+
return docsLocaleMatch ? docsLocaleMatch[1] : 'en';
33+
};
34+
35+
// Normalize path for comparison (remove locale prefix if present)
36+
const normalizePath = (path) => {
37+
if (!path) return '';
38+
// Remove locale prefix from path for comparison
39+
return path.replace(/^\/docs\/(jp|ja|ru|zh|zh-CN)/, '/docs');
40+
};
41+
42+
// Check if the current path exists in the sidebar
43+
const isCurrentPathInSidebar = () => {
44+
if (!sidebar || sidebar.length === 0) return false;
45+
46+
const normalizedCurrentPath = normalizePath(location.pathname);
47+
48+
const checkItemsRecursively = (items) => {
49+
return items.some(item => {
50+
// Check if this item matches the current path
51+
const itemHref = item.href || (item.customProps && item.customProps.href);
52+
if (itemHref) {
53+
const normalizedItemHref = normalizePath(itemHref);
54+
if (normalizedCurrentPath === normalizedItemHref || normalizedCurrentPath.startsWith(normalizedItemHref + '/')) {
55+
return true;
56+
}
57+
}
58+
59+
// Check children recursively
60+
if (item.items && item.items.length > 0) {
61+
return checkItemsRecursively(item.items);
62+
}
63+
64+
return false;
65+
});
66+
};
67+
68+
return checkItemsRecursively(sidebar);
69+
};
70+
2571
// Check if we're on a docs root page (should show only top-level menu)
2672
const isDocsRootPage = () => {
2773
const docsRootPaths = ['/docs/', '/docs/jp/', '/docs/ru/', '/docs/zh/'];
2874
return docsRootPaths.includes(location.pathname);
2975
};
3076

77+
// Check if we should show the main menu instead of sidebar
78+
const shouldShowMainMenu = () => {
79+
return isDocsRootPage() || !isCurrentPathInSidebar();
80+
};
81+
3182
// Find which top-level category we're currently in
3283
const getCurrentCategory = () => {
3384
if (!menu || !path) return null;
@@ -44,17 +95,42 @@ const MobileSideBarMenuContents = ({ className, onClick, onClose, sidebar, path,
4495

4596
const currentCategory = getCurrentCategory();
4697

47-
// Handle item click - close the mobile sidebar
98+
// Handle item click - navigate and potentially close the mobile sidebar
4899
const handleItemClick = (item) => {
100+
// Handle navigation for items with href
101+
let itemHref = item.href || (item.customProps && item.customProps.href);
102+
103+
if (itemHref) {
104+
// Fix URLs for main menu items - add /docs/ prefix if missing and handle localization
105+
// Use shouldShowMainMenu() instead of showTopLevel to catch invalid pages too
106+
if (shouldShowMainMenu() && itemHref && !itemHref.startsWith('/docs/') && !itemHref.startsWith('http')) {
107+
const currentLocale = getCurrentLocale();
108+
if (currentLocale !== 'en') {
109+
itemHref = `/docs/${currentLocale}${itemHref}`;
110+
} else {
111+
itemHref = `/docs${itemHref}`;
112+
}
113+
}
114+
115+
// Navigate to the href
116+
if (itemHref.startsWith('http')) {
117+
// External link
118+
window.open(itemHref, '_blank', 'noopener,noreferrer');
119+
} else {
120+
// Internal link
121+
history.push(itemHref);
122+
}
123+
124+
// Close the menu after navigation
125+
if (onClose) {
126+
onClose();
127+
}
128+
}
129+
49130
// Call the onClick handler from parent if provided
50131
if (onClick) {
51132
onClick(item);
52133
}
53-
54-
// For non-collapsible items, close the menu
55-
if (item && !item.collapsible && onClose) {
56-
onClose();
57-
}
58134
};
59135

60136
// Generic function to render CustomSidebarItems with consistent styling
@@ -79,7 +155,7 @@ const MobileSideBarMenuContents = ({ className, onClick, onClose, sidebar, path,
79155

80156
// Render the enhanced header with logo and navigation toggle
81157
const renderHeader = () => {
82-
const isTopLevel = showTopLevel || isDocsRootPage();
158+
const isTopLevel = showTopLevel || shouldShowMainMenu();
83159

84160
return (
85161
<div className={clsx("navbar-sidebar__brand", styles.docsMobileMenu_header)}>
@@ -97,7 +173,7 @@ const MobileSideBarMenuContents = ({ className, onClick, onClose, sidebar, path,
97173
</div>
98174
</div>
99175
<div className={styles.bottomLevel}>
100-
{!isDocsRootPage() && (
176+
{!shouldShowMainMenu() && (
101177
<button
102178
className={styles.levelToggleButton}
103179
onClick={() => setShowTopLevel(!showTopLevel)}
@@ -145,8 +221,8 @@ const MobileSideBarMenuContents = ({ className, onClick, onClose, sidebar, path,
145221
);
146222
};
147223

148-
// If we're on a docs root page, always show the top-level menu
149-
if (isDocsRootPage()) {
224+
// If we're on a docs root page or invalid path, always show the top-level menu
225+
if (shouldShowMainMenu()) {
150226
return (
151227
<div className={clsx(styles.docsMobileMenu, className)}>
152228
{renderTopLevelMenu()}

0 commit comments

Comments
 (0)