11import { Link , useLocation } from 'react-router-dom'
2+ import { useState } from 'react'
23import ThemeToggle from './ThemeToggle'
34import { useAuth } from '../contexts/AuthContext'
4- import { LogOut } from 'lucide-react'
5+ import { LogOut , Menu , X } from 'lucide-react'
56
67/* Header component that includes navigation links, user info, logout button, and theme toggle. */
78export default function AppHeader ( ) {
89 const { pathname } = useLocation ( )
910 const { user, logout } = useAuth ( )
11+ const [ menuOpen , setMenuOpen ] = useState ( false )
12+ const [ closing , setClosing ] = useState ( false )
1013 const isHome = pathname === '/'
1114 const isHistory = pathname === '/history'
1215 const isAbout = pathname === '/about'
@@ -20,23 +23,34 @@ export default function AppHeader() {
2023 const handleLogout = async ( ) => {
2124 try {
2225 await logout ( )
26+ closeMenu ( )
2327 } catch ( error ) {
2428 console . error ( 'Logout error:' , error )
2529 }
2630 }
2731
32+ const closeMenu = ( ) => {
33+ // Trigger slide-out animation, then unmount after duration
34+ setClosing ( true )
35+ setTimeout ( ( ) => {
36+ setMenuOpen ( false )
37+ setClosing ( false )
38+ } , 300 )
39+ }
40+
2841 return (
29- < header className = "fixed top-0 left-0 right-0 z-50 grid grid-cols-3 items-center px-5 py-3 border-b dark:border-zinc-700 bg-[#f5f5f5] dark:bg-[#18181b]" >
42+ < >
43+ < header className = "fixed top-0 left-0 right-0 z-50 flex items-center justify-between md:grid md:grid-cols-3 px-5 py-3 border-b dark:border-zinc-700 bg-[#f5f5f5] dark:bg-[#18181b]" >
3044 < div className = "justify-self-start flex items-center gap-2" >
3145 < img src = "/logo.png" alt = "Wordler Logo" className = "h-8 w-8" />
3246 < Link to = "/" className = "text-xl font-semibold tracking-tight" > Wordler</ Link >
3347 </ div >
34- < nav className = "justify-self-center flex gap-4" >
48+ < nav className = "justify-self-center hidden md: flex gap-4" >
3549 < Link to = "/" className = { `text-sm transition-colors ${ isHome ? active : inactive } ` } > Home</ Link >
3650 < Link to = "/history" className = { `text-sm transition-colors ${ isHistory ? active : inactive } ` } > History</ Link >
3751 < Link to = "/about" className = { `text-sm transition-colors ${ isAbout ? active : inactive } ` } > About Us</ Link >
3852 </ nav >
39- < div className = "justify-self-end flex items-center gap-3" >
53+ < div className = "flex items-center gap-3 md:justify-self-end " >
4054 { user && (
4155 < >
4256 < Link to = "/profile" className = "text-xs text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 hidden md:inline" > { user . email } </ Link >
@@ -49,9 +63,88 @@ export default function AppHeader() {
4963 </ button >
5064 </ >
5165 ) }
66+ { /* Icons cluster (logout already above if user) */ }
5267 < ThemeToggle />
68+ < button
69+ type = "button"
70+ aria-label = "Open menu"
71+ className = "md:hidden inline-flex items-center justify-center rounded-lg p-2 bg-gray-200 dark:bg-zinc-800 hover:bg-gray-300 dark:hover:bg-zinc-700 transition-colors"
72+ onClick = { ( ) => setMenuOpen ( true ) }
73+ >
74+ < Menu className = "h-5 w-5" />
75+ </ button >
5376 </ div >
5477 </ header >
78+ { /* Mobile sidebar overlay */ }
79+ { ( menuOpen || closing ) && (
80+ < div
81+ className = "fixed inset-0 z-[60] bg-black/40 backdrop-blur-sm"
82+ onClick = { closeMenu }
83+ >
84+ < aside
85+ className = { `absolute left-0 top-0 h-full w-72 max-w-[85vw] bg-white/80 dark:bg-zinc-900/80 border-r border-gray-200/60 dark:border-zinc-700/60 shadow-xl backdrop-blur-xl p-4 flex flex-col ${ closing ? 'animate-slideOutLeft' : 'animate-slideInLeft' } ` }
86+ onClick = { ( e ) => e . stopPropagation ( ) }
87+ >
88+ < div className = "flex items-center justify-between mb-4" >
89+ < div className = "flex items-center gap-2" >
90+ < img src = "/logo.png" alt = "Wordler Logo" className = "h-7 w-7" />
91+ < span className = "text-lg font-semibold" > Wordler</ span >
92+ </ div >
93+ < button
94+ aria-label = "Close menu"
95+ className = "inline-flex items-center justify-center rounded-lg p-2 bg-gray-200 dark:bg-zinc-800 hover:bg-gray-300 dark:hover:bg-zinc-700 transition-colors"
96+ onClick = { closeMenu }
97+ >
98+ < X className = "h-5 w-5" />
99+ </ button >
100+ </ div >
101+
102+ < nav className = "flex flex-col gap-2" >
103+ < Link
104+ to = "/"
105+ className = { `px-3 py-2 rounded-md ${ isHome ? active : inactive } hover:bg-gray-100/70 dark:hover:bg-zinc-800/60` }
106+ onClick = { closeMenu }
107+ >
108+ Home
109+ </ Link >
110+ < Link
111+ to = "/history"
112+ className = { `px-3 py-2 rounded-md ${ isHistory ? active : inactive } hover:bg-gray-100/70 dark:hover:bg-zinc-800/60` }
113+ onClick = { closeMenu }
114+ >
115+ History
116+ </ Link >
117+ < Link
118+ to = "/about"
119+ className = { `px-3 py-2 rounded-md ${ isAbout ? active : inactive } hover:bg-gray-100/70 dark:hover:bg-zinc-800/60` }
120+ onClick = { closeMenu }
121+ >
122+ About Us
123+ </ Link >
124+ < Link
125+ to = "/profile"
126+ className = { `px-3 py-2 rounded-md hover:bg-gray-100/70 dark:hover:bg-zinc-800/60 ${ pathname === '/profile' ? active : inactive } ` }
127+ onClick = { closeMenu }
128+ >
129+ Profile
130+ </ Link >
131+ </ nav >
132+
133+ { user && (
134+ < div className = "mt-auto pt-4" >
135+ < div className = "text-xs mb-2 text-gray-600 dark:text-gray-400 truncate" > { user . email } </ div >
136+ < button
137+ onClick = { handleLogout }
138+ className = "w-full flex items-center justify-center gap-2 px-3 py-2 text-sm rounded-md bg-gray-200 dark:bg-zinc-800 hover:bg-gray-300 dark:hover:bg-zinc-700 transition-colors"
139+ >
140+ < LogOut className = "h-4 w-4" /> Sign out
141+ </ button >
142+ </ div >
143+ ) }
144+ </ aside >
145+ </ div >
146+ ) }
147+ </ >
55148 )
56149}
57150
0 commit comments