- 법인차량 관리 3개 페이지 (차량등록, 운행일지, 정비이력) - MES 데이터 정합성 분석 보고서 v1/v2 - sam-docs 프론트엔드 기술문서 v1 (9개 챕터) - claudedocs 가이드/테스트URL 업데이트
177 lines
5.6 KiB
Markdown
177 lines
5.6 KiB
Markdown
# UI 컴포넌트 카탈로그
|
|
|
|
**경로**: `src/components/ui/`
|
|
**기반**: shadcn/ui (Radix UI + Tailwind CSS)
|
|
|
|
---
|
|
|
|
## 입력 컴포넌트
|
|
|
|
### 기본 입력
|
|
|
|
| 컴포넌트 | 파일 | 용도 |
|
|
|----------|------|------|
|
|
| `Input` | `input.tsx` | 텍스트 입력 |
|
|
| `Textarea` | `textarea.tsx` | 여러 줄 텍스트 |
|
|
| `Checkbox` | `checkbox.tsx` | 체크박스 |
|
|
| `RadioGroup` | `radio-group.tsx` | 라디오 버튼 |
|
|
| `Switch` | `switch.tsx` | 토글 스위치 |
|
|
| `Slider` | `slider.tsx` | 슬라이더 |
|
|
| `Select` | `select.tsx` | 셀렉트 (Radix UI) |
|
|
|
|
### 특화 입력
|
|
|
|
| 컴포넌트 | 파일 | 용도 | 특징 |
|
|
|----------|------|------|------|
|
|
| `DatePicker` | `date-picker.tsx` | 날짜 선택 | 한글 locale, 주말/휴일 색상, 연/월 선택, "오늘" 버튼 |
|
|
| `DateRangePicker` | `date-range-picker.tsx` | 기간 선택 | 시작~종료 날짜 |
|
|
| `DateTimePicker` | `date-time-picker.tsx` | 날짜+시간 | |
|
|
| `TimePicker` | `time-picker.tsx` | 시간만 | |
|
|
| `PhoneInput` | `phone-input.tsx` | 전화번호 | 자동 하이픈 (010-1234-5678) |
|
|
| `BusinessNumberInput` | `business-number-input.tsx` | 사업자번호 | 자동 포맷 (000-00-00000) |
|
|
| `PersonalNumberInput` | `personal-number-input.tsx` | 주민번호 | 마스킹 가능 |
|
|
| `CardNumberInput` | `card-number-input.tsx` | 카드번호 | 4자리 구분 |
|
|
| `AccountNumberInput` | `account-number-input.tsx` | 계좌번호 | |
|
|
| `NumberInput` | `number-input.tsx` | 숫자 | |
|
|
| `CurrencyInput` | `currency-input.tsx` | 금액 | 천단위 콤마, ₩ 접두사 |
|
|
| `QuantityInput` | `quantity-input.tsx` | 수량 | +/- 버튼 |
|
|
| `FileInput` | `file-input.tsx` | 파일 | |
|
|
| `FileDropzone` | `file-dropzone.tsx` | 파일 드래그 앤 드롭 | |
|
|
| `ImageUpload` | `image-upload.tsx` | 이미지 업로드 | 미리보기 |
|
|
|
|
### 검색/선택
|
|
|
|
| 컴포넌트 | 파일 | 용도 |
|
|
|----------|------|------|
|
|
| `SearchableSelect` | `searchable-select.tsx` | 검색 가능 셀렉트 |
|
|
| `MultiSelectCombobox` | `multi-select-combobox.tsx` | 다중 선택 콤보박스 |
|
|
| `Command` | `command.tsx` | 검색/필터 커맨드 팔레트 |
|
|
|
|
---
|
|
|
|
## 피드백 컴포넌트
|
|
|
|
| 컴포넌트 | 파일 | 용도 |
|
|
|----------|------|------|
|
|
| `Button` | `button.tsx` | 버튼 (variant: default, destructive, outline, secondary, ghost, link) |
|
|
| `Badge` | `badge.tsx` | 뱃지 |
|
|
| `Alert` | `alert.tsx` | 알림 |
|
|
| `AlertDialog` | `alert-dialog.tsx` | 알림 다이얼로그 |
|
|
| `ConfirmDialog` | `confirm-dialog.tsx` | 확인 다이얼로그 |
|
|
| `ErrorCard` | `error-card.tsx` | 에러 카드 |
|
|
| `ErrorMessage` | `error-message.tsx` | 에러 메시지 |
|
|
| `LoadingSpinner` | `loading-spinner.tsx` | 로딩 스피너 |
|
|
| `Skeleton` | `skeleton.tsx` | 스켈레톤 (로딩 플레이스홀더) |
|
|
| `toast` | `sonner` 라이브러리 | 토스트 알림 |
|
|
|
|
---
|
|
|
|
## 레이아웃 컴포넌트
|
|
|
|
| 컴포넌트 | 파일 | 용도 |
|
|
|----------|------|------|
|
|
| `Card` | `card.tsx` | 카드 (CardHeader, CardContent, CardFooter) |
|
|
| `Dialog` | `dialog.tsx` | 다이얼로그 (모달) |
|
|
| `Drawer` | `drawer.tsx` | 드로어 (하단/측면 패널) |
|
|
| `Popover` | `popover.tsx` | 팝오버 |
|
|
| `Sheet` | `sheet.tsx` | 시트 (측면 패널) |
|
|
| `Accordion` | `accordion.tsx` | 아코디언 (접기/펼치기) |
|
|
| `Tabs` | `tabs.tsx` | 탭 |
|
|
| `Table` | `table.tsx` | 테이블 (Table, TableHeader, TableBody, TableRow, TableCell) |
|
|
|
|
---
|
|
|
|
## 기타 컴포넌트
|
|
|
|
| 컴포넌트 | 파일 | 용도 |
|
|
|----------|------|------|
|
|
| `Label` | `label.tsx` | 라벨 |
|
|
| `Separator` | `separator.tsx` | 구분선 |
|
|
| `ScrollArea` | `scroll-area.tsx` | 스크롤 영역 |
|
|
| `Tooltip` | `tooltip.tsx` | 툴팁 |
|
|
| `Progress` | `progress.tsx` | 진행률 바 |
|
|
| `FileList` | `file-list.tsx` | 파일 목록 표시 |
|
|
| `ChartWrapper` | `chart-wrapper.tsx` | 차트 래퍼 (Recharts) |
|
|
| `EmptyState` | `empty-state.tsx` | 빈 상태 표시 |
|
|
|
|
---
|
|
|
|
## DatePicker 사용법
|
|
|
|
프로젝트 전체에서 `<input type="date">` 대신 사용.
|
|
|
|
```tsx
|
|
import { DatePicker } from '@/components/ui/date-picker';
|
|
|
|
// 기본
|
|
<DatePicker
|
|
value={date} // "yyyy-MM-dd" 문자열
|
|
onChange={(date) => setDate(date)}
|
|
/>
|
|
|
|
// 옵션
|
|
<DatePicker
|
|
value={date}
|
|
onChange={setDate}
|
|
placeholder="날짜 선택"
|
|
size="sm" // "default" | "sm" | "lg"
|
|
disabled={!isEditMode}
|
|
minDate={new Date('2024-01-01')}
|
|
maxDate={new Date()}
|
|
/>
|
|
```
|
|
|
|
**Props**:
|
|
- `value`: `string` (yyyy-MM-dd 형식)
|
|
- `onChange`: `(date: string) => void`
|
|
- `size?`: `"default"` | `"sm"` | `"lg"`
|
|
- `disabled?`, `placeholder?`, `className?`
|
|
- `minDate?`, `maxDate?`: `Date` 타입 (**문자열 아님**)
|
|
|
|
---
|
|
|
|
## Radix UI Select 주의사항
|
|
|
|
빈 값('')으로 마운트 후 value 변경이 반영 안 되는 버그:
|
|
|
|
```tsx
|
|
// ✅ key prop으로 강제 리마운트
|
|
<Select
|
|
key={`${fieldKey}-${stringValue}`}
|
|
value={stringValue}
|
|
onValueChange={onChange}
|
|
>
|
|
{/* options */}
|
|
</Select>
|
|
```
|
|
|
|
---
|
|
|
|
## 팝업 정책
|
|
|
|
```
|
|
❌ 금지: alert(), confirm(), prompt()
|
|
✅ 사용: AlertDialog, ConfirmDialog, toast (sonner)
|
|
```
|
|
|
|
```tsx
|
|
// 토스트
|
|
import { toast } from 'sonner';
|
|
toast.success('저장되었습니다');
|
|
toast.error('오류가 발생했습니다');
|
|
|
|
// 확인 다이얼로그
|
|
<AlertDialog open={open} onOpenChange={setOpen}>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>삭제 확인</AlertDialogTitle>
|
|
<AlertDialogDescription>정말 삭제하시겠습니까?</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
<AlertDialogFooter>
|
|
<AlertDialogCancel>취소</AlertDialogCancel>
|
|
<AlertDialogAction onClick={handleDelete}>삭제</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
```
|