Skip to main content

logicaffeine_web/ui/components/
main_nav.rs

1//! Unified navigation component for consistent header across all pages.
2//!
3//! Features:
4//! - Logo and brand name
5//! - Navigation links with active underline indicator (desktop)
6//! - Mobile drawer with expandable trees for Syntax Guide and Learn
7//! - GitHub icon and CTA buttons
8//! - Responsive design with 980px breakpoint
9
10use dioxus::prelude::*;
11use crate::ui::router::Route;
12use crate::ui::components::icon::{Icon, IconVariant, IconSize};
13use crate::content::ContentEngine;
14use crate::ui::pages::guide::content::SECTIONS;
15
16/// Embedded logo SVG — the single embedded copy, shared by nav and footer.
17pub(crate) const LOGO_SVG: &str = include_str!("../../../assets/logo.svg");
18
19/// Which page is currently active
20#[derive(Clone, Copy, PartialEq, Default)]
21pub enum ActivePage {
22    #[default]
23    Guide,
24    Crates,
25    Learn,
26    Studio,
27    Roadmap,
28    Pricing,
29    Registry,
30    Profile,
31    News,
32    Benchmarks,
33    Other,
34}
35
36impl ActivePage {
37    /// Determine the active page from a Route
38    pub fn from_route(route: &Route) -> Self {
39        match route {
40            Route::Landing {} => ActivePage::Other,
41            Route::Guide {} => ActivePage::Guide,
42            Route::Crates {} => ActivePage::Crates,
43            Route::Learn {} => ActivePage::Learn,
44            Route::Studio { .. } => ActivePage::Studio,
45            Route::Workspace { .. } => ActivePage::Studio,
46            Route::Roadmap {} => ActivePage::Roadmap,
47            Route::Pricing {} => ActivePage::Pricing,
48            Route::Success { .. } => ActivePage::Pricing,
49            Route::Registry { .. } => ActivePage::Registry,
50            Route::PackageDetail { .. } => ActivePage::Registry,
51            Route::Profile {} => ActivePage::Profile,
52            Route::News { .. } => ActivePage::News,
53            Route::NewsArticle { .. } => ActivePage::News,
54            Route::Benchmarks {} => ActivePage::Benchmarks,
55            _ => ActivePage::Other,
56        }
57    }
58}
59
60const MAIN_NAV_STYLE: &str = r#"
61.main-nav {
62    position: sticky;
63    top: 0;
64    z-index: 150;
65    backdrop-filter: blur(18px);
66    -webkit-backdrop-filter: blur(18px);
67    background: linear-gradient(180deg, rgba(7,10,18,0.72), rgba(7,10,18,0.44));
68    border-bottom: 1px solid rgba(255,255,255,0.06);
69}
70
71.main-nav-inner {
72    display: flex;
73    align-items: center;
74    justify-content: space-between;
75    padding: var(--spacing-lg) var(--spacing-xl);
76    max-width: 1280px;
77    margin: 0 auto;
78    gap: var(--spacing-lg);
79}
80
81.main-nav-brand {
82    display: flex;
83    align-items: center;
84    gap: var(--spacing-md);
85    text-decoration: none;
86    color: var(--text-primary);
87    z-index: 1001;
88}
89
90.main-nav-logo {
91    width: 64px;
92    height: 64px;
93    border-radius: var(--radius-lg);
94    overflow: hidden;
95    flex-shrink: 0;
96}
97
98.main-nav-logo svg {
99    width: 100%;
100    height: 100%;
101    filter: invert(1);
102}
103
104.main-nav-brand-text {
105    display: flex;
106    flex-direction: column;
107    line-height: 1.05;
108}
109
110.main-nav-brand-name {
111    font-weight: 800;
112    letter-spacing: -0.5px;
113    font-size: var(--font-body-md);
114}
115
116.main-nav-brand-subtitle {
117    font-size: var(--font-caption-sm);
118    color: var(--text-tertiary);
119}
120
121.main-nav-links {
122    display: flex;
123    gap: var(--spacing-xs);
124    align-items: center;
125}
126
127.main-nav-link {
128    position: relative;
129    text-decoration: none;
130    padding: 10px 14px;
131    font-size: var(--font-body-md);
132    font-weight: 500;
133    color: var(--text-secondary);
134    transition: color 0.18s ease;
135    border-radius: var(--radius-md);
136}
137
138.main-nav-link:hover {
139    color: var(--text-primary);
140    background: rgba(255,255,255,0.04);
141}
142
143/* Active underline indicator */
144.main-nav-link::after {
145    content: "";
146    position: absolute;
147    bottom: 2px;
148    left: 14px;
149    right: 14px;
150    height: 2px;
151    background: linear-gradient(90deg, var(--color-accent-blue), var(--color-accent-purple));
152    border-radius: 2px;
153    opacity: 0;
154    transform: scaleX(0);
155    transition: opacity 0.18s ease, transform 0.18s ease;
156}
157
158.main-nav-link.active {
159    color: var(--text-primary);
160}
161
162.main-nav-link.active::after {
163    opacity: 1;
164    transform: scaleX(1);
165}
166
167.main-nav-cta {
168    display: flex;
169    gap: 10px;
170    align-items: center;
171}
172
173.main-nav-btn {
174    display: inline-flex;
175    align-items: center;
176    justify-content: center;
177    gap: var(--spacing-sm);
178    padding: 10px var(--spacing-lg);
179    border-radius: var(--radius-lg);
180    border: 1px solid rgba(255,255,255,0.10);
181    background: rgba(255,255,255,0.05);
182    text-decoration: none;
183    font-weight: 600;
184    font-size: var(--font-body-md);
185    color: var(--text-primary);
186    transition: transform 0.18s ease, background 0.18s ease, border-color 0.18s ease;
187}
188
189.main-nav-btn:hover {
190    transform: translateY(-1px);
191    background: rgba(255,255,255,0.08);
192    border-color: rgba(255,255,255,0.18);
193}
194
195.main-nav-btn.primary {
196    background: linear-gradient(135deg, rgba(0,212,255,0.95), rgba(129,140,248,0.95));
197    border-color: rgba(255,255,255,0.20);
198    color: #09090b;
199    box-shadow: 0 12px 30px rgba(0,212,255,0.18);
200}
201
202.main-nav-btn.primary:hover {
203    background: linear-gradient(135deg, rgba(0,212,255,1.0), rgba(129,140,248,1.0));
204}
205
206.main-nav-btn.ghost {
207    background: rgba(255,255,255,0.03);
208}
209
210.main-nav-btn-icon {
211    padding: 10px;
212    background: rgba(255,255,255,0.03);
213}
214
215.main-nav-btn-icon svg {
216    width: 20px;
217    height: 20px;
218    fill: currentColor;
219}
220
221/* Mobile hamburger button */
222.mobile-menu-btn {
223    display: none;
224    width: 44px;
225    height: 44px;
226    border-radius: 5px;
227    border: 2px solid rgba(255,255,255,0.2);
228    background: rgba(255,255,255,0.05);
229    color: var(--text-primary);
230    cursor: pointer;
231    align-items: center;
232    justify-content: center;
233    z-index: 1001;
234}
235
236.mobile-menu-btn:hover {
237    background: rgba(255,255,255,0.1);
238    border-color: rgba(255,255,255,0.3);
239}
240
241/* Mobile drawer overlay */
242.mobile-drawer-overlay {
243    display: none;
244    position: fixed;
245    inset: 0;
246    background: rgba(0,0,0,0.6);
247    z-index: 999;
248    opacity: 0;
249    pointer-events: none;
250    transition: opacity 0.3s ease;
251}
252
253.mobile-drawer-overlay.open {
254    opacity: 1;
255    pointer-events: auto;
256}
257
258/* Mobile drawer */
259.mobile-drawer {
260    position: fixed;
261    top: 0;
262    right: 0;
263    width: 320px;
264    max-width: 85vw;
265    height: 100vh;
266    background: rgba(12, 16, 24, 0.98);
267    backdrop-filter: blur(20px);
268    -webkit-backdrop-filter: blur(20px);
269    border-left: 1px solid rgba(255,255,255,0.08);
270    z-index: 1000;
271    transform: translateX(100%);
272    transition: transform 0.3s ease;
273    overflow-y: auto;
274    display: none;
275}
276
277.mobile-drawer.open {
278    transform: translateX(0);
279}
280
281.mobile-drawer-header {
282    display: flex;
283    align-items: center;
284    justify-content: space-between;
285    padding: 16px var(--spacing-lg) var(--spacing-lg);
286    border-bottom: 1px solid rgba(255,255,255,0.06);
287}
288
289.mobile-drawer-title {
290    font-weight: 700;
291    font-size: var(--font-body-lg);
292    color: var(--text-primary);
293}
294
295.mobile-drawer-close {
296    width: 36px;
297    height: 36px;
298    border-radius: var(--radius-md);
299    border: 1px solid rgba(255,255,255,0.1);
300    background: rgba(255,255,255,0.03);
301    color: var(--text-secondary);
302    cursor: pointer;
303    display: flex;
304    align-items: center;
305    justify-content: center;
306}
307
308.mobile-drawer-close:hover {
309    background: rgba(255,255,255,0.08);
310    color: var(--text-primary);
311}
312
313.mobile-drawer-content {
314    padding: var(--spacing-md);
315}
316
317/* Mobile nav section */
318.mobile-nav-section {
319    margin-bottom: var(--spacing-md);
320}
321
322.mobile-nav-header {
323    display: flex;
324    align-items: center;
325    justify-content: space-between;
326    padding: var(--spacing-md);
327    border-radius: var(--radius-md);
328    cursor: pointer;
329    transition: background 0.15s ease;
330}
331
332.mobile-nav-header:hover {
333    background: rgba(255,255,255,0.04);
334}
335
336.mobile-nav-header-left {
337    display: flex;
338    align-items: center;
339    gap: var(--spacing-sm);
340}
341
342.mobile-nav-header-icon {
343    color: var(--color-accent-blue);
344}
345
346.mobile-nav-header-title {
347    font-weight: 600;
348    font-size: var(--font-body-md);
349    color: var(--text-primary);
350}
351
352.mobile-nav-header-chevron {
353    color: var(--text-tertiary);
354    transition: transform 0.2s ease;
355}
356
357.mobile-nav-header-chevron.expanded {
358    transform: rotate(90deg);
359}
360
361.mobile-nav-tree {
362    max-height: 0;
363    overflow: hidden;
364    transition: max-height 0.3s ease;
365}
366
367.mobile-nav-tree.expanded {
368    max-height: 2000px;
369}
370
371.mobile-nav-tree-inner {
372    padding: var(--spacing-xs) 0 var(--spacing-sm) var(--spacing-xl);
373    border-left: 2px solid rgba(255,255,255,0.06);
374    margin-left: var(--spacing-lg);
375}
376
377.mobile-nav-item {
378    display: block;
379    padding: var(--spacing-sm) var(--spacing-md);
380    border-radius: var(--radius-sm);
381    color: var(--text-secondary);
382    font-size: var(--font-body-sm);
383    text-decoration: none;
384    transition: all 0.15s ease;
385}
386
387.mobile-nav-item:hover {
388    background: rgba(255,255,255,0.04);
389    color: var(--text-primary);
390}
391
392.mobile-nav-item.active {
393    background: rgba(0,212,255,0.12);
394    color: #00d4ff;
395}
396
397/* Simple mobile link (no tree) */
398.mobile-nav-link {
399    display: flex;
400    align-items: center;
401    gap: var(--spacing-sm);
402    padding: var(--spacing-md);
403    border-radius: var(--radius-md);
404    color: var(--text-secondary);
405    text-decoration: none;
406    transition: all 0.15s ease;
407}
408
409.mobile-nav-link:hover {
410    background: rgba(255,255,255,0.04);
411    color: var(--text-primary);
412}
413
414.mobile-nav-link.active {
415    background: rgba(0,212,255,0.12);
416    color: #00d4ff;
417}
418
419.mobile-nav-link-icon {
420    color: var(--color-accent-blue);
421}
422
423.mobile-nav-divider {
424    height: 1px;
425    background: rgba(255,255,255,0.06);
426    margin: var(--spacing-md) 0;
427}
428
429/* Responsive */
430@media (max-width: 980px) {
431    .main-nav-links {
432        display: none;
433    }
434    .main-nav-brand-text {
435        display: none;
436    }
437    .mobile-menu-btn {
438        display: flex;
439    }
440    .mobile-drawer {
441        display: block;
442    }
443    .mobile-drawer-overlay {
444        display: block;
445    }
446}
447
448@media (max-width: 640px) {
449    .main-nav-inner {
450        padding: var(--spacing-md) var(--spacing-lg);
451    }
452    .main-nav-btn {
453        padding: var(--spacing-sm) var(--spacing-md);
454        font-size: var(--font-caption-md);
455    }
456    .main-nav-logo {
457        width: 48px;
458        height: 48px;
459    }
460}
461"#;
462
463/// Main navigation component with consistent styling and active page underline
464#[component]
465pub fn MainNav(
466    /// The currently active page
467    #[props(default)]
468    active: ActivePage,
469    /// Optional subtitle for the brand (e.g., "Programmer's Guide")
470    #[props(default)]
471    subtitle: Option<&'static str>,
472    /// Whether to show the full nav links (default true)
473    #[props(default = true)]
474    show_nav_links: bool,
475) -> Element {
476    let mut drawer_open = use_signal(|| false);
477    let mut guide_expanded = use_signal(|| false);
478    let mut learn_expanded = use_signal(|| false);
479
480    // Get content for trees
481    let content_engine = ContentEngine::new();
482    let eras = content_engine.eras();
483
484    // Get guide sections grouped by part
485    let guide_parts: Vec<(&str, Vec<&crate::ui::pages::guide::content::Section>)> = {
486        let mut parts: Vec<(&str, Vec<&crate::ui::pages::guide::content::Section>)> = Vec::new();
487        for section in SECTIONS {
488            if let Some(part) = parts.iter_mut().find(|(p, _)| *p == section.part) {
489                part.1.push(section);
490            } else {
491                parts.push((section.part, vec![section]));
492            }
493        }
494        parts
495    };
496
497    rsx! {
498        style { "{MAIN_NAV_STYLE}" }
499
500        header { class: "main-nav",
501            div { class: "main-nav-inner",
502                // Brand
503                Link {
504                    to: Route::Landing {},
505                    class: "main-nav-brand",
506                    div {
507                        class: "main-nav-logo",
508                        dangerous_inner_html: "{LOGO_SVG}"
509                    }
510                    div { class: "main-nav-brand-text",
511                        span { class: "main-nav-brand-name", "LOGICAFFEINE" }
512                        if let Some(sub) = subtitle {
513                            span { class: "main-nav-brand-subtitle", "{sub}" }
514                        } else {
515                            span { class: "main-nav-brand-subtitle", "Debug your thoughts." }
516                        }
517                    }
518                }
519
520                // Desktop navigation links with active underline
521                if show_nav_links {
522                    nav { class: "main-nav-links",
523                        Link {
524                            to: Route::Guide {},
525                            class: if active == ActivePage::Guide { "main-nav-link active" } else { "main-nav-link" },
526                            "Syntax Guide"
527                        }
528                        Link {
529                            to: Route::Crates {},
530                            class: if active == ActivePage::Crates { "main-nav-link active" } else { "main-nav-link" },
531                            "Crates"
532                        }
533                        Link {
534                            to: Route::Learn {},
535                            class: if active == ActivePage::Learn { "main-nav-link active" } else { "main-nav-link" },
536                            "Learn Logic"
537                        }
538                        Link {
539                            to: Route::Studio { file: None },
540                            class: if active == ActivePage::Studio { "main-nav-link active" } else { "main-nav-link" },
541                            "Studio"
542                        }
543                        Link {
544                            to: Route::Roadmap {},
545                            class: if active == ActivePage::Roadmap { "main-nav-link active" } else { "main-nav-link" },
546                            "Roadmap"
547                        }
548                        Link {
549                            to: Route::Pricing {},
550                            class: if active == ActivePage::Pricing { "main-nav-link active" } else { "main-nav-link" },
551                            "Contact"
552                        }
553                        Link {
554                            to: Route::News { tag: None },
555                            class: if active == ActivePage::News { "main-nav-link active" } else { "main-nav-link" },
556                            "News"
557                        }
558                        Link {
559                            to: Route::Benchmarks {},
560                            class: if active == ActivePage::Benchmarks { "main-nav-link active" } else { "main-nav-link" },
561                            "Benchmarks"
562                        }
563                    }
564                }
565
566                // CTA buttons
567                div { class: "main-nav-cta",
568                    // GitHub button
569                    a {
570                        href: "https://github.com/Brahmastra-Labs/logicaffeine",
571                        target: "_blank",
572                        class: "main-nav-btn main-nav-btn-icon",
573                        title: "View on GitHub",
574                        svg {
575                            xmlns: "http://www.w3.org/2000/svg",
576                            view_box: "0 0 24 24",
577                            path {
578                                d: "M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"
579                            }
580                        }
581                    }
582                    // Profile button
583                    Link {
584                        to: Route::Profile {},
585                        class: if active == ActivePage::Profile { "main-nav-btn main-nav-btn-icon active" } else { "main-nav-btn main-nav-btn-icon" },
586                        title: "Your Profile",
587                        svg {
588                            xmlns: "http://www.w3.org/2000/svg",
589                            view_box: "0 0 24 24",
590                            path {
591                                d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"
592                            }
593                        }
594                    }
595                    // Mobile menu button
596                    button {
597                        class: "mobile-menu-btn",
598                        onclick: move |_| drawer_open.set(true),
599                        Icon { variant: IconVariant::Menu, size: IconSize::Medium }
600                    }
601                }
602            }
603        }
604
605        // Mobile drawer overlay
606        div {
607            class: if *drawer_open.read() { "mobile-drawer-overlay open" } else { "mobile-drawer-overlay" },
608            onclick: move |_| drawer_open.set(false),
609        }
610
611        // Mobile drawer
612        div {
613            class: if *drawer_open.read() { "mobile-drawer open" } else { "mobile-drawer" },
614
615            // Header
616            div { class: "mobile-drawer-header",
617                span { class: "mobile-drawer-title", "Navigation" }
618                button {
619                    class: "mobile-drawer-close",
620                    onclick: move |_| drawer_open.set(false),
621                    Icon { variant: IconVariant::Close, size: IconSize::Medium }
622                }
623            }
624
625            // Content
626            div { class: "mobile-drawer-content",
627                // Syntax Guide section with tree
628                div { class: "mobile-nav-section",
629                    div {
630                        class: "mobile-nav-header",
631                        onclick: move |_| {
632                            let current = *guide_expanded.read();
633                            guide_expanded.set(!current);
634                        },
635                        div { class: "mobile-nav-header-left",
636                            span { class: "mobile-nav-header-icon",
637                                Icon { variant: IconVariant::Book, size: IconSize::Medium }
638                            }
639                            span { class: "mobile-nav-header-title", "Syntax Guide" }
640                        }
641                        span {
642                            class: if *guide_expanded.read() { "mobile-nav-header-chevron expanded" } else { "mobile-nav-header-chevron" },
643                            Icon { variant: IconVariant::ChevronRight, size: IconSize::Small }
644                        }
645                    }
646                    div {
647                        class: if *guide_expanded.read() { "mobile-nav-tree expanded" } else { "mobile-nav-tree" },
648                        div { class: "mobile-nav-tree-inner",
649                            for (part_name, sections) in guide_parts.iter() {
650                                div { style: "margin-bottom: var(--spacing-sm);",
651                                    div {
652                                        style: "font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-tertiary); padding: var(--spacing-xs) var(--spacing-md); margin-bottom: var(--spacing-xs);",
653                                        "{part_name}"
654                                    }
655                                    for section in sections.iter() {
656                                        a {
657                                            href: "/guide#{section.id}",
658                                            class: "mobile-nav-item",
659                                            onclick: move |_| drawer_open.set(false),
660                                            "{section.number}. {section.title}"
661                                        }
662                                    }
663                                }
664                            }
665                        }
666                    }
667                }
668
669                // Learn section with tree
670                div { class: "mobile-nav-section",
671                    div {
672                        class: "mobile-nav-header",
673                        onclick: move |_| {
674                            let current = *learn_expanded.read();
675                            learn_expanded.set(!current);
676                        },
677                        div { class: "mobile-nav-header-left",
678                            span { class: "mobile-nav-header-icon",
679                                Icon { variant: IconVariant::GraduationCap, size: IconSize::Medium }
680                            }
681                            span { class: "mobile-nav-header-title", "Learn Logic" }
682                        }
683                        span {
684                            class: if *learn_expanded.read() { "mobile-nav-header-chevron expanded" } else { "mobile-nav-header-chevron" },
685                            Icon { variant: IconVariant::ChevronRight, size: IconSize::Small }
686                        }
687                    }
688                    div {
689                        class: if *learn_expanded.read() { "mobile-nav-tree expanded" } else { "mobile-nav-tree" },
690                        div { class: "mobile-nav-tree-inner",
691                            for era in eras.iter() {
692                                div { style: "margin-bottom: var(--spacing-sm);",
693                                    div {
694                                        style: "font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-tertiary); padding: var(--spacing-xs) var(--spacing-md); margin-bottom: var(--spacing-xs);",
695                                        "{era.meta.title}"
696                                    }
697                                    for module in era.modules.iter() {
698                                        a {
699                                            href: "/learn#{module.meta.id}",
700                                            class: "mobile-nav-item",
701                                            onclick: move |_| drawer_open.set(false),
702                                            "{module.meta.title}"
703                                        }
704                                    }
705                                }
706                            }
707                        }
708                    }
709                }
710
711                div { class: "mobile-nav-divider" }
712
713                // Simple links for other pages
714                Link {
715                    to: Route::Studio { file: None },
716                    class: if active == ActivePage::Studio { "mobile-nav-link active" } else { "mobile-nav-link" },
717                    onclick: move |_| drawer_open.set(false),
718                    span { class: "mobile-nav-link-icon",
719                        Icon { variant: IconVariant::Beaker, size: IconSize::Medium }
720                    }
721                    "Studio"
722                }
723                Link {
724                    to: Route::Crates {},
725                    class: if active == ActivePage::Crates { "mobile-nav-link active" } else { "mobile-nav-link" },
726                    onclick: move |_| drawer_open.set(false),
727                    span { class: "mobile-nav-link-icon",
728                        Icon { variant: IconVariant::Package, size: IconSize::Medium }
729                    }
730                    "Crates"
731                }
732                Link {
733                    to: Route::Roadmap {},
734                    class: if active == ActivePage::Roadmap { "mobile-nav-link active" } else { "mobile-nav-link" },
735                    onclick: move |_| drawer_open.set(false),
736                    span { class: "mobile-nav-link-icon",
737                        Icon { variant: IconVariant::Map, size: IconSize::Medium }
738                    }
739                    "Roadmap"
740                }
741                Link {
742                    to: Route::Pricing {},
743                    class: if active == ActivePage::Pricing { "mobile-nav-link active" } else { "mobile-nav-link" },
744                    onclick: move |_| drawer_open.set(false),
745                    span { class: "mobile-nav-link-icon",
746                        Icon { variant: IconVariant::Diamond, size: IconSize::Medium }
747                    }
748                    "Contact"
749                }
750                Link {
751                    to: Route::News { tag: None },
752                    class: if active == ActivePage::News { "mobile-nav-link active" } else { "mobile-nav-link" },
753                    onclick: move |_| drawer_open.set(false),
754                    span { class: "mobile-nav-link-icon",
755                        Icon { variant: IconVariant::Newspaper, size: IconSize::Medium }
756                    }
757                    "News"
758                }
759                Link {
760                    to: Route::Benchmarks {},
761                    class: if active == ActivePage::Benchmarks { "mobile-nav-link active" } else { "mobile-nav-link" },
762                    onclick: move |_| drawer_open.set(false),
763                    span { class: "mobile-nav-link-icon",
764                        Icon { variant: IconVariant::Lightning, size: IconSize::Medium }
765                    }
766                    "Benchmarks"
767                }
768
769                div { class: "mobile-nav-divider" }
770
771                Link {
772                    to: Route::Profile {},
773                    class: if active == ActivePage::Profile { "mobile-nav-link active" } else { "mobile-nav-link" },
774                    onclick: move |_| drawer_open.set(false),
775                    span { class: "mobile-nav-link-icon",
776                        Icon { variant: IconVariant::User, size: IconSize::Medium }
777                    }
778                    "Profile"
779                }
780                a {
781                    href: "https://github.com/Brahmastra-Labs/logicaffeine",
782                    target: "_blank",
783                    class: "mobile-nav-link",
784                    span { class: "mobile-nav-link-icon",
785                        Icon { variant: IconVariant::Github, size: IconSize::Medium }
786                    }
787                    "GitHub"
788                }
789            }
790        }
791    }
792}