# 컴포넌트 스펙 모든 컴포넌트는 `cn()` 유틸리티(`src/utils/cn.ts`)를 사용하고, CSS 변수 토큰을 통해 색상을 지정한다. --- ## Button ### 변형 (Variant) | Variant | 배경 | 텍스트 | 테두리 | 용도 | |---------|------|--------|--------|------| | `primary` | `--color-primary` | white | none | 주요 CTA | | `secondary` | `--color-secondary` | `--color-secondary-text` | none | 보조 액션 | | `accent` | `--color-accent` | `--color-accent-text` | none | 포인트 액션 | | `outline` | transparent | `--color-primary` | `--color-primary` | 조용한 강조 | | `ghost` | transparent | `--color-text-secondary` | none | 최소 강조 | | `danger` | `--color-danger` | white | none | 삭제, 경고 | ### 사이즈 | Size | padding | font-size | height | border-radius | |------|---------|-----------|--------|---------------| | `sm` | `px-3 py-1.5` | `text-sm` | 32px | `rounded-md` | | `md` | `px-4 py-2` | `text-base` | 40px | `rounded-lg` | | `lg` | `px-6 py-3` | `text-lg` | 48px | `rounded-lg` | ### 상태 - **disabled**: `opacity-50 cursor-not-allowed pointer-events-none` - **loading**: 스피너 아이콘 표시, 텍스트 유지, disabled 처리 - **hover**: 각 variant에 맞는 `-hover` 토큰 적용 - **active**: 각 variant에 맞는 `-active` 토큰 적용 - **focus-visible**: `ring-2 ring-[var(--color-primary)] ring-offset-2` ### 구현 예시 ```tsx const buttonVariants = { primary: 'bg-[var(--color-primary)] text-white hover:bg-[var(--color-primary-hover)] active:bg-[var(--color-primary-active)]', secondary: 'bg-[var(--color-secondary)] text-[var(--color-secondary-text)] hover:bg-[var(--color-secondary-hover)]', accent: 'bg-[var(--color-accent)] text-[var(--color-accent-text)] hover:bg-[var(--color-accent-hover)]', outline: 'border border-[var(--color-primary)] text-[var(--color-primary)] hover:bg-[var(--color-primary-subtle)]', ghost: 'text-[var(--color-text-secondary)] hover:bg-[var(--color-bg-surface)] hover:text-[var(--color-text-primary)]', danger: 'bg-[var(--color-danger)] text-white hover:opacity-90', }; ``` --- ## Badge 상태, 카테고리, 태그 표시에 사용한다. Shape에 따라 Pill과 Filled로 구분한다. ### Pill 변형 (rounded-full) — 상태 표시용 | Variant | 용도 | Light 배경 | Dark 배경 | |---------|------|-----------|-----------| | `default` | 기본 | `--color-bg-base` | `--color-bg-base` | | `success` | 성공/활성 | green-50 | green-500/15 | | `warning` | 경고/대기 | amber-50 | amber-500/15 | | `danger` | 에러/비활성 | red-50 | red-500/15 | | `info` | 정보/식별자 | blue-50 | blue-500/15 | ### Filled 변형 (rounded-md) — 카테고리/서비스 라벨용 Chart Palette와 1:1 매핑. `className="rounded-md"`를 추가하여 Filled shape 적용. | Variant | Chart # | Light 배경 | Light 텍스트 | Dark 배경 | Dark 텍스트 | |---------|---------|-----------|-------------|-----------|-------------| | `blue` | 1 | primary-100 | primary-900 | primary-900 | primary-300 | | `gold` | 2 | accent-100 | accent-900 | accent-900 | accent-300 | | `rose` | 3 | #fce4ec | #B5607D | rgba(212,131,155,0.12) | #D4839B | | `teal` | 4 | #e0f2f1 | #2E7D6E | rgba(91,181,166,0.12) | #5BB5A6 | | `lavender` | 5 | #f3e8ff | #7B5DA5 | rgba(183,159,212,0.12) | #B79FD4 | | `coral` | 6 | #fff3e0 | #A86440 | rgba(212,149,107,0.12) | #D4956B | > **주의**: success, warning, danger, info는 Pill 전용. Filled에 사용 금지. ### 스펙 - **Pill**: `rounded-full`, `px-2 py-0.5`, `text-xs font-medium` - **Filled**: `rounded-md`, `px-3 py-1`, `text-xs font-medium` - 사이즈: `sm` (px-1.5 py-0.5 text-[10px]), `md` (px-2 py-0.5 text-xs) --- ## Card 콘텐츠를 담는 기본 컨테이너. ### 구조 ```html

제목

부제목

``` ### 변형 | Variant | 설명 | |---------|------| | `default` | border + shadow-sm | | `elevated` | shadow-md, 모달 내부 카드 | | `flat` | border만, shadow 없음 | | `interactive` | hover 시 shadow-md + scale-[1.01] | --- ## Input ### 기본 스펙 ```html

도움말 텍스트

``` ### 상태 | 상태 | 테두리 색상 | |------|-------------| | 기본 | `--color-border` | | 포커스 | `--color-primary` (ring) | | 오류 | `--color-danger` | | 성공 | `--color-success` | | 비활성 | `--color-border` + opacity-50 | ### 사이즈 | Size | padding | font-size | height | |------|---------|-----------|--------| | `sm` | `px-3 py-1.5` | `text-sm` | 32px | | `md` | `px-3 py-2` | `text-base` | 40px | | `lg` | `px-4 py-3` | `text-lg` | 48px | --- ## Modal ### 구조 ```html

제목

...
``` ### 사이즈 | Size | max-width | |------|-----------| | `sm` | `max-w-sm` (384px) | | `md` | `max-w-md` (448px) | | `lg` | `max-w-lg` (512px) | | `xl` | `max-w-xl` (576px) | ### 접근성 - `role="dialog"`, `aria-modal="true"`, `aria-labelledby` 필수 - 열릴 때 첫 번째 포커스 가능 요소로 포커스 이동 - Escape 키로 닫기 - Backdrop 클릭 시 닫기 (선택적) - 열린 동안 body 스크롤 잠금 --- ## Toast ### 위치 `fixed bottom-4 right-4 z-[60]` (Modal보다 위) ### 변형 | Variant | 아이콘 | 색상 | |---------|--------|------| | `success` | CheckCircle | `--color-success` | | `warning` | AlertTriangle | `--color-warning` | | `error` | XCircle | `--color-danger` | | `info` | Info | `--color-info` | ### 구조 ```html
``` ### 동작 - 기본 자동 닫힘: 4000ms - 진입: `translate-y-2 opacity-0` → `translate-y-0 opacity-100` - 퇴장: `translate-y-0 opacity-100` → `translate-y-2 opacity-0` - 트랜지션: `duration-200 ease-out`