Files

98 lines
2.9 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { Menu, X } from "lucide-react";
import { cn } from "@/lib/utils";
import { navItems } from "./nav-config";
export function MobileNav() {
const [isOpen, setIsOpen] = useState(false);
const pathname = usePathname();
useEffect(() => {
setIsOpen(false);
}, [pathname]);
useEffect(() => {
if (!isOpen) {
document.body.style.overflow = "";
return;
}
document.body.style.overflow = "hidden";
function handleKeyDown(e: KeyboardEvent) {
if (e.key === "Escape") setIsOpen(false);
}
document.addEventListener("keydown", handleKeyDown);
return () => {
document.removeEventListener("keydown", handleKeyDown);
};
}, [isOpen]);
return (
<>
<button
aria-label="메뉴 열기"
className="flex size-9 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground md:hidden"
onClick={() => setIsOpen(true)}
type="button"
>
<Menu aria-hidden="true" className="size-5" />
</button>
{/* 배경 오버레이 — 탭하면 닫힘 */}
<div
aria-hidden="true"
className={cn(
"fixed inset-0 z-20 bg-black/50 transition-opacity duration-200 md:hidden",
isOpen ? "opacity-100" : "pointer-events-none opacity-0"
)}
onClick={() => setIsOpen(false)}
/>
{/* 슬라이드인 패널 */}
<aside
aria-hidden={!isOpen}
className={cn(
"fixed inset-y-0 left-0 z-30 w-64 border-r bg-background transition-transform duration-200 md:hidden",
isOpen ? "translate-x-0" : "-translate-x-full"
)}
>
<div className="flex h-16 items-center justify-between border-b px-5">
<Link className="text-lg font-semibold" href="/">
chocoadmin
</Link>
<button
aria-label="메뉴 닫기"
className="flex size-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
onClick={() => setIsOpen(false)}
type="button"
>
<X aria-hidden="true" className="size-4" />
</button>
</div>
<nav className="space-y-1 p-3">
{navItems.map((item) => {
const Icon = item.icon;
return (
<Link
className="flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
href={item.href}
key={item.href}
>
<Icon aria-hidden="true" className="size-4" />
{item.label}
</Link>
);
})}
</nav>
</aside>
</>
);
}