1- import { useEffect , useState , type MouseEvent , type ReactNode } from 'react' ;
1+ import { useEffect , useRef , useState , type MouseEvent , type ReactNode } from 'react' ;
22import { Link , NavLink , useLocation , useNavigate } from 'react-router' ;
33import { flushSync } from 'react-dom' ;
44import { motion } from 'framer-motion' ;
@@ -403,7 +403,16 @@ export default function AppLayout({ children }: { children: ReactNode }) {
403403
404404 const titleKey = TITLE_KEYS . find ( ( [ re ] ) => re . test ( pathname ) ) ?. [ 1 ] ?? 'nav.dashboard' ;
405405 const count = useInverterCount ( ) ;
406- const { navItems, chargerOn } = useNavItems ( ) ;
406+ const { navItems } = useNavItems ( ) ;
407+ /* Bottom-nav deslizable: centra el tab activo en la fila scrolleable. */
408+ const bottomNavRef = useRef < HTMLDivElement > ( null ) ;
409+ useEffect ( ( ) => {
410+ const el = bottomNavRef . current ;
411+ const activeEl = el ?. querySelector ( '[data-active="true"]' ) ;
412+ if ( el && activeEl ) {
413+ activeEl . scrollIntoView ( { inline : 'center' , block : 'nearest' } ) ;
414+ }
415+ } , [ pathname ] ) ;
407416 const resolvedTitleKey = titleKey === 'nav.inversores' ? invLabelKey ( count ) : titleKey ;
408417 const lgMargin = collapsed ? 'lg:ml-16' : 'lg:ml-[232px]' ;
409418
@@ -466,13 +475,21 @@ export default function AppLayout({ children }: { children: ReactNode }) {
466475 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"
467476 aria-label = { t ( 'nav.dashboard' ) }
468477 >
469- { /* Sin Ajustes: en móvil el acceso es el avatar del header (→ /ajustes) */ }
470- < div className = { cn ( 'grid h-16' , chargerOn ? 'grid-cols-5' : 'grid-cols-4' ) } >
478+ { /* Fila deslizable (keynest #284 / deltos #290 / netpulse #1312):
479+ min-width por tab, scrollbar oculta y auto-scroll al activo. */ }
480+ < div ref = { bottomNavRef } className = "flex h-16 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden" >
471481 { navItems . map ( ( { to, labelKey, icon : Icon } ) => {
472482 const active = isActive ( pathname , to ) ;
473483 const label = t ( labelKey === 'nav.inversores' ? invLabelKey ( count ) : labelKey ) ;
474484 return (
475- < NavLink key = { to } to = { to } onClick = { handleMobileNav ( to ) } className = "relative flex flex-col items-center justify-center gap-1" aria-label = { label } >
485+ < NavLink
486+ key = { to }
487+ to = { to }
488+ onClick = { handleMobileNav ( to ) }
489+ data-active = { active ? 'true' : undefined }
490+ className = "relative flex min-w-[64px] flex-1 flex-col items-center justify-center gap-1"
491+ aria-label = { label }
492+ >
476493 < motion . span
477494 animate = { active ? { scale : [ 1 , 1.15 , 1 ] } : { scale : 1 } }
478495 transition = { { duration : 0.25 , type : 'spring' , stiffness : 500 , damping : 20 } }
@@ -486,9 +503,7 @@ export default function AppLayout({ children }: { children: ReactNode }) {
486503 ) ;
487504 } ) }
488505 </ div >
489- </ nav >
490-
491- < HeliosToaster />
506+ </ nav > < HeliosToaster />
492507 </ div >
493508 ) ;
494509}
0 commit comments