ERP-node/design-system.md

182 lines
5.4 KiB
Markdown

# WACE PLM — Modal Design System
> 이 파일은 Claude Code(`CLAUDE.md`)와 Cursor(`.cursor/rules/modal-design.mdc`)에서 자동 참조됩니다.
> **모달 패턴만** 정의합니다. Designer 페이지 레이아웃은 변경하지 않습니다.
---
## 1. 모달 Shell 구조
```tsx
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-[{SIZE}] h-[80vh] overflow-hidden flex flex-col p-0 [&>button]:hidden">
<DialogTitle className="sr-only">{title}</DialogTitle>
<DialogDescription className="sr-only">{description}</DialogDescription>
{/* Header */}
<div className="px-6 py-4 border-b border-border flex items-center justify-between">
<div className="flex items-center gap-2">
<{Icon} className="w-4 h-4 text-blue-600" />
<h2 className="text-base font-semibold text-foreground">{title}</h2>
</div>
<Button variant="ghost" size="icon" onClick={() => onOpenChange(false)} className="w-8 h-8">
<X className="w-4 h-4" />
</Button>
</div>
{/* Tab (선택) */}
{/* → Section 2 참조 */}
{/* Content */}
<div className="flex-1 overflow-y-auto px-6 py-4">
{/* 콘텐츠 */}
</div>
{/* Footer */}
<div className="px-6 py-4 border-t border-border flex items-center justify-end gap-2">
<Button variant="outline" onClick={() => onOpenChange(false)}>취소</Button>
<Button className="bg-blue-600 hover:bg-blue-700">저장</Button>
</div>
</DialogContent>
</Dialog>
```
### 사이즈 변형
| 용도 | className |
|------|-----------|
| 기본 (512px) | `max-w-lg` |
| 중간 (672px) | `max-w-2xl` |
| 넓음 (800px) | `max-w-[800px]` |
| 최대 (1024px) | `max-w-5xl` |
---
## 2. 탭 패턴 (모달 내부)
```tsx
<div className="mx-6 mt-3">
<div className="h-9 bg-muted/30 rounded-lg p-0.5 inline-flex">
{tabs.map(tab => (
<button
key={tab.value}
onClick={() => setActiveTab(tab.value)}
className={`px-3 py-1.5 rounded-md text-xs font-medium transition-all flex items-center gap-1.5 ${
activeTab === tab.value
? "bg-blue-50 text-blue-700 shadow-sm"
: "bg-transparent text-foreground hover:text-foreground/80"
}`}
>
<tab.Icon className="w-3.5 h-3.5" />
{tab.label}
</button>
))}
</div>
</div>
```
- shadcn `<Tabs>` 컴포넌트 **사용 금지** — 위 커스텀 버튼 패턴 사용
- 활성 탭: `bg-blue-50 text-blue-700 shadow-sm`
- 비활성 탭: `bg-transparent text-foreground`
---
## 3. 섹션 패턴
### 정보 섹션 (강조, Teal)
```tsx
<div className="bg-teal-50 border border-teal-200 rounded-xl p-4">
{/* 데이터 소스, 정보 입력 등 주요 섹션 */}
</div>
```
### 일반 섹션 (흰색)
```tsx
<div className="bg-white border border-border rounded-xl p-4 space-y-4">
{/* 설정, 목록 등 */}
</div>
```
---
## 4. 폼 필드 패턴
```tsx
{/* Label + Input */}
<div className="space-y-2">
<Label className="text-xs font-medium text-foreground">라벨</Label>
<Input className="h-9 text-sm" placeholder="..." />
</div>
{/* Label + Select */}
<div className="space-y-2">
<Label className="text-xs font-medium text-foreground">라벨</Label>
<Select>
<SelectTrigger className="h-9 text-sm">
<SelectValue placeholder="선택하세요" />
</SelectTrigger>
<SelectContent>...</SelectContent>
</Select>
</div>
{/* 읽기 전용 Input */}
<div className="space-y-2">
<Label className="text-xs font-medium text-muted-foreground">라벨 (자동 감지)</Label>
<Input className="h-9 text-sm bg-muted" readOnly />
</div>
```
- 필드 간격: `space-y-3`
- Label: `text-xs font-medium`
- Input/Select 높이: `h-9`
---
## 5. 버튼 규칙 (모달 내)
| 위치 | variant | 용도 |
|------|---------|------|
| Footer 취소 | `outline` | 닫기, 취소 |
| Footer 저장 | `className="bg-blue-600 hover:bg-blue-700"` | 저장, 확인 |
| Footer 삭제 | `variant="destructive"` | 삭제 확인 |
| 콘텐츠 내 추가 | `variant="outline" size="sm" className="w-full gap-2"` | 행/항목 추가 |
| 콘텐츠 내 아이콘 | `variant="ghost" size="sm"` | 인라인 액션 |
| 삭제 아이콘 | `variant="ghost" size="sm" className="text-destructive hover:text-destructive hover:bg-destructive/10"` | 인라인 삭제 |
---
## 6. 오버레이 & 애니메이션
- 오버레이: `rgba(0, 0, 0, 0.6)` — globals.css에 이미 전역 설정됨
- 모달 열기: `fade-in 200ms + zoom-in-95` (shadcn 기본)
- 모달 닫기: `fade-out 150ms + zoom-out-95` (shadcn 기본)
- 탭 전환: 애니메이션 없음 (즉시)
---
## 7. 아이콘 규칙 (모달 내)
| 위치 | 크기 | 색상 |
|------|------|------|
| 헤더 타이틀 아이콘 | `w-4 h-4` (16px) | `text-blue-600` |
| 탭 내부 아이콘 | `w-3.5 h-3.5` (14px) | 탭 상태에 따라 자동 |
| 닫기 버튼 X | `w-4 h-4` (16px) | 기본 foreground |
| 콘텐츠 내 액션 아이콘 | `w-3 h-3` (12px) | `text-muted-foreground` |
| 행 추가 버튼 아이콘 | `w-3.5 h-3.5` (14px) | 기본 |
---
## 8. 접근성 필수 사항
```tsx
{/* DialogContent 내부 반드시 포함 */}
<DialogTitle className="sr-only">{모달 목적 설명}</DialogTitle>
<DialogDescription className="sr-only">{상세 설명}</DialogDescription>
```
- Escape 키로 닫기: shadcn Dialog 기본 제공
- 포커스 트랩: shadcn Dialog 기본 제공
- 닫기 버튼에 `aria-label` 불필요 (shadcn 처리)