From f8f687af4eb298c07290dfbbd314394a0f8157b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Tue, 1 Sep 2026 19:23:38 +0200 Subject: [PATCH] Polish the mobile menu - Header: replaces the plain "Menu" title with the brand mark (animated, matching the dashboard hero) + wordmark and a short description line - Nav rows get icons and an active-state background/icon tint instead of reusing the desktop tab strip's underline - Desktop tabs also gain matching icons - Theme toggle and Log out move from the cramped mobile header into labeled rows at the bottom of the drawer; desktop keeps them in the header - The header hamburger button is now a self-contained, controlled toggle whose bars morph into an X on open/close, sized to match the drawer's built-in close button Co-Authored-By: Claude Sonnet 5 --- components/layout/NavBar.tsx | 142 +++++++++++++++++++++++++++++------ 1 file changed, 117 insertions(+), 25 deletions(-) diff --git a/components/layout/NavBar.tsx b/components/layout/NavBar.tsx index 86e2d2a..8763d3e 100644 --- a/components/layout/NavBar.tsx +++ b/components/layout/NavBar.tsx @@ -4,19 +4,19 @@ import { useState } from "react"; import Link from "next/link"; import { usePathname, useRouter } from "next/navigation"; import { useTheme } from "next-themes"; -import { Menu, Moon, Sun, LogOut } from "lucide-react"; +import { Moon, Sun, LogOut, Gauge, SlidersHorizontal, ListMusic, Bluetooth, BarChart3 } from "lucide-react"; import { Button } from "@/components/ui/button"; -import { Sheet, SheetContent, SheetTitle, SheetTrigger } from "@/components/ui/sheet"; +import { Sheet, SheetContent, SheetDescription, SheetTitle } from "@/components/ui/sheet"; import { ConnectionStatus } from "./ConnectionStatus"; import { BrandMark } from "./BrandMark"; import { cn } from "@/lib/utils"; const LINKS = [ - { href: "/", label: "Dashboard" }, - { href: "/control", label: "Control" }, - { href: "/sessions", label: "Sessions" }, - { href: "/devices", label: "Devices" }, - { href: "/stats", label: "Stats" }, + { href: "/", label: "Dashboard", icon: Gauge }, + { href: "/control", label: "Control", icon: SlidersHorizontal }, + { href: "/sessions", label: "Sessions", icon: ListMusic }, + { href: "/devices", label: "Devices", icon: Bluetooth }, + { href: "/stats", label: "Stats", icon: BarChart3 }, ]; function isActive(pathname: string, href: string): boolean { @@ -33,12 +33,13 @@ function NavLinks({ onNavigate }: { onNavigate?: () => void }) { href={link.href} onClick={onNavigate} className={cn( - "border-b-2 px-2.5 py-1.5 text-xs font-medium tracking-wide uppercase transition-colors", + "flex items-center gap-1.5 border-b-2 px-2.5 py-1.5 text-xs font-medium tracking-wide uppercase transition-colors", isActive(pathname, link.href) ? "border-primary text-foreground" : "border-transparent text-muted-foreground hover:text-foreground", )} > + {link.label} ))} @@ -46,6 +47,60 @@ function NavLinks({ onNavigate }: { onNavigate?: () => void }) { ); } +/** Drawer rows for the mobile menu - icon + label, styled as tappable + * console rows rather than the desktop tab strip's underline treatment. */ +function MobileNavLinks({ onNavigate }: { onNavigate: () => void }) { + const pathname = usePathname(); + return ( + <> + {LINKS.map((link) => { + const active = isActive(pathname, link.href); + return ( + + + {link.label} + + ); + })} + + ); +} + +/** Hamburger that morphs into an X - the top/bottom bars rotate into place + * and the middle bar collapses, rather than a straight icon swap. */ +function MenuToggleIcon({ open }: { open: boolean }) { + return ( + + + + + + ); +} + export function NavBar() { const { theme, setTheme } = useTheme(); const router = useRouter(); @@ -71,30 +126,67 @@ export function NavBar() {
+ +
+ + +
+ - - - - - - Menu -