- Vite + React 프로젝트 구조 설정 - 불필요한 PDF 파일 삭제 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
13 KiB
13 KiB
디자인 시스템 표준화 가이드
목적
SAM MES 시스템의 모든 페이지가 일관된 디자인을 유지하도록 표준화합니다.
1. 필수 컴포넌트 사용
1.1 PageLayout
모든 페이지는 반드시 PageLayout으로 감싸야 합니다.
import { PageLayout } from "./organisms/PageLayout";
export function YourPage() {
return (
<PageLayout maxWidth="full">
{/* 페이지 내용 */}
</PageLayout>
);
}
maxWidth 옵션:
full: 대시보드, 목록 페이지 (기본값)2xl: 넓은 폼 페이지xl: 일반 폼 페이지lg: 좁은 폼 페이지
1.2 PageHeader
모든 페이지는 반드시 PageHeader를 사용해야 합니다.
import { PageHeader } from "./organisms/PageHeader";
import { Package } from "lucide-react";
import { Button } from "./ui/button";
<PageHeader
title="페이지 제목"
description="페이지에 대한 간단한 설명"
icon={Package}
actions={
<>
<Button variant="outline">취소</Button>
<Button>등록</Button>
</>
}
/>
금지 사항:
// ❌ 직접 헤더 작성 금지
<div className="flex justify-between">
<h1>제목</h1>
<Button>등록</Button>
</div>
// ✅ PageHeader 사용
<PageHeader title="제목" actions={<Button>등록</Button>} />
2. 표준 페이지 구조
2.1 기본 목록 페이지 구조
import { PageLayout } from "./organisms/PageLayout";
import { PageHeader } from "./organisms/PageHeader";
import { StatCards } from "./organisms/StatCards";
import { SearchFilter } from "./organisms/SearchFilter";
import { DataTable } from "./organisms/DataTable";
export function ListPage() {
return (
<PageLayout>
{/* 1. 헤더 (제목 + 서브제목 + 아이콘 + 액션 버튼) */}
<PageHeader
title="페이지 제목"
description="페이지 설명"
icon={Icon}
actions={<Button>등록</Button>}
/>
{/* 2. 통계 카드 (4개) */}
<StatCards
stats={[
{ title: "통계1", value: "100", icon: Icon, color: "blue" },
{ title: "통계2", value: "200", icon: Icon, color: "green" },
{ title: "통계3", value: "300", icon: Icon, color: "yellow" },
{ title: "통계4", value: "400", icon: Icon, color: "purple" },
]}
/>
{/* 3. 검색/필터 */}
<SearchFilter
searchValue={searchValue}
onSearchChange={setSearchValue}
filters={filterConfig}
/>
{/* 4. 콘텐츠 (테이블) */}
<DataTable
columns={columns}
data={filteredData}
/>
</PageLayout>
);
}
2.2 대시보드 페이지 구조
export function DashboardPage() {
return (
<PageLayout>
<PageHeader
title="대시보드"
description="실시간 현황을 확인하세요"
icon={LayoutDashboard}
/>
<StatCards stats={stats} />
{/* 차트 및 위젯 */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<Widget1 />
<Widget2 />
<Widget3 />
</div>
</PageLayout>
);
}
2.3 폼 페이지 구조
export function FormPage() {
return (
<PageLayout maxWidth="xl">
<PageHeader
title="신규 등록"
description="필수 항목을 입력하세요"
icon={Plus}
actions={
<>
<Button variant="outline" onClick={handleCancel}>
취소
</Button>
<Button onClick={handleSubmit}>
저장
</Button>
</>
}
/>
<FormSection title="기본 정보">
{/* 폼 필드들 */}
</FormSection>
<FormSection title="추가 정보">
{/* 폼 필드들 */}
</FormSection>
</PageLayout>
);
}
3. 스타일 가이드
3.1 금지된 패턴
// ❌ 직접 패딩/여백 정의 금지
<div className="p-6 space-y-6">
// ❌ 배경 그라데이션 금지 (특별한 경우 제외)
<div className="bg-gradient-to-br from-slate-50 to-blue-50/30">
// ❌ 불필요한 min-h-screen 금지
<div className="min-h-screen">
// ❌ 인라인 헤더 스타일 금지
<h1 className="text-3xl font-bold text-foreground">
// ❌ 커스텀 카드 스타일 금지
<div className="bg-card border border-border/20 rounded-xl p-6">
3.2 권장 패턴
// ✅ PageLayout 사용
<PageLayout>
// ✅ PageHeader 사용
<PageHeader title="제목" />
// ✅ Card 컴포넌트 사용
import { Card, CardHeader, CardTitle, CardContent } from "./ui/card";
<Card>
<CardHeader>
<CardTitle>제목</CardTitle>
</CardHeader>
<CardContent>
{/* 내용 */}
</CardContent>
</Card>
// ✅ 그리드 레이아웃
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
4. 타이포그래피 표준
4.1 절대 사용하지 말 것
globals.css에 타이포그래피가 정의되어 있으므로 Tailwind 클래스를 사용하지 마세요.
// ❌ 절대 금지!
className="text-2xl"
className="text-xl"
className="text-lg"
className="font-bold"
className="font-semibold"
className="leading-tight"
4.2 올바른 사용법
// ✅ HTML 태그 사용 (자동 스타일 적용)
<h1>대제목</h1>
<h2>중제목</h2>
<h3>소제목</h3>
<p>본문</p>
<label>레이블</label>
예외: 사용자 요청이 있을 때만 타이포그래피 클래스 사용
5. 색상 시스템
5.1 디자인 토큰 사용
// ✅ CSS 변수 사용
className="bg-primary text-primary-foreground"
className="bg-secondary text-secondary-foreground"
className="bg-muted text-muted-foreground"
className="bg-destructive text-destructive-foreground"
className="border-border"
className="bg-background text-foreground"
className="bg-card text-card-foreground"
5.2 아이콘 배경 색상
// ✅ 표준 아이콘 배경
<div className="p-2 bg-primary/10 rounded-lg">
<Icon className="w-6 h-6 text-primary" />
</div>
// ✅ 다른 색상 옵션
bg-blue-100 text-blue-600
bg-green-100 text-green-600
bg-yellow-100 text-yellow-600
bg-purple-100 text-purple-600
bg-orange-100 text-orange-600
bg-red-100 text-red-600
6. 반응형 디자인
6.1 브레이크포인트
// 모바일 우선
className="grid-cols-1" // < 768px
className="md:grid-cols-2" // 768px ~ 1023px (태블릿)
className="lg:grid-cols-4" // 1024px+ (데스크톱)
6.2 통계 카드 레이아웃
// ✅ 표준 반응형 그리드
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<StatCard />
<StatCard />
<StatCard />
<StatCard />
</div>
6.3 폼 레이아웃
// ✅ 반응형 폼
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<FormField />
<FormField />
<FormField />
</div>
7. 컴포넌트 사용 우선순위
7.1 Organisms (가장 높은 우선순위)
- PageLayout - 모든 페이지 필수
- PageHeader - 모든 페이지 필수
- StatCards - 통계 카드가 있는 페이지
- SearchFilter - 검색/필터가 있는 페이지
- DataTable - 테이블이 있는 페이지
- FormSection - 폼이 있는 페이지
- EmptyState - 데이터가 없을 때
7.2 Molecules
- StatCard - 개별 통계 카드
- FormField - 개별 폼 필드
- SearchBar - 검색 입력
- StatusBadge - 상태 표시
- TableActions - 테이블 액션 버튼
7.3 ShadCN UI Components
- Card - 카드 레이아웃
- Button - 버튼
- Input - 입력 필드
- Select - 드롭다운
- Dialog - 다이얼로그
- Table - 테이블 (DataTable 내부에서 사용)
8. 페이지별 체크리스트
✅ 목록 페이지 체크리스트
- PageLayout으로 감싸져 있는가?
- PageHeader를 사용하고 있는가?
- 아이콘이 PageHeader에 전달되었는가?
- 통계 카드가 4개인가?
- StatCards 컴포넌트를 사용하는가?
- SearchFilter 컴포넌트를 사용하는가?
- DataTable 컴포넌트를 사용하는가?
- 데이터가 없을 때 EmptyState를 보여주는가?
- 반응형 레이아웃인가? (grid-cols-1 md:grid-cols-2 lg:grid-cols-4)
✅ 대시보드 페이지 체크리스트
- PageLayout으로 감싸져 있는가?
- PageHeader를 사용하고 있는가?
- StatCards를 사용하는가?
- 위젯이 반응형 그리드로 배치되어 있는가?
- 타이포그래피 클래스를 사용하지 않았는가?
✅ 폼 페이지 체크리스트
- PageLayout (maxWidth="xl")으로 감싸져 있는가?
- PageHeader를 사용하고 있는가?
- 액션 버튼이 PageHeader에 전달되었는가?
- FormSection으로 섹션을 구분했는가?
- FormField를 사용하는가?
- 반응형 폼 레이아웃인가?
9. 마이그레이션 예시
Before (❌)
export function OldPage() {
return (
<div className="p-6 space-y-6 bg-gradient-to-br from-slate-50 to-blue-50/30 min-h-screen">
<div className="flex justify-between items-center">
<div>
<h1 className="text-3xl font-bold text-foreground">페이지 제목</h1>
<p className="text-sm text-muted-foreground mt-1">설명</p>
</div>
<Button>등록</Button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<Card>
<CardHeader>
<CardTitle>통계 1</CardTitle>
</CardHeader>
<CardContent>
<p className="text-2xl font-bold">100</p>
</CardContent>
</Card>
{/* ... */}
</div>
<div className="bg-card border rounded-xl p-4">
<Input placeholder="검색..." />
</div>
<Card>
<Table>
{/* ... */}
</Table>
</Card>
</div>
);
}
After (✅)
import { PageLayout } from "./organisms/PageLayout";
import { PageHeader } from "./organisms/PageHeader";
import { StatCards } from "./organisms/StatCards";
import { SearchFilter } from "./organisms/SearchFilter";
import { DataTable } from "./organisms/DataTable";
import { Package } from "lucide-react";
export function NewPage() {
return (
<PageLayout>
<PageHeader
title="페이지 제목"
description="설명"
icon={Package}
actions={<Button>등록</Button>}
/>
<StatCards
stats={[
{ title: "통계 1", value: "100", icon: Package, color: "blue" },
{ title: "통계 2", value: "200", icon: Package, color: "green" },
{ title: "통계 3", value: "300", icon: Package, color: "yellow" },
{ title: "통계 4", value: "400", icon: Package, color: "purple" },
]}
/>
<SearchFilter
searchValue={searchValue}
onSearchChange={setSearchValue}
/>
<DataTable
columns={columns}
data={data}
/>
</PageLayout>
);
}
10. 자주 발생하는 실수
❌ 실수 1: 직접 헤더 작성
<div className="flex justify-between">
<h1>제목</h1>
<Button>등록</Button>
</div>
✅ 해결
<PageHeader
title="제목"
actions={<Button>등록</Button>}
/>
❌ 실수 2: 커스텀 카드 스타일
<div className="bg-card border border-border/20 rounded-xl p-6">
<h3 className="text-lg font-semibold">제목</h3>
<p>내용</p>
</div>
✅ 해결
<Card>
<CardHeader>
<CardTitle>제목</CardTitle>
</CardHeader>
<CardContent>
<p>내용</p>
</CardContent>
</Card>
❌ 실수 3: 타이포그래피 클래스 사용
<h1 className="text-3xl font-bold">제목</h1>
✅ 해결
<h1>제목</h1> {/* globals.css에 정의된 스타일 자동 적용 */}
11. 개발 워크플로우
새 페이지 생성 시
- ✅ PageLayout으로 시작
- ✅ PageHeader 추가
- ✅ 필요한 Organisms 컴포넌트 추가 (StatCards, SearchFilter, DataTable 등)
- ✅ ShadCN UI 컴포넌트로 나머지 구현
- ✅ 타이포그래피 클래스 사용하지 않기
- ✅ 반응형 확인 (모바일, 태블릿, 데스크톱)
- ✅ 다크모드 확인
기존 페이지 수정 시
- ✅ 현재 PageLayout 사용 여부 확인
- ✅ PageHeader 사용 여부 확인
- ✅ 커스텀 스타일 제거
- ✅ Organisms 컴포넌트로 교체
- ✅ 타이포그래피 클래스 제거
12. 참고 자료
- 디자인 토큰:
/styles/globals.css - 공통 컴포넌트:
/components/organisms/,/components/molecules/ - ShadCN UI:
/components/ui/ - 디자인 시스템 관리: "기준정보 > 디자인시스템" 메뉴
요약
핵심 원칙 3가지
- PageLayout + PageHeader는 필수
- 타이포그래피 클래스 사용 금지
- Organisms 컴포넌트 최대한 활용
이 가이드를 따르면 모든 페이지가 일관된 디자인을 유지할 수 있습니다.