Repository Public MIT
1"use client";2import Link from "next/link";3import { Menu } from "lucide-react";4import { usePathname } from "next/navigation";5import { useEffect, useRef } from "react";67/** Native <details> menu (works without JavaScript); with JavaScript it closes on navigation, Escape and outside clicks. */8export function MobileMenu({ links }: { links: { href: string; label: string }[] }) {9 const ref = useRef<HTMLDetailsElement>(null);10 const pathname = usePathname();11 useEffect(() => {12 ref.current?.removeAttribute("open");13 }, [pathname]);14 useEffect(() => {15 const close = (e: Event) => {16 if (e instanceof KeyboardEvent ? e.key === "Escape" : !ref.current?.contains(e.target as Node)) ref.current?.removeAttribute("open");17 };18 document.addEventListener("click", close);19 document.addEventListener("keydown", close);20 return () => {21 document.removeEventListener("click", close);22 document.removeEventListener("keydown", close);23 };24 }, []);25 return (26 <details ref={ref} className="group relative md:hidden">27 <summary className="grid h-9 w-9 cursor-pointer list-none place-items-center rounded-lg border border-line text-muted [&::-webkit-details-marker]:hidden" aria-label="Menu">28 <Menu size={16} aria-hidden />29 </summary>30 <nav aria-label="Mobile" className="absolute right-0 top-11 z-50 w-56 rounded-xl border border-line-strong bg-graphite p-2 [box-shadow:var(--shadow-pop)]">31 {links.map((n) => (32 <Link key={n.href} href={n.href} onClick={() => ref.current?.removeAttribute("open")} className="block rounded-lg px-3 py-2.5 text-sm text-text hover:bg-raised">33 {n.label}34 </Link>35 ))}36 </nav>37 </details>38 );39}40