This commit is contained in:
Andras Schmelczer 2026-04-04 17:44:44 +01:00
parent b94cf17d75
commit 0c6d207967
41 changed files with 1809 additions and 1204 deletions

View file

@ -1,6 +1,8 @@
import { useTranslation } from 'react-i18next';
import type { Page } from './Header';
import { PAGE_PATHS } from './Header';
import type { AuthUser } from '../../hooks/useAuth';
import { SUPPORTED_LANGUAGES } from '../../i18n';
import { DownloadIcon } from './icons/DownloadIcon';
import { BookmarkIcon } from './icons/BookmarkIcon';
import { CheckIcon } from './icons/CheckIcon';
@ -45,6 +47,8 @@ export default function MobileMenu({
onShare,
copied,
}: MobileMenuProps) {
const { t, i18n } = useTranslation();
const mobileNavItem = (page: Page, label: string) => (
<a
key={page}
@ -72,24 +76,24 @@ export default function MobileMenu({
{/* Menu panel */}
<div className="fixed top-0 right-0 bottom-0 w-64 bg-navy-900 z-50 flex flex-col shadow-xl">
<div className="flex items-center justify-between px-4 h-12 border-b border-navy-700">
<span className="font-semibold">Menu</span>
<span className="font-semibold">{t('mobileMenu.menu')}</span>
<button
onClick={onClose}
className="flex items-center justify-center w-10 h-10 -mr-2 rounded hover:bg-navy-800 transition-colors"
aria-label="Close menu"
aria-label={t('header.closeMenu')}
>
<CloseIcon className="w-5 h-5" />
</button>
</div>
<nav className="flex-1 flex flex-col gap-1 p-3 overflow-y-auto">
{mobileNavItem('home', 'Home')}
{mobileNavItem('dashboard', 'Dashboard')}
{mobileNavItem('learn', 'Learn')}
{mobileNavItem('home', t('mobileMenu.home'))}
{mobileNavItem('dashboard', t('header.dashboard'))}
{mobileNavItem('learn', t('header.learn'))}
{user?.subscription !== 'licensed' &&
!user?.isAdmin &&
mobileNavItem('pricing', 'Pricing')}
{user && mobileNavItem('invites', 'Invite Friends')}
{user && mobileNavItem('account', 'Account')}
mobileNavItem('pricing', t('header.pricing'))}
{user && mobileNavItem('invites', t('header.inviteFriends'))}
{user && mobileNavItem('account', t('userMenu.account'))}
{/* Dashboard actions */}
{activePage === 'dashboard' && (
@ -102,7 +106,7 @@ export default function MobileMenu({
className="w-full flex items-center gap-2 px-4 py-3 text-base text-warm-300 hover:bg-navy-800 hover:text-white rounded"
>
{copied ? <CheckIcon className="w-5 h-5" /> : <ClipboardIcon className="w-5 h-5" />}
{copied ? 'Copied!' : 'Share'}
{copied ? t('common.copied') : t('common.share')}
</button>
<button
onClick={() => {
@ -113,7 +117,7 @@ export default function MobileMenu({
className="w-full flex items-center gap-2 px-4 py-3 text-base text-warm-300 hover:bg-navy-800 hover:text-white rounded disabled:opacity-50"
>
<DownloadIcon className="w-5 h-5" />
{exporting ? 'Exporting...' : 'Export'}
{exporting ? t('header.exporting') : t('header.exportLabel')}
</button>
{onSaveSearch && (
<button
@ -129,13 +133,13 @@ export default function MobileMenu({
) : (
<BookmarkIcon className="w-5 h-5" />
)}
Save
{t('common.save')}
</button>
)}
{user && mobileNavItem('saved', 'Saved')}
{user && mobileNavItem('saved', t('header.saved'))}
</div>
)}
{activePage !== 'dashboard' && user && mobileNavItem('saved', 'Saved')}
{activePage !== 'dashboard' && user && mobileNavItem('saved', t('header.saved'))}
</nav>
{/* Theme toggle + Auth section at bottom */}
@ -148,9 +152,30 @@ export default function MobileMenu({
className="w-full flex items-center gap-3 px-4 py-3 text-base text-warm-300 hover:bg-navy-800 hover:text-white rounded transition-colors"
>
{theme === 'light' ? <SunIcon className="w-5 h-5" /> : <MoonIcon className="w-5 h-5" />}
<span>Theme: {theme === 'light' ? 'Light' : 'Dark'}</span>
<span>{theme === 'light' ? t('userMenu.themeLight') : t('userMenu.themeDark')}</span>
</button>
{/* Language selector */}
<div className="flex gap-1 px-4">
{SUPPORTED_LANGUAGES.map((lang) => (
<button
key={lang.code}
onClick={() => {
i18n.changeLanguage(lang.code);
localStorage.setItem('language', lang.code);
}}
className={`flex-1 flex items-center justify-center gap-1.5 px-2 py-2 rounded text-sm ${
i18n.language === lang.code
? 'bg-navy-700 text-white font-medium'
: 'text-warm-400 hover:bg-navy-800 hover:text-white'
}`}
>
<span className="text-base leading-none">{lang.flag}</span>
<span className="hidden sm:inline">{lang.label}</span>
</button>
))}
</div>
{/* Auth buttons */}
<div>
{user ? (
@ -163,7 +188,7 @@ export default function MobileMenu({
}}
className="shrink-0 text-sm text-warm-400 hover:text-white"
>
Log out
{t('userMenu.logOut')}
</button>
</div>
) : (
@ -175,7 +200,7 @@ export default function MobileMenu({
}}
className="flex-1 px-3 py-2.5 rounded bg-navy-800 hover:bg-navy-700 transition-colors text-sm text-center"
>
Log in
{t('header.logIn')}
</button>
<button
onClick={() => {
@ -184,7 +209,7 @@ export default function MobileMenu({
}}
className="flex-1 px-3 py-2.5 rounded bg-teal-600 hover:bg-teal-700 transition-colors text-sm font-medium text-center"
>
Create account
{t('header.createAccount')}
</button>
</div>
)}