fix(sw): align header logo styles and refine viewer UI
Deploy Storybook / deploy (push) Successful in 1m13s

This commit is contained in:
shkim4 committed 2026-10-23 09:55:13 +09:00
1 parent 1d206c86cf
commit 205864b8a0
15 files changed
+236 -96

No files matched your search

+1 -1
View File
@@ -548,7 +548,7 @@ Composed Controls의 기존 레이어·색상·상세보기 예제는 보존하
| 토큰 | 기본값 | 사용처 |
|---|---|---|
| `--hm-sw-header-height` / `-bar-height` / `-field-height` | 49px / 48px / 38px | 헤더 / 면 / 필드 |
| `--hm-sw-header-logo-width` / `-logo-height` | 32px / 17px | 로고 영역(공통 배치, 로고 이미지는 프로그램별) |
| `--hm-sw-header-logo-width` / `-logo-height` | `auto`(2026-10-23, 이전 32px) / 17px | 로고 영역(공통 배치, 로고 이미지는 프로그램별). 폭은 로고 원본 비율, 홈·사선 배경이 로고 폭을 따름 |
| `--hm-sw-header-gap` | 4px | 필드 간격 |
| `--hm-sw-header-font-family` / `-font-size` / `-label-size` | Noto Sans KR… / 14px / 12px | 전체 / 값 / 라벨 |
| `--hm-sw-header-background` | `#060606` | 헤더 바탕 |
+72
View File
@@ -0,0 +1,72 @@
# SW Viewer 설정창(SWViewerPanel) 영역 구분 스타일
> 작성 2026-10-23. **현재 구현 조사 문서**이며 새 규칙을 정하지 않습니다. 값은 아래 소스와 Storybook `SW/Viewer › Settings Popup`(`sw-viewer--content-variants`)의 Computed Style 실측(Chromium, 2026-10-23)으로 확인했습니다. 구현으로 확인되지 않거나 기준이 불명확한 부분은 §6 확인 필요 항목에만 적습니다.
>
> - 공통(패키지) 스타일: `packages/sw/src/theme/sw.css`(SWPopup 프레임 `.hm-sw-property*`), `packages/sw/src/theme/sw-viewer.css`(뷰어 패널·콘텐츠 `.hm-sw-viewer-*`)
> - 컴포넌트: `packages/sw/src/components/sw-viewer/SWViewerPanel.tsx`(프레임 = `SWPopup`), `SWViewerControls.tsx`(`SWViewerSection`, `SWViewerField`, `SWViewerInput`, `SWViewerBadge`, `SWViewerHint` 등)
> - Storybook 전용 스타일: `src/sw/sw-viewer-stories.css`(`.sw-viewer-story-*`), 콘텐츠 구성 `src/sw/sw-viewer-fixture.tsx`(`LayerPanel`, `PropertiesPanel`, `OptionsPanel`)
>
> 실측의 `0.666667px` 테두리는 기기 배율(DPR 1.5)에서 1px CSS 값이 그려진 결과입니다. 아래 표에는 CSS 선언값을 적습니다.
## 1. 구조 요약
```
SWViewerPanel (= SWPopup, .hm-sw-property.hm-sw-viewer-panel) ← 테두리 박스(프레임)
├─ .hm-sw-property__titlebar ← 배경(그라데이션)만
├─ .hm-sw-property__body ← 배경·간격만(본문 스크롤)
│ └─ children: SWViewerSection(card | plain) / SWViewerField / 목록 …
└─ footer → .hm-sw-viewer-panel__footer ← 위쪽 선
.hm-sw-viewer-panel__resize ← 모서리 Grip(빗금)
```
## 2. 선(Border/Divider)으로 구분되는 영역
| 영역 | 목적 | 선택자 | 실제 값 | 조건·예외 | 구분 | Storybook 예시 |
|---|---|---|---|---|---|---|
| Footer 위 구분선 | 스크롤 본문과 하단 버튼 영역 분리 | `.hm-sw-viewer-panel__footer` | `border-top: 1px solid var(--hm-sw-viewer-panel-inner-border)`(#948871), `padding: 7px`, `gap: 8px`, 오른쪽 정렬 | `footer` Prop이 있고 접힘(`collapsed`)이 아닐 때만 렌더링 | 공통 | `SW/Viewer › Viewer Header`의 `모듈 구성 · 라이선스 고지` modal(`AboutPanel`, `확인` 버튼). Settings Popup 3개에는 footer 없음 |
| 전체 레이어 행 아래 선 | 고정 행(검색·전체 레이어)과 레이어 목록 분리 | `.sw-viewer-story-layers .sw-viewer-story-all` | `border-bottom: 1px solid var(--hm-sw-property-table)`(#d2c8b4), `padding-bottom: 8px`(실측 `padding: 0 6px 8px 0`) | 레이어 Popup에만 해당. 검색과 전체 레이어 사이에는 선 없음 | **Storybook 전용** | Settings Popup › `레이어 (9개)` |
| 속성 행 사이 선 | 속성 키/값 행 구분 | `.sw-viewer-story-props > div` | `border-bottom: 1px solid var(--hm-sw-viewer-panel-inner-border)`(#948871), `padding: 6px 0`, `gap: 12px` | 각 그룹의 **마지막 행에도** 선이 있음(실측 9행 모두) | **Storybook 전용** | Settings Popup › `속성` |
## 3. 선이 표시되지 않는 영역
| 영역 | 목적 | 선택자 | 실제 값 | 조건·예외 | 구분 | Storybook 예시 |
|---|---|---|---|---|---|---|
| Plain Section | 패널 본문에 카드 없이 콘텐츠를 바로 배치 | `.hm-sw-viewer-section[data-surface="plain"]` | 전용 규칙 없음 → 기본 `.hm-sw-viewer-section`만 적용: `display: flex; flex-direction: column; gap: 12px`, 테두리·배경·padding 0 | `SWViewerSection surface="plain"`을 명시했을 때 | 공통 | 레이어 Popup의 목록 Section, 속성 Popup의 `일반 정보`·`기하 속성` |
| 제목줄 ↔ 본문 경계 | — | `.hm-sw-property__titlebar` / `.hm-sw-property__body` | 경계선 없음. 제목줄은 배경 그라데이션, 본문은 위쪽 inset 하이라이트(§5)로만 구분 | 모든 패널 | 공통(SWPopup) | Settings Popup 전체 |
| 검색 ↔ 전체 레이어 | 고정 행 두 개 | `.sw-viewer-story-toolbar` | 선 없음, `gap: 12px 4px` | 레이어 Popup | Storybook 전용 | `레이어 (9개)` |
| 레이어 목록 행 사이 | 레이어 항목 나열 | `.sw-viewer-story-list`, `li` | 선 없음, 목록 `gap: 4px`, 행 `padding: 4px 6px` | — | Storybook 전용 | `레이어 (9개)` |
| 카드 Section 사이 | 옵션 그룹 나열 | 본문 `.hm-sw-property__body` | 선 없음, 본문 `gap: 8px`로만 분리(각 카드는 자기 테두리를 가짐) | `surface="card"` 연속 배치 | 공통 | `옵션` |
## 4. 테두리가 있는 박스 영역
| 영역 | 목적 | 선택자 | Border | Background | Radius | Padding·기타 | 조건·예외 | 구분 | 예시 |
|---|---|---|---|---|---|---|---|---|---|
| 패널 프레임 | 팝업 전체 외곽 | `.hm-sw-property`(SWPopup) + `.hm-sw-viewer-panel` | `1px solid var(--hm-sw-property-border)`(#a67d03) + `box-shadow: inset 0 0 0 1px #000`(안쪽 검정 1px) | `var(--hm-sw-property-surface)`(#e4dbc9) | 4px | padding 0, `overflow: hidden` | 모든 SWViewerPanel. modal이면 뒤에 `.hm-sw-viewer-panel-backdrop`(`rgba(0,0,0,.1)`) | 공통(SWPopup 그대로) | Settings Popup 3개 |
| Card Section | 설정 그룹 묶음 | `.hm-sw-viewer-section[data-surface="card"]` | `1px solid var(--hm-sw-viewer-panel-inner-border)`(#948871) | `var(--hm-sw-viewer-panel-field-background)`(#f1ece1) | `var(--hm-sw-viewer-radius)` 4px | `padding: var(--hm-sw-viewer-panel-spacing)` 12px, `gap: 12px`, `box-shadow: inset 0 1px 0 #fff` | `SWViewerSection`의 **기본값**(`surface` 생략 시 card) | 공통 | `옵션`의 `선가중치`·`표시`·`2.5D` |
| 검색 입력 | 레이어 검색 | `.hm-sw-theme .hm-sw-viewer-input[type="search"]` | `1px solid var(--hm-sw-viewer-panel-inner-border)` | field-background #f1ece1 | 4px | 80px 기본 폭, 높이 28px, `padding: 0 10px` | `type="search"`만. 값 입력(§5)과 다름 | 공통 | `레이어 (9개)` |
| 패널 버튼 outline | 보조 버튼 | `.hm-sw-theme .hm-sw-viewer-button` | `1px solid var(--hm-sw-viewer-panel-primary)`(#123328) | #fff (`primary`는 #123328) | 4px | 높이 24px, `padding: 0 8px` | 제목줄의 `variant="ghost"`는 테두리·배경 없음(26 × 26) | 공통 | `모듈 구성` modal의 `확인`(primary). Settings Popup에는 ghost만 |
## 5. 배경색·간격만으로 구분되는 영역
| 영역 | 목적 | 선택자 | 실제 값 | 조건·예외 | 구분 | 예시 |
|---|---|---|---|---|---|---|
| 제목줄 | 제목·닫기·동작 버튼 | `.hm-sw-property__titlebar` | 높이 30px, `background: var(--hm-sw-header-document-background)`(녹색 세로 그라데이션), Figma 제목 아트(`property-title-single.svg`, 314px 초과 폭은 왼쪽 늘림 복제 `::before`) | 모든 패널. 드래그 가능하면 `cursor: grab` | 공통 | 전체 |
| 본문 | 스크롤 콘텐츠 영역 | `.hm-sw-property__body` + `.hm-sw-viewer-panel .hm-sw-property__body` | `padding: 7px 7px 0`, `border-bottom: 8px solid transparent`(스크롤 영역 밖 하단 여백), `gap: 8px`, `box-shadow: inset 0 2px 2px rgba(255,255,255,.6)`, 배경은 프레임 surface | 접힘이면 `display: none` | 공통(SWPopup 7px + 뷰어 하단 8px 덮어쓰기) | 전체 |
| Field | 라벨 + 컨트롤 행 | `.hm-sw-viewer-field`, `__row` | 선·배경 없음, field `gap: 6px`, row `gap: 8px`, `min-height: 20px` | disabled면 `opacity: .5` | 공통 | `옵션` |
| 값 입력·단위 칸 | 숫자 입력 | `.hm-sw-viewer-input:not([type="search"])`, `.hm-sw-viewer-field__control:has(> unit)` | 기본 **투명 테두리**(1px transparent), radius 2px, 높이 28px. Hover/편집 시에만 `--hm-sw-property-field-hover-border-color` 테두리, 편집 중 배경 `--hm-sw-property-field-editing-background` | 상태가 바뀔 때만 박스로 보임 | 공통 | `옵션`의 `표시 배율`(px/mm) |
| Badge | 개수·유형 표시 | `.hm-sw-viewer-badge` | 테두리 없음, `background: var(--hm-sw-viewer-panel-badge-background)`(#d2c8b4), radius 4px, `padding: 2px 8px` | — | 공통 | 레이어 개수, `LINE · h=2F1A` |
| 레이어 행 Hover | 행 강조 | `.sw-viewer-story-list li:hover` | `background: rgba(154,146,132,.25)`, radius 3px | Hover일 때만. 숨긴 레이어는 `opacity: .45` | Storybook 전용 | `레이어 (9개)` |
| 속성 그룹 간격 | 두 속성 그룹 분리 | `.sw-viewer-story-props-next` | `margin-top: var(--hm-sw-viewer-panel-spacing)` 12px(본문 gap 8px과 합쳐 20px) | 두 번째 그룹 | Storybook 전용 | `속성` |
| Hint | 보조 설명 | `.hm-sw-viewer-hint` | 선·배경 없음, 12px | — | 공통 | `옵션` |
| 빈 상태 | 선택 없음 안내 | `.sw-viewer-story-empty` | 선·배경 없음, `padding: 40px 0`, 가운데 정렬 | `PropertiesPanel selected={false}` | Storybook 전용 | `SW/Viewer › States` 등 |
| Resize Grip | 크기 조절 | `.hm-sw-viewer-panel__resize` | 14 × 14, inner-border 색 빗금 그라데이션(선 아님) | `resizable` 이고 접힘이 아닐 때 | 공통 | 전체 |
## 6. 확인 필요 항목
1. **Card가 기본값인 이유:** `SWViewerSection`의 기본 `surface`는 `card`입니다. 그러나 레이어·속성 Popup은 모두 `plain`을 명시하고, card는 `옵션` Popup만 씁니다. 어느 콘텐츠에 card/plain을 쓰는지에 대한 디자인 기준 문서는 확인되지 않았습니다.
2. **레이어 구분선 위치:** "전체 레이어 행 아래 `#d2c8b4` 1px 선, 검색과 사이에는 없음" 규칙은 `packages/sw/ai/VIEWER.md`에 소비 앱 규칙으로 적혀 있습니다. 실제 구현은 Storybook/예제의 소비 앱 CSS뿐이고 패키지 공통 스타일은 아닙니다.
3. **구분선 색 두 가지:** 레이어 구분선은 `--hm-sw-property-table`(#d2c8b4)이고, 속성 행 선·Footer 선·Card 테두리는 `--hm-sw-viewer-panel-inner-border`(#948871)입니다. 용도별로 색을 나누는 기준은 문서화되어 있지 않습니다.
4. **속성 행 마지막 선:** 각 그룹의 마지막 행에도 아래 선이 그려집니다(Storybook 전용 CSS). 의도인지 확인되지 않았습니다.
5. **Footer 예시 부족:** Footer 구분선은 대표 Settings Popup에 없습니다. `Viewer Header` Story의 modal에서만 보이며, 비-modal 패널 Footer의 디자인 기준 화면은 확인되지 않았습니다.
6. **입력 박스 두 형태:** 검색 입력은 항상 테두리 박스이고, 값 입력은 Hover/편집 때만 테두리가 생깁니다(2026-10-22 사용자 요청 주석). 다른 텍스트 입력(예: 검색이 아닌 일반 text)에 어느 쪽을 쓸지는 `type="search"` 여부로만 갈립니다.
7. **Card 안쪽 하이라이트:** `box-shadow: inset 0 1px 0 #fff`는 하드코드 값이고 대응 토큰이 없습니다.