master-project
CHAPTER 14 / 50
읽기 약 2분
FUNCTION
레이아웃: 헤더 + 사이드바 + 메인 + 푸터
핵심 개념
RootLayout + (app)/layout — 헤더·사이드바·푸터 구성·반응형·인증 분기 — 모든 페이지 공통 골격.
본문
레이아웃 구조
RootLayout (전체)
├── (marketing)/layout — 헤더 + 푸터 (랜딩)
├── (auth)/layout — 헤더 only (로그인)
└── (app)/layout — 헤더 + 사이드바 + 푸터 (인증 필요)(app) Layout — 인증 가드
// src/app/(app)/layout.tsx
import { redirect } from 'next/navigation'
import { createClient } from '@/lib/supabase/server'
import { Sidebar } from '@/components/app/sidebar'
import { Header } from '@/components/app/header'
export default async function AppLayout({ children }: { children: React.ReactNode }) {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) redirect('/login')
return (
<div className="flex h-screen">
<Sidebar />
<div className="flex-1 flex flex-col overflow-hidden">
<Header user={user} />
<main className="flex-1 overflow-y-auto p-6">{children}</main>
</div>
</div>
)
}Header
// src/components/app/header.tsx
'use client'
import { Bell, Search } from 'lucide-react'
import { UserMenu } from './user-menu'
import { ThemeToggle } from '@/components/theme-toggle'
export function Header({ user }: { user: User }) {
return (
<header className="border-b bg-background h-14 flex items-center px-6 gap-4">
<div className="flex-1 max-w-md relative">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<input
placeholder="검색..."
className="w-full pl-9 pr-3 py-1.5 bg-muted rounded-md text-sm"
/>
</div>
<button className="relative">
<Bell className="h-5 w-5" />
<span className="absolute -top-1 -right-1 h-2 w-2 bg-red-500 rounded-full" />
</button>
<ThemeToggle />
<UserMenu user={user} />
</header>
)
}Sidebar (반응형)
// src/components/app/sidebar.tsx
'use client'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { Home, Sparkles, History, Settings } from 'lucide-react'
import { cn } from '@/lib/utils'
const NAV = [
{ href: '/dashboard', label: '대시보드', icon: Home },
{ href: '/generate', label: 'AI 생성', icon: Sparkles },
{ href: '/history', label: '히스토리', icon: History },
{ href: '/settings', label: '설정', icon: Settings },
]
export function Sidebar() {
const pathname = usePathname()
return (
<aside className="hidden md:flex w-60 border-r bg-muted/30 flex-col">
<div className="p-6">
<Link href="/dashboard" className="font-bold text-lg">My SaaS</Link>
</div>
<nav className="flex-1 px-3 space-y-1">
{NAV.map(({ href, label, icon: Icon }) => (
<Link
key={href}
href={href}
className={cn(
'flex items-center gap-3 px-3 py-2 rounded-md text-sm',
pathname === href
? 'bg-primary text-primary-foreground'
: 'hover:bg-muted'
)}
>
<Icon className="h-4 w-4" />
{label}
</Link>
))}
</nav>
</aside>
)
}Mobile Sidebar (Sheet)
// src/components/app/mobile-sidebar.tsx
'use client'
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'
import { Menu } from 'lucide-react'
import { Sidebar } from './sidebar'
export function MobileSidebar() {
return (
<Sheet>
<SheetTrigger className="md:hidden">
<Menu />
</SheetTrigger>
<SheetContent side="left" className="p-0 w-60">
<Sidebar />
</SheetContent>
</Sheet>
)
}다음 챕터
CH.15 "인증 UI: 로그인/회원가입/소셜 로그인".
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude
무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6
내 마스터 프로젝트의 레이아웃 구현 부분을 분석해서 실전 적용 + 개선 우선순위 3가지를 알려줘.
ChatGPT
무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro
레이아웃 구현 관련 모범 사례·안티패턴 5개를 비교 분석해서 실전 적용를 위한 추천 방안을 알려줘.
Gemini
무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro
내 프로젝트 전체에서 레이아웃 구현 최적화 가능 위치와 리스크를 보고해줘.
Grok
무료: Grok 4.1 / SuperGrok $30/mo
2026년 한국 1인 개발자 시장의 레이아웃 구현 트렌드와 차별화 포인트를 정리해줘.
⭐ 이것만 기억하세요
레이아웃: 헤더 + 사이드바 + 메인 + 푸터는 이 3가지만 확실히 잡으세요
1.(app) 레이아웃 = 인증 가드 + 사이드바 + 헤더
2.Mobile은 Sheet로 사이드바 토글
3.다음 챕터에서 인증 UI 구현
공유하기
진행도 14 / 50