임동욱 임동욱 07-27
feat: 관리자 레이아웃 셸 공용 컴포넌트 추가
Co-Authored-By: Claude Opus 5 
@f450ad141271f2fb0b94c931edbc592e6bffcdb6
 
components/ui/header.tsx (added)
+++ components/ui/header.tsx
@@ -0,0 +1,34 @@
+import Image from "next/image";
+import type { ReactNode } from "react";
+
+interface HeaderProps {
+  title?: string;
+  leading?: ReactNode;
+  /** 우측 슬롯 */
+  children?: ReactNode;
+  /** 배치(레이아웃) 조정용 클래스 패스스루만 허용 — 디자인 값(색상·타이포·간격 등) 주입 금지. */
+  className?: string;
+}
+
+/** 상단 헤더 셸 — 로고 + 타이틀 + 우측 슬롯. */
+export function Header({ title, leading, children, className }: HeaderProps) {
+  return (
+    <header
+      className={`flex items-center justify-between gap-4 border-b border-border bg-surface px-6 py-4 ${className ?? ""}`}
+    >
+      <div className="flex items-center gap-3">
+        {leading}
+        <Image
+          src="/images/logo-foxpay.svg"
+          alt="FoxPay"
+          width={170}
+          height={62}
+          className="h-8 w-auto"
+          priority
+        />
+        {title && <span className="text-title-md text-foreground">{title}</span>}
+      </div>
+      {children && <div className="flex items-center gap-3">{children}</div>}
+    </header>
+  );
+}
 
components/ui/sidebar.tsx (added)
+++ components/ui/sidebar.tsx
@@ -0,0 +1,22 @@
+import type { ReactNode } from "react";
+
+interface SidebarProps {
+  header?: ReactNode;
+  children: ReactNode;
+  footer?: ReactNode;
+  /** 배치(레이아웃) 조정용 클래스 패스스루만 허용 — 디자인 값 주입 금지. */
+  className?: string;
+}
+
+/** 사이드바 셸(컨테이너). 내비게이션 항목 구성·활성 상태 판단은 호출부(feature) 책임. */
+export function Sidebar({ header, children, footer, className }: SidebarProps) {
+  return (
+    <aside
+      className={`flex h-full w-64 flex-col border-r border-border bg-surface ${className ?? ""}`}
+    >
+      {header && <div className="border-b border-border p-4">{header}</div>}
+      <nav className="flex-1 overflow-y-auto p-2">{children}</nav>
+      {footer && <div className="border-t border-border p-4">{footer}</div>}
+    </aside>
+  );
+}
Add a comment
List