Files
HMDesign/docs/sw/sw-viewer-mode-2026-10-19.md
T
shkim4 7f42923ccf feat(sw): viewer mode header, dropdown and popup panel
- SWViewerHeader: data-driven viewer menu (button / toggle / menu / tabs / switch / custom), More by
  collapseBelow, trailing slot, onCommand; SWHeader logo props with no default logo
- SWViewerMenu: dropdown, check / radio, multi-level submenu, context menu at a point
- SWViewerPanel: viewer popup frame with free children / footer, drag, corner resize, collapse, modal
- Panel controls: SWViewerSection / Field / Hint / Switch / Slider / Input / Button / Badge / Status
- SWHeader black text outline tokens on viewer text, matching icon outline (drop-shadow)
- Storybook SW/Viewer stories; remove SW/Tool story (SW/Popup kept)
- AI guide ai/VIEWER.md, example H, verification scripts and evidence
2026-10-19 16:09:26 +09:00

12 KiB
Raw Blame History

SW 뷰어 모드 상단 메뉴·팝업 (2026-10-19)

  • 작업 위치: worktree D:\디자인시스템\HMDesign-SW-Viewer, 브랜치 feature/sw-viewer-header(기준 feature/sw-package e8409ef). Task A+B 통합 worktree(HMDesign-SW-Integration)는 변경하지 않았습니다. Commit·Push 없음.
  • 범위(사용자 확정): HMDesign Storybook 데모 기준. 실제 SW 프로그램 연결과 DWG/DXF 기능은 제외했습니다. 참고 프로젝트 D:\디자인시스템\테스트\dwg-dxf-viewer-hm은 읽기만 했고, 최신 소스는 scratchpad로 빌드해 vite preview로 띄웠습니다(참고 폴더에 쓰기 없음).
  • 추가 요청 반영: ① Viewer Header 텍스트·아이콘에 SW Header와 같은 검정 외곽선 ② Storybook Tool Popup 메뉴 정리: SW/Tool 삭제. SW/Popup은 공통 SWPopup 예시이므로 Commit 승인 시 지시에 따라 복원·유지 ③ 로고 미제공 시 HM 등 아무것도 표시하지 않음.
  • 증거: docs/sw/viewer-qa/(같은 해상도 캡처, report.json 74항목), docs/sw/viewer-qa/regression/regression.json(기존 SW Header 33장 픽셀 비교).

A. 분석 결과

참고 뷰어 상단 메뉴(Toolbar.tsx, sw-header.css — @hm-design/ui SWHeader 조합, 1440px 실측)

  • 52px Header(그라디언트 #266651 → #123328 → #0A221D, 1px #071E18 테두리), 72px 사선 로고 면(HM), 파일명 면 clamp(220px, 25vw, 360px), 객체 수정 면(반경 6, 테두리 #135643).
  • 그룹: 파일(파일 열기 109×34, 샘플▾ 80×34) / 도면 공간 field 면(Model·Layout 탭 97·87×40, 개수 11px) / 화면 보기 field 면(전체 보기, 2.5D·어두운 배경 스위치 칸 52·70×40) / 오른쪽 끝(레이어·설정·속성 토글 81·68·68×40, 상태 11px, 정보 32×40).
  • 상태: Hover = #266651 면, On·Open·선택 탭 = #FFC600 글자, Disabled = 60%, 스위치 off #0A221D / on #FFC600.
  • 반응형: 1180px 미만 = 샘플·탭·스위치가 더보기(베이지 #F5F0E5, 260px)로, 900px 미만 = 패널 토글도 더보기로, 560px 미만 = 아이콘만 표시하고 상태 글자 숨김.

참고 팝업·설정창

  • 샘플 Dropdown(흰 면, #DEDBD2 테두리, 반경 4, 항목 36px, 강조 rgba(189,223,212,.45))과 더보기 Dropdown(라벨, 체크, 라디오 구획).
  • DraggablePanel 3종(레이어 320×420, 옵션 340×520, 속성 320×420): 베이지 #E0DACE, 2px #897445, 제목 막대 #221D13·#FFC600 700, 곡선 녹색 닫기(Hover #E40000), 접기, 드래그(경계 10px), 네이티브 resize, 본문 12px 패딩, 카드 섹션 #F5F0E5.
  • 라이선스 모달 Dialog.
  • Context Menu와 다단계 서브메뉴는 참고 뷰어에 없습니다. 요청에 따라 공통 Dropdown 기능으로 추가했습니다.

기존 SW 패키지와의 차이

  • 기존 SWHeader는 Figma 26:8944 기준(49px, 고정 필드 구성)입니다. 데이터 기반 메뉴, 탭, 스위치, 드래그 패널이 없습니다.
  • SWPopup은 314px 고정 Figma 속성창 프레임으로, 이동·크기 조절·접기를 지원하지 않습니다.
  • 재사용: 사용자 확정 면 토큰 3종(--hm-sw-header-document-*, object-*, property-*, 참고 뷰어와 같은 값), SW 외곽선 토큰(--hm-sw-header-text-outline, label-outline, text-outline-room), SWTheme 범위·버튼 초기화, SWHeader 로고 Props 규칙.

분류

항목 분류 근거
일반 모드 Header 재사용(변경 없음) SWHeader
면 배경·외곽선·글꼴 재사용 기존 토큰
뷰어 Header 신규 기존 SWHeader는 Figma 고정 구성이고, 뷰어 메뉴 구조·크기가 다름
Dropdown·서브메뉴·Context 신규 SW 패키지에 범용 Dropdown 없음(필드 전용 Dropdown만 있음)
뷰어 팝업 신규 SWPopup 프레임(314px Figma art)과 외형·동작이 다름. Variant로 만들면 기존 속성창 DOM·CSS를 바꿔야 해서 분리

B. 패키지 변경 결과

신규 파일

  • packages/sw/src/components/sw-viewer/: types.ts, SWViewerHeader.tsx, SWViewerMenu.tsx, SWViewerPanel.tsx, SWViewerControls.tsx, index.ts
  • packages/sw/src/theme/sw-viewer.css
  • packages/sw/ai/VIEWER.md, packages/sw/ai/examples/ExampleH-ViewerMode.tsx
  • packages/sw/tests/viewer.browser.mjs, viewer-regression.browser.mjs

수정 파일

  • packages/sw/src/index.ts: 끝에 Export 1블록
  • packages/sw/ai/AI_USAGE.md: 문서 표 1행
  • packages/sw/tests/storybook-inventory.mjs: 삭제한 Story id 기록

기존 컴포넌트·sw.css·SWHeaderPropertyPanel.tsx는 수정하지 않았습니다. A+B 통합 작업과 충돌 가능성이 있는 곳은 index.ts·AI_USAGE.md 각 1군데뿐입니다.

공개 API(@hm-design/sw)

  • SWViewerHeader: groups·trailing·onCommand·documentTitle·logo/logoSrc/logoAlt/onHomeClick
  • SWViewerHeaderButton
  • SWViewerMenu: entries·anchorRef/anchorPoint·surface·initialFocus
  • SWViewerPanel: children·footer·headerActions·크기·위치·strategy·드래그·크기 조절·접기·modal
  • 패널 콘텐츠: SWViewerSection, SWViewerField, SWViewerHint, SWViewerSwitch, SWViewerSlider, SWViewerInput, SWViewerButton, SWViewerBadge, SWViewerStatus
  • 타입: SWViewerHeaderItem, SWViewerHeaderGroup, SWViewerMenuEntry, SWViewerCommand, SWViewerPanelPlacement 및 각 Props

외곽선(SW Header 분석 → 같은 기준 적용)

  • 텍스트: SW Header는 14px 글자에 검정 1.3px(16 text-shadow), 12px 라벨에 1px을 씁니다. 뷰어의 14px 글자(파일명·버튼·탭·로고)는 --hm-sw-header-text-outline, 11px(스위치 캡션·개수·상태)는 --hm-sw-header-label-outline을 그대로 사용합니다. 말줄임 파일명에는 overflow-clip-margin을 적용했습니다.
  • 아이콘: SW Header 아이콘 자산(print·K·레이어)은 채움 + 1px 검정 바깥 Stroke(Figma mask outside) + glow(stdDeviation 1.615, #061A14)입니다. 프로그램 아이콘은 자유 SVG라서 같은 효과를 drop-shadow 체인(1px × 4방향 + glow)으로 재현합니다. 토큰 --hm-sw-viewer-icon-outline이며 아이콘 윤곽을 따라갑니다.
  • 색·크기·굵기·간격은 유지합니다. Hover·Active는 채움 색만 바뀌고, Disabled는 버튼 전체 opacity로 함께 흐려집니다. Dropdown과 패널에는 외곽선이 없습니다(SW Header More 메뉴와 같음).

로고

  • SWHeader와 같은 Props(logo, logoSrc, logoAlt, onHomeClick)를 씁니다.
  • 로고를 주지 않으면 사선 끝 24px만 남고 문자·아이콘은 없습니다.
  • 로고를 주면 72px 면이 되고, 로고가 더 넓으면 24 + 로고 + 25px입니다. Header 높이 52px와 메뉴 위치는 변하지 않습니다.

Storybook

  • SW/Viewer 10개: Viewer Header(로고 없음 기본), Menu Groups, Item States, Header + Dropdown(서브메뉴·체크·라디오·Context Menu), Settings Popup(footer), Popup Content Variants, Variable Size Popups, Responsive Widths, SWHeader vs Viewer Header(모드 전환), Logo
  • 공개 API만 사용합니다. Story CSS는 배치와 Story 자체 목록에만 쓰고 hm-sw-*는 사용하지 않습니다.
  • SW/Tool(sw-tool.stories.tsx)만 삭제했습니다. SW/Popup(sw-popup.stories.tsx, 공통 SWPopup 예시)과 sw-integrated-stories.css는 원본 그대로 유지합니다. SWToolButton/SWToolGroup/SWPopup과 그 API도 유지합니다.
  • 삭제한 sw-tool--tool-buttons를 여는 기존 integrated-improvement.browser.mjs는 과거 검증 기록용으로만 남습니다. 지금 다시 실행하면 해당 단계가 실패합니다.

AI 지침: ai/VIEWER.md(역할·사용 환경·Props·이벤트·Import·Viewer 적용 조건·콘텐츠 교체·외곽선·로고·주의사항·올바른 예/잘못된 예), 예제 H, AI_USAGE.md 문서 표 반영.

C. SW 프로그램 통합 결과

이번 범위에서 제외(사용자 결정)했으므로 NOT TESTED입니다. Storybook SWHeader vs Viewer Header에서 Header 교체만 UI로 시연했고, 화면 상태(파일명·패널)는 유지됩니다.

메뉴 명령은 모두 onCommand 로그로만 표시하며 실제 기능은 미연결입니다: 파일 열기, 전체 보기, 선택 확대, 인쇄, 내보내기, 측정.

D. 검증 결과

항목 판정 근거
Typecheck PASS npm run typecheck(전체 패키지 build + tsc -b + 5개 workspace) exit 0
Package Build PASS build:packages / build:sw 성공
Storybook Build PASS npm run build-storybook exit 0. CSS 경고 1건은 기존 docs의 bg-[var(...)] 문구(기존부터 있음)
공개 Export PASS ai-docs.check.mjs 25/25(문서 식별자·예제 Import·링크)
독립 소비 프로젝트 PASS (일부) ai-template-consumer.mjs: npm pack → 새 프로젝트 설치 → 예제 A~H tsc + vite build 통과. 예제 H의 브라우저 렌더링은 소비 프로젝트에서 미실행(Storybook에서만 확인)
실제 화면 비교 PASS (알려진 차이 있음) 1440×900 같은 해상도 캡처와 수치 비교. 버튼·토글·탭·스위치 칸 크기가 참고와 같음(px 단위). 도면 공간 field 면은 42px로 참고(41px)와 1px 차이. 원인은 참고 Tabs 루트 39px. 파일명 면 x는 로고 규칙 때문에 −48px(의도된 차이)
사용자 인터랙션 PASS viewer.browser.mjs 74/74 PASS (아래 항목 참조)
외곽선 PASS 텍스트 1.3px/1px 검정 각 16 shadow, 아이콘 drop-shadow 5개, 색·크기·굵기 유지, Hover·Disabled에서 유지, 3배 확대 캡처(outline-*.png)
로고 PASS 없음: 문자·이미지 0, 면 24px. logoSrc·logo 표시. 높이 52px, 메뉴 y 동일
SW/Tool 삭제·SW/Popup 유지 PASS dev index.json: SW 제목은 SW/Header, SW/Popup, SW/Viewer (viewer.browser.mjs 재실행)
기존 기능 회귀 PASS 기존 SW/Header Story 11개 × 3폭(1920/1180/768) 픽셀 차이 0(33/33). 비교 대상은 기준 Storybook(6024, e8409ef)과 이 브랜치. test:components 9/9, test:guard 94/94, git diff --check 통과
Window Move Motion Story NOT TESTED 애니메이션이라 픽셀 비교에서 제외
Firefox·Safari, 실제 창 크기 변경 NOT TESTED Chrome headless만 실행. 폭은 viewport와 Story 폭으로 재현

viewer.browser.mjs 74개 항목: 메뉴 열기·위치·Enter/Arrow/Escape(Focus 복귀)·바깥 클릭, 탭 화살표, 스위치, Hover 면, 토글 → 팝업, 패널 Focus·Escape·Focus 복귀, 모서리 크기 조절, 드래그·경계 10px, 접기·더블클릭, 닫기 Hover #E40000, 앞으로 가져오기, 모달 배경·Focus Trap·Escape, 서브메뉴 →/← 3단계, 체크·라디오·비활성 항목, menuAlign·menuWidth, Context Menu 포인터 위치, 화면 경계, 1440/1100/860/520 가로 넘침 0, More 구획(샘플 도면/도면 공간/화면 보기/패널), More 체크·라디오 명령, 모드 전환과 상태 유지, 로고, 외곽선, 메뉴 삭제, 페이지 오류 0.

참고 뷰어와 의도적으로 다른 점

  • 모서리 크기 조절: 네이티브 resize 대신 같은 위치의 Grip을 씁니다. Firefox 등 모든 브라우저에서 동작하고 자동 검증할 수 있습니다.
  • 패널 Escape 닫기를 추가했습니다(Focus가 패널 안에 있을 때).
  • 로고 기본 표시를 없앴습니다(사용자 결정).
  • 서브메뉴와 Context Menu를 추가했습니다(요청 범위).

E. 최종 판정

PARTIAL: 패키지 컴포넌트 구현, Storybook, AI 지침, 주요 UI·인터랙션 검증은 끝났습니다. PASS가 아닌 이유는 요청 원문의 “SW 프로그램 뷰어 모드 통합”이 이번 범위에서 제외되어(사용자 결정) 진행하지 않았기 때문입니다. Commit·Push는 승인 대기입니다.