diff --git a/app/src/components/shell/AppLayout.tsx b/app/src/components/shell/AppLayout.tsx index 529f863..0740042 100644 --- a/app/src/components/shell/AppLayout.tsx +++ b/app/src/components/shell/AppLayout.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState, type MouseEvent, type ReactNode } from 'react'; +import { useEffect, useRef, useState, type MouseEvent, type ReactNode } from 'react'; import { Link, NavLink, useLocation, useNavigate } from 'react-router'; import { flushSync } from 'react-dom'; import { motion } from 'framer-motion'; @@ -403,7 +403,16 @@ export default function AppLayout({ children }: { children: ReactNode }) { const titleKey = TITLE_KEYS.find(([re]) => re.test(pathname))?.[1] ?? 'nav.dashboard'; const count = useInverterCount(); - const { navItems, chargerOn } = useNavItems(); + const { navItems } = useNavItems(); + /* Bottom-nav deslizable: centra el tab activo en la fila scrolleable. */ + const bottomNavRef = useRef(null); + useEffect(() => { + const el = bottomNavRef.current; + const activeEl = el?.querySelector('[data-active="true"]'); + if (el && activeEl) { + activeEl.scrollIntoView({ inline: 'center', block: 'nearest' }); + } + }, [pathname]); const resolvedTitleKey = titleKey === 'nav.inversores' ? invLabelKey(count) : titleKey; const lgMargin = collapsed ? 'lg:ml-16' : 'lg:ml-[232px]'; @@ -466,13 +475,21 @@ export default function AppLayout({ children }: { children: ReactNode }) { className="[view-transition-name:helios-nav] fixed bottom-0 left-0 right-0 z-50 border-t border-app bg-surface/85 pb-safe backdrop-blur-[16px] md:hidden" aria-label={t('nav.dashboard')} > - {/* Sin Ajustes: en móvil el acceso es el avatar del header (→ /ajustes) */} -
+ {/* Fila deslizable (keynest #284 / deltos #290 / netpulse #1312): + min-width por tab, scrollbar oculta y auto-scroll al activo. */} +
{navItems.map(({ to, labelKey, icon: Icon }) => { const active = isActive(pathname, to); const label = t(labelKey === 'nav.inversores' ? invLabelKey(count) : labelKey); return ( - + - - - +
); }