# Web(@hm-design/ui) 디자인 규칙 출처: `@hm-design/ui/theme.css`(원본 `src/theme/primitives.css`·`default.css`·컴포넌트별 `theme/*.css`)에 실제 선언된 값. 이 문서와 그 CSS에 없는 값은 확정값이 아닙니다. 새 UI는 아래 변수를 `var(--…)`로 읽고 HEX·px 값을 새로 만들지 않습니다. 참고할 변수가 없을 때만 [AI_USAGE.md](./AI_USAGE.md) §1-5 ③으로 구성하고 "AI 구성 값 — 디자인 확인 필요"로 보고합니다. - 토큰 범위: `:root, [data-hm-theme]`. Runtime Theme(`@hm-design/ui/theme`)가 같은 변수를 바꿉니다. - Light/Dark 분기 없음. 컴포넌트 CSS에 `html`·`body`·`*` 규칙을 추가하지 않습니다. - 이름을 추측하지 않습니다. 특히 `--hm-sem-text-*`, `--hm-sem-border-*`, `--hm-sem-stroke-divider`는 **선언되어 있지 않습니다**(아래 표의 이름을 씀). 없는 토큰을 fallback 색으로 감추지 않습니다. - Tailwind utility로는 shadcn 매핑 utility(`bg-card`, `text-primary`, `text-muted-foreground` 등)를 쓸 수 있습니다. HM 값과 다를 수 있는 임의 utility 색(`bg-green-700` 등)은 쓰지 않습니다. ## 1. 기본 팔레트 (primitives → `--hm-sem-palette-*`) | 역할 | 값 | 변수 | |---|---|---| | Green(주색) | `#123328` | `--hm-sem-palette-green-default` | | Green 진한 글자 | `#0A221D` | `--hm-sem-palette-green-dark-1` | | Green Focus·Active | `#266651` | `--hm-sem-palette-green-light-2` | | Green Tint(강조 면) | `#BDDFD4` | `--hm-sem-palette-green-tint` | | Beige(콘텐츠 면) | `#F5F0E5` | `--hm-sem-palette-beige-light` | | Warm neutral | dark `#6E6759`, mid `#9A9284`, pale `#DEDBD2`, muted `#F4F1EA` | `--hm-sem-palette-warm-neutral-dark` / `-mid` / `-pale` / `-muted` | | Red | `#D32F2F` | `--hm-sem-palette-red-danger` | | Gray placeholder | `#999999` | `--hm-sem-palette-neutral-gray-500` | | White / Black | `#FFFFFF` / `#000000` | `--hm-sem-palette-white` / `--hm-sem-palette-black` | Brown·Orange 계열 팔레트(`--hm-sem-palette-brown-*`, `--hm-sem-palette-orange-*`)도 선언되어 있으며 Button `secondary`(Brown)·`modify`(Orange) 역할에 쓰입니다. 새 UI는 팔레트보다 §2의 Semantic 변수를 우선합니다. ## 2. Semantic 색·면 (새 UI가 읽는 변수) | 역할 | 변수 | 기본 | |---|---|---| | 페이지·콘텐츠 배경 | `--hm-sem-bg-content` | Beige | | 카드·팝업 표면 | `--hm-sem-bg-surface` | White | | 보조 면 | `--hm-sem-bg-subtle` | warm-neutral-muted | | 브랜드 배경(gradient) | `--hm-sem-bg-brand`, `--hm-sem-bg-brown`, `--hm-sem-bg-orange` | 세로 gradient(GNB·Brand 버튼 면) | | 기본 글자 | `--hm-sem-fg-primary` | green-dark-1 | | 보조 글자 | `--hm-sem-fg-secondary` | warm-neutral-dark | | placeholder | `--hm-sem-fg-placeholder` | gray-500 | | 일반 테두리 | `--hm-sem-stroke-default` | warm-neutral-mid | | 입력 테두리 | `--hm-sem-stroke-input-default` | warm-neutral-pale | | Focus 테두리 | `--hm-sem-stroke-input-focus` | green-light-2 | | 주 액션 / 위 글자 | `--hm-sem-action-primary` / `--hm-sem-on-action-primary` | Green / White | | 취소 액션 | `--hm-sem-action-cancel` | warm-neutral-dark | | 위험 액션 | `--hm-sem-action-destructive` | Red | | 오류 상태(잠정) | `--hm-sem-status-error` | `#B3261E` | | 강조 면 / 위 글자 | `--hm-sem-accent` / `--hm-sem-on-accent` | green-tint / `#123328` | | 선택(Active) / 위 글자 | `--hm-sem-state-active` / `--hm-sem-on-state-active` | green-light-2 / White | | 하이라이트 | `--hm-sem-surface-highlight` | accent 45% | | Floating(Popover·Menu·Tooltip 류) | `--hm-sem-floating-background`, `-border-width`(1px), `-border-color`, `-radius`, `-shadow` | White, 입력 테두리, 4px, `0 0 12px` 검정 20% | | Overlay(Dim) | `--hm-sem-overlay-background` | 검정 10% | ## 3. Typography | 항목 | 값 | |---|---| | 글꼴 | `--hm-font-family-base`: "Noto Sans KR", "Malgun Gothic", sans-serif (글꼴 파일 포함) | | Weight | **400 / 500 / 700만**(600 없음). `--hm-font-weight-medium`(500), `--hm-font-weight-bold`(700). 카드·Dialog 제목 700 | | Card 제목 | 20 / 28px / 700 (`--hm-card-title-*`) | | Dialog | 제목 20 / 28 / 700, 설명 14 / 20, 본문 16 / 24 (`--hm-dialog-*`) | | Button | sm 12/18, default 13/20, lg 15/22. Brand 700, Standard(solid·outline) 500 | | Input | small 12, medium 14, large 16 (weight 400) | ## 4. 크기·간격·Radius | 항목 | 값 | 변수 | |---|---|---| | 기본 control 높이 | 34px | `--hm-control-height-md` | | Button 높이(min) | sm 28 · default 34 · lg 42, padding-x 10 · 14 · 18 | — | | Input 높이 | small 28 · medium 34 · large 42(기본), padding-x 10 · 12 · 12 | `--hm-input-*` | | Select Trigger 높이 | medium 34 · large 44(기본) | — | | Control radius | 4px | `--hm-radius-control-md` → `--hm-radius-button`, `--hm-radius-input`, `--hm-radius-select`, `--hm-radius-container` | | Card | border 1px, padding 24px, radius 4px, 그림자 없음 | `--hm-card-*` | | Dialog | radius 8px, padding 24px, Header 아래 16px, Footer 위 16px, 버튼 간격 8px, 그림자 `0 0 12px` 검정 20% | `--hm-dialog-*` | ## 5. 상태 | 상태 | 규칙(실제 CSS) | |---|---| | Button Hover·Pressed(brand·solid) | 면 위 검정 20% inset overlay. transition·눌림 이동 없음 | | Button Hover(outline) | 역할 색으로 채우고 흰 글자. Red outline은 Red 8% 면 | | Disabled | Button·Input·Select `opacity: 0.6` + `cursor: not-allowed`, 기본 면 유지 (전역 Disabled 토큰 아님) | | Input Focus | 테두리만 1.5px `--hm-sem-stroke-input-focus`(그림자·glow 없음) | | Invalid | `aria-invalid="true"` → 오류 테두리, 키보드 Focus 시 3px 50% ring | | ReadOnly(Input) | 상자 없이 글자만, 흐리지 않음 | | Focus(그 밖) | shadcn 기본 `focus-visible` ring 유지 | | 선택 | `--hm-sem-state-active` / `--hm-sem-on-state-active` | 새 상호작용 UI는 이 표의 같은 상태 규칙을 따르고, 가능하면 상태를 가진 기존 컴포넌트(`Button`, `Toggle`, `Input`)를 안쪽에 써서 상태를 다시 만들지 않습니다. ## 6. 스크롤바 - 스크롤 영역이 필요하면 `ScrollArea`(Radix)를 씁니다. 막대는 Hover·스크롤 중에 표시됩니다. - 값: 두께 10px(`--hm-scroll-area-scrollbar-size`), thumb `--hm-sem-stroke-default`, Hover `--hm-sem-fg-secondary`, radius 9999px. - 브라우저 기본 스크롤바를 CSS(`::-webkit-scrollbar`)로 새로 꾸미지 않습니다. ## 7. Overlay·Panel 레이아웃 - 모달 = `Dialog`(Header · Body(스크롤) · Footer). 확인 = `AlertDialog`. 측면 상세 = `Sheet`. 하단 작업 = `Drawer`. 비모달 보조 = `Popover`. - 새 Panel 모양이 필요하면 `Card`(White `surface` / Beige `content`)로 만듭니다. Floating 모양이 꼭 필요하면 `--hm-sem-floating-*`만 읽습니다. - Dim은 `--hm-sem-overlay-background`. - Scoped Theme(`[data-hm-theme]`)는 body Portal(SelectContent·PopoverContent·DatePicker 팝업)에 자동 전달되지 않습니다. ## 8. 아이콘 - `lucide-react`(패키지 의존성)의 아이콘을 씁니다. Button 안 아이콘 기본 크기는 16px(`size-4`, shadcn 기본). - 아이콘 색은 글자색을 상속합니다. 아이콘 전용 색 토큰은 없습니다. ## 9. 새 컴포넌트 체크리스트 1. 같은 역할의 기존 컴포넌트·Pattern이 없는지 [COMPONENT_CATALOG.md](./COMPONENT_CATALOG.md)에서 확인했다. 2. 소비 프로젝트에 작성했고 패키지 파일·`hm-*`/`data-slot` 규칙을 덮어쓰지 않았다. 3. 면·글자·테두리·radius는 §2·§4 변수만 읽는다. HEX·임의 px 없음. 4. 버튼·입력·선택은 기존 컴포넌트를 안쪽에 썼다(상태 재구현 없음). 5. Font Weight 400/500/700, 글꼴은 상속(`--hm-font-family-base`). 6. Label·키보드·Focus 복귀·Disabled를 확인했다.