@@ -16,6 +16,8 @@ import {
1616 Wallet ,
1717 Repeat ,
1818 Trophy ,
19+ Menu ,
20+ X ,
1921 type LucideIcon ,
2022} from 'lucide-react' ;
2123
@@ -175,49 +177,91 @@ function NavSection({ item, pathname }: { item: NavItem; pathname: string }) {
175177
176178export default function Sidebar ( ) {
177179 const pathname = usePathname ( ) ;
180+ const [ mobileOpen , setMobileOpen ] = useState ( false ) ;
181+
182+ // Close sidebar on navigation
183+ const handleNavClick = ( ) => setMobileOpen ( false ) ;
178184
179185 return (
180- < aside className = "w-64 shrink-0 bg-[var(--sidebar-bg)] border-r border-[var(--sidebar-border)] h-full flex flex-col overflow-hidden" >
181- { /* Header */ }
182- < div className = "px-4 py-3 border-b border-[var(--sidebar-border)]" >
183- < Link href = "/" className = "flex items-center gap-2.5 rounded-lg px-1 py-1 hover:bg-[var(--sidebar-accent)] transition-colors" >
184- < div className = "shrink-0" >
185- < svg
186- xmlns = "http://www.w3.org/2000/svg"
187- fill = "none"
188- viewBox = "0 0 112 154"
189- className = "w-6 h-auto text-[var(--sidebar-primary)]"
190- >
191- < path d = "M48.303 153.213c-10.797 0-21.457-2.796-31.1-8.277l5.078-8.934c12.275 6.977 26.536 8.756 40.153 5.008 13.616-3.749 24.963-12.576 31.94-24.863 6.976-12.28 8.756-26.542 5.008-40.158-3.749-13.617-12.577-24.958-24.863-31.94l5.073-8.934c14.67 8.337 25.211 21.882 29.693 38.142 4.476 16.266 2.353 33.294-5.983 47.957-8.337 14.669-21.883 25.212-38.143 29.687a63.538 63.538 0 01-16.857 2.295v.017z" fill = "currentColor" />
192- < path d = "M48.338 132.661c-7.284 0-14.48-1.886-20.983-5.581l5.002-8.828c7.514 4.269 16.307 5.245 24.637 2.951 8.331-2.294 15.267-7.692 19.53-15.207 8.81-15.51 3.358-35.293-12.145-44.097l5.073-8.934c20.434 11.607 27.612 37.67 16.006 58.11-5.623 9.897-14.764 17.016-25.738 20.037a42.877 42.877 0 01-11.382 1.549z" fill = "currentColor" />
193- < path d = "M32.357 118.258c-14.664-8.33-25.212-21.876-29.688-38.136-4.475-16.266-2.353-33.3 5.978-47.969C25.86 1.881 64.486-8.757 94.764 8.443l-5.073 8.935c-25.353-14.404-57.7-5.5-72.11 19.854-6.977 12.28-8.757 26.548-5.002 40.164 3.749 13.617 12.529 24.975 24.81 31.946l-5.026 8.916h-.006z" fill = "currentColor" />
194- < path d = "M42.455 100.408C22.02 88.801 14.896 62.744 26.503 42.304c5.622-9.897 14.775-17.028 25.767-20.073 11.003-3.05 22.515-1.632 32.413 3.991l-5.085 8.91c-7.503-4.262-16.23-5.309-24.585-2.997-8.354 2.312-15.308 7.728-19.576 15.248-8.81 15.51-3.359 35.293 12.144 44.097l-5.126 8.928z" fill = "currentColor" />
195- < path d = "M58.502 72.24c-5.872-3.334-7.894-10.08-4.79-15.544 1.686-2.962 3.986-4.783 6.835-5.41 2.768-.609 5.93-.012 8.905 1.68l5.061-8.911c-5.185-2.945-10.926-3.962-16.17-2.809-5.66 1.242-10.478 4.925-13.57 10.371-5.895 10.377-2.14 23.402 8.62 29.534 5.771 3.281 7.834 10.175 4.695 15.704-1.508 2.66-3.82 4.41-6.675 5.061-2.892.662-6.073.124-8.964-1.52l-5.073 8.934c3.642 2.07 7.621 3.134 11.565 3.134a21.61 21.61 0 004.766-.532c5.664-1.295 10.394-4.849 13.32-10.005 5.978-10.524 2.236-23.561-8.525-29.693v.006z" fill = "currentColor" />
196- </ svg >
197- </ div >
198- < p className = "text-sm font-semibold text-[var(--sidebar-primary)] truncate" > Developer< br > </ br > Data< br > </ br > Portal</ p >
199- </ Link >
200- </ div >
186+ < >
187+ { /* Mobile hamburger button */ }
188+ < button
189+ onClick = { ( ) => setMobileOpen ( true ) }
190+ className = "fixed top-3 left-3 z-50 md:hidden p-2 rounded-lg bg-[var(--sidebar-bg)] border border-[var(--sidebar-border)] shadow-sm"
191+ aria-label = "Open menu"
192+ >
193+ < Menu className = "h-5 w-5 text-[var(--sidebar-primary)]" />
194+ </ button >
201195
202- { /* Navigation */ }
203- < nav className = "flex-1 overflow-y-auto py-1" >
204- { navItems . map ( ( item ) => (
205- < NavSection key = { item . href } item = { item } pathname = { pathname } />
206- ) ) }
207- </ nav >
208-
209- { /* Footer */ }
210- < div className = "border-t border-[var(--sidebar-border)] px-4 py-3" >
211- < a
212- href = "https://github.com/opensource-observer/ddp"
213- target = "_blank"
214- rel = "noopener noreferrer"
215- className = "flex items-center gap-2 px-1 text-sm text-[var(--sidebar-muted)] hover:text-[var(--sidebar-primary)] transition-colors"
216- >
217- < svg className = "h-4 w-4" viewBox = "0 0 24 24" fill = "currentColor" > < path d = "M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" /> </ svg >
218- < span > GitHub</ span >
219- </ a >
220- </ div >
221- </ aside >
196+ { /* Mobile overlay */ }
197+ { mobileOpen && (
198+ < div
199+ className = "fixed inset-0 z-40 bg-black/30 md:hidden"
200+ onClick = { ( ) => setMobileOpen ( false ) }
201+ />
202+ ) }
203+
204+ < aside
205+ className = { `
206+ bg-[var(--sidebar-bg)] border-r border-[var(--sidebar-border)] h-full flex flex-col overflow-hidden
207+ md:w-64 md:shrink-0 md:relative md:translate-x-0
208+ fixed inset-y-0 left-0 z-50 w-full md:w-64 transition-transform duration-200 ease-in-out
209+ ${ mobileOpen ? 'translate-x-0' : '-translate-x-full md:translate-x-0' }
210+ ` }
211+ >
212+ { /* Header */ }
213+ < div className = "px-4 py-3 border-b border-[var(--sidebar-border)] flex items-center justify-between" >
214+ < Link
215+ href = "/"
216+ onClick = { handleNavClick }
217+ className = "flex items-center gap-2.5 rounded-lg px-1 py-1 hover:bg-[var(--sidebar-accent)] transition-colors"
218+ >
219+ < div className = "shrink-0" >
220+ < svg
221+ xmlns = "http://www.w3.org/2000/svg"
222+ fill = "none"
223+ viewBox = "0 0 112 154"
224+ className = "w-6 h-auto text-[var(--sidebar-primary)]"
225+ >
226+ < path d = "M48.303 153.213c-10.797 0-21.457-2.796-31.1-8.277l5.078-8.934c12.275 6.977 26.536 8.756 40.153 5.008 13.616-3.749 24.963-12.576 31.94-24.863 6.976-12.28 8.756-26.542 5.008-40.158-3.749-13.617-12.577-24.958-24.863-31.94l5.073-8.934c14.67 8.337 25.211 21.882 29.693 38.142 4.476 16.266 2.353 33.294-5.983 47.957-8.337 14.669-21.883 25.212-38.143 29.687a63.538 63.538 0 01-16.857 2.295v.017z" fill = "currentColor" />
227+ < path d = "M48.338 132.661c-7.284 0-14.48-1.886-20.983-5.581l5.002-8.828c7.514 4.269 16.307 5.245 24.637 2.951 8.331-2.294 15.267-7.692 19.53-15.207 8.81-15.51 3.358-35.293-12.145-44.097l5.073-8.934c20.434 11.607 27.612 37.67 16.006 58.11-5.623 9.897-14.764 17.016-25.738 20.037a42.877 42.877 0 01-11.382 1.549z" fill = "currentColor" />
228+ < path d = "M32.357 118.258c-14.664-8.33-25.212-21.876-29.688-38.136-4.475-16.266-2.353-33.3 5.978-47.969C25.86 1.881 64.486-8.757 94.764 8.443l-5.073 8.935c-25.353-14.404-57.7-5.5-72.11 19.854-6.977 12.28-8.757 26.548-5.002 40.164 3.749 13.617 12.529 24.975 24.81 31.946l-5.026 8.916h-.006z" fill = "currentColor" />
229+ < path d = "M42.455 100.408C22.02 88.801 14.896 62.744 26.503 42.304c5.622-9.897 14.775-17.028 25.767-20.073 11.003-3.05 22.515-1.632 32.413 3.991l-5.085 8.91c-7.503-4.262-16.23-5.309-24.585-2.997-8.354 2.312-15.308 7.728-19.576 15.248-8.81 15.51-3.359 35.293 12.144 44.097l-5.126 8.928z" fill = "currentColor" />
230+ < path d = "M58.502 72.24c-5.872-3.334-7.894-10.08-4.79-15.544 1.686-2.962 3.986-4.783 6.835-5.41 2.768-.609 5.93-.012 8.905 1.68l5.061-8.911c-5.185-2.945-10.926-3.962-16.17-2.809-5.66 1.242-10.478 4.925-13.57 10.371-5.895 10.377-2.14 23.402 8.62 29.534 5.771 3.281 7.834 10.175 4.695 15.704-1.508 2.66-3.82 4.41-6.675 5.061-2.892.662-6.073.124-8.964-1.52l-5.073 8.934c3.642 2.07 7.621 3.134 11.565 3.134a21.61 21.61 0 004.766-.532c5.664-1.295 10.394-4.849 13.32-10.005 5.978-10.524 2.236-23.561-8.525-29.693v.006z" fill = "currentColor" />
231+ </ svg >
232+ </ div >
233+ < p className = "text-sm font-semibold text-[var(--sidebar-primary)] truncate" > Developer< br > </ br > Data< br > </ br > Portal</ p >
234+ </ Link >
235+ { /* Mobile close button */ }
236+ < button
237+ onClick = { ( ) => setMobileOpen ( false ) }
238+ className = "md:hidden p-1 rounded-md hover:bg-[var(--sidebar-accent)] transition-colors"
239+ aria-label = "Close menu"
240+ >
241+ < X className = "h-5 w-5 text-[var(--sidebar-muted)]" />
242+ </ button >
243+ </ div >
244+
245+ { /* Navigation */ }
246+ < nav className = "flex-1 overflow-y-auto py-1" onClick = { handleNavClick } >
247+ { navItems . map ( ( item ) => (
248+ < NavSection key = { item . href } item = { item } pathname = { pathname } />
249+ ) ) }
250+ </ nav >
251+
252+ { /* Footer */ }
253+ < div className = "border-t border-[var(--sidebar-border)] px-4 py-3" >
254+ < a
255+ href = "https://github.com/opensource-observer/ddp"
256+ target = "_blank"
257+ rel = "noopener noreferrer"
258+ className = "flex items-center gap-2 px-1 text-sm text-[var(--sidebar-muted)] hover:text-[var(--sidebar-primary)] transition-colors"
259+ >
260+ < svg className = "h-4 w-4" viewBox = "0 0 24 24" fill = "currentColor" > < path d = "M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" /> </ svg >
261+ < span > GitHub</ span >
262+ </ a >
263+ </ div >
264+ </ aside >
265+ </ >
222266 ) ;
223267}
0 commit comments