refactor: 레이아웃 크롬을 공용 UI 컴포넌트로 교체
Co-Authored-By: Claude Opus 5
@72f3c1354382f0b74698195aa59c8045ebe885a0
--- app/(protected)/(basic)/_components/admin-header.tsx
+++ app/(protected)/(basic)/_components/admin-header.tsx
... | ... | @@ -1,39 +1,46 @@ |
| 1 | 1 |
import { logout } from '@/app/(protected)/_actions';
|
| 2 |
+import { Header } from '@/components/ui/header';
|
|
| 2 | 3 |
|
| 3 | 4 |
interface AdminHeaderProps {
|
| 4 | 5 |
onOpenSidebar: () => void; |
| 5 | 6 |
onToggleSidebarCollapse: () => void; |
| 6 | 7 |
} |
| 7 | 8 |
|
| 9 |
+/** |
|
| 10 |
+ * 헤더 배치 — 비주얼 셸(Header)은 design 공용 컴포넌트를 그대로 쓰고, 사이드바 토글 버튼(공용 |
|
| 11 |
+ * 컴포넌트가 제공하지 않는 상호작용)만 `leading` 슬롯에 주입한다. 로그아웃은 `children`(우측 |
|
| 12 |
+ * 슬롯)에 주입한다. |
|
| 13 |
+ */ |
|
| 8 | 14 |
export function AdminHeader({
|
| 9 | 15 |
onOpenSidebar, |
| 10 | 16 |
onToggleSidebarCollapse, |
| 11 | 17 |
}: AdminHeaderProps) {
|
| 12 | 18 |
return ( |
| 13 |
- <header className="flex items-center justify-between border-b border-foreground/15 bg-background px-6 py-4"> |
|
| 14 |
- <div className="flex items-center gap-3"> |
|
| 15 |
- {/* 모바일 전용 — 사이드바를 오버레이로 연다 */}
|
|
| 16 |
- <button |
|
| 17 |
- type="button" |
|
| 18 |
- aria-label="사이드바 열기" |
|
| 19 |
- onClick={onOpenSidebar}
|
|
| 20 |
- className="border border-foreground/25 px-2 py-1 text-sm text-foreground md:hidden" |
|
| 21 |
- > |
|
| 22 |
- 메뉴 |
|
| 23 |
- </button> |
|
| 24 |
- {/* 데스크톱 전용 — 사이드바를 접거나 펼친다 */}
|
|
| 25 |
- <button |
|
| 26 |
- type="button" |
|
| 27 |
- aria-label="사이드바 접기/펼치기" |
|
| 28 |
- onClick={onToggleSidebarCollapse}
|
|
| 29 |
- className="hidden border border-foreground/25 px-2 py-1 text-sm text-foreground md:inline-flex" |
|
| 30 |
- > |
|
| 31 |
- 메뉴 |
|
| 32 |
- </button> |
|
| 33 |
- <span className="text-base font-semibold text-foreground"> |
|
| 34 |
- 에듀페이 관리자 |
|
| 35 |
- </span> |
|
| 36 |
- </div> |
|
| 19 |
+ <Header |
|
| 20 |
+ title="에듀페이 관리자" |
|
| 21 |
+ leading={
|
|
| 22 |
+ <> |
|
| 23 |
+ {/* 모바일 전용 — 사이드바를 오버레이로 연다 */}
|
|
| 24 |
+ <button |
|
| 25 |
+ type="button" |
|
| 26 |
+ aria-label="사이드바 열기" |
|
| 27 |
+ onClick={onOpenSidebar}
|
|
| 28 |
+ className="border border-foreground/25 px-2 py-1 text-sm text-foreground md:hidden" |
|
| 29 |
+ > |
|
| 30 |
+ 메뉴 |
|
| 31 |
+ </button> |
|
| 32 |
+ {/* 데스크톱 전용 — 사이드바를 접거나 펼친다 */}
|
|
| 33 |
+ <button |
|
| 34 |
+ type="button" |
|
| 35 |
+ aria-label="사이드바 접기/펼치기" |
|
| 36 |
+ onClick={onToggleSidebarCollapse}
|
|
| 37 |
+ className="hidden border border-foreground/25 px-2 py-1 text-sm text-foreground md:inline-flex" |
|
| 38 |
+ > |
|
| 39 |
+ 메뉴 |
|
| 40 |
+ </button> |
|
| 41 |
+ </> |
|
| 42 |
+ } |
|
| 43 |
+ > |
|
| 37 | 44 |
<form action={logout}>
|
| 38 | 45 |
<button |
| 39 | 46 |
type="submit" |
... | ... | @@ -42,6 +49,6 @@ |
| 42 | 49 |
로그아웃 |
| 43 | 50 |
</button> |
| 44 | 51 |
</form> |
| 45 |
- </header> |
|
| 52 |
+ </Header> |
|
| 46 | 53 |
); |
| 47 | 54 |
} |
--- app/(public)/layout.tsx
+++ app/(public)/layout.tsx
... | ... | @@ -1,13 +1,12 @@ |
| 1 |
-// Auth 레이아웃 — 배경 위 카드를 화면 중앙에 배치하는 공용 래퍼. `(public)` 하위 화면(로그인 등)이 |
|
| 2 |
-// 공유한다. |
|
| 1 |
+import { AuthCard } from '@/components/ui/auth-card';
|
|
| 2 |
+ |
|
| 3 |
+// Auth 레이아웃 — design 공용 AuthCard(프라이머리 배경 + 로고 + 카드)로 `(public)` 하위 화면 |
|
| 4 |
+// (로그인 등)을 감싼다. 화면별 제목은 AuthCard의 title 슬롯 대신 각 페이지 콘텐츠가 자체 |
|
| 5 |
+// 렌더한다 — 레이아웃은 여러 화면이 공유하므로 화면별 제목을 여기서 결정하기 어렵다. |
|
| 3 | 6 |
export default function Layout({
|
| 4 | 7 |
children, |
| 5 | 8 |
}: Readonly<{
|
| 6 | 9 |
children: React.ReactNode; |
| 7 | 10 |
}>) {
|
| 8 |
- return ( |
|
| 9 |
- <main className="flex min-h-screen flex-1 items-center justify-center bg-background p-6"> |
|
| 10 |
- {children}
|
|
| 11 |
- </main> |
|
| 12 |
- ); |
|
| 11 |
+ return <AuthCard>{children}</AuthCard>;
|
|
| 13 | 12 |
} |
--- app/(public)/login/_components/login-form.tsx
+++ app/(public)/login/_components/login-form.tsx
... | ... | @@ -9,10 +9,7 @@ |
| 9 | 9 |
const [state, formAction, isPending] = useActionState(login, initialState); |
| 10 | 10 |
|
| 11 | 11 |
return ( |
| 12 |
- <form |
|
| 13 |
- action={formAction}
|
|
| 14 |
- className="flex w-full max-w-sm flex-col gap-4 border border-foreground/15 p-8" |
|
| 15 |
- > |
|
| 12 |
+ <form action={formAction} className="flex w-full flex-col gap-4">
|
|
| 16 | 13 |
<h1 className="text-xl font-semibold text-foreground"> |
| 17 | 14 |
에듀페이 관리자 로그인 |
| 18 | 15 |
</h1> |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?