style(sw): viewer popup typography, 전체 레이어 title and options layout
Deploy Storybook / deploy (push) Successful in 2m10s

- Property popup: row labels 14px 500, read-only values 14px in the panel text
  color, monospace removed; 일반 정보 / 기하 속성 groups 20px apart
  (--hm-sw-viewer-panel-spacing on the second section).
- Layer popup: 전체 레이어 is a plain SWViewerSection title (existing
  .hm-sw-viewer-section__title) with the all-layers switch on the same row;
  layer names 14px 500, no monospace.
- Options popup follows the user image: 표시 (LWDISPLAY), 표시 배율 with the
  px/mm unit on the input row, updated lineweight hints.
- Remove stray monospace font-family from SW Story CSS.
- VIEWER.md §4.1 / new §4.2, DESIGN_RULES §11, Example H aligned.
This commit is contained in:
shkim4 committed 2026-10-22 16:56:22 +09:00
1 parent da0e647b49
commit 84d70f5cdf
9 files changed
+41 -22

No files matched your search

+2 -2
View File
@@ -160,8 +160,8 @@
| 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만 씁니다.
- **레이어 Popup 가시성(2026-10-22 필수, 10-21 눈 아이콘 규정 대체):** SW Viewer 레이어 Popup에서 레이어별 표시·숨김은 SW Header 레이어 메뉴와 같은 전구 아이콘(`SWLayerVisibilityIcon`, 20 × 20, 표시 = 색 있는 전구 / 숨김 = 회색) 버튼을 사용한다. 버튼 24 × 24 · radius 4 · Hover 면 `rgba(154, 146, 132, .3)` · `cursor: pointer`, 숨긴 행 불투명도 0.45. 전체 레이어 켜기·끄기는 Popup 상단 `SWViewerField` + `SWViewerSwitch` 하나(전체 표시일 때만 ON). 레이어별 표시·숨김은 Switch로 대체하지 않는다([VIEWER.md](./VIEWER.md) §4.1).
- **Typography(뷰어):** Header 항목 14px 500, 캡션·개수·상태 11px 400, 패널 필드 라벨 14px 500, Section 제목 12px 700, 패널 버튼·Badge 12px 500, Input 12px. 패널 콘텐츠(2026-10-22): 레이어 이름·속성 행 Label 14px 500, 읽기 전용 속성값 14px(패널 기본 Weight), 설명·Input·Select 값·Placeholder 12px, 별도 `font-family` 지정 없음([VIEWER.md](./VIEWER.md) §4.2). Font Weight는 400/500/700만 씁니다.
- **레이어 Popup 가시성(2026-10-22 필수, 10-21 눈 아이콘 규정 대체):** SW Viewer 레이어 Popup에서 레이어별 표시·숨김은 SW Header 레이어 메뉴와 같은 전구 아이콘(`SWLayerVisibilityIcon`, 20 × 20, 표시 = 색 있는 전구 / 숨김 = 회색) 버튼을 사용한다. 버튼 24 × 24 · radius 4 · Hover 면 `rgba(154, 146, 132, .3)` · `cursor: pointer`, 숨긴 행 불투명도 0.45. 전체 레이어 켜기·끄기는 Popup 상단 `SWViewerSection title="전체 레이어"`(기존 Section 제목) + 같은 줄의 `SWViewerSwitch` 하나(전체 표시일 때만 ON). 레이어별 표시·숨김은 Switch로 대체하지 않는다([VIEWER.md](./VIEWER.md) §4.1).
- **뷰어 신규 컴포넌트 체크리스트:** ① VIEWER.md·카탈로그 §9 컴포넌트로 해결되는지 먼저 본다 ② 위 토큰을 `var(--…)`로만 읽고 일반 모드 전용 모양(§8 `SWPopupRow`, §9 `SWToolButton`)을 섞지 않는다 ③ 상태는 위 표대로 ④ 토큰에 없는 값은 결과 보고에 "AI 구성 값 — 디자인 확인 필요"로 적는다 ⑤ `hm-sw-viewer-*` class를 쓰거나 덮어쓰지 않는다.
## 12. 로고 클릭 메뉴 (`SWHeader homeMenu` / `SWHomeMenu`, Figma 26:10591) — SW 일반 모드 전용
+8 -1
View File
@@ -105,9 +105,16 @@
- 전구 아이콘 버튼: 프로그램의 `<button type="button">` 24 × 24, radius 4, Hover 면 `rgba(154, 146, 132, .3)`, `cursor: pointer` 안에 `<SWLayerVisibilityIcon on={visible} />`(20 × 20, 장식용). 표시 중이면 색 있는 전구, 숨김이면 회색 전구(Header 레이어 메뉴와 같은 그림). 숨긴 행은 불투명도 0.45. 아이콘을 직접 그리거나 `hm-sw-header__*` class를 붙이지 않습니다.
- 접근성 이름에 다음 동작을 넣습니다: 표시 중 `"<레이어> 숨기기"`, 숨김 `"<레이어> 표시하기"`(`title`도 같은 동사).
- 클릭하면 그 레이어 하나의 가시성만 바꾸고 프로그램의 가시성 Callback·상태를 그대로 호출합니다. 아이콘만 그리고 기능을 빼지 않습니다.
- 전체 레이어 Switch: `<SWViewerField label="전체 레이어">{id => <SWViewerSwitch id={id} checked={allVisible} onCheckedChange={setAll} />}</SWViewerField>`. `checked`는 모든 레이어가 표시 중일 때만 `true`이고, 일부만 표시 중이면 `false`로 보이며 누르면 전체 표시가 됩니다. ON → 전체 표시, OFF → 전체 숨김. 별도 상태를 두지 않고 레이어 가시성 상태에서 계산하므로 개별 전환 시 자동으로 맞춰집니다. 이전의 `전체 켜기`·`전체 끄기` 버튼 두 개는 쓰지 않습니다.
- 전체 레이어 Switch(2026-10-22 제목 형식): `<SWViewerSection surface="plain" title="전체 레이어" className="app-…"><SWViewerSwitch aria-label="전체 레이어" checked={allVisible} onCheckedChange={setAll} /></SWViewerSection>`. 제목은 기존 Section 제목(`.hm-sw-viewer-section__title`, 12px 700)을 그대로 쓰고 별도 제목 CSS·Prop을 만들지 않습니다. 제목과 Switch를 한 줄에 두는 것은 소비 앱 자기 class(예: `section.app-viewer-all-layers { flex-direction: row; align-items: center; justify-content: space-between; min-height: 20px }`, 예제 `example-layout.css`)로 하고 `hm-sw-viewer-*` class는 덮지 않습니다. `checked`는 모든 레이어가 표시 중일 때만 `true`이고, 일부만 표시 중이면 `false`로 보이며 누르면 전체 표시가 됩니다. ON → 전체 표시, OFF → 전체 숨김. 별도 상태를 두지 않고 레이어 가시성 상태에서 계산하므로 개별 전환 시 자동으로 맞춰집니다. 이전의 `전체 켜기`·`전체 끄기` 버튼 두 개는 쓰지 않습니다.
- 그 밖의 `SWViewerSwitch`는 옵션 패널의 ON/OFF 설정(그리드·2.5D 등)에 씁니다.
### 4.2 패널 콘텐츠 글자 기준 (2026-10-22)
- 일반 콘텐츠(레이어 이름, 속성 행 Label)·`SWViewerField` Label: 14px 500. 읽기 전용 속성값은 14px, Weight는 패널 기본(400), 색 `--hm-sw-viewer-panel-text`(검정 계열). 속성 행 Label 색은 `--hm-sw-viewer-panel-label`.
- 설명·안내(`SWViewerHint`, 빈 상태 문구)·Input 값·`SWSelect` 선택값·Placeholder·Badge: 12px(기존 Weight 유지). Section 제목 12px 700, 패널 제목 14px 700은 그대로입니다.
- 글꼴은 패널이 상속하는 `--hm-sw-header-font-family`(Noto Sans KR)만 씁니다. 목록·값에 `ui-monospace` 등 다른 `font-family`를 따로 지정하지 않습니다.
- 속성 패널의 그룹(예: 일반 정보 / 기하 속성)을 더 떨어뜨릴 때는 두 번째 Section에 자기 class로 `margin-top: var(--hm-sw-viewer-panel-spacing)`(12px, 본문 간격 8px과 합쳐 20px)을 줍니다. 패널 본문 공통 간격은 바꾸지 않습니다.
## 5. 올바른 사용
```tsx
@@ -77,7 +77,9 @@ export function ExampleHViewerMode({ onEvent }: { onEvent?: (name: string) => vo
<SWViewerPanel title="레이어" open={panels.layers} onClose={() => setPanels({ ...panels, layers: false })}>
<SWViewerSection surface="plain" aria-label="레이어 목록">
{/* Top: all-layers SWViewerSwitch. Rows: swatch · name · count · bulb button (SWLayerVisibilityIcon), not a switch. */}
<SWViewerField label="전체 레이어">{id => <SWViewerSwitch id={id} checked={allVisible} onCheckedChange={setAllLayers} />}</SWViewerField>
<SWViewerSection surface="plain" title="전체 레이어" className="app-viewer-all-layers">
<SWViewerSwitch aria-label="전체 레이어" checked={allVisible} onCheckedChange={setAllLayers} />
</SWViewerSection>
<ul className="app-viewer-layers">
{layers.map(layer => {
const visible = !hiddenLayers.has(layer.name)
+4 -2
View File
@@ -36,12 +36,14 @@
}
/* Viewer layer list (example H), the same look as Storybook SW/Viewer's layer popup. Panel tokens only.
Layer visibility is a 24 x 24 button around SWLayerVisibilityIcon (header bulb), never a switch or checkbox;
the all-layers control above the list is SWViewerField + SWViewerSwitch. */
the all-layers control above the list is SWViewerSection title="전체 레이어" + SWViewerSwitch on one row. */
.app-viewer-layers { display: flex; flex-direction: column; gap: 4px; margin: 0; padding: 0; list-style: none; }
.app-viewer-layers > li { display: flex; align-items: center; gap: 8px; padding: 4px 6px; border-radius: 3px; }
.app-viewer-layers > li:hover { background: rgba(154, 146, 132, 0.25); }
.app-viewer-layers > li[data-visible="false"] { opacity: 0.45; }
/* 전체 레이어: the plain SWViewerSection laid out as one row — title (.hm-sw-viewer-section__title) left, switch right. */
section.app-viewer-all-layers { flex-direction: row; align-items: center; justify-content: space-between; min-height: 20px; }
.app-viewer-layer-swatch { flex: 0 0 10px; width: 10px; height: 10px; border: 1px solid var(--hm-sw-viewer-panel-inner-border); border-radius: 9999px; }
.app-viewer-layer-name { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-family: ui-monospace, monospace; font-size: 12px; }
.app-viewer-layer-name { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 14px; font-weight: 500; }
.app-viewer-layer-bulb { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0; border: 0; border-radius: 4px; background: none; cursor: pointer; }
.app-viewer-layer-bulb:hover { background: rgba(154, 146, 132, 0.3); }