import * as React from "react"; import { useThemeHooks, useLanguagePicker } from "@redocly/theme/core/hooks"; import { BdsLink } from "../../../../shared/components/Link/Link"; import { CloseIcon, ChevronIcon } from "../icons"; import { xrpSymbolBlack, globeIcon, chevronDown, modeToggleIcon, searchIcon } from "../constants/icons"; import { navItems } from "../constants/navigation"; import { MobileMenuContent, type MobileMenuKey } from "./MobileMenuContent"; interface MobileMenuProps { isOpen: boolean; onClose: () => void; onSearch?: () => void; } /** * Mobile Menu Component. * Full-screen slide-out menu for mobile devices. */ export function MobileMenu({ isOpen, onClose, onSearch }: MobileMenuProps) { const { useTranslate } = useThemeHooks(); const { translate } = useTranslate(); const [expandedItem, setExpandedItem] = React.useState("Develop"); // Handle body scroll lock React.useEffect(() => { if (isOpen) { document.body.classList.add('bds-mobile-menu-open'); } else { document.body.classList.remove('bds-mobile-menu-open'); } return () => { document.body.classList.remove('bds-mobile-menu-open'); }; }, [isOpen]); const toggleAccordion = (item: string) => { setExpandedItem(expandedItem === item ? null : item); }; const handleSearch = () => { if (onSearch) { onSearch(); } onClose(); }; const handleModeToggle = () => { const newTheme = document.documentElement.classList.contains("dark") ? "light" : "dark"; window.localStorage.setItem("user-prefers-color", newTheme); document.body.style.transition = "background-color .2s ease"; document.documentElement.classList.remove("dark", "light"); document.documentElement.classList.add(newTheme); }; const renderAccordionContent = (label: string) => { // All nav items with submenus use the unified MobileMenuContent const validKeys: MobileMenuKey[] = ['Develop', 'Use Cases', 'Community', 'Network']; if (validKeys.includes(label as MobileMenuKey)) { return ; } return null; }; return (
{/* Header */}
{translate("XRP
{/* Content */}
{navItems.map((item) => ( {item.hasSubmenu && (
{renderAccordionContent(item.label)}
)}
))}
{/* Footer */}
); } interface MobileMenuFooterProps { onModeToggle: () => void; onSearch: () => void; } /** * Get short display name for a locale code. */ function getLocaleShortName(code: string | undefined): string { if (!code) return "En"; const shortNames: Record = { "en-US": "En", "en": "En", "ja": "日本語", }; return shortNames[code] || code.substring(0, 2).toUpperCase(); } function MobileMenuFooter({ onModeToggle, onSearch }: MobileMenuFooterProps) { const { currentLocale, locales, setLocale } = useLanguagePicker(); const { useL10n, useTranslate } = useThemeHooks(); const { changeLanguage } = useL10n(); const { translate } = useTranslate(); const [isLangOpen, setIsLangOpen] = React.useState(false); const displayName = getLocaleShortName(currentLocale?.code); const handleLanguageSelect = (localeCode: string) => { setLocale(localeCode); changeLanguage(localeCode); setIsLangOpen(false); }; return (
{isLangOpen && locales.length >= 2 && (
{locales.map((locale) => { const isActive = locale.code === currentLocale?.code; return ( ); })}
)}
); }