- A: SWViewerIcon draws the SWHeader black outline as SVG stroke on a copy behind the icon (no CSS filter) - B: SWViewerPanel renders the common SWPopup frame (same DOM / CSS) and adds drag, corner resize, collapse, bounds and modal; SWPopup gains optional titleActions / footer; title art spans any width - C: shared Story canvas grid (--sw-story-canvas) behind the SW Header work area and dropdown room - D: SWViewerButton tone="green" for 전체 켜기 / 전체 끄기: default kept, hover = primary (확인) hover token, pressed = primary face - AI guide, verification scripts (76 checks, element regression) and evidence updated
15 KiB
SW 뷰어 모드 상단 메뉴·팝업 (2026-10-19)
- 작업 위치: worktree
D:\디자인시스템\HMDesign-SW-Viewer, 브랜치feature/sw-viewer-header(기준feature/sw-packagee8409ef). 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.json74항목),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.tspackages/sw/src/theme/sw-viewer.csspackages/sw/ai/VIEWER.md,packages/sw/ai/examples/ExampleH-ViewerMode.tsxpackages/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/onHomeClickSWViewerHeaderButtonSWViewerMenu:entries·anchorRef/anchorPoint·surface·initialFocusSWViewerPanel: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/Viewer10개: 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는 승인 대기입니다.
F. 후속 디자인 수정 (Push 7f42923 이후, 미커밋)
| 항목 | 적용 | 검증 |
|---|---|---|
| A. 아이콘 외곽선 filter → SVG stroke | 신규 SWViewerIcon(공개). 아이콘 뒤 복사본의 도형을 검정 Stroke(원래 두께 + 화면 기준 양쪽 1px, --hm-sw-viewer-icon-outline-width), 채운 도형은 검정 채움. 위 아이콘은 그대로. CSS filter와 glow 제거 |
계산값: filter none, 복사본 stroke 검정 5 unit / 원본 2 unit(24 unit 아이콘을 16px로 그린 경우 1px = 1.5 unit). 3배 캡처에서 모양·선 두께 유지 |
| B. Viewer Popup = SW Popup | SWViewerPanel이 공통 SWPopup을 렌더링(같은 DOM·CSS). SWPopup에 선택 Props titleActions, footer 추가(기본 동작 동일). 제목 아이콘 Prop 제거, 기본 폭 314. 314px가 아닌 폭은 제목 아트를 오른쪽 정렬 + 왼쪽 평면 확장(이음매 없음). 패널 콘텐츠 토큰을 SW 속성창 토큰(--hm-sw-property-*)에 연결 |
SW/Popup·Viewer 패널 계산값 동일(1px #A67D03, r4, inset 1px 검정, #E4DBC9, 제목 막대 30px, 제목 #FFC600 14px 700 + 1px 외곽선). 드래그·크기 조절·접기·Escape·모달·앞으로 가져오기 PASS |
| C. SW Header 메뉴 배경 그리드 | Story 공용 변수 --sw-story-canvas(Viewer 캔버스와 같은 40px 칸, 1px #266651 18%, #0A0A0B)를 SW Header Overview 작업 영역과 Dropdown 공간에 적용. SW Header 컴포넌트 자체는 변경 없음 |
캡처 확인. 회귀: 이전 배경을 테스트 CSS로 되돌리면 Header·Popup 요소 39/39 픽셀 동일, 실제 차이는 배경 투과 픽셀뿐 |
| D. 레이어 전체 켜기 / 끄기 | SWViewerButton tone="green": 기본 유지, Hover = 확인(primary) 버튼 Hover와 같은 토큰 --hm-sw-viewer-hover, 누르는 동안 = primary 면 --hm-sw-viewer-panel-primary. 새 HEX 없음. 다른 버튼 영향 없음 |
기본 → Hover → Active → 놓은 뒤 Hover → 이탈 후 기본 계산값 PASS, 확인 버튼 Hover와 정확히 동일 |
- 해석(C): “Viewer Header의 검정 그리드”는 Header 컴포넌트가 아니라 Story 도면 영역 배경이라 Story 레벨 공용 변수로 적용했습니다.
- 높이(추가 요청): 패키지에 뷰어 영역 고정 높이가 없음을 확인했습니다(Header 52px 한 줄, 팝업 최대 90vh). Storybook 프레임 높이는 Story 전용 값이고, 프로그램 레이아웃 규칙은
ai/VIEWER.md§7에 적었습니다. 실제 테스트 프로젝트(HMDesignSwTest-viewer)는 다른 세션이 작업 중이라 이 세션에서는 수정하지 않았습니다. 읽기 확인 결과, 화면 높이는h-full세로 flex에 도면 영역flex-1 min-h-0이고, 렌더러 크기 조정은 windowresize에만 연결되어 있습니다(컨테이너 크기 변화에는 미대응). - 검증:
viewer.browser.mjs76/76, 요소 회귀 39/39(--neutral-canvas),npm run typecheck0 오류,build-storybook성공,ai-docs.check25/25.