대시보드·목록·상세폼·탭·빈 페이지 등 페이지 단위 레이아웃 5종입니다.
요약 카드 + 차트 그리드로 구성하는 기본 대시보드 구조입니다.
<div className="flex flex-col gap-3">
<div className="flex items-center gap-2">
<ChartBarIcon size={16} className="text-primary" />
<span className="text-sm font-bold">대시보드 제목</span>
<Badge variant="secondary">총 1,234건</Badge>
</div>
<div className="grid grid-cols-3 gap-1.5 md:grid-cols-5">
{summaries.map((s) => (
<Card key={s.label}>
<CardContent className="px-2 py-2">
<p className="text-[9px] text-muted-foreground">{s.label}</p>
<span className="text-base font-black text-primary">{s.value}</span>
</CardContent>
</Card>
))}
</div>
<div className="grid grid-cols-1 gap-2 lg:grid-cols-2">
{charts.map((c) => (
<Card key={c.title}>
<CardContent className="px-2 pt-2 pb-1">{/* 차트 */}</CardContent>
</Card>
))}
</div>
</div>고정 헤더 테이블 + ScrollArea + 페이징으로 구성하는 목록 화면입니다.
<div className="flex flex-col flex-1 min-h-0 gap-2">
<div className="flex items-center justify-between">
<span className="text-sm font-bold">직원 관리</span>
<Button size="sm" variant="outline">등록</Button>
</div>
<Card>
<CardContent className="p-0">
<ScrollArea className="h-[140px]">
<Table>
<TableHeader className="sticky top-0 z-10 bg-background">
<TableRow>{/* ... */}</TableRow>
</TableHeader>
<TableBody>{/* ... */}</TableBody>
</Table>
</ScrollArea>
</CardContent>
</Card>
</div>2~4컬럼 폼 레이아웃으로 구성하는 등록/수정 화면입니다.
<div className="rounded-md border bg-muted/30 p-4">
<div className="grid grid-cols-2 gap-3 md:grid-cols-4">
{fields.map((field) => (
<div key={field.label} className="space-y-1">
<Label className="text-[10px]">{field.label}</Label>
<Input className="h-8 text-xs" />
</div>
))}
</div>
<div className="mt-3 flex justify-end gap-2">
<Button size="sm" variant="outline">취소</Button>
<Button size="sm">저장</Button>
</div>
</div>여러 탭으로 화면을 분리하는 레이아웃 — 탭별로 파일을 분리해 구현합니다.
<div className="flex gap-1 border-b border-border">
{tabs.map((tab) => (
<button
key={tab.value}
className={cn(
"rounded-t border-b-2 px-3 py-1.5 text-xs font-medium",
tab.active
? "border-primary bg-accent/50 text-foreground"
: "border-transparent text-muted-foreground",
)}
>
{tab.label}
</button>
))}
</div>새 화면을 시작할 때 쓰는 최소 구조 스켈레톤입니다.
<div className="flex flex-col gap-3">
<div className="space-y-1">
<Skeleton className="h-8 w-[160px]" />
<Skeleton className="h-4 w-[240px]" />
</div>
<div className="grid grid-cols-3 gap-1.5 md:grid-cols-5">
{Array.from({ length: 5 }).map((_, i) => (
<Card key={i}>
<CardContent className="space-y-1 px-2 py-2">
<Skeleton className="h-3 w-[40px]" />
<Skeleton className="h-5 w-[60px]" />
</CardContent>
</Card>
))}
</div>
</div>