@@ -4,10 +4,28 @@ import { Menu, X } from 'lucide-react';
44import Link from 'next/link' ;
55
66const Hamburger = ( ) => {
7+ // Needs dom element to be same bfore and after
8+ // setIsOpen(true) occurs first while dom portal doesnt exist
9+ // Then creates dom portal
10+ // So it tries to go from isOpen=true to isOpen=true
11+ // So no animation occurs as it starts from its finishing val
12+ // So we need to create dom portal first, then menu
13+ // animation should only start after dom portal is created
714 const [ isOpen , setIsOpen ] = useState ( false ) ;
15+ const [ showMenu , setShowMenu ] = useState ( false ) ;
16+
17+ const openMenu = ( ) => {
18+ setShowMenu ( true ) ;
19+ setTimeout ( ( ) => setIsOpen ( true ) , 10 ) ;
20+ } ;
21+
22+ const closeMenu = ( ) => {
23+ setIsOpen ( false ) ;
24+ setTimeout ( ( ) => setShowMenu ( false ) , 300 ) ;
25+ } ;
826
927 useEffect ( ( ) => {
10- if ( isOpen ) {
28+ if ( showMenu ) {
1129 document . body . style . overflow = 'hidden' ;
1230 } else {
1331 document . body . style . overflow = 'scroll' ;
@@ -16,87 +34,85 @@ const Hamburger = () => {
1634 return ( ) => {
1735 document . body . style . overflow = 'scroll' ;
1836 } ;
19- } , [ isOpen ] ) ;
37+ } , [ showMenu ] ) ;
2038
2139 useEffect ( ( ) => {
2240 const handleEscape = ( e : KeyboardEvent ) => {
23- if ( e . key === 'Escape' ) setIsOpen ( false ) ;
41+ if ( e . key === 'Escape' ) closeMenu ( ) ;
2442 } ;
2543
26- if ( isOpen ) document . addEventListener ( 'keydown' , handleEscape ) ;
44+ if ( showMenu ) document . addEventListener ( 'keydown' , handleEscape ) ;
2745
2846 return ( ) => {
2947 document . removeEventListener ( 'keydown' , handleEscape ) ;
3048 } ;
31- } , [ isOpen , setIsOpen ] ) ;
32-
33- useEffect ( ( ) => {
34- if ( isOpen ) {
35- document . body . style . overflow = 'hidden' ;
36- } else {
37- document . body . style . overflow = 'scroll' ;
38- }
39-
40- return ( ) => {
41- document . body . style . overflow = 'scroll' ;
42- } ;
43- } , [ isOpen ] ) ;
49+ } , [ showMenu ] ) ;
4450
4551 // Portal renders the backdrop at document.body level
46- // Hence, instead of showing just at nav, it shows over all components
52+ // Hence, instead of showing just at nav, shows over all components
4753 const backdrop =
48- isOpen && typeof document !== 'undefined'
54+ showMenu && typeof document !== 'undefined'
4955 ? ReactDOM . createPortal (
50- < div className = "inset-0 fixed bg-black/50 z-50 backdrop-blur-sm" >
51- { /* Backdrop */ }
52- < div className = "absolute inset-0" onClick = { ( ) => setIsOpen ( false ) } />
53-
56+ // Backdrop
57+ < div
58+ className = { `fixed inset-0 z-50 ease-out transition-all duration-300 ${
59+ isOpen
60+ ? 'bg-black/50 backdrop-blur-sm'
61+ : 'bg-black/0 backdrop-blur-none'
62+ } `}
63+ onClick = { closeMenu }
64+ >
5465 { /* Sidebar */ }
55- < div className = "absolute right-0 top-0 bg-[#3977F9] h-screen w-80 z-50" >
66+ < div
67+ className = { `absolute top-0 right-0 bg-[#3977F9] h-screen w-80 z-50 ease-in-out transition-transform duration-300 ${
68+ isOpen ? 'translate-x-0' : 'translate-x-full'
69+ } `}
70+ onClick = { ( e ) => e . stopPropagation ( ) }
71+ >
5672 < button
57- onClick = { ( ) => setIsOpen ( false ) }
58- className = "text-white absolute top-[45px] right-[30px] p-2"
73+ onClick = { closeMenu }
74+ className = "text-white top-[45px] right-[35px] absolute p-2"
5975 >
6076 < X className = "h-6 w-6" />
6177 </ button >
6278
63- < div className = "p-6 pt-20 flex flex-col gap-4 items-start " >
79+ < div className = "p-6 pt-20 items-start flex flex-col gap-4" >
6480 < Link
6581 href = "/about"
6682 className = "text-white text-lg p-3 hover:underline"
67- onClick = { ( ) => setIsOpen ( false ) }
83+ onClick = { closeMenu }
6884 >
6985 About Us
7086 </ Link >
7187
7288 < Link
7389 href = "/events"
7490 className = "text-white text-lg p-3 hover:underline"
75- onClick = { ( ) => setIsOpen ( false ) }
91+ onClick = { closeMenu }
7692 >
7793 Events
7894 </ Link >
7995
8096 < Link
8197 href = "/resources"
8298 className = "text-white text-lg p-3 hover:underline"
83- onClick = { ( ) => setIsOpen ( false ) }
99+ onClick = { closeMenu }
84100 >
85101 Resources
86102 </ Link >
87103
88104 < Link
89105 href = "/sponsors"
90106 className = "text-white text-lg p-3 hover:underline"
91- onClick = { ( ) => setIsOpen ( false ) }
107+ onClick = { closeMenu }
92108 >
93109 Sponsors
94110 </ Link >
95111
96112 < Link
97113 href = "/contact-us"
98114 className = "text-white text-lg p-3 hover:underline"
99- onClick = { ( ) => setIsOpen ( false ) }
115+ onClick = { closeMenu }
100116 >
101117 Contact Us
102118 </ Link >
@@ -105,7 +121,7 @@ const Hamburger = () => {
105121 href = "https://csesoc-merch.square.site/"
106122 target = "_blank"
107123 className = "text-white text-lg p-3 hover:underline"
108- onClick = { ( ) => setIsOpen ( false ) }
124+ onClick = { closeMenu }
109125 >
110126 Merch
111127 </ a >
@@ -118,12 +134,12 @@ const Hamburger = () => {
118134
119135 return (
120136 < >
121- < button className = "p-2 z-50 relative " onClick = { ( ) => setIsOpen ( ! isOpen ) } >
137+ < button className = "p-2 relative z-50" onClick = { openMenu } >
122138 < Menu className = "text-white w-6 h-6" />
123139 </ button >
124140 { backdrop }
125141 </ >
126142 ) ;
127143} ;
128144
129- export default Hamburger ;
145+ export default Hamburger ;
0 commit comments