From 9edd63990cf820f619395ded058f59d18f3d49bf Mon Sep 17 00:00:00 2001 From: Mateus Elias Date: Thu, 23 Jul 2026 09:26:28 -0300 Subject: [PATCH] fix: stable topbar across languages, mobile layout, localized tab title - Auth buttons reserve their longest translation via ch minimums, and the controls block is pinned right, so switching language no longer shrinks/expands the bar (es labels previously overflowed the fixed 260px column and blew the grid) - Mobile: compact single-button language cycler, icon brand, tighter paddings, login moves behind the register CTA; no overflow at 360px - Tab title, meta description, and html lang now follow the active language (en, pt-BR, es) via an i18next languageChanged listener --- client/src/components/layout/Navbar.tsx | 134 ++++++++++++++---------- client/src/i18n/index.ts | 15 +++ client/src/i18n/locales/en.json | 33 ++++-- client/src/i18n/locales/es.json | 33 ++++-- client/src/i18n/locales/pt.json | 33 ++++-- 5 files changed, 172 insertions(+), 76 deletions(-) diff --git a/client/src/components/layout/Navbar.tsx b/client/src/components/layout/Navbar.tsx index 7edc820..5020e73 100644 --- a/client/src/components/layout/Navbar.tsx +++ b/client/src/components/layout/Navbar.tsx @@ -10,6 +10,31 @@ import { cn } from '@/lib/utils'; const LANGS = ['EN', 'PT', 'ES'] as const; type Lang = (typeof LANGS)[number]; +interface NavLinkProps { + to: string; + label: string; + active: boolean; +} + +function NavLink({ to, label, active }: NavLinkProps) { + return ( + + {label} + {active && ( + + )} + + ); +} + export function Navbar() { const { isAuthenticated, user, clearAuth } = useAuthStore(); const { theme, toggle } = useThemeStore(); @@ -20,7 +45,12 @@ export function Navbar() { const activeLang = inst.language.toUpperCase().slice(0, 2) as Lang; const handleLogout = async () => { - try { await api.post('/auth/logout'); } finally { clearAuth(); navigate('/'); } + try { + await api.post('/auth/logout'); + } finally { + clearAuth(); + navigate('/'); + } }; const switchLang = (lang: Lang) => { @@ -28,65 +58,45 @@ export function Navbar() { localStorage.setItem('chesskernel-lang', lang.toLowerCase()); }; - const isActive = (to: string) => location.pathname === to || location.pathname.startsWith(to + '/'); + const cycleLang = () => { + const next = LANGS[(LANGS.indexOf(activeLang) + 1) % LANGS.length]; + switchLang(next); + }; + + const isActive = (to: string) => + location.pathname === to || location.pathname.startsWith(to + '/'); return (