1- import React , { useState , useEffect } from 'react' ;
1+ import React , { useState , useEffect , useCallback } from 'react' ;
22import { Link } from 'react-router-dom' ;
33import { motion , AnimatePresence } from 'framer-motion' ;
44import { dropdowns } from '../constants/Header' ;
@@ -9,31 +9,52 @@ const Header: React.FC = () => {
99 const [ menuOpen , setMenuOpen ] = useState ( false ) ;
1010 const [ scrolled , setScrolled ] = useState ( false ) ;
1111
12- const handleScroll = ( ) => {
12+ // Prevent body scroll when mobile menu is open
13+ useEffect ( ( ) => {
14+ if ( menuOpen ) {
15+ document . body . style . overflow = 'hidden' ;
16+ } else {
17+ document . body . style . overflow = 'unset' ;
18+ }
19+ return ( ) => {
20+ document . body . style . overflow = 'unset' ;
21+ } ;
22+ } , [ menuOpen ] ) ;
23+
24+ const handleScroll = useCallback ( ( ) => {
1325 setScrolled ( window . scrollY > 20 ) ;
14- } ;
26+ } , [ ] ) ;
1527
1628 useEffect ( ( ) => {
1729 window . addEventListener ( 'scroll' , handleScroll ) ;
1830 return ( ) => window . removeEventListener ( 'scroll' , handleScroll ) ;
19- } , [ ] ) ;
31+ } , [ handleScroll ] ) ;
2032
2133 useEffect ( ( ) => {
2234 setMenuOpen ( false ) ;
2335 setActiveDropdown ( null ) ;
2436 } , [ ] ) ;
2537
38+ const closeMenu = ( ) => {
39+ setMenuOpen ( false ) ;
40+ setActiveDropdown ( null ) ;
41+ } ;
42+
2643 return (
2744 < >
28- < header
45+ < div
2946 className = { `fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
3047 scrolled ? 'backdrop-blur-md bg-white/90 shadow-lg' : 'bg-white'
3148 } `}
3249 >
33- < nav className = "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" >
50+ < div className = "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" >
3451 < div className = "flex justify-between items-center h-20" >
3552 { /* Logo */ }
36- < Link to = "/" className = "flex-shrink-0 flex items-center" >
53+ < Link
54+ to = "/"
55+ className = "flex-shrink-0 flex items-center"
56+ onClick = { closeMenu }
57+ >
3758 < img
3859 src = { logo }
3960 alt = "Sugar Labs"
@@ -43,9 +64,10 @@ const Header: React.FC = () => {
4364
4465 { /* Mobile Menu Button */ }
4566 < button
46- className = "md:hidden relative w-10 h-10 focus:outline-none group"
67+ className = "md:hidden relative w-10 h-10 focus:outline-none group z-50 "
4768 onClick = { ( ) => setMenuOpen ( ! menuOpen ) }
4869 aria-label = "Toggle menu"
70+ aria-expanded = { menuOpen }
4971 >
5072 < div className = "absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2" >
5173 < span
@@ -81,8 +103,9 @@ const Header: React.FC = () => {
81103 >
82104 < button
83105 className = { `px-3 py-2 text-gray-700 hover:text-blue-600 font-medium rounded-md
84- transition-all duration-200 hover:bg-gray-50 flex items-center space-x-1
85- ${ activeDropdown === key ? 'text-blue-600' : '' } ` }
106+ transition-all duration-200 hover:bg-gray-50 flex items-center space-x-1
107+ ${ activeDropdown === key ? 'text-blue-600' : '' } ` }
108+ aria-expanded = { activeDropdown === key }
86109 >
87110 < span > { label } </ span >
88111 < svg
@@ -117,11 +140,11 @@ const Header: React.FC = () => {
117140 key = { item . path }
118141 to = { item . path }
119142 className = "group flex items-center px-4 py-3 text-sm text-gray-700 hover:bg-gray-50
120- transition-all duration-200 hover:text-blue-600"
143+ transition-all duration-200 hover:text-blue-600"
121144 >
122145 < span
123146 className = "w-2 h-2 rounded-full bg-blue-600 opacity-0 group-hover:opacity-100
124- transition-all duration-200 mr-2 transform scale-0 group-hover:scale-100"
147+ transition-all duration-200 mr-2 transform scale-0 group-hover:scale-100"
125148 />
126149 { item . label }
127150 </ Link >
@@ -140,7 +163,7 @@ const Header: React.FC = () => {
140163 key = { item }
141164 to = { `/${ item . toLowerCase ( ) . replace ( ' ' , '-' ) } ` }
142165 className = "px-3 py-2 text-gray-700 hover:text-blue-600 font-medium rounded-md
143- transition-all duration-200 hover:bg-gray-50"
166+ transition-all duration-200 hover:bg-gray-50"
144167 >
145168 { item }
146169 </ Link >
@@ -151,26 +174,42 @@ const Header: React.FC = () => {
151174 < Link
152175 to = "/try-sugar"
153176 className = "inline-flex items-center px-6 py-2.5 rounded-full font-semibold text-white
154- bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800
155- transition-all duration-300 transform hover:scale-105 hover:shadow-lg
156- focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
177+ bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800
178+ transition-all duration-300 transform hover:scale-105 hover:shadow-lg
179+ focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
157180 >
158181 TRY NOW
159182 </ Link >
160183 </ div >
161184
162- { /* Mobile Navigation */ }
185+ { /* Mobile Navigation Backdrop */ }
163186 < AnimatePresence >
164187 { menuOpen && (
165188 < motion . div
166- initial = { { opacity : 0 , x : 100 } }
189+ initial = { { opacity : 0 } }
190+ animate = { { opacity : 1 } }
191+ exit = { { opacity : 0 } }
192+ transition = { { duration : 0.2 } }
193+ className = "fixed inset-0 bg-black/30 md:hidden z-40"
194+ onClick = { closeMenu }
195+ />
196+ ) }
197+ </ AnimatePresence >
198+
199+ { /* Mobile Navigation Menu */ }
200+ < AnimatePresence >
201+ { menuOpen && (
202+ < motion . div
203+ initial = { { opacity : 0 , x : '100%' } }
167204 animate = { { opacity : 1 , x : 0 } }
168- exit = { { opacity : 0 , x : 100 } }
169- transition = { { type : 'tween' } }
170- className = "fixed md:hidden top-20 right-0 bottom-0 w-full bg-white shadow-xl z-40"
205+ exit = { { opacity : 0 , x : '100%' } }
206+ transition = { { type : 'tween' , duration : 0.3 } }
207+ className = "fixed md:hidden top-0 right-0 bottom-0 w-[80%] max-w-sm bg-white shadow-xl z-40
208+ flex flex-col h-full"
171209 >
172- < div className = "flex flex-col h-full overflow-y-auto pb-20" >
173- < div className = "px-4 py-6 space-y-6" >
210+ < div className = "h-20" />
211+ < div className = "flex-1 overflow-y-auto overscroll-contain px-4 py-6" >
212+ < div className = "space-y-6" >
174213 { Object . entries ( dropdowns ) . map (
175214 ( [ key , { label, items } ] ) => (
176215 < div key = { key } className = "space-y-2" >
@@ -181,7 +220,8 @@ const Header: React.FC = () => {
181220 )
182221 }
183222 className = "flex items-center justify-between w-full text-left px-2 py-2
184- text-gray-700 font-medium rounded-lg hover:bg-gray-50"
223+ text-gray-700 font-medium rounded-lg hover:bg-gray-50"
224+ aria-expanded = { activeDropdown === key }
185225 >
186226 < span > { label } </ span >
187227 < svg
@@ -215,8 +255,9 @@ const Header: React.FC = () => {
215255 < Link
216256 key = { item . path }
217257 to = { item . path }
258+ onClick = { closeMenu }
218259 className = "flex items-center px-4 py-2 text-sm text-gray-600
219- rounded-lg hover:bg-gray-50 hover:text-blue-600"
260+ rounded-lg hover:bg-gray-50 hover:text-blue-600"
220261 >
221262 { item . label }
222263 </ Link >
@@ -238,30 +279,33 @@ const Header: React.FC = () => {
238279 < Link
239280 key = { item }
240281 to = { `/${ item . toLowerCase ( ) . replace ( ' ' , '-' ) } ` }
282+ onClick = { closeMenu }
241283 className = "block px-4 py-2 text-gray-700 font-medium rounded-lg
242- hover:bg-gray-50 hover:text-blue-600"
284+ hover:bg-gray-50 hover:text-blue-600"
243285 >
244286 { item }
245287 </ Link >
246288 ) ) }
247-
248- < Link
249- to = "/try-sugar"
250- className = "flex items-center justify-center px-6 py-3 rounded-xl font-semibold
251- text-white bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700
252- hover:to-blue-800 transition-all duration-300"
253- >
254- TRY NOW
255- </ Link >
256289 </ div >
257290 </ div >
291+ < div className = "p-4 border-t border-gray-200" >
292+ < Link
293+ to = "/try-sugar"
294+ onClick = { closeMenu }
295+ className = "flex items-center justify-center px-6 py-3 rounded-xl font-semibold
296+ text-white bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700
297+ hover:to-blue-800 transition-all duration-300 w-full"
298+ >
299+ TRY NOW
300+ </ Link >
301+ </ div >
258302 </ motion . div >
259303 ) }
260304 </ AnimatePresence >
261305 </ div >
262- </ nav >
263- </ header >
264- < div className = "h-20" > </ div >
306+ </ div >
307+ </ div >
308+ < div className = "h-10" / >
265309 </ >
266310 ) ;
267311} ;
0 commit comments