From d9d407b8fa4f39254a43d22e2d84a886cd2eb874 Mon Sep 17 00:00:00 2001 From: manueldezman Date: Sun, 31 May 2026 14:17:16 +0100 Subject: [PATCH 1/5] feat: add mobile navigation drawer --- src/app/(dashboard)/layout.tsx | 2 +- src/components/MobileNav.tsx | 136 +++++++++++++++++++++++++++++++++ src/components/Sidebar.tsx | 18 +---- src/components/Topbar.tsx | 7 +- src/lib/nav-items.ts | 21 +++++ 5 files changed, 166 insertions(+), 18 deletions(-) create mode 100644 src/components/MobileNav.tsx create mode 100644 src/lib/nav-items.ts diff --git a/src/app/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx index f72a963..11253ee 100644 --- a/src/app/(dashboard)/layout.tsx +++ b/src/app/(dashboard)/layout.tsx @@ -10,7 +10,7 @@ export default function DashboardLayout({
-
+
{children}
diff --git a/src/components/MobileNav.tsx b/src/components/MobileNav.tsx new file mode 100644 index 0000000..bbcef72 --- /dev/null +++ b/src/components/MobileNav.tsx @@ -0,0 +1,136 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; +import Image from "next/image"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { LogOut, Menu, X } from "lucide-react"; + +import { navItems } from "@/lib/nav-items"; +import { cn } from "@/lib/utils"; + +export function MobileNav() { + const pathname = usePathname(); + const [open, setOpen] = useState(false); + const closeButtonRef = useRef(null); + + useEffect(() => { + if (!open) return; + setOpen(false); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [pathname]); + + useEffect(() => { + if (!open) return; + + const previousOverflow = document.body.style.overflow; + document.body.style.overflow = "hidden"; + + const onKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") setOpen(false); + }; + + window.addEventListener("keydown", onKeyDown); + closeButtonRef.current?.focus(); + + return () => { + window.removeEventListener("keydown", onKeyDown); + document.body.style.overflow = previousOverflow; + }; + }, [open]); + + return ( +
+ + +
+
setOpen(false)} + /> + +
+
+
+ Shade + + Shade + +
+ + +
+ + + +
+ +
+
+
+
+ ); +} + diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 58145e4..704409c 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -3,28 +3,16 @@ import Link from "next/link"; import Image from "next/image"; import { usePathname } from "next/navigation"; -import { - FileText, - LayoutDashboard, - LogOut, - Settings, - Users, -} from "lucide-react"; +import { LogOut } from "lucide-react"; import { cn } from "@/lib/utils"; - -const navItems = [ - { href: "/dashboard", label: "Dashboard", icon: LayoutDashboard }, - { href: "/invoices", label: "Invoices", icon: FileText }, - { href: "/customers", label: "Customers", icon: Users }, - { href: "/settings", label: "Settings", icon: Settings }, -]; +import { navItems } from "@/lib/nav-items"; export function Sidebar() { const pathname = usePathname(); return ( -