From 6d2c90ae6ba0c65154c216c3dd7002ae6999c7fa Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 17 Jun 2026 14:21:24 -0600 Subject: [PATCH] feat(admin): add MoreSheet (native dialog) with grouped secondary nav --- src/components/admin/MoreSheet.tsx | 111 +++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 src/components/admin/MoreSheet.tsx diff --git a/src/components/admin/MoreSheet.tsx b/src/components/admin/MoreSheet.tsx new file mode 100644 index 0000000..9764bb4 --- /dev/null +++ b/src/components/admin/MoreSheet.tsx @@ -0,0 +1,111 @@ +"use client"; + +import Link from "next/link"; +import { useEffect, useRef } from "react"; + +const MORE_SECTIONS = [ + { + heading: "Operations", + links: [ + { label: "Pickup", href: "/admin/pickup", icon: "📦" }, + { label: "Shipping", href: "/admin/shipping", icon: "🚚" }, + { label: "Reports", href: "/admin/reports", icon: "📊" }, + { label: "Analytics", href: "/admin/analytics", icon: "📈" }, + ], + }, + { + heading: "Marketing", + links: [ + { label: "Communications", href: "/admin/communications", icon: "📧" }, + { label: "Sales", href: "/admin/sales", icon: "💵" }, + ], + }, + { + heading: "Settings", + links: [ + { label: "Settings", href: "/admin/settings", icon: "⚙️" }, + { label: "Advanced", href: "/admin/advanced", icon: "🛠" }, + ], + }, +]; + +interface MoreSheetProps { + open: boolean; + onClose: () => void; +} + +export function MoreSheet({ open, onClose }: MoreSheetProps) { + const dialogRef = useRef(null); + const lastFocusedRef = useRef(null); + + useEffect(() => { + const dialog = dialogRef.current; + if (!dialog) return; + if (open) { + lastFocusedRef.current = document.activeElement as HTMLElement | null; + if (!dialog.open) dialog.showModal(); + } else if (dialog.open) { + dialog.close(); + lastFocusedRef.current?.focus(); + } + }, [open]); + + useEffect(() => { + const dialog = dialogRef.current; + if (!dialog) return; + const onCancel = (e: Event) => { + e.preventDefault(); + onClose(); + }; + dialog.addEventListener("cancel", onCancel); + return () => dialog.removeEventListener("cancel", onCancel); + }, [onClose]); + + return ( + { + // Click on the backdrop (the dialog element itself) closes; clicks on content don't + if (e.target === dialogRef.current) onClose(); + }} + className="w-full max-w-[640px] p-0 m-0 ml-auto h-full max-h-screen backdrop:bg-black/40" + style={{ + backgroundColor: "var(--color-bg)", + color: "var(--color-text)", + borderLeft: "1px solid var(--color-surface-3)", + }} + > +
+
+

More

+
+
+ {MORE_SECTIONS.map((section) => ( +
+

+ {section.heading.toUpperCase()} +

+
    + {section.links.map((link) => ( +
  • + + + {link.label} + +
  • + ))} +
+
+ ))} +
+
+
+ ); +} + +export default MoreSheet;