1+ import { useState , useEffect } from 'react'
12import { Link , useLocation } from 'react-router-dom'
23import { useThemeStore } from '../../store/themeStore'
34import type { Theme } from '../../store/themeStore'
@@ -21,52 +22,106 @@ export function Navbar() {
2122 const location = useLocation ( )
2223 const { theme, cycleTheme } = useThemeStore ( )
2324 const meta = THEME_META [ theme ]
25+ const [ menuOpen , setMenuOpen ] = useState ( false )
26+
27+ // Close menu on route change
28+ useEffect ( ( ) => { setMenuOpen ( false ) } , [ location . pathname ] )
29+
30+ // Prevent body scroll when menu is open
31+ useEffect ( ( ) => {
32+ document . body . style . overflow = menuOpen ? 'hidden' : ''
33+ return ( ) => { document . body . style . overflow = '' }
34+ } , [ menuOpen ] )
2435
2536 return (
26- < nav className = "fixed top-0 left-0 right-0 z-50 bg-surface-light/80 backdrop-blur-md border-b border-surface-lighter" >
37+ < nav className = "fixed top-0 left-0 right-0 z-50 bg-surface-light/90 backdrop-blur-md border-b border-surface-lighter" >
2738 < div className = "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" >
2839 < div className = "flex items-center justify-between h-14" >
29- < Link to = "/" className = "flex items-center gap-2 text-lg font-bold text-primary-light no-underline" >
30- < span className = "text-xl" > { '\uD83E\uDDE0' } </ span >
31- < span > RL Interactive Lab</ span >
40+
41+ { /* Brand */ }
42+ < Link to = "/" className = "flex items-center gap-2 text-base font-bold text-primary-light no-underline flex-shrink-0" >
43+ < span className = "text-xl" > 🧠</ span >
44+ < span className = "hidden sm:inline" > RL Interactive Lab</ span >
45+ < span className = "sm:hidden" > RL Lab</ span >
3246 </ Link >
3347
34- < div className = "flex items-center gap-2" >
35- < div className = "flex gap-1" >
36- { navItems . map ( ( { path, label } ) => {
37- const isActive = path === '/learn'
38- ? location . pathname . startsWith ( '/learn' )
39- : location . pathname === path
40- return (
41- < Link
42- key = { path }
43- to = { path }
44- className = { `px-3 py-1.5 rounded-md text-sm font-medium no-underline transition-colors ${
45- isActive
46- ? 'bg-primary/20 text-primary-light'
47- : 'text-text-muted hover:text-text hover:bg-surface-lighter/50'
48- } `}
49- >
50- { label }
51- </ Link >
52- )
53- } ) }
54- </ div >
48+ { /* Desktop nav links — hidden on mobile */ }
49+ < div className = "hidden md: flex items-center gap-1" >
50+ { navItems . map ( ( { path, label } ) => {
51+ const isActive = path === '/learn'
52+ ? location . pathname . startsWith ( '/learn' )
53+ : location . pathname === path
54+ return (
55+ < Link
56+ key = { path }
57+ to = { path }
58+ className = { `px-3 py-1.5 rounded-md text-sm font-medium no-underline transition-colors ${
59+ isActive
60+ ? 'bg-primary/20 text-primary-light'
61+ : 'text-text-muted hover:text-text hover:bg-surface-lighter/50'
62+ } `}
63+ >
64+ { label }
65+ </ Link >
66+ )
67+ } ) }
68+ </ div >
5569
70+ { /* Right side */ }
71+ < div className = "flex items-center gap-2" >
5672 { /* Theme Toggle */ }
5773 < button
5874 onClick = { cycleTheme }
59- className = "ml-2 flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium
75+ className = "flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg text-sm font-medium
6076 bg-surface-lighter/50 text-text-muted hover:text-text hover:bg-surface-lighter
6177 border-0 cursor-pointer transition-colors"
6278 title = { `Theme: ${ meta . label } . Click to switch.` }
6379 >
6480 < span className = "text-base" > { meta . icon } </ span >
6581 < span className = "hidden sm:inline text-xs" > { meta . label } </ span >
6682 </ button >
83+
84+ { /* Hamburger — visible only on mobile */ }
85+ < button
86+ onClick = { ( ) => setMenuOpen ( ! menuOpen ) }
87+ className = "md:hidden flex flex-col justify-center items-center w-9 h-9 rounded-lg
88+ bg-surface-lighter/50 hover:bg-surface-lighter border-0 cursor-pointer transition-colors gap-1.5"
89+ aria-label = "Toggle menu"
90+ >
91+ < span className = { `block w-5 h-0.5 bg-text-muted transition-all duration-200 ${ menuOpen ? 'rotate-45 translate-y-2' : '' } ` } />
92+ < span className = { `block w-5 h-0.5 bg-text-muted transition-all duration-200 ${ menuOpen ? 'opacity-0' : '' } ` } />
93+ < span className = { `block w-5 h-0.5 bg-text-muted transition-all duration-200 ${ menuOpen ? '-rotate-45 -translate-y-2' : '' } ` } />
94+ </ button >
6795 </ div >
6896 </ div >
6997 </ div >
98+
99+ { /* Mobile dropdown menu */ }
100+ { menuOpen && (
101+ < div className = "md:hidden border-t border-surface-lighter bg-surface-light/95 backdrop-blur-md" >
102+ < div className = "px-4 py-3 flex flex-col gap-1" >
103+ { navItems . map ( ( { path, label } ) => {
104+ const isActive = path === '/learn'
105+ ? location . pathname . startsWith ( '/learn' )
106+ : location . pathname === path
107+ return (
108+ < Link
109+ key = { path }
110+ to = { path }
111+ onClick = { ( ) => setMenuOpen ( false ) }
112+ className = { `px-4 py-3 rounded-lg text-sm font-medium no-underline transition-colors ${
113+ isActive
114+ ? 'bg-primary/20 text-primary-light'
115+ : 'text-text-muted hover:text-text hover:bg-surface-lighter/50'
116+ } `}
117+ >
118+ { label }
119+ </ Link >
120+ )
121+ } ) }
122+ </ div >
123+ </ div >
124+ ) }
70125 </ nav >
71126 )
72127}
0 commit comments