Files
HMDesign/packages/sw/ai/DESIGN_RULES.md
T
shkim4 7621934f69 docs(ai): split SW usage into general / viewer mode in packaged AI guides
- Usage types are now Web / SW (general mode, viewer mode) / OrgChart / mixed.
  Shared AI_GUIDE step 1 asks for the SW mode only when the request or the
  project setting (HMDesign 사용 유형: SW 일반 | SW 뷰어) leaves it open;
  examples B0/B1/B2 cover "HMDesign SW로 화면을 만들어 주세요", general and viewer.
- Missing-component handling in three steps (reuse in the chosen type/mode ->
  build with that mode's tokens -> HMDesign-consistent style, reported as
  "AI 구성 값 — 디자인 확인 필요"), plus SW general/viewer separation rules.
- sw/ai: AI_USAGE §0 mode selection, catalog §8 lists all 33 SWViewer* exports,
  DESIGN_RULES §11 viewer tokens, PATTERNS 7 viewer composition; examples B/F
  marked as general mode. ui/ai and org-chart/ai aligned with the new types.
- AGENTS_SNIPPET, AGENTS.md and MAINTAINING updated; copies synced.
- scripts/ai-docs.mjs: shared-copy check ignores CRLF/LF (core.autocrlf=true
  checks out packages/sw as LF and the rest as CRLF).
- Verification record updated (code samples typechecked, built and rendered).
2026-10-19 17:34:15 +09:00

152 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SW 디자인 규칙
출처: `@hm-design/sw` `styles.css`(원본 `src/theme/sw.css`)의 토큰과 규칙, Figma 이지빔 SW `rj6wpsfk24lOWvWiVRAANP` node `26:8944`와 사용자 확정값. 이 문서에 없는 값은 확정값이 아닙니다. 새 컴포넌트에 임의 값을 만들지 말고 아래 토큰을 `var(--…)`로 읽으세요. 참고할 토큰·값이 없을 때만 [AI_USAGE.md](./AI_USAGE.md) §0.4 ③으로 구성하고 "AI 구성 값 — 디자인 확인 필요"로 보고합니다.
- 토큰은 `.hm-sw-header`와 `.hm-sw-theme`(`<SWTheme>`)에만 정의됩니다. 새 컴포넌트는 그 안에 렌더링합니다.
- SW는 `@hm-design/ui` 토큰을 쓰지 않습니다. UI 패키지 토큰을 복제하거나 섞지 않습니다.
- Light/Dark 분기 없음. 전역 선택자(`html`, `body`, `*`) 없음.
- **모드:** §1~10은 SW **일반 모드**(`SWHeader`·`SWPopup`·`SWToolButton`) 기준입니다. SW **뷰어 모드**(`SWViewer*`)의 토큰·상태는 §11과 [VIEWER.md](./VIEWER.md)를 봅니다. 모드 선택·혼합 금지는 [AI_USAGE.md](./AI_USAGE.md) §0.
## 1. 크기·간격
| 항목 | 값 | 토큰 |
|---|---|---|
| Header 높이 / 면 높이 | 49px / 48px | `--hm-sw-header-height` / `--hm-sw-header-bar-height` |
| 면 사이 간격 | 2px | (Header bar `gap`) |
| 필드 높이 | 38px(면 안 위아래 5px) | `--hm-sw-header-field-height` |
| 필드 사이 간격 | 4px | `--hm-sw-header-gap` |
| 로고 슬롯 | 32 × 17 (홈 80 × 48 안 12, 16) | `--hm-sw-header-logo-width` / `-height` |
| 필드 폭 | 레이어 234, 색상 192, 선스타일 284, 문자·치수스타일 164 | — |
| 상세보기 / 창 영역 | 157 × 38 / 240 × 48(pill 85 × 42, 창 이동 88, 버튼 32 × 2) | — |
| 필드 내부 | padding 0 10px 0 11px, 텍스트 사이 12px | — |
## 2. 색·표면
| 역할 | 값 | 토큰 |
|---|---|---|
| Header 배경 | `#060606` | `--hm-sw-header-background` |
| 기본 글자 / 제목 | `#F6F4F2` / `#F0F7F5` | `--hm-sw-header-text-color` / `--hm-sw-header-title-color` |
| Selected·On·Hover 글자 | `#FFC600` | `--hm-sw-header-selected-color` |
| 화살표 | `#47AF91` | `--hm-sw-header-arrow-color` |
| 파일명 면 | 세로 gradient, 테두리 `#0E4C3A` | `--hm-sw-header-document-background`, `--hm-sw-header-document-border-color` |
| 객체 수정 면 | gradient, 테두리 `#135643`, radius 6px | `--hm-sw-header-object-background`, `-object-border-color`, `-object-radius` |
| 속성 필드 면 | 검정 45–40% gradient, 테두리 `#08251C`, radius 3px, shadow `0 1px 4px rgba(9,39,30,.7)` | `--hm-sw-header-property-background`, `-property-border-color`, `-property-radius`, `-property-shadow` |
| 인쇄·K pill | `rgba(0,0,0,.8)`, 테두리 `#092920` | `--hm-sw-header-pill-background`, `-pill-border-color` |
| 문서 Dropdown | `#103127`, 테두리 `#041611` | `--hm-sw-header-document-menu-*` |
| 필드 Dropdown(레이어·색상·선·문자·치수) | `#27241D`, 테두리 `#000`, radius 3px, 행 Hover `#62533D` + 글자 `#FF5C00` | `--hm-sw-header-layer-menu-*`, `--hm-sw-header-layer-row-hover-*` |
| Input | 글자 `#E60403`, 편집 `#0F0D0A` | `--hm-sw-header-input-*` |
| Tooltip | `rgba(0,0,0,.8)` / `#FFF` | `--hm-sw-header-tooltip-*` |
사용자 확정 면 3개(파일명·객체 수정·속성 필드)는 기본값 유지를 권장합니다.
## 3. Typography
| 항목 | 값 |
|---|---|
| 글꼴 | Noto Sans KR → Malgun Gothic → Apple SD Gothic Neo (Figma Dotum 대체, 의도된 결정). 폰트 파일은 앱이 로드 |
| 기본 / 라벨 | 14px / 12px (`--hm-sw-header-font-size` / `--hm-sw-header-label-size`) |
| Weight | 400, 500, 700만 사용(600 없음). 값·제목·토글 700 |
| 자간 | 값 0.04em, 라벨 0.02em, 파일명 0.06em |
| Text Stroke | Figma Stroke가 있는 텍스트만 검정 외곽선: 14·16px `--hm-sw-header-text-outline`(1.3px), 12px `--hm-sw-header-label-outline`(1px). 자기 색 Stroke 없음. More·Tooltip·`+ New`/`Open` 제외 |
| 말줄임 | 값은 한 줄 `ellipsis`, `title`로 전체 표시 |
## 4. 상태
| 상태 | 규칙 |
|---|---|
| Hover(테두리 있는 버튼·필드·More·인쇄·K) | 1px 테두리가 노란 세로 gradient로 바뀜(`--hm-sw-header-hover-border-gradient`, 폭 `--hm-sw-header-hover-border-width`). 크기·배경·그림자 변화 없음, 자기 Dropdown이 열린 필드는 Hover 없음 |
| Hover(파일명, 속성Bar/속성창 토글) | 글자만 `#FFC600`. 링·배경 없음 |
| Hover(필드 미리보기) | 텍스트·선/폰트/치수 미리보기 `#FFC600` |
| Selected / On | 글자·단색 아이콘 `#FFC600`(`data-selected="true"`), 배경·테두리 변화 없음 |
| Expanded(Dropdown 열림) | 필드 테두리 `#081813`, 아래 모서리 직각, 필드+목록을 감싸는 1px 노란 링 |
| Focus | 2px `#F0F7F5` outline, offset −2px(`:focus-visible`) |
| Disabled | opacity 0.4, 커서 기본. 창 버튼은 `disabled` 영향 없음 |
| 목록 행 | Hover와 Selected가 같은 강조(`#62533D` + `#FF5C00`) |
## 5. Overlay·Dropdown
- 필드 Dropdown은 필드 바로 아래(`top: 100%`)에 겹쳐 열립니다. Portal·Dim 없음, `z-index` 30. 화면(또는 Header) 밖으로 나가면 좌우만 보정합니다. 부모에 `overflow: hidden`을 두지 않습니다.
- 목록 최대 높이 240px(8행), 넘치면 내부 스크롤. 색상 팔레트 118px.
- 속성창·K 가이드는 `position: fixed` Overlay(뷰포트 안 보정, Portal·Dim 없음).
- 한 번에 하나의 Dropdown(SWHeader). 단독 사용 시 각 컴포넌트가 바깥 클릭으로 스스로 닫힙니다.
## 6. Motion
| 대상 | 규칙 |
|---|---|
| 창 이동 Hover | 1.4s 반복(커서 상승 → 약 444ms 문구 → 오른쪽 위 이동 → 약 888ms부터 유지). Drag(`:active`) 중 정지. Reduced Motion: 원본 아이콘과 정적 Tooltip |
| K 가이드 | 원본 이미지 Pan/Zoom 반복(400ms 대기 후 1022·1022·511·511ms 전환). Reduced Motion 정적 |
| 레이어 토글 | 배경·아이콘 300ms ease-out |
| 기타 | Hover·Selected는 즉시 전환(Transition 없음) |
## 7. 반응형 (`SWHeader` 전용)
Container `hm-sw-header` 기준 Breakpoint: **< 1800** 선/문자/치수스타일 → More, **< 1180** 그리기모드 숨김, **< 1080** 상세보기 → More·창 이동 24px(창 영역 176), **< 900** 색상 → More, **< 640** 인쇄·K → More·창 이동 숨김(창 영역 64), **< 520** 레이어 상태 아이콘 숨김. More에서 고른 필드는 첫 칸(레이어 자리)에 표시되고 Dropdown이 바로 열립니다(UI 상태만, 데이터 Callback 없음).
조합 Header(개별 컴포넌트)에는 이 규칙이 적용되지 않습니다. 필요한 컨트롤만 배치하고 폭 정책은 소비 앱이 정합니다.
## 8. Popup (속성창 프레임, `SWPopup` / `SWHeaderPropertyPanel`)
프로젝트마다 내용이 달라도 아래 외형은 그대로 유지됩니다(프레임은 패키지가 그림). 새 Popup 화면은 `SWPopup`을 쓰고 프레임을 다시 만들지 않습니다.
| 항목 | 값 | 토큰 |
|---|---|---|
| 폭 / 높이 | 314px / 콘텐츠 높이(최대 화면 − 8px), 넘치면 본문 세로 스크롤 | — |
| 표면 / 테두리 / radius | `#E4DBC9` / 1px `#A67D03` / 4px, 안쪽 1px 검정 그림자 | `--hm-sw-property-surface`, `--hm-sw-property-border` |
| 제목줄 | 30px, Figma 제목 아트, 제목 14px 700 `#FFC600` + 검정 외곽선, 닫기 44 × 30(Hover 자산) | `--hm-sw-header-selected-color` |
| 본문 | padding 7px, 그룹 사이 8px | — |
| 그룹 면(`SWPopupSection`) | 제목 700 · 검정 70%, 내용 면 `#F1ECE1`, 1px `#585349`, radius 4px | `--hm-sw-property-content` |
| 행(`SWPopupRow`) | 최소 32px, 라벨 72px 700 검정, 값 글자 `#E60403` 500, 단위 12px | `--hm-sw-property-label`, `--hm-sw-header-input-color` |
| 값 상자 | 28px, Hover 1px `rgba(33,29,19,.4)`, 숫자 편집 On `#0F0D0A`(단위 흰색), Dropdown On `#211D13` | `--hm-sw-property-field-*` |
| 동작 | Non-modal(Dim·Portal·Focus trap 없음). Escape는 Popup 안이면 그 Popup, 밖이면 최근 사용 Popup 하나. `autoFocus`면 열릴 때 Focus, 안에서 닫히면 원래 위치로 | — |
- 밝은 Popup 면에는 SW Header의 어두운 컨트롤(필드·`SWToolButton`)이 디자인상 맞지 않습니다. 쓸 수는 있지만(Dropdown은 고정 Overlay로 잘리지 않음) 행 모양이 필요하면 `SWPopupRow` + `SWHeaderInput` 또는 속성창 `picker`를 씁니다.
- Popup 하단 버튼의 SW 디자인은 없습니다. 임의 색·크기로 만들지 말고 `@hm-design/ui` `Button` 등 기존 컴포넌트를 쓰거나 사용자에게 디자인을 확인합니다.
## 9. 도구 버튼 (`SWToolButton` / `SWToolGroup`)
| appearance | 기존 기준 | 상태 |
|---|---|---|
| `text` | 속성Bar·속성창 토글: 19px 행, 14px 700, 자간 0.04em, 묶음 위 12px 캡션, 버튼 사이 1px 구분선 | Hover·`pressed` 글자 `#FFC600`, 테두리·배경 변화 없음 |
| `pill` | 인쇄·K: pill(`rgba(0,0,0,.8)`, 1px `#092920`, radius 4px) 안 40 × 38 버튼, 아이콘 영역 24 × 23 | Hover 노란 gradient 링 + `hoverIcon`. 아이콘 색은 기존 인쇄 아이콘 `#B6D0C9` → Hover `#FFC600`(`--hm-sw-header-selected-color`) |
| `document` | 파일명 면: 48px, gradient 표면, 위·오른쪽·아래 1px `#0E4C3A`, 글자 `#F0F7F5` 700 · 자간 0.06em | 글자만 Hover `#FFC600`. Home 바로 뒤면 로고 사선 접점 공유, 그 뒤 파일명은 왼쪽 여백 12px |
## 10. 새 컴포넌트 체크리스트
1. `<SWTheme>`(또는 `SWHeader`의 `tools`) 안에서 렌더링한다.
2. 표면·크기·색은 위 토큰만 쓴다. 필드형이면 38px·속성 필드 면·12px 라벨 + 14px 700 값.
3. Hover/Focus/Disabled/Selected를 §4 규칙대로 구현한다(테두리형은 gradient 링, 텍스트형은 글자만 `#FFC600`).
4. 입력이 필요하면 `SWHeaderInput`을 재사용한다.
5. 값은 Props, 동작은 Callback. CAD 데이터를 내부에서 바꾸지 않는다.
6. `hm-sw-*` class를 새로 쓰거나 덮어쓰지 않는다(자기 접두사 사용, 예: `app-`).
7. 버튼·탭·토글이면 먼저 `SWToolButton`의 세 모양(§9)으로 해결되는지 본다. 팝업·설정창이면 `SWPopup` + `SWPopupSection` / `SWPopupRow`(§8).
8. 팝업 안의 새 콘텐츠는 §8의 Popup 토큰(`--hm-sw-property-*`)만 읽는다. Header용 어두운 토큰을 밝은 Popup 면에 섞지 않는다.
## 11. 뷰어 모드 토큰·상태 요약 (`SWViewer*` 전용)
출처: `@hm-design/sw` `styles.css`(원본 `src/theme/sw-viewer.css`)에서 그대로 옮긴 값입니다. 사용 규칙·크기 상세는 [VIEWER.md](./VIEWER.md), 모드 선택·혼합 금지는 [AI_USAGE.md](./AI_USAGE.md) §0입니다. §1~10은 일반 모드 기준이며 이 절의 토큰은 **뷰어 모드 신규 UI에서만** 읽습니다(일반 모드 신규 UI에 쓰지 않음). 토큰은 `.hm-sw-header`, `.hm-sw-theme`에 선언됩니다.
| 영역 | 토큰 = 기본값 |
|---|---|
| Header | `--hm-sw-viewer-height` 52px, `--hm-sw-viewer-background` `linear-gradient(180deg, #266651 0%, #123328 45%, #0a221d 100%)`, `--hm-sw-viewer-border-color` #071e18, `--hm-sw-viewer-text` #fff, `--hm-sw-viewer-muted` #bddfd4, `--hm-sw-viewer-accent` #ffc600, `--hm-sw-viewer-hover` #266651 |
| 로고 면 | `--hm-sw-viewer-brand-width` 72px, `--hm-sw-viewer-brand-empty-width` 24px(로고 없음), `--hm-sw-viewer-brand-top` #123328, `--hm-sw-viewer-brand-middle` #205241, `--hm-sw-viewer-brand-bottom` #071e18 |
| 크기·글자 | `--hm-sw-viewer-gap` 4px, `--hm-sw-viewer-radius` 4px, `--hm-sw-viewer-control-height` 40px, `--hm-sw-viewer-button-height` 34px, `--hm-sw-viewer-font-size` 14px, `--hm-sw-viewer-label-size` 11px, `--hm-sw-viewer-icon-size` 16px, `--hm-sw-viewer-disabled-opacity` 0.6 |
| Header 스위치·아이콘 | `--hm-sw-viewer-switch-off` #0a221d, `--hm-sw-viewer-switch-bevel` `inset 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 -1px 1px rgba(0, 0, 0, 0.25)`, `--hm-sw-viewer-icon-outline-color` = `var(--hm-sw-header-text-outline-color)`, `--hm-sw-viewer-icon-outline-width` 1px |
| Dropdown·More | `--hm-sw-viewer-menu-background` #fff, `--hm-sw-viewer-menu-border-color` #dedbd2, `--hm-sw-viewer-menu-text` #0a221d, `--hm-sw-viewer-menu-muted` #6e6759, `--hm-sw-viewer-menu-highlight` `rgba(189, 223, 212, 0.45)`, `--hm-sw-viewer-menu-highlight-text` #123328, `--hm-sw-viewer-menu-shadow` `0 0 12px rgba(0, 0, 0, 0.2)`, `--hm-sw-viewer-menu-item-height` 36px, `--hm-sw-viewer-more-background` #f5f0e5, `--hm-sw-viewer-more-border-color` #897445 |
| 패널 콘텐츠 | `--hm-sw-viewer-panel-background` = `var(--hm-sw-property-surface)`, `--hm-sw-viewer-panel-field-background` = `var(--hm-sw-property-content)`, `--hm-sw-viewer-panel-inner-border` = `var(--hm-sw-property-inner-border)`, `--hm-sw-viewer-panel-text` = `var(--hm-sw-property-label)`, `--hm-sw-viewer-panel-heading` #3e3523, `--hm-sw-viewer-panel-label` #6e6759, `--hm-sw-viewer-panel-primary` #123328, `--hm-sw-viewer-panel-switch-off` = `var(--hm-sw-property-inner-border)`, `--hm-sw-viewer-panel-switch-on` #266651, `--hm-sw-viewer-panel-badge-background` = `var(--hm-sw-property-table)`, `--hm-sw-viewer-panel-overlay` `rgba(0, 0, 0, 0.1)`, `--hm-sw-viewer-panel-spacing` 12px |
- **공유 토큰(모드 혼합 아님):** 뷰어 Header의 파일명·객체 수정·속성 면은 `--hm-sw-header-document-*`, `--hm-sw-header-object-*`, `--hm-sw-header-property-*`를, 글자 외곽선은 `--hm-sw-header-text-outline`·`--hm-sw-header-label-outline`을 그대로 읽습니다(§2·§3). 패널 제목 막대 추가 버튼(`ghost`)의 Hover·Focus 색은 `--hm-sw-header-selected-color`입니다.
| 상태 | Header 항목(button·toggle·menu·tabs·switch) | 패널 콘텐츠 |
|---|---|---|
| Hover | 면 `--hm-sw-viewer-hover`(#266651) | `outline` 버튼: 면 `--hm-sw-viewer-panel-field-background` / `primary`: 면·테두리 `--hm-sw-viewer-hover` / `tone="green"`: 면·테두리 `--hm-sw-viewer-hover`, 글자 #fff / `ghost`: 글자만 `--hm-sw-header-selected-color` |
| Active·Pressed·열림·선택 탭 | 글자·아이콘 `--hm-sw-viewer-accent`(#ffc600), 선택 박스 없음 | `tone="green"` 누르는 동안: 면·테두리 `--hm-sw-viewer-panel-primary`, 글자 #fff |
| Checked(스위치) | 면 `--hm-sw-viewer-accent`, thumb `--hm-sw-viewer-switch-off` | 면 `--hm-sw-viewer-panel-switch-on` |
| Focus | 2px solid `--hm-sw-viewer-accent` 외곽선 | 버튼·Input·Slider: 2px solid `--hm-sw-viewer-panel-switch-on` 외곽선 |
| Disabled | `--hm-sw-viewer-disabled-opacity`(0.6) | 버튼·Input·Field 0.5 |
| Dropdown 항목 | 면 `--hm-sw-viewer-menu-highlight`, 글자 `--hm-sw-viewer-menu-highlight-text`(Focus·Hover·서브메뉴 열림), Disabled 0.5 | — |
| 상태 표시 | `SWViewerStatus`: 글자 `--hm-sw-viewer-muted` 11px 400, `error`는 `--hm-sw-viewer-accent`, `loading` 아이콘 회전 | — |
- **Typography(뷰어):** Header 항목 14px 500, 캡션·개수·상태 11px 400, 패널 필드 라벨 14px 500, Section 제목 12px 700, 패널 버튼·Badge 12px 500, Input 12px. Font Weight는 400/500/700만 씁니다.
- **뷰어 신규 컴포넌트 체크리스트:** ① VIEWER.md·§8 컴포넌트로 해결되는지 먼저 본다 ② 위 토큰을 `var(--…)`로만 읽고 일반 모드 전용 모양(§8 `SWPopupRow`, §9 `SWToolButton`)을 섞지 않는다 ③ 상태는 위 표대로 ④ 토큰에 없는 값은 결과 보고에 "AI 구성 값 — 디자인 확인 필요"로 적는다 ⑤ `hm-sw-viewer-*` class를 쓰거나 덮어쓰지 않는다.