@@ -7,6 +7,15 @@ use crate::{LOGO, Route};
7
7
/// Shared navbar component.
8
8
#[ component]
9
9
pub ( crate ) fn Navbar ( ) -> Element {
10
+ // Get the current route
11
+ let route = use_route :: < Route > ( ) ;
12
+
13
+ // Helper function to determine if a link is active
14
+ let is_active = |path : Route | -> bool { route == path } ;
15
+
16
+ // Add state to track if mobile menu is open
17
+ let mut is_menu_open = use_signal ( || false ) ;
18
+
10
19
rsx ! {
11
20
nav {
12
21
div { class: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" ,
@@ -16,38 +25,70 @@ pub(crate) fn Navbar() -> Element {
16
25
r#type: "button" ,
17
26
class: "inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500" ,
18
27
aria_controls: "mobile-menu" ,
19
- aria_expanded: "false" ,
28
+ aria_expanded: "{is_menu_open}" ,
29
+ onclick: move |_| is_menu_open. set( !is_menu_open( ) ) ,
20
30
span { class: "sr-only" , "Menu" }
21
31
i {
22
- svg {
23
- xmlns: "http://www.w3.org/2000/svg" ,
24
- width: "24" ,
25
- height: "24" ,
26
- view_box: "0 0 24 24" ,
27
- fill: "none" ,
28
- stroke: "currentColor" ,
29
- "stroke-width" : "2" ,
30
- "stroke-linecap" : "round" ,
31
- "stroke-linejoin" : "round" ,
32
- class: "lucide lucide-menu" ,
32
+ // Show different icon based on menu state
33
+ if * is_menu_open. read( ) {
34
+ // X icon when menu is open
35
+ svg {
36
+ xmlns: "http://www.w3.org/2000/svg" ,
37
+ width: "24" ,
38
+ height: "24" ,
39
+ view_box: "0 0 24 24" ,
40
+ fill: "none" ,
41
+ stroke: "currentColor" ,
42
+ "stroke-width" : "2" ,
43
+ "stroke-linecap" : "round" ,
44
+ "stroke-linejoin" : "round" ,
45
+ class: "lucide lucide-x" ,
33
46
34
- line {
35
- x1: "4" ,
36
- x2: "20" ,
37
- y1: "12" ,
38
- y2: "12" ,
39
- }
40
- line {
41
- x1: "4" ,
42
- x2: "20" ,
43
- y1: "6" ,
44
- y2: "6" ,
47
+ line {
48
+ x1: "18" ,
49
+ x2: "6" ,
50
+ y1: "6" ,
51
+ y2: "18" ,
52
+ }
53
+ line {
54
+ x1: "6" ,
55
+ x2: "18" ,
56
+ y1: "6" ,
57
+ y2: "18" ,
58
+ }
45
59
}
46
- line {
47
- x1: "4" ,
48
- x2: "20" ,
49
- y1: "18" ,
50
- y2: "18" ,
60
+ } else {
61
+ // Hamburger icon when menu is closed
62
+ svg {
63
+ xmlns: "http://www.w3.org/2000/svg" ,
64
+ width: "24" ,
65
+ height: "24" ,
66
+ view_box: "0 0 24 24" ,
67
+ fill: "none" ,
68
+ stroke: "currentColor" ,
69
+ "stroke-width" : "2" ,
70
+ "stroke-linecap" : "round" ,
71
+ "stroke-linejoin" : "round" ,
72
+ class: "lucide lucide-menu" ,
73
+
74
+ line {
75
+ x1: "4" ,
76
+ x2: "20" ,
77
+ y1: "12" ,
78
+ y2: "12" ,
79
+ }
80
+ line {
81
+ x1: "4" ,
82
+ x2: "20" ,
83
+ y1: "6" ,
84
+ y2: "6" ,
85
+ }
86
+ line {
87
+ x1: "4" ,
88
+ x2: "20" ,
89
+ y1: "18" ,
90
+ y2: "18" ,
91
+ }
51
92
}
52
93
}
53
94
}
@@ -65,37 +106,42 @@ pub(crate) fn Navbar() -> Element {
65
106
div { class: "hidden sm:ml-6 sm:flex sm:space-x-8" ,
66
107
Link {
67
108
id: "home" ,
68
- class: "border-indigo-500 text-gray-900 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" ,
109
+ class: if is_active( Route :: Home { } ) { "border-indigo-500 text-gray-900 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" } else { "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" } ,
110
+ aria_current: if is_active( Route :: Home { } ) { "page" } else { "" } ,
69
111
to: Route :: Home { } ,
70
112
"Home"
71
113
}
72
114
Link {
73
- id : "create" ,
74
- class : "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" ,
115
+ class : if is_active ( Route :: Create { } ) { "border-indigo-500 text-gray-900 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" } else { "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" } ,
116
+ aria_current : if is_active ( Route :: Create { } ) { "page" } else { "" } ,
75
117
to: Route :: Create { } ,
76
118
"Create"
77
119
}
78
120
Link {
79
121
id: "sign" ,
80
- class: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" ,
122
+ class: if is_active( Route :: Sign { } ) { "border-indigo-500 text-gray-900 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" } else { "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" } ,
123
+ aria_current: if is_active( Route :: Sign { } ) { "page" } else { "" } ,
81
124
to: Route :: Sign { } ,
82
125
"Sign"
83
126
}
84
127
Link {
85
128
id: "combine" ,
86
- class: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" ,
129
+ class: if is_active( Route :: Combine { } ) { "border-indigo-500 text-gray-900 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" } else { "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" } ,
130
+ aria_current: if is_active( Route :: Combine { } ) { "page" } else { "" } ,
87
131
to: Route :: Combine { } ,
88
132
"Combine"
89
133
}
90
134
Link {
91
135
id: "broadcast" ,
92
- class: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" ,
136
+ class: if is_active( Route :: Broadcast { } ) { "border-indigo-500 text-gray-900 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" } else { "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" } ,
137
+ aria_current: if is_active( Route :: Broadcast { } ) { "page" } else { "" } ,
93
138
to: Route :: Broadcast { } ,
94
139
"Broadcast"
95
140
}
96
141
Link {
97
142
id: "spend" ,
98
- class: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" ,
143
+ class: if is_active( Route :: Spend { } ) { "border-indigo-500 text-gray-900 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" } else { "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium" } ,
144
+ aria_current: if is_active( Route :: Spend { } ) { "page" } else { "" } ,
99
145
to: Route :: Spend { } ,
100
146
"Spend"
101
147
}
@@ -104,7 +150,8 @@ pub(crate) fn Navbar() -> Element {
104
150
div { class: "flex" ,
105
151
Link {
106
152
id: "settings" ,
107
- class: "p-2 rounded-full text-gray-500 hover:text-gray-700 focus:outline-none" ,
153
+ class: if is_active( Route :: Settings { } ) { "p-2 rounded-full text-indigo-500 focus:outline-none" } else { "p-2 rounded-full text-gray-500 hover:text-gray-700 focus:outline-none" } ,
154
+ aria_current: if is_active( Route :: Settings { } ) { "page" } else { "" } ,
108
155
to: Route :: Settings { } ,
109
156
i {
110
157
svg {
@@ -140,42 +187,49 @@ pub(crate) fn Navbar() -> Element {
140
187
}
141
188
}
142
189
}
143
- div { id: "mobile-menu" , class: "sm:hidden" ,
190
+ div {
191
+ id: "mobile-menu" ,
192
+ class: if * is_menu_open. read( ) { "sm:hidden" } else { "hidden sm:hidden" } ,
144
193
div { class: "pt-2 pb-3 space-y-1" ,
145
194
Link {
146
195
id: "home" ,
147
- class: "bg-indigo-50 border-indigo-500 text-indigo-700 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" ,
148
- aria_current: "page" ,
196
+ class: if is_active ( Route :: Home { } ) { "bg-indigo-50 border-indigo-500 text-indigo-700 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" } else { "border-transparent text-gray-600 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-800 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" } ,
197
+ aria_current: if is_active ( Route :: Home { } ) { "page" } else { "" } ,
149
198
to: Route :: Home { } ,
150
199
"Home"
151
200
}
152
201
Link {
153
202
id: "create" ,
154
- class: "border-transparent text-gray-600 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-800 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" ,
203
+ class: if is_active( Route :: Create { } ) { "bg-indigo-50 border-indigo-500 text-indigo-700 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" } else { "border-transparent text-gray-600 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-800 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" } ,
204
+ aria_current: if is_active( Route :: Create { } ) { "page" } else { "" } ,
155
205
to: Route :: Create { } ,
156
206
"Create"
157
207
}
158
208
Link {
159
209
id: "sign" ,
160
- class: "border-transparent text-gray-600 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-800 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" ,
210
+ class: if is_active( Route :: Sign { } ) { "bg-indigo-50 border-indigo-500 text-indigo-700 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" } else { "border-transparent text-gray-600 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-800 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" } ,
211
+ aria_current: if is_active( Route :: Sign { } ) { "page" } else { "" } ,
161
212
to: Route :: Sign { } ,
162
213
"Sign"
163
214
}
164
215
Link {
165
216
id: "combine" ,
166
- class: "border-transparent text-gray-600 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-800 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" ,
217
+ class: if is_active( Route :: Combine { } ) { "bg-indigo-50 border-indigo-500 text-indigo-700 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" } else { "border-transparent text-gray-600 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-800 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" } ,
218
+ aria_current: if is_active( Route :: Combine { } ) { "page" } else { "" } ,
167
219
to: Route :: Combine { } ,
168
220
"Combine"
169
221
}
170
222
Link {
171
223
id: "broadcast" ,
172
- class: "border-transparent text-gray-600 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-800 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" ,
224
+ class: if is_active( Route :: Broadcast { } ) { "bg-indigo-50 border-indigo-500 text-indigo-700 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" } else { "border-transparent text-gray-600 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-800 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" } ,
225
+ aria_current: if is_active( Route :: Broadcast { } ) { "page" } else { "" } ,
173
226
to: Route :: Broadcast { } ,
174
227
"Broadcast"
175
228
}
176
229
Link {
177
230
id: "spend" ,
178
- class: "border-transparent text-gray-600 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-800 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" ,
231
+ class: if is_active( Route :: Spend { } ) { "bg-indigo-50 border-indigo-500 text-indigo-700 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" } else { "border-transparent text-gray-600 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-800 block pl-3 pr-4 py-2 border-l-4 text-base font-medium" } ,
232
+ aria_current: if is_active( Route :: Spend { } ) { "page" } else { "" } ,
179
233
to: Route :: Spend { } ,
180
234
"Spend"
181
235
}
0 commit comments