@@ -3,9 +3,10 @@ import { Logo } from "@/components/logo";
33import { Button } from "@/components/ui/button" ;
44import useUser from "@/hooks/use-user" ;
55import { cn } from "@/lib/utils" ;
6- import { BarChart3 , BookOpen , ChevronDown , MessageSquare , Swords } from "lucide-react" ;
6+ import { BarChart3 , BookOpen , ChevronDown , Menu , MessageSquare , Swords , X } from "lucide-react" ;
77import Link from "next/link" ;
8- import { Suspense } from "react" ;
8+ import { Suspense , useState } from "react" ;
9+ import { Collapsible , CollapsibleContent , CollapsibleTrigger } from "./ui/collapsible" ;
910import { DropdownMenu , DropdownMenuContent , DropdownMenuItem , DropdownMenuTrigger } from "./ui/dropdown-menu" ;
1011
1112interface NavItemProps {
@@ -19,7 +20,11 @@ function NavItem({ icon, label, active = false }: NavItemProps) {
1920 < Button
2021 variant = "ghost"
2122 className = { cn (
22- "flex h-auto items-center gap-3 rounded px-3 py-2 text-sm" ,
23+ `
24+ flex h-auto w-full items-center justify-start gap-3 rounded px-3 py-2
25+ text-sm
26+ md:w-auto md:justify-center
27+ ` ,
2328 active && "bg-primary text-primary-foreground" ,
2429 ) }
2530 >
@@ -56,45 +61,107 @@ function UserMenu() {
5661
5762export default function AppNavbar ( { path } : { path : string } ) {
5863 const navItemLabel = getActiveNavItemLabel ( path ) ;
64+ const [ isMobileMenuOpen , setIsMobileMenuOpen ] = useState ( false ) ;
5965
6066 return (
61- < nav className = "border-b border-stone-200 bg-stone-50" >
62- < div className = "flex items-center justify-between px-6 py-0" >
63- { /* Left Section */ }
64- < div className = "flex items-center gap-4" >
65- { /* Logo and Title */ }
66- < Link href = "/" >
67- < div className = "flex items-center gap-3 px-3 py-4" >
68- < Logo className = "h-4 w-4" />
69- < span className = "whitespace-nowrap text-stone-900" >
70- 資料庫練功房
71- </ span >
67+ < Collapsible open = { isMobileMenuOpen } onOpenChange = { setIsMobileMenuOpen } >
68+ < nav className = "border-b border-stone-200 bg-stone-50" >
69+ < div className = "flex items-center justify-between px-6 py-0" >
70+ { /* Left Section */ }
71+ < div className = "flex items-center gap-4" >
72+ { /* Logo and Title */ }
73+ < Link href = "/" >
74+ < div className = "flex items-center gap-3 px-3 py-4" >
75+ < Logo className = "h-4 w-4" />
76+ < span className = "whitespace-nowrap text-stone-900" >
77+ 資料庫練功房
78+ </ span >
79+ </ div >
80+ </ Link >
81+
82+ { /* Desktop Navigation Items - Hidden on mobile */ }
83+ < div
84+ className = { `
85+ hidden items-center gap-1
86+ md:flex
87+ ` }
88+ >
89+ { navItems . map ( ( item ) => (
90+ < Link href = { item . pathPrefix } key = { item . label } >
91+ < NavItem
92+ key = { item . label }
93+ icon = { item . icon }
94+ label = { item . label }
95+ active = { navItemLabel === item . label }
96+ />
97+ </ Link >
98+ ) ) }
7299 </ div >
73- </ Link >
100+ </ div >
74101
75- { /* Navigation Items */ }
76- < div className = "flex items-center gap-1" >
77- { navItems . map ( ( item ) => (
78- < Link href = { item . pathPrefix } key = { item . label } >
79- < NavItem
80- key = { item . label }
81- icon = { item . icon }
82- label = { item . label }
83- active = { navItemLabel === item . label }
84- />
85- </ Link >
86- ) ) }
102+ { /* Right Section */ }
103+ < div className = "flex items-center gap-2" >
104+ { /* Desktop User Menu - Hidden on mobile */ }
105+ < div
106+ className = { `
107+ hidden
108+ md:block
109+ ` }
110+ >
111+ < Suspense >
112+ < UserMenu />
113+ </ Suspense >
114+ </ div >
115+
116+ { /* Mobile Menu Button - Only visible on mobile */ }
117+ < CollapsibleTrigger asChild className = "md:hidden" >
118+ < Button
119+ variant = "ghost"
120+ size = "icon"
121+ className = "h-10 w-10"
122+ aria-label = "Toggle mobile menu"
123+ >
124+ { isMobileMenuOpen ? < X className = "h-5 w-5" /> : (
125+ < Menu
126+ className = { `h-5 w-5` }
127+ />
128+ ) }
129+ </ Button >
130+ </ CollapsibleTrigger >
87131 </ div >
88132 </ div >
89133
90- { /* Right Section - User Menu */ }
91- < div className = "flex items-center" >
92- < Suspense >
93- < UserMenu />
94- </ Suspense >
95- </ div >
96- </ div >
97- </ nav >
134+ { /* Mobile Navigation Menu */ }
135+ < CollapsibleContent className = "md:hidden" >
136+ < div className = "border-t border-stone-200 bg-stone-50" >
137+ < div className = "flex flex-col space-y-1 px-6 py-4" >
138+ { /* Mobile Navigation Items */ }
139+ { navItems . map ( ( item ) => (
140+ < Link
141+ href = { item . pathPrefix }
142+ key = { item . label }
143+ onClick = { ( ) => setIsMobileMenuOpen ( false ) }
144+ >
145+ < NavItem
146+ key = { item . label }
147+ icon = { item . icon }
148+ label = { item . label }
149+ active = { navItemLabel === item . label }
150+ />
151+ </ Link >
152+ ) ) }
153+
154+ { /* Mobile User Menu */ }
155+ < div className = "mt-4 border-t border-stone-200 pt-4" >
156+ < Suspense >
157+ < UserMenu />
158+ </ Suspense >
159+ </ div >
160+ </ div >
161+ </ div >
162+ </ CollapsibleContent >
163+ </ nav >
164+ </ Collapsible >
98165 ) ;
99166}
100167
0 commit comments