feat(sw): viewer header logo menu and file list; simplify SW Storybook

SW Viewer Header (approved optional props, public export names unchanged at 170):
- SWViewerHeader: logoMenu, documents, activeDocumentId, onDocumentSelect,
  onDocumentOpen, documentOpenLabel; measured responsive toggles (full ->
  icons -> More) with the SWHeader More / file-list styling.
- SW AI guides, ExampleH, viewer/text-weight/theme-inheritance tests and the
  logo-document-menu tests with their QA record.

SW Storybook cleanup (Story IDs and test fixtures kept):
- Sidebar: Overview -> "SW Header" (first), 전체 Footer -> "SW Footer",
  Footer/Viewer responsive pages -> "Responsive More", Viewer content-variants
  -> "Settings Popup" (merges the settings popup page).
- Hidden by the verification tag (direct URL kept): Header Dropdown,
  Document Open, Interactive States, Document Dropdown, Hidden Sub Controls,
  Home Menu standalone; Footer tool groups / custom content / parts;
  SW/Theme; Viewer menu groups / item states / variable size / settings
  panel / Header + Dropdown.
- Removed demo UI: Overview size and callback output (demo data and
  selection only with &verification), Home Menu Figma node table and width
  demo, Header Responsive More reduced to 1440 / 768 / 390, Popup reopen
  button, property-panel comparison captions, Viewer context-menu demo
  (&verification only).
- Tests: storybook-inventory records the hidden and renamed Stories;
  overview / range-cross-browser / viewer open the demo controls with
  &verification; integrated-popup reloads the Story instead of the reopen
  button; dropdown-consolidation asserts Dropdown is hidden from the sidebar
  and still opens by its direct URL.
This commit is contained in:
shkim4 committed 2026-10-21 14:52:46 +09:00
1 parent 46119eacb5
commit 23d522c136
57 files changed
+2623 -333

No files matched your search

+10 -4
View File
@@ -36,12 +36,16 @@
| `type: "custom"` | `render()`, `menuEntries?`(More에 넣을 항목) |
| `onCommand(command)` | 모든 명령을 한 곳에서 받습니다: `{ id, itemId, value? }`. 항목 자체 Callback 다음에 호출 |
| `documentTitle`, `documentPlaceholder`, `documentTooltip`, `document?` | 파일명 면 |
| `documents?: SWHeaderDocument[]`, `activeDocumentId?`, `onDocumentSelect?(document)` | 파일명 클릭 시 아래 문서 목록(샘플 도면 등). `SWHeader` 파일명 목록(`SWHeaderDocumentTitle`)과 같은 모양·키보드(ArrowDown 열기, Escape, 바깥 클릭)이며 **Open·+ New는 표시하지 않음**. 목록 외곽 너비는 파일명 버튼 외곽 너비와 `SWHeader` 목록 너비(312px) 이상이며 긴 항목이면 넓어집니다. 열려도 로고가 위에 표시됨. 선택 시 프로그램이 파일을 불러오고 `documentTitle`·`activeDocumentId`를 갱신. `document`가 있으면 `document`가 우선 |
| `onDocumentOpen?()`, `documentOpenLabel?` | 로고 오른쪽 파일 열기 버튼(`SWHeader` `documentOpenPlacement="header"`와 같은 파일명 면 `SWToolButton appearance="document"` + `SWHeader` `...` 버튼 테두리의 폴더 아이콘 + `documentOpenLabel`, 기본 `Open`). 공간이 부족하면 아이콘만(라벨은 Tooltip·접근성 이름) 표시하고 More로 옮기지 않습니다. 실행 후 `onCommand({ id: "open", itemId: "document" })` |
| `logoMenu?: { title?, items }` | (2026-10-21 이후 뷰어 화면에서 사용하지 않음, 호환용) 로고 클릭 메뉴. 파일 열기는 `onDocumentOpen` 버튼을 씁니다. 항목 `{ id, label, icon?, value?, checked?, disabled?, hidden?, onSelect? }` |
| `logo?`, `logoSrc?`, `logoAlt?`, `onHomeClick?` | `SWHeader`와 같은 로고 Props. **주지 않으면 아무것도 그리지 않습니다**(“HM” 문자·기본 아이콘 없음, 로고 면은 사선 끝 24px만). 주면 72px 면(로고가 더 넓으면 그만큼), 높이 최대 24px |
| `trailing?: ReactNode` | 오른쪽 끝 자유 영역: `SWViewerStatus`, `SWViewerHeaderButton` |
| `moreLabel?`, `toolbarLabel?`, `<header>` 속성, `ref` | |
- **반응형(참고 뷰어와 동일):** 항목별 `collapseBelow`로 More(⋯, 베이지 260px Dropdown)로 이동합니다. 참고 뷰어 기준값: 샘플·도면 공간·2.5D·어두운 배경 `1180`, 패널 토글 `900`, 파일 열기·전체 보기 `iconOnlyBelow: 560`. 1180px 미만은 간격 2px, 560px 미만은 상태 글자 숨김(CSS container). 가로 스크롤은 만들지 않습니다.
- **반응형(2026-10-21, 실제 가용 폭 기준 3단계):** 고정 Breakpoint를 쓰지 않고 Header 행의 실제 남는 폭(로고·파일명·메뉴·Gap·Padding·More 버튼 포함, 파일명은 글자 폭까지만)을 측정합니다. ① 모두 들어가면 기본 형태(아이콘+텍스트), ② 부족하면 `icon`과 `iconOnlyBelow`가 있는 항목을 모두 아이콘만(라벨은 Tooltip·접근성 이름), ③ 그래도 부족하면 `collapseBelow` 항목을 하나씩 More(⋯, 베이지 260px Dropdown)로 옮깁니다(값이 큰 것부터, 같으면 오른쪽 먼저). 넓어지면 More → 아이콘 → 기본 순서로 복귀하고, 상단과 More에 같은 항목이 동시에 나오지 않습니다. `collapseBelow`·`iconOnlyBelow`의 숫자는 순서만 정합니다(Props 형식 동일). 파일 열기는 `logoMenu`, 샘플은 `documents`. 레이어·설정·속성은 `collapseBelow` 없이 아이콘까지만. 1180px 미만 간격 2px, 560px 미만 상태 글자 숨김(CSS container)은 그대로입니다. 가로 스크롤은 만들지 않습니다.
- More는 그룹/항목 단위 구획으로 자동 구성됩니다: menu·tabs는 자기 구획(`moreLabel`), button·toggle·switch는 그룹 구획(`group.moreLabel ?? group.label`). toggle·switch는 체크 항목, tabs는 라디오 항목이 됩니다.
- **Dropdown 색(2026-10-21):** Header 안의 Dropdown — 메뉴 버튼(`type: "menu"`), More(⋯), 로고 메뉴 — 은 크기·간격·글자는 `SWViewerMenu` 그대로, 색은 일반 `SWHeader`의 `...` 메뉴와 같습니다(면 #0e3d2f, Border `--hm-sw-header-object-border-color`, 그림자 0 4px 12px rgba(0,0,0,.5), 글자 `--hm-sw-header-text-color`, 보조 글자는 같은 색 80%, Hover `--hm-sw-header-hover`, 구분선 `--hm-sw-header-document-menu-divider-color`). 파일명 목록(`documents`)은 `SWHeader` 파일명 목록 모양을 유지하고, 단독 `SWViewerMenu`(우클릭 메뉴 등)는 기존 색 그대로입니다.
- **상태 표현:** Hover = #266651 면, Active·Pressed·열림·선택 탭 = 글자·아이콘 #FFC600(선택 박스 없음), Disabled = 60% 불투명, Focus = 2px #FFC600 외곽선.
- **글자·아이콘 외곽선(SWHeader와 동일):** 14px 글자 `--hm-sw-header-text-outline`(검정 1.3px), 11px 캡션·개수·상태 `--hm-sw-header-label-outline`(검정 1px), 아이콘 `SWViewerIcon`(SWHeader 아이콘 자산의 1px 검정 바깥 Stroke를 **SVG stroke**로 재현: 아이콘 뒤 복사본의 모든 도형을 검정, 원래 선 두께 + 화면 기준 양쪽 1px(`--hm-sw-viewer-icon-outline-width`)로 그림. 위 아이콘은 그대로라 색·모양·선 두께 유지. CSS `filter` 미사용, glow는 생략). Header 항목·`SWViewerHeaderButton`의 `icon`은 자동 적용, `custom` / `trailing`의 직접 그린 아이콘은 `<SWViewerIcon>`으로 감쌉니다. 색·크기·굵기·간격은 그대로이고 Hover/Active는 채움 색만 바뀝니다. Dropdown·패널 안에는 외곽선이 없습니다(SWHeader More 메뉴와 같음). 프로그램 아이콘은 `currentColor`로 그리면 상태 색과 외곽선이 자동 적용됩니다.
@@ -82,9 +86,11 @@ import "@hm-design/sw/styles.css"
const groups: SWViewerHeaderGroup[] = [
{ id: "view", label: "화면 보기", surface: "field", items: [{ type: "button", id: "fit", label: "전체 보기", icon: <FitIcon />, onSelect: fit }] },
{ id: "panels", label: "패널", placement: "end", items: [{ type: "toggle", id: "options", label: "설정", icon: <OptionsIcon />, pressed: open, onPressedChange: setOpen, collapseBelow: 900 }] },
{ id: "panels", label: "패널", placement: "end", items: [{ type: "toggle", id: "options", label: "설정", icon: <OptionsIcon />, pressed: open, onPressedChange: setOpen, iconOnlyBelow: 900 }] },
]
<SWViewerHeader documentTitle={fileName} groups={groups} onCommand={runCommand} />
<SWViewerHeader documentTitle={fileName} groups={groups} onCommand={runCommand}
onDocumentOpen={openFile} documentOpenLabel="파일 열기"
documents={samples} activeDocumentId={sampleId} onDocumentSelect={loadSample} />
<SWViewerPanel title="옵션" open={open} onClose={() => setOpen(false)}>
<SWViewerSection title="표시">
<SWViewerField label="그리드">{id => <SWViewerSwitch id={id} checked={grid} onCheckedChange={setGrid} />}</SWViewerField>
@@ -97,7 +103,7 @@ const groups: SWViewerHeaderGroup[] = [
| 하지 말 것 | 이유 / 대신 |
|---|---|
| `<SWViewerHeader logo="HM" />`처럼 로고가 없다고 임의 문자·아이콘 넣기 | 로고는 프로그램이 정합니다. 없으면 생략 |
| 뷰어 화면에 로고(홈) 메뉴(`SWHomeMenu`·`SWRecentFiles`, `SWHeader homeMenu`) 넣기 또는 비슷한 2단 메뉴 직접 만들기 | 홈 메뉴는 SW 일반 모드 전용입니다. 뷰어 로고 클릭은 `onHomeClick`, 파일 열기·샘플은 `groups`의 `button`·`menu` 항목 |
| 뷰어 화면에 로고(홈) 메뉴(`SWHomeMenu`·`SWRecentFiles`, `SWHeader homeMenu`) 넣기 또는 비슷한 2단 메뉴 직접 만들기 | 홈 메뉴는 SW 일반 모드 전용입니다. 뷰어 로고의 파일 열기 메뉴는 `logoMenu`, 샘플 목록은 `documents`(직접 만든 Dropdown 금지) |
| 뷰어 Header를 `div` + `button`으로 다시 만들기, `hm-sw-viewer-*` class를 소비 코드에 붙이기 | 데이터(`groups`)와 `custom` / `trailing`으로 구성 |
| Header 버튼 글자에 `-webkit-text-stroke`·`border`로 외곽선 만들기 | 외곽선은 패키지 토큰이 이미 적용합니다 |
| 메뉴 색·간격을 `#123456`, `margin` 등 임의 값으로 덮기 | 토큰 `--hm-sw-viewer-*` / `--hm-sw-header-*`만 가장 바깥 SW 범위(`<SWTheme>` 또는 단독 컴포넌트 루트)의 `style`로 조정(기본값 유지 권장, [AI_USAGE.md](./AI_USAGE.md) §3.1) |