SPB Git

spb/rareindex

Public
2.7 KB · 62 lines tsx
1'use client';23import Link from 'next/link';4import { useEffect, useState } from 'react';5import { usePathname } from 'next/navigation';6import { Menu, X } from 'lucide-react';7import type { NavItem } from '@/config/nav';89export function MobileNav({ items, groups }: { items: NavItem[]; groups: Array<{ id: NavItem['group']; label: string }> }) {10  const [open, setOpen] = useState(false);11  const pathname = usePathname();12  const [prevPath, setPrevPath] = useState(pathname);13  if (pathname !== prevPath) {14    // close the drawer on navigation (state adjustment during render, no effect needed)15    setPrevPath(pathname);16    setOpen(false);17  }18  useEffect(() => {19    document.body.style.overflow = open ? 'hidden' : '';20    return () => {21      document.body.style.overflow = '';22    };23  }, [open]);24  return (25    <div className="lg:hidden">26      <button type="button" aria-label="Open menu" aria-expanded={open} className="inline-flex h-8 w-8 items-center justify-center rounded-md text-muted hover:bg-inset hover:text-fg" onClick={() => setOpen(true)}>27        <Menu className="h-5 w-5" />28      </button>29      {open ? (30        <div className="fixed inset-0 z-50 flex" role="dialog" aria-modal="true">31          <div className="absolute inset-0 bg-black/40" onClick={() => setOpen(false)} />32          <div className="relative flex h-[100dvh] w-[86vw] max-w-sm flex-col overflow-y-auto bg-elevated shadow-pop safe-bottom">33            <div className="flex h-14 items-center justify-between border-b border-border px-4">34              <span className="text-sm font-semibold">Menu</span>35              <button type="button" aria-label="Close menu" className="inline-flex h-8 w-8 items-center justify-center rounded-md text-muted hover:bg-inset" onClick={() => setOpen(false)}>36                <X className="h-5 w-5" />37              </button>38            </div>39            <nav className="flex-1 px-2 py-3">40              {groups.map((g) => (41                <div key={g.id} className="mb-3">42                  <p className="px-2 pb-1 text-[10px] font-semibold uppercase tracking-wider text-subtle">{g.label}</p>43                  {items44                    .filter((n) => n.group === g.id)45                    .map((n) => (46                      <Link key={n.href} href={n.href} className={`block rounded-md px-2 py-2 text-[15px] ${pathname === n.href ? 'bg-inset font-medium text-fg' : 'text-muted'}`}>47                        {n.label}48                      </Link>49                    ))}50                </div>51              ))}52              <Link href="/account" className="mt-2 block rounded-md border border-border px-3 py-2 text-center text-sm font-medium">53                Sign in54              </Link>55            </nav>56          </div>57        </div>58      ) : null}59    </div>60  );61}62
Files · 93afc664ddb333d55c451ac27e1a79bfd8e89448
Menu

Theme