06 · Developer Guide · 레시피
모바일 메가패널Mega Panel
햄버거 메뉴 → 풀스크린 패널. 모바일·데스크탑이 같은 컴포넌트지만 안은 완전히 다른 레이아웃.
언제 쓰는가
- 주 메뉴가 5개 이상이고 각 메뉴마다 sub 메뉴 6~10개씩 있는 큰 IA
- 모바일 가독성을 위해 사이드바 2분할이 부적합한 경우
- 검색·로그인·자주 가는 메뉴를 한 자리에 모으고 싶을 때
① 분기 — sm 기준으로 두 가지 레이아웃
데스크탑: 좌측 200px 카테고리 사이드바 + 우측 활성 카테고리 상세.
모바일: 카테고리별 <details> 아코디언으로 세로 적층.
components/preview/MegaPanel.tsxtsx
// 데스크탑(sm+): 카테고리 사이드바 + 상세 패널 2분할
// 모바일(<sm): 세로 아코디언 (각 카테고리 펼쳤다 접기)
<aside className="flex h-full w-full max-w-[820px] flex-col bg-navy-900 text-white">
{/* 상단 헤더 — 닫기 버튼 */}
<div className="flex items-center justify-between px-5 py-4">
<span>전체 메뉴</span>
<button onClick={onClose}><X size={16} /></button>
</div>
{/* 검색 영역 */}
<div className="border-b border-white/10 px-5 py-5">
<input type="search" placeholder="검색어를 입력해 주세요" />
</div>
{/* 모바일: 세로 아코디언 */}
<div className="flex-1 overflow-y-auto px-5 py-4 sm:hidden">
{menus.map((m) => (
<details key={m.href} className="group border-b border-white/10">
<summary>{m.label}</summary>
<ul>
{m.items.map((it) => <li><Link href={it.href}>{it.label}</Link></li>)}
</ul>
</details>
))}
</div>
{/* 데스크탑: 사이드바 + 상세 */}
<div className="hidden flex-1 overflow-hidden sm:flex">
<ul className="w-[200px] flex-none">{/* 카테고리 사이드바 */}</ul>
<div className="flex-1 overflow-y-auto">{/* 활성 카테고리 상세 */}</div>
</div>
</aside>② 상태 — open / active / 키 이벤트
tsx
"use client";
export function MegaPanel({ open, onClose, menus }: Props) {
const [active, setActive] = useState(0);
// body 스크롤 잠금 + ESC 닫기
useEffect(() => {
if (!open) return;
const handler = (e: KeyboardEvent) => {
if (e.key === "Escape") onClose();
};
document.body.style.overflow = "hidden";
document.addEventListener("keydown", handler);
return () => {
document.body.style.overflow = "";
document.removeEventListener("keydown", handler);
};
}, [open, onClose]);
if (!open) return null;
const activeMenu = menus[active] ?? menus[0];
// ... JSX
}