1- import { NavLink } from 'react-router-dom'
1+ import { useEffect } from 'react'
2+ import { NavLink , useLocation } from 'react-router-dom'
23
34const SIDEBAR_ITEMS = [
45 {
@@ -58,9 +59,9 @@ const SETTINGS_ITEMS = [
5859 } ,
5960] as const
6061
61- export function AdminSidebar ( ) {
62+ function NavItems ( { onNavigate } : { onNavigate ?: ( ) => void } ) {
6263 return (
63- < aside className = "flex w-56 shrink-0 flex-col border-r border-slate-800 bg-slate-950/80" >
64+ < >
6465 < div className = "flex flex-col gap-0.5 p-3" >
6566 < p className = "mb-2 px-3 text-[10px] font-semibold uppercase tracking-wider text-slate-500" >
6667 Content
@@ -70,6 +71,7 @@ export function AdminSidebar() {
7071 key = { to }
7172 to = { to }
7273 end = { end }
74+ onClick = { onNavigate }
7375 className = { ( { isActive } ) =>
7476 `flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition ${
7577 isActive
@@ -92,6 +94,7 @@ export function AdminSidebar() {
9294 key = { to }
9395 to = { to }
9496 end = { end }
97+ onClick = { onNavigate }
9598 className = { ( { isActive } ) =>
9699 `flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition ${
97100 isActive
@@ -105,6 +108,75 @@ export function AdminSidebar() {
105108 </ NavLink >
106109 ) ) }
107110 </ div >
108- </ aside >
111+ </ >
112+ )
113+ }
114+
115+ type AdminSidebarProps = {
116+ drawerOpen : boolean
117+ onClose : ( ) => void
118+ }
119+
120+ export function AdminSidebar ( { drawerOpen, onClose } : AdminSidebarProps ) {
121+ const location = useLocation ( )
122+
123+ // Close drawer on route change
124+ useEffect ( ( ) => {
125+ onClose ( )
126+ } , [ location . pathname , onClose ] )
127+
128+ // Lock body scroll when drawer is open
129+ useEffect ( ( ) => {
130+ if ( drawerOpen ) {
131+ document . body . style . overflow = 'hidden'
132+ } else {
133+ document . body . style . overflow = ''
134+ }
135+ return ( ) => {
136+ document . body . style . overflow = ''
137+ }
138+ } , [ drawerOpen ] )
139+
140+ return (
141+ < >
142+ { /* Desktop sidebar — always visible on md+ */ }
143+ < aside className = "hidden w-56 shrink-0 flex-col border-r border-slate-800 bg-slate-950/80 md:flex" >
144+ < NavItems />
145+ </ aside >
146+
147+ { /* Mobile drawer */ }
148+ { /* Backdrop */ }
149+ < div
150+ className = { `fixed inset-0 z-40 bg-black/60 transition-opacity duration-300 md:hidden ${
151+ drawerOpen ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'
152+ } `}
153+ onClick = { onClose }
154+ aria-hidden = "true"
155+ />
156+ { /* Drawer panel */ }
157+ < aside
158+ className = { `fixed inset-y-0 left-0 z-50 flex w-64 flex-col border-r border-slate-800 bg-slate-950 transition-transform duration-300 ease-in-out md:hidden ${
159+ drawerOpen ? 'translate-x-0' : '-translate-x-full'
160+ } `}
161+ aria-label = "Navigation drawer"
162+ >
163+ < div className = "flex h-14 shrink-0 items-center justify-between border-b border-slate-800 px-4" >
164+ < span className = "text-sm font-semibold text-slate-200" > Menu</ span >
165+ < button
166+ type = "button"
167+ onClick = { onClose }
168+ className = "flex h-8 w-8 items-center justify-center rounded-md text-slate-400 transition hover:bg-slate-800 hover:text-slate-200"
169+ aria-label = "Close navigation menu"
170+ >
171+ < svg className = "h-5 w-5" fill = "none" viewBox = "0 0 24 24" stroke = "currentColor" strokeWidth = { 2 } >
172+ < path strokeLinecap = "round" strokeLinejoin = "round" d = "M6 18L18 6M6 6l12 12" />
173+ </ svg >
174+ </ button >
175+ </ div >
176+ < div className = "flex-1 overflow-y-auto" >
177+ < NavItems />
178+ </ div >
179+ </ aside >
180+ </ >
109181 )
110182}
0 commit comments