# SW Step Header 디자인 명세 (`SWProcessHeader`) > 상태: `@hm-design/sw` 1차 구현 기준(2026-11-03). 코드: `packages/sw/src/components/sw-process-header/`, CSS: `packages/sw/src/theme/sw-process-header.css`, Story: `SW / Step Header`(2026-11-03 표시 명칭 변경, 컴포넌트·공개 API 이름 `SWProcessHeader`·`SWProcessBar` 등은 유지). > 원본: Strana Main Header — `D:\Strana\Git_StranaDevDesign` HEAD `edda3cc`(Header 7173e82 + 분할 버튼 b7f412c)의 `HeaderStyles.xaml`, `HeaderBrushes.xaml`, `MainProcessBar.xaml`, `MainWorkspaceWindowView.xaml`, Hanmac `Colors.xaml`. Strana 저장소는 읽기 전용 참고이며 수정하지 않습니다. > 승인: 2026-11-03 사용자 승인(방안 B · 설계 계획서 7절 9개 항목 권장안). ## 1. 개요 SW 일반 모드의 **독립 Header**입니다. `SWHeader`(편집 메뉴 Header), `SWViewerHeader`(뷰어 모드)와 같은 층위이며 한 화면에는 Header를 하나만 둡니다. `SWHeader`·`SWViewerHeader`·`sw.css`는 바꾸지 않았습니다. | 공개 컴포넌트 | 역할 | |---|---| | `SWProcessHeader` | 49px Header 프레임: 로고 → 파일명 → 가운데(프로세스 · Layer 면) → 창 영역(도구 pill · 창 이동 · 최소화 · 최대화/복원 · 종료) | | `SWProcessBar` | 프로세스 단계 영역(그룹 번호·이름, 단계 탭, 그룹 사이 화살표, 활성 그룹 발광). Header 밖에서는 `SWTheme` 안에서 씁니다 | | `SWProcessSplitButton` | `tools` pill 안 화면 분할 도구(버튼 + 6칸 선택 패널, §11.3) | ## 2. 구조와 재사용 ``` SWProcessHeader
49px (면 48 + 아래 1px 배경) ├─ SWHeaderHome 재사용 — 9-slice 홈 도형(Strana HomeFace/HomeBorder/HomeShadow와 같은 경로·gradient·그림자) ├─ SWHeaderDocumentTitle 재사용 — 파일명 면(DocFace / DocBorder = SW 문서 토큰과 같은 값) ├─ __center │ ├─ SWProcessBar 신규 │ └─ __layer 면 SW 객체 면 토큰(ObjFace / LayerFaceBorder와 같은 값) │ └─ Layer 필드 신규 내부 — 전구는 SWHeaderLayerToggle(내부) 재사용, Strana 전구와 같은 그림 └─ __window DocFace 면 + DocBorder 1px ├─ SWToolGroup pill 재사용(`tools` 슬롯을 감쌈) — 테두리·면만 Strana 값으로 범위 안에서 조정 ├─ 창 이동 재사용 — SWHeaderWindowControls(창 이동만): 줄무늬 · 아이콘 · 1.4s Hover Motion · 툴팁 └─ 캡션 버튼 3개 신규 내부 — 최소화 · 최대화/복원 · 종료 ``` `SWHeaderLayerControl`·`SWHomeMenu`는 쓰지 않습니다(빈 20px 칸, 2단 타일 메뉴가 Strana와 달라서). `SWHeaderWindowControls`는 창 이동만 쓰고(`showMinimize`·`showClose` false), 최소화·최대화/복원·종료는 이 Header의 캡션 버튼입니다(2026-11-03 변경, §10). ## 3. 레이아웃·반응형 Strana Grid의 별 비율을 CSS flex 비율로 옮겼습니다. 숨김 단계·More는 없습니다(Strana와 같음). 보장 폭은 1100px 이상이며 그보다 좁으면 Header 안에서 잘립니다. | 영역 | Strana | 구현 | |---|---|---| | 홈 | 106 × 48, 오른쪽 17px이 파일명 위로 겹침 | **SWHeader 우선(2026-11-03):** `SWHeaderHome` 그대로 = 12 + 로고 칸(높이 17, 로고 비율 폭) + 36, 32 × 17 로고 → 80. 오른쪽 15px이 파일명과 겹친 뒤 2px 간격(SWHeader bar gap, `margin-right: -15px`). `logoText`는 18px 700·`--hm-sw-header-text-color`·SW 외곽선·한 줄(줄바꿈 없음), 최소 58px 칸 가운데(→ 홈 최소 106). 글자가 더 넓으면 칸이 글자 폭만큼 넓어지고 홈(클릭 영역)·사선 배경·파일명 시작 위치가 따라감(2026-11-05, 잘림 없음). 홈은 줄지 않으므로(`flex: 0 0 auto`) 늘어난 폭만큼 파일명(최소 100)과 가운데 영역이 flex 비율대로 줄어듦. 참고 실측(Noto Sans KR, 글꼴에 따라 다름): StrAna 59.29 → 홈 107.29, Accessway 93.72 → 홈 141.72 | | 파일명 | `286*`, 최소 100, 최대 286, 글자 시작 22 | 폭만 Strana: `flex: 286 1 0`, `min-width: 100px`, `max-width: 286px`. 글자는 SWHeader 그대로(x 65 시작, padding 5 / 12 → 글자 x 70, 14px 700·자간 0.84px·SW 외곽선·세로 가운데), SW 화살표 숨김 | | 가운데 | `1260*` | `flex: 1260 1 0` | | 프로세스 | `1003*` | `flex: 1003 1 0` | | Layer 면 | `257*`, 최소 152, 최대 257, 양옆 1 | `flex: 257 1 0`, 칸 152 ~ 257, 면은 칸 안 양옆 1px(150 ~ 255, 가상 요소), 높이 48, radius 6 | | Layer 필드 | 면 안 양옆 8, 최대 234 × 38, padding 12 / 10 | 같음(가운데 정렬) | | 창 영역 | Auto: pill(위·왼쪽 3, 높이 42) + 창 이동 88 + 버튼 32 × 3 | 같음(약 313px, 도구 3개 기준) | | 프로세스 그룹 | 자연 폭까지, 좁아지면 자연 폭 비율로 함께 줄어듦, 양옆 남는 폭은 같게 | 그룹 `flex: 0 1 auto`(flex-shrink가 기본 폭에 비례), 양옆 `flex: 1 1 0` | | 단계 탭 | UniformGrid, 넓을 때 127 + 간격 1, 좁으면 0까지 | flex 한 줄 `flex: 1 1 0`(같은 폭), 크기 기준 요소 127px, 선택 탭도 함께 축소(§11.1) | ## 4. 프로세스 영역 규칙 | 요소 | 규칙 | |---|---| | 바탕 | ProcessBase 세로 gradient, DocBorder 1px, 위 모서리 6 | | 비활성 덮개 | 비활성 그룹 위 `--hm-sw-process-dim`. 왼쪽 남는 폭 = 첫 그룹, 오른쪽 남는 폭 = 마지막 그룹 밝기. 화살표 칸: 꼭지(앞 그룹 비활성) / 홈(뒤 그룹 비활성) | | 활성 그룹 면 | 기운 왼쪽 변 + 둥근 아래 모서리 도형(ProcessGlowLeft), 화살표 쪽으로 사라짐, 발광 Halo + 가장자리 빛. 첫 그룹은 왼쪽 40px, 마지막 그룹은 좌우 반전·오른쪽 44px 밖으로 | | 비활성 그룹 면 | ProcessIdleLeft 도형, Blur + 어두운 Halo + 테두리 빛, 바깥쪽에서 안쪽으로 사라짐(첫 그룹 79.8 → 198.4, 마지막 그룹 236.7 → 273.1) | | 사다리꼴 배치(확정 2026-11-03) | 그룹 면(사다리꼴)은 프로세스 영역의 **시작(첫 그룹)과 끝(마지막 그룹)에만** 둡니다. 그 그룹이 켜져 있으면 발광 면, 아니면 비활성 면. 가운데 그룹에는 켜져 있어도 도형이 없고 밝은 바탕(덮개 없음)만 보입니다(Figma 873:17421). 그룹 수와 관계없이 같으며 `default`·`multi` 공통. 화살표·비활성 덮개·선택 상태는 그대로 | | 화살표 | 16 × 48, 앞 그룹 활성 = On(채움 #27D9A5), 아니면 Dim(채움 25%, 선 50%) | | 번호 / 이름 | 12px, 줄 높이 14. 번호 500 `#69C2A6`. 이름 최대 56px 줄바꿈, 활성 700 흰색 / 비활성 500 `#C3EBDF`, 폭은 늘 700 기준. 위 여백 10.67(한 줄) / 8.67(두 줄) | | 탭 | 높이 32, padding 0 12 2.67, 16px 700 `#F0F7F5`. 모서리: 단독 16, 첫 탭 16 4 4 16, 마지막 탭 4 16 16 4, 가운데 4 | | 탭 상태 | 기본 층 Opacity 0.7. Hover = 글자 `#FFC600`. Checked = 층 1, 바탕·그늘·광택 교체, 위 5 · 왼쪽 6 안쪽 그림자 0.75, 테두리 2px 0.25, 글자 `#FFC600`. Disabled = 층 0.5, 글자 `#64A491` | Strana의 2그룹(01 Modeling: Structure · Loads / 02 Analysis Result: Results)이 확정 디자인입니다. 1그룹·3그룹 이상은 렌더링되지만 디자인 미확정입니다. ## 5. HM 규칙 적용으로 바뀐 점 (원본 대비 변경) | 항목 | Strana 원본 | 구현 | 근거 | |---|---|---|---| | 파일명 | TextBox(말줄임 없음, 편집 가능하나 반영 안 됨) | 버튼 + 말줄임, `title`로 전체 이름 | 승인 7 | | Focus | 표시 없음(FocusVisual null) | SW 2px `#F0F7F5` outline | 승인 7 | | 글자 외곽선 | DropShadow Blur 2 | SW `--hm-sw-header-text-outline`(14·16·18px) / `--hm-sw-header-label-outline`(10·12px). `multi`도 같음(Figma에는 Stroke 없음) | 승인 7, 2026-11-03 요청 | | 창 이동 | 정적 장식(Motion 없음) | SWHeader 창 이동 Motion(1.4s 반복, Hover 해제 즉시 복원, 툴팁 `창 이동`, Drag 중 정지, Reduced Motion 정적) | 2026-11-03 요청(이전 승인 5의 "Motion 없음"을 대체) | | 파일명 자간 | 0 | 0.06em(재사용한 SW 파일명 면) | 재사용 부품 | | Layer 필드 | ToggleButton 안에 전구 ToggleButton 중첩 | 형제 button 2개(전구 · 필드), 보이는 모양 같음 | HTML은 버튼 중첩 불가 | | 탭 3개 이상 가운데 탭 | 정의 없음(첫 탭 외 모두 오른쪽 모서리) | 모서리 4 | 일반화 | | 테마 | 4개(Hanmac · Dark · Light · HighContrast) | Hanmac 값만 기본값, 나머지는 §7 Override | 승인 4, Light/Dark preset 금지 | | 로고 메뉴 · Layer Popup | 있음 | 1차 범위 제외(버튼 상태·Callback만) | 승인 6 | | 화면 분할 버튼 · 선택 Popup | 있음 | `SWProcessSplitButton`으로 추가(2026-11-03, §11). 버튼 아래 연장을 Header 끝까지 늘려 패널이 Header 아래에서 시작(Strana는 3px — 창 버튼 아래 끝을 가림) | 2026-11-03 요청 | | 도구 아이콘 | DesignSystem Geometry | Storybook fixture(`src/sw/sw-process-header-fixture.tsx`)의 TSX 아이콘, 패키지는 `tools` 슬롯. 상태 색은 `currentColor` | 승인 8 | | 좁은 폭의 탭 글자 · Layer 이름 | 잘림(Clip) | `…` 말줄임 | HM 말줄임 규칙(승인 7과 같은 기준) | | 그림 자산 | XAML Geometry · DrawingBrush | 파일 대신 인라인 SVG(TSX)와 CSS — 색을 토큰으로 바꿀 수 있게 | 승인 4(토큰 Override) | | 도구 버튼 눌림 | 노란 링 + 아이콘 `#FFC600` | 같음. `SWToolButton` pill에는 눌림 모양이 없어 이 Header 범위 안에서만 더함(`SWHeader`의 pill은 그대로) | 원본 재현 | | 발광 · Blur | WPF DropShadow 30 / 15, Blur 10 / 8 / 2 | CSS `drop-shadow` 30 / 15px, `blur` 5 / 4 / 1px(반경 → 표준편차) | 근사값 — 1920 캡처 비교로 확인 | ## 6. 토큰 새 토큰은 `--hm-sw-process-*`이며 `sw-process-header.css`의 가장 바깥 SW 범위(`sw-footer.css`와 같은 규칙)에 선언합니다. 값이 SW 토큰과 같은 곳은 SW 토큰을 그대로 읽습니다(파일명 면·테두리, 객체 면·테두리, 속성 필드 면·그림자, Hover gradient, 선택 `#FFC600`, 제목·글자, 창 이동 줄무늬, 창 버튼 글리프·Hover 배경). 전체 목록과 Strana 원본 키는 §7 표의 왼쪽 두 열을 봅니다. ## 7. Strana 테마 → 토큰 Override 대응표 Hanmac 열이 기본값입니다. 다른 테마는 Header의 `style`(가장 바깥 SW 범위)에 같은 토큰을 지정합니다. 예: `style={{ "--hm-sw-header-selected-color": "#FFC833" }}`. Strana ARGB `#AARRGGBB`는 CSS `rgba()`로 바꿉니다. 아래 표는 Strana `Styles/Theme/*/Colors.xaml`(HEAD `edda3cc`)에서 생성했습니다. | 토큰 | Strana `Color.Header.*` | Hanmac(기본값) | Dark | Light | HighContrast | |---|---|---|---|---|---| | `--hm-sw-header-background` | Background | `#060606` | `#0b0d11` | `#b9c7d7` | `#000000` | | `--hm-sw-header-text-color` | Text | `#f6f4f2` | `#f4f7fa` | `#1c2430` | `#ffffff` | | `--hm-sw-header-title-color · --hm-sw-process-tab-text` | Title | `#f0f7f5` | `#f4f7fa` | `#1c2430` | `#ffffff` | | `--hm-sw-header-selected-color` | Selected | `#ffc600` | `#ffc833` | `#0e54c6` | `#ffff00` | | `--hm-sw-header-text-outline-color` | TextOutline | `#000000` | `#000000` | `#ffffff` | `#000000` | | `--hm-sw-header-hover-border-gradient` | HoverBorderDark | `#a67d03` | `#a67d03` | `#2f5faf` | `#ffff00` | | ″ | HoverBorder | `#f2cc0f` | `#f2cc0f` | `#5c88d6` | `#ffff00` | | ″ | HoverBorderLight | `#fadd4f` | `#fadd4f` | `#8fb0e8` | `#ffff00` | | ″ | HoverBorderDeep | `#926e03` | `#926e03` | `#2f5faf` | `#ffff00` | | `--hm-sw-header-document-background` | DocFaceEdge | `#081813` | `#12151a` | `#c6d4e3` | `#000000` | | ″ | DocFaceDeep | `#09271e` | `#181c23` | `#d0dce8` | `#000000` | | ″ | DocFaceMid | `#0b3227` | `#1e232b` | `#d9e3ef` | `#000000` | | ″ | DocFaceLight | `#0e3d2f` | `#262c36` | `#e3ebf4` | `#000000` | | ″ | DocFaceLow | `#0a2b21` | `#1a1e25` | `#cfdae6` | `#000000` | | `--hm-sw-header-document-border-gradient · --hm-sw-process-base-border-gradient` | DocBorderTop | `#0e4c3a` | `#3a4250` | `#ffffff` | `#ffffff` | | ″ | DocBorderDark | `#041611` | `#0b0d11` | `#afbecd` | `#ffffff` | | ″ | DocBorderBottom | `#18503f` | `#3f4856` | `#9daec0` | `#ffffff` | | `--hm-sw-header-document-border-color` | DocBorderTop | `#0e4c3a` | `#3a4250` | `#ffffff` | `#ffffff` | | `--hm-sw-header-object-background` | ObjFaceEdge | `#144838` | `#1c2027` | `#d3dce6` | `#000000` | | ″ | ObjFaceLow | `#1a4536` | `#20252d` | `#dae2eb` | `#000000` | | ″ | ObjFaceMid | `#1f4134` | `#22272f` | `#dde5ed` | `#000000` | | ″ | ObjFaceDeep | `#10392d` | `#1a1e25` | `#d3dce6` | `#000000` | | ″ | ObjFaceLight | `#296b55` | `#353d48` | `#f0f4f8` | `#000000` | | ″ | ObjFaceUpper | `#1f5a47` | `#2a3039` | `#e7edf3` | `#000000` | | ″ | ObjFaceTop | `#124133` | `#1e232b` | `#d8e0ea` | `#000000` | | `--hm-sw-header-object-border-gradient` | ObjBorderTop | `#135643` | `#313843` | `#c3cfdb` | `#ffffff` | | ″ | ObjBorderDeep | `#0e3d2f` | `#1e232b` | `#afbecd` | `#ffffff` | | ″ | ObjBorderHighlight | `#34daaa` | `#74c4b4` | `#5c88d6` | `#ffffff` | | ″ | ObjBorderDark | `#08241c` | `#12151a` | `#afbecd` | `#ffffff` | | ″ | ObjBorderBottom | `#1f5e4b` | `#2e353f` | `#c3cfdb` | `#ffffff` | | `--hm-sw-header-property-background` | PropertyFace | `rgba(0, 0, 0, 0.451)` | `rgba(0, 0, 0, 0.451)` | `rgba(255, 255, 255, 0.349)` | `rgba(0, 0, 0, 1)` | | ″ | PropertyFaceLight | `rgba(0, 0, 0, 0.4)` | `rgba(0, 0, 0, 0.4)` | `rgba(255, 255, 255, 0.302)` | `rgba(0, 0, 0, 1)` | | `--hm-sw-header-property-shadow` | PropertyShadow | `#09271e` | `#000000` | `#5a6878` | `#000000` | | `--hm-sw-header-stripe-color` | Stripe | `rgba(28, 106, 81, 0.322)` | `rgba(63, 72, 86, 0.322)` | `rgba(47, 95, 175, 0.239)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-header-window-icon-color` | WindowIcon | `#adb0af` | `#adb0af` | `#4a5868` | `#ffffff` | | `--hm-sw-header-window-icon-hover-color` | WindowIconHover | `#ffffff` | `#ffffff` | `#1c2430` | `#000000` | | `--hm-sw-header-window-button-hover-background` | WindowButtonHover | `rgba(0, 0, 0, 0.2)` | `rgba(0, 0, 0, 0.2)` | `rgba(0, 0, 0, 0.122)` | `#ffff00` | | `--hm-sw-header-layer-icon-hover-background` | LayerIconHover | `rgba(0, 0, 0, 0.251)` | `rgba(0, 0, 0, 0.251)` | `rgba(0, 0, 0, 0.149)` | `rgba(255, 255, 255, 0.251)` | | `--hm-sw-process-base-background` | ProcessBaseEdge | `#0c5941` | `#1c2027` | `#c6d4e3` | `#000000` | | ″ | ProcessBaseLight | `#19bf8d` | `#4a5260` | `#f0f4f8` | `#000000` | | ″ | ProcessBaseMid | `#109069` | `#313843` | `#d9e3ef` | `#000000` | | `--hm-sw-process-dim` | ProcessDim | `rgba(0, 68, 48, 0.902)` | `rgba(11, 13, 17, 0.902)` | `rgba(207, 218, 230, 0.902)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-number-color` | ProcessNumber | `#69c2a6` | `#74c4b4` | `#2c5a88` | `#ffffff` | | `--hm-sw-process-group-color` | ProcessGroupText | `#c3ebdf` | `#c9d3de` | `#4a5868` | `#ffffff` | | `--hm-sw-process-group-active-color` | ProcessGroupActive | `#ffffff` | `#ffffff` | `#1c2430` | `#ffff00` | | `--hm-sw-process-glow-face-base` | ProcessGlowFaceTop | `#063b2b` | `#1a1e25` | `#e3ebf4` | `rgba(0, 0, 0, 0)` | | ″ | ProcessGlowFaceFade | `rgba(13, 101, 74, 0.051)` | `rgba(42, 48, 57, 0.051)` | `rgba(217, 227, 239, 0.051)` | `rgba(0, 0, 0, 0)` | | ″ | ProcessGlowInner | `rgba(24, 134, 101, 0.702)` | `rgba(63, 111, 104, 0.702)` | `rgba(92, 136, 214, 0.702)` | `rgba(0, 0, 0, 0)` | | ″ | ProcessGlowInnerFade | `rgba(24, 134, 101, 0)` | `rgba(63, 111, 104, 0)` | `rgba(92, 136, 214, 0)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-glow-face-rim` | ProcessGlowRim | `#247a60` | `#3f6f68` | `#5c88d6` | `rgba(0, 0, 0, 0)` | | ″ | ProcessGlowFaceFade | `rgba(13, 101, 74, 0.051)` | `rgba(42, 48, 57, 0.051)` | `rgba(217, 227, 239, 0.051)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-glow-face-sheen` | ProcessGlowSheenTop | `#20322c` | `#1e232b` | `#ffffff` | `rgba(0, 0, 0, 0)` | | ″ | ProcessGlowSheen | `#3dc79d` | `#74c4b4` | `#8fb0e6` | `rgba(0, 0, 0, 0)` | | ″ | ProcessGlowSheenFade | `rgba(61, 199, 157, 0.051)` | `rgba(116, 196, 180, 0.051)` | `rgba(143, 176, 230, 0.051)` | `rgba(0, 0, 0, 0)` | | ″ | ProcessGlowTint | `rgba(0, 95, 66, 0.251)` | `rgba(42, 48, 57, 0.251)` | `rgba(92, 136, 214, 0.251)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-glow-halo (× 0.85)` | ProcessGlowHalo | `#58b599` | `#74c4b4` | `#5c88d6` | `#000000` | | `--hm-sw-process-glow-edge (× 0.65)` | ProcessGlowEdge | `#58b599` | `#74c4b4` | `#5c88d6` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-idle-face` | ProcessIdleInset | `rgba(0, 0, 0, 0.502)` | `rgba(0, 0, 0, 0.502)` | `rgba(0, 0, 0, 0.149)` | `rgba(0, 0, 0, 0)` | | ″ | ProcessIdleInsetFade | `rgba(0, 0, 0, 0)` | `rgba(0, 0, 0, 0)` | `rgba(0, 0, 0, 0)` | `rgba(0, 0, 0, 0)` | | ″ | ProcessIdleShade | `rgba(23, 42, 26, 0.251)` | `rgba(0, 0, 0, 0.2)` | `rgba(47, 74, 110, 0.078)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-idle-halo (× 0.8)` | ProcessIdleHalo | `#11694f` | `#3a4656` | `#8fb0e6` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-idle-rim` | ProcessIdleRim | `rgba(4, 128, 90, 0.322)` | `rgba(116, 196, 180, 0.302)` | `rgba(255, 255, 255, 0.4)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-arrow-fill` | ProcessArrowFill | `#27d9a5` | `#74c4b4` | `#5c88d6` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-arrow-dim-fill` | ProcessArrowDimFill | `#abc7bf` | `#c9d3de` | `#8fa3b8` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-arrow-fill-fade` | ProcessArrowFillFade | `rgba(16, 109, 81, 0)` | `rgba(42, 48, 57, 0)` | `rgba(217, 227, 239, 0)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-arrow-edge` | ProcessArrowEdge | `#00432e` | `#1a1e25` | `#afbecd` | `#ffffff` | | `--hm-sw-process-arrow-mid` | ProcessArrowMid | `#1c6a51` | `#4a5260` | `#5c88d6` | `#ffffff` | | `--hm-sw-process-arrow-light` | ProcessArrowLight | `#3d9c7e` | `#5e8f87` | `#8fb0e6` | `#ffffff` | | `--hm-sw-process-arrow-shadow` | ProcessArrowShadow | `rgba(0, 0, 0, 0.502)` | `rgba(0, 0, 0, 0.502)` | `rgba(255, 255, 255, 0.502)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-shade · -shade-mid · -shade-fade` | ProcessShade | `rgba(4, 34, 25, 0.878)` | `rgba(11, 13, 17, 0.878)` | `rgba(175, 190, 205, 0.878)` | `rgba(0, 0, 0, 0)` | | ″ | ProcessShadeMid | `rgba(4, 34, 25, 0.706)` | `rgba(11, 13, 17, 0.706)` | `rgba(175, 190, 205, 0.706)` | `rgba(0, 0, 0, 0)` | | ″ | ProcessShadeFade | `rgba(4, 34, 25, 0)` | `rgba(11, 13, 17, 0)` | `rgba(175, 190, 205, 0)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-tab-glow` | TabGlow | `rgba(31, 148, 113, 0.702)` | `rgba(74, 82, 96, 0.702)` | `rgba(255, 255, 255, 0.702)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-tab-depth` | TabDepthFade | `rgba(0, 61, 41, 0)` | `rgba(26, 30, 37, 0)` | `rgba(198, 212, 227, 0)` | `rgba(0, 0, 0, 1)` | | ″ | TabDepth | `rgba(0, 61, 41, 0.8)` | `rgba(26, 30, 37, 0.8)` | `rgba(198, 212, 227, 0.8)` | `rgba(0, 0, 0, 1)` | | `--hm-sw-process-tab-shade` | TabShade | `rgba(0, 0, 0, 0.4)` | `rgba(0, 0, 0, 0.4)` | `rgba(0, 0, 0, 0.149)` | `rgba(0, 0, 0, 0)` | | ″ | TabShadeFade | `rgba(0, 0, 0, 0)` | `rgba(0, 0, 0, 0)` | `rgba(0, 0, 0, 0)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-tab-sheen` | TabSheen | `rgba(74, 255, 196, 0.502)` | `rgba(116, 196, 180, 0.502)` | `rgba(255, 255, 255, 0.502)` | `rgba(0, 0, 0, 0)` | | ″ | TabSheenFade | `rgba(74, 255, 196, 0)` | `rgba(116, 196, 180, 0)` | `rgba(255, 255, 255, 0)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-tab-border-gradient` | TabBorder | `#001e15` | `#0b0d11` | `#9daec0` | `#ffffff` | | ″ | TabStrokeHighlight | `#17a77b` | `#4a5260` | `#ffffff` | `#ffffff` | | ″ | TabStrokeLow | `#0b533d` | `#262c36` | `#9daec0` | `#ffffff` | | `--hm-sw-process-tab-ring` | TabRing | `rgba(0, 0, 0, 0.251)` | `rgba(0, 0, 0, 0.251)` | `rgba(255, 255, 255, 0.251)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-tab-active-base` | TabActiveBase | `rgba(0, 0, 0, 0.4)` | `rgba(0, 0, 0, 0.4)` | `rgba(255, 255, 255, 0.4)` | `rgba(0, 0, 0, 1)` | | ″ | TabActiveBaseDeep | `rgba(0, 0, 0, 0.451)` | `rgba(0, 0, 0, 0.451)` | `rgba(255, 255, 255, 0.451)` | `rgba(0, 0, 0, 1)` | | `--hm-sw-process-tab-active-shade` | TabActiveShade | `rgba(0, 0, 0, 0.6)` | `rgba(0, 0, 0, 0.6)` | `rgba(92, 136, 214, 0.2)` | `rgba(0, 0, 0, 0)` | | ″ | TabShadeFade | `rgba(0, 0, 0, 0)` | `rgba(0, 0, 0, 0)` | `rgba(0, 0, 0, 0)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-tab-active-sheen` | TabActiveSheenFade | `rgba(122, 206, 179, 0)` | `rgba(116, 196, 180, 0)` | `rgba(92, 136, 214, 0)` | `rgba(0, 0, 0, 0)` | | ″ | TabActiveSheen | `rgba(122, 206, 179, 0.102)` | `rgba(116, 196, 180, 0.102)` | `rgba(92, 136, 214, 0.102)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-tab-inset (끝은 투명)` | TabInset | `rgba(0, 0, 0, 0.659)` | `rgba(11, 13, 17, 0.659)` | `rgba(175, 190, 205, 0.659)` | `rgba(0, 0, 0, 0)` | | ″ | TabInsetFade | `rgba(0, 0, 0, 0)` | `rgba(11, 13, 17, 0)` | `rgba(175, 190, 205, 0)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-tab-disabled-shade` | TabShadeFade | `rgba(0, 0, 0, 0)` | `rgba(0, 0, 0, 0)` | `rgba(0, 0, 0, 0)` | `rgba(0, 0, 0, 0)` | | ″ | TabDisabledShade | `rgba(0, 0, 0, 0.8)` | `rgba(0, 0, 0, 0.8)` | `rgba(0, 0, 0, 0.2)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-tab-disabled-sheen` | TabDisabledSheen | `rgba(130, 181, 164, 0.502)` | `rgba(128, 142, 156, 0.502)` | `rgba(255, 255, 255, 0.502)` | `rgba(0, 0, 0, 0)` | | ″ | TabActiveSheenFade | `rgba(122, 206, 179, 0)` | `rgba(116, 196, 180, 0)` | `rgba(92, 136, 214, 0)` | `rgba(0, 0, 0, 0)` | | `--hm-sw-process-tab-disabled-text` | TabDisabledText | `#64a491` | `#6d7784` | `#8a97a6` | `#a0a0a0` | | `--hm-sw-process-layer-border-gradient` | PropertyBorder | `#08251c` | `#12151a` | `#afbecd` | `#ffffff` | | ″ | ObjBorderDeep | `#0e3d2f` | `#1e232b` | `#afbecd` | `#ffffff` | | ″ | LayerFieldBorderHighlight | `#1e7c60` | `#4a5260` | `#ffffff` | `#ffffff` | | ″ | ObjBorderDark | `#08241c` | `#12151a` | `#afbecd` | `#ffffff` | | ″ | ToolBorderBottom | `#051612` | `#0b0d11` | `#9daec0` | `#ffffff` | | `--hm-sw-process-pill-background` | PillFaceTop | `rgba(0, 0, 0, 0.851)` | `rgba(0, 0, 0, 0.851)` | `rgba(224, 228, 232, 0.851)` | `rgba(0, 0, 0, 1)` | | ″ | PillFace | `rgba(0, 0, 0, 0.8)` | `rgba(0, 0, 0, 0.8)` | `rgba(246, 249, 252, 0.8)` | `rgba(0, 0, 0, 1)` | | `--hm-sw-process-pill-border-gradient` | PillBorder | `#092920` | `#1a1e25` | `#afbecd` | `#ffffff` | | ″ | PillBorderBottom | `#1c6f56` | `#313843` | `#c3cfdb` | `#ffffff` | | `--hm-sw-process-tool-border-gradient` | PropertyBorder | `#08251c` | `#12151a` | `#afbecd` | `#ffffff` | | ″ | ToolBorderHighlight | `#208769` | `#4a5260` | `#ffffff` | `#ffffff` | | ″ | ObjBorderDark | `#08241c` | `#12151a` | `#afbecd` | `#ffffff` | | ″ | ToolBorderBottom | `#051612` | `#0b0d11` | `#9daec0` | `#ffffff` | | `--hm-sw-process-tool-icon-color` | Icon | `#b6d0c9` | `#c9d3de` | `#26303c` | `#ffffff` | | `--hm-sw-process-close-hover-background` | CloseHover | `#e40000` | `#e40000` | `#e40000` | `#ff0000` | | `--hm-sw-process-close-icon-hover` | CloseIconHover | `#ffffff` | `#ffffff` | `#ffffff` | `#ffffff` | | `--hm-sw-process-tool-open-background` | ToolOpenEdge | `#081813` | `#0b0d11` | `#dce4ed` | `#000000` | | ″ | ToolOpenMid | `#0b3227` | `#171b21` | `#e8eef5` | `#000000` | | ″ | ToolOpenCenter | `#0e3d2f` | `#1e232b` | `#f3f6fa` | `#000000` | | `--hm-sw-process-tool-open-edge` | ToolOpenEdge | `#081813` | `#0b0d11` | `#dce4ed` | `#000000` | | `--hm-sw-process-split-panel-background` | SplitPanelFace | `#082018` | `#14171c` | `#ffffff` | `#000000` | | `--hm-sw-process-split-cell-pane` | SplitCellPane | `#1b6b53` | `#3a4656` | `#e3ebf4` | `#000000` | | `--hm-sw-process-split-icon-pane` | IconCell | `#003425` | `#12151a` | `#afbecd` | `#000000` | 그라데이션 토큰은 여러 키의 조합입니다. 같은 위치(stop)에 테마 값을 넣어 토큰 전체를 지정합니다. 다음 키는 토큰이 아닙니다: `HomeFaceBottom`, `HomeFaceDeep`, `HomeFaceMid`, `HomeFaceTop`, `HomeBorderTop`, `HomeBorderLight`, `HomeBorderDark`, `HomeBorderBottom`, `HomeShadow`, `IconOutline`, `WindowMoveIcon`, `LayerBulbBase`, `LayerBulbBar`, `LayerBulbOnLight`, `LayerBulbOnMid`, `LayerBulbOnDark`, `LayerBulbOffLight`, `LayerBulbOffMid`, `LayerBulbOffDark`(SW 홈·전구·창 이동 그림 자산 — 테마 Override 대상 아님, Hanmac 그림), `IconScreen`, `IconScreenDeep`, `IconMonitorScreen`(Strana 도구 아이콘 전용 — 도구 아이콘은 소비 측이 그림). ## 8. 검증 2026-11-03 1차 구현(Chromium, Storybook 6024). | 항목 | 결과 | |---|---| | 폭 측정(파일명 / 프로세스 / Layer 칸 / 창 영역) | 1920: 280.8 / 984.8 / 252.3 / 313 = Strana 별 비율 계산값. 1100: 129.1 / 416.9 / 152(최소) / 313. 1366: 178.3 / 625.4 / 160.3 / 313. 2560: 286(최대) / 1615 / 257(최대) / 313. 넘침 없음. 홈 80(SWHeader 기준, 2026-11-03) 이후 파일명 / 프로세스: 1100 133.7 / 437, 1366 182.9 / 641.4, 1920 285.4 / 1000.8, 2560 286 / 1639.7, 창 영역 312, 넘침 없음 | | Strana 캡처 비교(1.5배, 나란히) | Hanmac 1920 Modeling · Results, 1366, 1100 — 배치·면·발광·화살표·탭·Layer·도구·창 버튼 일치. 차이: 글자 외곽선 두께, 파일명 자간, 좁은 폭의 말줄임(§5) | | 동작 | 탭 클릭·Arrow·Home·End(비활성 건너뜀), 같은 탭 재클릭 시 Callback 없음, 전구·필드 분리, 최대화/복원 전환, 로고 열림 모양, 도구 눌림 모양, Hover(종료 `#E40000`, 최소화, Layer 링, 탭 글자), Focus outline | | 로고 폭(2026-11-05, Chromium, `multi`, 1440·1100) | 기준: 글자 잘림 0, 홈 = 12 + 로고 칸 + 36, 사선 배경 = 홈 + 12(왼쪽 −8 · 오른쪽 +4, 홈 끝을 따라감), 홈·파일명 겹침 15, Header 49, 단계 클릭·Enter 동작 유지. 참고 실측: Accessway 홈 106 → 141.72에서 가운데 영역 1440 1024.2 → 992.5(−31.7), 1100 728 → 696.89(−31.11), 파일명 151.47 → 146.78 / 107.67 → 103.06. 더 긴 글자(187.44)는 파일명이 최소 100에서 멈춤. 이미지 로고(32 × 17) Story는 `default`·`multi` 모두 홈 80 그대로. 커스텀 `logo`는 코드 경로만 확인(같은 로고 칸) | | 기존 `SWHeader` | 변경 전후 빌드에서 `SW/Header` Overview · Responsive More 출력 HTML 동일, `dist/styles.css`의 기존 내용 동일(새 규칙만 추가) | Strana 비교 캡처는 `D:\Strana\_verification\header-rework-20261029\renders\Hanmac-{1100,1366,1920}-*.png`(최종 Commit 7173e82 · b7f412c 이전 렌더)입니다. 분할 버튼 변경(b7f412c) 이후 최신 캡처와 다른 테마(Dark · Light · HighContrast)의 화면 비교는 미확인입니다. Firefox · Safari는 확인하지 않았습니다. ## 9. `appearance="multi"` — StrAna-SW 다중 Step (2026-11-03) 원본: Figma StrAna-SW `4y8lTK1E1hAGYiMcYZwuNe`, 노드 `873:16481` · `873:16254` · `873:17421`(각 1920 × 49). Story: `SW / Step Header › Step Header`(Step Header 섹션 = `default` + Multi Step 섹션 = 세 시안, 노드 ID는 화면에 표시하지 않고 `data-figma-node`로만 유지), `Responsive More`, 검증용(숨김) `Multi Step`(세 시안 1920) · `화면 분할` · `Fixed Widths` · `Process Bar` · `Many Groups` · `Many Steps` · `States` · `Theme Override`. ### 9.1 시안 비교 세 시안은 **같은 구조의 상태 차이**입니다. 그래서 별도 컴포넌트 없이 `SWProcessHeader` / `SWProcessBar`의 `appearance="multi"` 하나로 구현했습니다. | 시안 | 파일명 면 | 켜진 그룹 · 선택 단계 | 그룹 상태 | |---|---|---|---| | 873:16481 | 파일 없음: `프로젝트 생성 전` 10px 700 `#AEDBCC` 오른쪽 위 | 01 데이터 구축 · 데이터입력 | 2·3 미진행(70%), 4·5 비활성(회색) | | 873:16254 | 파일명 14px 700 `#F0F7F5`, 말줄임. 위치·여백은 SWHeader 우선(글자 x 70, padding 5 / 12, 자간 0.84px) | 01 데이터 구축 · 데이터입력 | 같음 | | 873:17421 | 파일 없음 | 03 구조물 상세 및 계획 · 본체계획 | 1·2 진행 완료(덮개 + 밝은 탭), 4·5 비활성 | ### 9.2 `default`와 공유한 것 / 다른 것 - **사다리꼴 배치:** 시작·끝 그룹에만(§4 확정 규칙). 873:17421처럼 가운데 그룹이 켜지면 도형 없이 밝은 바탕만 보입니다(2026-11-03 수정 — 이전 구현은 켜진 가운데 그룹에도 발광 면을 그렸음). - **같은 구현(값 대조 일치):** 프로세스 바탕(ProcessBase gradient · DocBorder · 위 모서리 6), 비활성 덮개(`#004430` 90%, 꼭지·홈 모양 포함), 활성 발광 면·비활성 바깥 면(같은 경로), 화살표(선·채움·그늘 같은 값, Dim 25% / 50%), 홈 도형, 파일명 면 gradient, 창 이동 아이콘·줄무늬 색, 캡션 버튼 글리프, 선택·키보드·Callback. - **multi 전용 CSS:** 49px 면, 파일명 최대 189·단색 테두리(로고·파일명 글자는 SWHeader 기준으로 default와 공통), SW 기본 pill(41 · 40 × 37), 창 이동 위치, 그룹 내용(제목 위 · 탭 25), 탭 4상태, 발광 면 위치(왼쪽 50 / 반전 48). - **새로 만든 것:** 진행 완료 상태(`data-progress="done"`, multi만), `documentEmptyLabel`, `labelHidden`, `appearance`. 컴포넌트 DOM은 하나이며 multi는 탭의 층 9개 대신 면 하나만 그립니다. - **Figma 도구 아이콘 5개**(help · view-3d · controls · menu-list · exit-arrow)는 Story fixture(`src/sw/assets/process-header/tool-*.svg`, Figma 원본)에만 둡니다. ### 9.3 넘침 처리 — 확정 정책(2026-11-03 사용자 승인) | 항목 | 결정 | 근거 | |---|---|---| | 그룹 폭 | 자연 폭(제목·탭 중 넓은 쪽 + 좌우 10)까지, 좁으면 자연 폭 비율로 함께 축소. 남는 폭은 양쪽에 같게 | `default`와 같은 규칙 | | 탭 | 글자 폭 + 25, 좁으면 선택 탭 포함 글자 폭 비율로 축소 + `…`(2026-11-03 개정) | 옆 탭이 비정상적으로 좁아지지 않게 | | 화살표 · 그룹 사이 36 | 고정 | Figma | | 실제 넘침 | 그룹 접기·좌우 스크롤·More 메뉴를 두지 않음. 더 좁으면 영역 안에서 잘림 | 확정(Figma에 정의 없음) | 측정(1920): 5그룹 11탭은 말줄임 없음. 1366에서는 11탭 중 10개, 8그룹 · 16탭(1920)에서는 15개가 말줄임됩니다. 겹침 · 영역 밖 탭 0. (개정 후 1366에서는 선택 탭도 다른 탭과 함께 줄어 `…`가 될 수 있습니다.) ### 9.4 Figma와 남은 차이 - 873:17421의 켜진 그룹 미선택 탭은 70% · `#0C3125` · `rgba(76,167,138,.8)`, 873:16481은 100% · `#0A5940` · `rgba(68,178,143,.8)`로 시안끼리 다릅니다. 873:16481 값으로 통일했습니다. - 873:17421의 선택 탭에만 있는 안쪽 2px 링(`rgba(0,0,0,.25)`)은 넣지 않았습니다(873:16481 기준). - 비활성 글자는 `#87AD9D`(1개 탭) / `#7D9F91`(3개 탭) 두 값 중 `#7D9F91`로 통일했습니다. - 873:17421의 `선형입력` 위치(599)는 873:16481(592.8)과 다릅니다. 구현은 그룹 간격 36 규칙(592)입니다. - Figma 로고 자리는 글자 `LOGO`이며, Story는 임시 로고 이미지입니다(로고·파일명 글자는 SWHeader와 같은 크기·위치). - ~~창 이동 아이콘 밝기 차이~~: SWHeader 창 이동 자산으로 바꾼 뒤 Figma와 같은 밝기(2026-11-03 해소). - 글자 외곽선: Figma multi 시안의 글자에는 Stroke가 없으나 SW 규칙에 맞춰 외곽선을 적용했습니다(의도된 차이, §10). - 장치 배율 1.5에서 1px 테두리 반올림으로 창 영역이 366.3px로 측정됩니다(Figma 367). ## 10. SWHeader 스타일 정합 (2026-11-03) `SWHeader`의 실제 구현(sw.css)과 브라우저 렌더를 기준으로 맞췄습니다. `SWHeader`·`SWViewerHeader`·`sw.css`는 바꾸지 않았고, 모두 `default`·`multi` 공통입니다. | 항목 | SWHeader | Process Header(적용 결과) | 구현 | |---|---|---|---| | 글자 Stroke | 14·16px 검정 1.3px, 12px 1px(16방향 text-shadow), 말줄임 글자는 `overflow-clip-margin` 2px | 같음: 파일명·탭(선택·비선택·비활성)·Layer 값 1.3px, 그룹 제목·번호·Layer 라벨·파일 없음 표시 1px | SW 토큰 재사용. `multi`의 `text-shadow: none` 제거, 탭·제목 말줄임 글자는 clip margin 공통 | | 창 이동 | 88 × 48, 줄무늬, 아이콘 → Hover 시 창·커서 1.4s 반복 + 툴팁, Drag 중 정지, 해제 즉시 복원, Reduced Motion 정적 | 같음(SWHeader 부품 그대로). `multi`만 Figma 위치로 줄무늬 82 × 39(3, 5)·아이콘 3px 위 | `SWHeaderWindowControls`(창 이동만) 재사용, 정적 그림·CSS·토큰 2개 삭제 | | 도구 버튼 Hover | 노란 gradient 링 + 노란 아이콘(`hoverIcon` 또는 색) | 같음. Default fixture 아이콘은 `currentColor`, Multi Figma 아이콘은 `#B6D0C9 → #FFC600` Hover 그림(SW 인쇄 버튼 방식) | SWToolButton `hoverIcon`, 눌림(pressed)도 링 + 노란 아이콘 | | 로고 · 파일명 · 탭 Hover | 로고 금색 테두리, 파일명 글자 `#FFC600` | 같음, 탭 글자 `#FFC600`, 비활성 탭은 변화 없음 | 재사용 | | Layer 필드 Hover | 필드 노란 링 + 글자 `#FFC600`, 전구는 어두운 배경 | 같음 | 재사용 | | 최소화 · 최대화 Hover | 배경 `rgba(0,0,0,.2)` + 흰 글리프(노랑 아님) | 같음 | SW 토큰 | | 종료 Hover | `#E40000` + 흰 X | 같음(유지) | 확정 디자인 | | Focus | 2px `#F0F7F5`, -2px | 같음(탭·도구·캡션 버튼) | SW 공통 규칙 | | 선택 · Disabled | — | 선택 탭 `#FFC600`(Hover와 같은 색이지만 면이 다름), Disabled는 Hover·Focus 없음 | 기존 확정 디자인 | ## 11. 선택 Step 표시 통일 · 아이콘 · 화면 분할 (2026-11-03) ### 11.1 선택 Step 폭(두 appearance 공통, 2026-11-03 개정) - **개정:** 선택된 탭도 다른 탭과 같은 비율로 줄어듭니다(이전 "선택 탭 전체 이름 유지" 폐기 — 선택 탭에 폭을 먼저 주느라 옆 탭이 24 · 27px까지 좁아지던 문제). 공간이 충분하면 전체 이름, 부족하면 모든 탭이 기본 폭 비율로 줄고 `…`입니다(`default` 같은 폭, `multi` 글자 폭 비례). 선택이 바뀌어도 탭 폭은 그대로입니다. - 그룹 최소 폭 = 좌우 여백 + (`default`만) 이름 + 모든 탭 여백 + 간격(측정). 그 위에서는 그룹이 비례로 줄고, 아래로는 줄지 않아 겹치지 않습니다. - 탭 배치는 두 appearance 모두 flex 한 줄입니다(이전 `default`의 grid 대체). 넓을 때 `default` 탭은 127 균등 그대로입니다. - 측정(개정 후, 고정 폭, `*` = 선택): `default` 1100 `*61 61 | 45`(이전 `*98 25 | 45`), 1366 `*124 124 | 124`, 1920 · 2560 `*127 127 | 127`(변화 없음). `multi` 1100 셋째 그룹 `*34 34 37 37`(이전 `*77 25 25 25`), 1366 `*54 54 61 61`(이전 `*77 47 53 53`), 1920 · 2560 `*77 77 89 89`(변화 없음). 겹침 0. 그룹 최소 폭의 합이 프로세스 영역보다 크면 영역 끝에서 잘립니다. ### 11.2 도구 아이콘이 사라지던 문제 - 원인: `sw.css`의 `:is(.hm-sw-header__action, …):hover:not(:disabled) > .hm-sw-header__icon { visibility: hidden }`는 Hover 그림(`hoverIcon`)이 있다고 가정합니다. `hoverIcon` 없이 `currentColor` 아이콘만 준 `SWToolButton`은 Hover 순간 아이콘이 비었습니다(Default 도구 3개). - 해결(2026-11-03 공통 수정): `SWToolButton`(pill)이 `hm-sw-header__icon` class를 `hoverIcon`이 있을 때만 기본 아이콘에 붙입니다. `hoverIcon`이 없으면 기본 아이콘이 Hover에도 그대로 보이고 색만 `#FFC600`입니다. `SWHeader`의 `tools`도 같은 컴포넌트라 함께 해결되었고, 이 Header 범위의 보완 CSS 규칙은 삭제했습니다(`sw.css` 변경 없음). 눌림은 Hover 그림이 있을 때만 그 그림으로 바뀝니다. Disabled·열림에서도 아이콘이 유지되며 크기 24 × 24로 같습니다. ### 11.3 화면 분할(`SWProcessSplitButton`) 원본: Strana `ViewportSplitSelector.xaml`, `Styles/Controls/ViewportSplitStyles.xaml`, `HeaderStyles.xaml`(ToolMenu · ToolOpenTail · ToolMenuStep · Icon.ToolLayout), MainWorkspaceWindowView 분할 Popup(HEAD `edda3cc`). | 항목 | Strana | 구현 | |---|---|---| | 버튼 | 도구 버튼 40 × 38, 아이콘 = 현재 분할 모양 | `SWToolButton` pill + 분할 아이콘(Strana Geometry, 틀은 `currentColor`) | | 열림 | 면 ToolOpenFace, 금색 위·양옆, 아래 열림, Hover 링 없음, 아이콘 노랑 | 같음 | | 연장 | 버튼 아래 3px(버튼 아래 1px 겹침) | 버튼 아래 1px 겹침, 길이는 Header 끝까지(최소 3px) — 패널이 창 버튼을 가리지 않게 | | 패널 | 233 × 36, 면 `#082018`, 금색 양옆·아래, radius 0 2 2 2, 그림자 0 2 4 60% | 같음, Header 바로 아래·버튼 왼쪽, 화면 밖이면 좌우만 보정(SW 필드 Dropdown 위치 훅) | | 위 선 | 버튼 오른쪽 끝 ~ 패널 끝 금색 | 같음 | | 칸 | 38 × 34 × 6(Type01~06), Hover·선택 = 창 노랑, Disabled 40% | 38.5 × 34(233 / 6), 같은 그림·상태. 틀 상자는 32 × 22 정수(Strana 31.6 × 21.73, 그림 29.6 × 19.73 그대로) | | 동작 | Popup StaysOpen=False(바깥 클릭 닫힘), 칸 선택 시 열린 채 | 같음 + Escape 닫고 버튼으로, Tab 이탈 닫힘, ArrowDown 열기, 방향키 선택(radiogroup) | 값은 Props(`value`, `open`), 동작은 Callback(`onValueChange`, `onOpenChange`)이며 창을 실제로 나누는 일은 호스트가 합니다. `tools` 안에 두므로 버튼 순서는 호스트가 정하고 `default`·`multi`가 같은 컴포넌트를 씁니다. Figma 다중 Step 시안 3개에는 화면 분할 버튼이 없어 해당 Story에는 넣지 않았습니다(`Step Header` 페이지의 Step Header 섹션과 검증용 `화면 분할` Story에서 Default·Multi Step을 확인). - **Popup 하단 잘림(2026-11-03, 수정):** 재현 조건 = Popup 아래 공간이 부족한 화면(예: Storybook Canvas 높이 400px의 Multi Step). 공용 위치 훅 `useSWFixedDropdownPosition`이 아래 공간이 없으면 필드 위로 뒤집는데(`flipped`), 이 선택기는 꼬리·패널을 항상 아래쪽 모양으로 그려 Header 위에 겹치고 패널 하단이 Header에 가려졌습니다(아이콘 SVG·`viewBox`·`overflow`·세로 정렬은 정상). 수정: `SWProcessSplitButton`이 뒤집힘을 쓰지 않고 항상 버튼 아래에 붙습니다(좌우 보정은 훅 그대로). 아래 공간이 부족하면 화면 끝에서 잘리지만 페이지 스크롤에 따라 위치가 갱신되어 스크롤하면 전체가 보입니다. Default·Multi 공통(같은 컴포넌트), CSS 변경 없음. - **아이콘 하단 잘림(2026-11-03, 수정):** 사용자 Chrome(배율 100%, 화면 1920 × 1080, Storybook 미리보기 1620 × 871)에서 재현. Responsive 1366 · 1100 행의 Popup 첫 열림에서 6개 틀이 21줄로 그려져 판 아래 밝은 테두리가 사라짐(아래가 잘린 것처럼 보임). 원인: 틀 상자 31.6 × 21.73(소수)이 화면 픽셀로 맞춰질 때 위치에 따라 21줄 또는 22줄이 되고, SVG 판은 크기가 고정이라 21줄일 때 아래 밝은 줄이 덮임. 패널 하단 테두리(`#926E03`)는 수정 전에도 그려져 있었음. 수정: 틀 상자를 32 × 22 정수로(그림 SVG·패널·위치 변경 없음). 수정 후 같은 Chrome에서 1366 · 1100 행, Default · Multi Step, 1920 고정 폭 Header 모두 틀 22줄 · 아래 밝은 줄 표시 확인. ## 12. UX 검토 항목 — 외부 소비 프로젝트 요청 (2026-11-05, 정책 변경 아님) 외부 소비 프로젝트의 개선 요청을 이 Header 고유 항목과 SW Header 공통 원칙으로 나눈 기록입니다. 공통 원칙(말줄임 원문 확인, 아이콘 버튼 이름·툴팁, class 역할, 글꼴별 폭)은 `packages/sw/ai/DESIGN_RULES.md` §15를 따릅니다. 아래 "현재 동작"은 그대로 유지하며, 정책 변경이 필요한 항목은 사용자 결정 전까지 바꾸지 않습니다. 이 절은 §8·§9의 과거 측정·검증 기록을 재판정하지 않습니다. | 항목 | 현재 동작(유지) | 사용자 경험상 문제 | 구분 | |---|---|---|---| | 단계가 많을 때 말줄임 | `multi` 1920 5그룹 11탭은 말줄임 없음, 1366에서는 11탭 중 10개 `…`(§9 측정, §11.1 개정 후 선택 탭 포함) | 짧게 잘린 단계명끼리 구분하기 어려움 | 별도 검토 | | 단계·그룹 원문 확인 | 단계 탭 `aria-label` = 전체 이름, 그룹 이름은 `aria-describedby`로 연결. 탭·`multi` 그룹 제목에 `title` 없음(파일명·Layer 값은 `title` 있음) | 마우스·터치 사용자는 잘린 이름의 원문을 볼 수 없음 | 개선 필요(구현 별도) | | 선택 단계 최소 폭 | 선택 탭도 다른 탭과 같은 비율로 줄어듦(§11.1, 선택 탭 우선 배정 폐기) | 선택 단계가 `…`가 되면 현재 단계를 알아보기 어려움 | 정책 결정 필요(폐기 사유인 옆 탭 24 · 27px 문제와 함께 검토) | | 권장 화면 폭 | 보장 폭 1100px 이상. 단계 수·이름 길이별 권장 폭 기준은 없음 | 소비 프로젝트가 단계 구성에 필요한 폭을 판단하기 어려움 | 별도 검토(측정 기준 정의 필요) | | 넘침 처리 | 그룹 접기·좌우 스크롤·More 없음(2026-11-03 확정) | 단계가 많으면 축소 외 수단이 없음 | 확정 정책 — 변경하려면 사용자 결정 필요 | | 도구 버튼 툴팁 | `SWProcessSplitButton`은 `label`을 `title`로 전달. 호스트 `tools`의 `SWToolButton pill`은 2026-11-05부터 공백이 아닌 문자열 `children`이 기본 `title`(명시 `title` 우선, `title=""` 끔, 숫자·JSX 제외). 이 Header의 Story 도구는 이미 `title`을 전달해 DOM 변화 없음 | 아이콘만 보여 의미를 알기 어려울 수 있음(키보드 Focus·터치에서는 `title`이 보이지 않음 — 미해결) | 공통 원칙(DESIGN_RULES §15.2) — 자동 툴팁 구현됨 | | 텍스트 로고 폭 | `main @ 06527ed` 기준: `logoText` 58px 고정 칸이라 더 긴 글자는 양쪽으로 넘쳐 홈 왼쪽에서 잘림. 2026-11-05 변경 기준: 최소 58px · 글자 폭만큼 확장(§3 홈 행, §8 로고 폭 행) | 글꼴에 따라 글자 폭·홈 폭이 달라짐(§3 실측은 Noto Sans KR 기준) | 공통 원칙(DESIGN_RULES §1 · §15.4). 로고 이름·글꼴별 고정 폭 예외를 두지 않음 | ## 13. Figma 도구 아이콘 공개 Export — 보류 및 향후 제안 (2026-11-05) 2026-11-05 사용자 결정(B안): 시안 기반 아이콘 선택·창 제어 버튼 생략 규칙은 `packages/sw/ai/AI_USAGE.md` §5에 단일 기준으로 정의하고, 아래 아이콘의 공개 Export는 **보류**합니다. 소스·Props·CSS·공개 API·`public-api.approved.json`은 바꾸지 않았고 Fixture 파일도 그대로입니다. | 기능 | Fixture(Storybook 전용) | Figma 프레임 이름 | 상태 | |---|---|---|---| | 도움말 | `src/sw/assets/process-header/tool-help(-hover).svg` | help | 공개 API 아님 | | 3D 보기 | `tool-view-3d(-hover).svg` | view-3d | 〃 | | 설정 | `tool-controls(-hover).svg` | controls(라벨 "설정"은 Story 기준, Figma 원본 라벨 미확인) | 〃 | | 메뉴 | `tool-menu-list(-hover).svg` | menu-list | 〃 | | 나가기 | `tool-exit(-hover).svg` | exit-arrow | 〃 | - **확인된 사실:** Figma StrAna-SW(`4y8lTK1E1hAGYiMcYZwuNe`) 원본 내보내기(adbb034, §9.2). 기본 `#B6D0C9` / Hover `#FFC600` 두 장, 24 × 24, ``로 쓰면 SVG 내부 id 충돌 없음. `SWToolButton`의 `icon`·`hoverIcon`과 그대로 호환(Process Header에서는 `pressed`도 Hover 그림). - **미확인:** 원작자·사용 권한·라이선스. 프레임 이름의 " 1" 접미사는 외부 SVG를 Figma로 가져왔을 가능성을 시사(추정). - **Export 전제 조건:** ① 5개 아이콘의 출처·사용 권한(공개 패키지 배포 포함) 사용자 확인, ② 아래 구조와 이름의 별도 승인, ③ `public-api.approved.json` 갱신 승인. - **제안 구조(미구현, 승인 전 문서화·사용 금지):** `swFooterToolIcons` 선례와 같은 방식. `packages/sw/src/components/sw-process-header/icons.tsx`에 `swProcessToolIcons: Record`(기능 키 `help` · `view3d` · `settings` · `menu` · `exit`, ``), SVG 10개는 같은 폴더 `assets/`로 이동(data URI 번들), `sw-process-header/index.ts`에서 Export. 사용: `도움말`. 지원 범위는 `SWProcessHeader`의 `tools`(두 appearance), `SWHeader` `tools`는 별도 검증. - **Export 시 함께 할 일:** Story를 공개 Export로 전환하고 Fixture 중복 제거, `COMPONENT_CATALOG.md` §11 Export 추가, `AI_USAGE.md` §5.2 공개 목록 갱신·§5.3 Storybook 전용 목록에서 제외, `check:ai-docs` · `typecheck:sw` · `build:sw` · `public-api` 검사 · Tarball 소비 프로젝트 Import·Hover/Pressed 확인.