diff --git a/docs/ai/AI_GUIDE.md b/docs/ai/AI_GUIDE.md index 27d6194..b68d1e2 100644 --- a/docs/ai/AI_GUIDE.md +++ b/docs/ai/AI_GUIDE.md @@ -212,7 +212,7 @@ import { Button, Card, CardContent, FilterBar, FilterBarActions, FilterBarSearch ### 예시 B1 — SW 일반 모드 (편집 Header + 도구 막대 + 설정 Popup) - 읽기: `node_modules/@hm-design/sw/ai/` → AI_USAGE §0(일반 모드) → COMPOSITION_PATTERNS "6. 파일 열기 + 도구 막대", 예제 `ai/examples/ExampleF-ViewerToolbar.tsx`(파일 이름의 Viewer는 과거 명칭이며 일반 모드 `SWHeader` 예제) -- 재사용: `SWHeader`(`documentOpenPlacement="header"`, `controls`, `tools`), `SWToolGroup` + `SWToolButton`(Model/Layout 탭, Fit 등), `SWPopup` + `SWPopupSection` + `SWPopupRow` + `SWHeaderInput`(설정 Popup) +- 재사용: `SWHeader`(`documentOpenPlacement="header"`, `controls`, `tools`), `SWToolGroup` + `SWToolButton`(Model/Layout 탭, Fit 등), `SWPopup` + `SWPopupSection` + `SWPopupRow` + `SWHeaderInput`(설정 Popup), 로고(홈) 버튼 메뉴는 `SWHeader`의 `homeMenu` + `SWRecentFiles`(**일반 모드 전용**, 예제 `ExampleG-HomeMenu.tsx`) - 신규: SW에 없는 기능(예: 검색) → 소비 프로젝트 컴포넌트, `` 안, `--hm-sw-header-*` 토큰, 안쪽 입력은 `SWHeaderInput`(예제 `ExampleD-SearchExtension.tsx`) ```tsx @@ -225,7 +225,7 @@ import "@hm-design/sw/styles.css" - 읽기: `node_modules/@hm-design/sw/ai/` → AI_USAGE §0(뷰어 모드) → `VIEWER.md`, 예제 `ai/examples/ExampleH-ViewerMode.tsx` - 재사용: `SWViewerHeader`(`groups` 데이터: `button`·`toggle`·`menu`·`tabs`·`switch`·`custom` 항목, `onCommand`, `trailing`에 `SWViewerStatus`·`SWViewerHeaderButton`), Dropdown은 `type: "menu"` 항목의 `entries`(단독·우클릭은 `SWViewerMenu`), 팝업은 `SWViewerPanel` + `SWViewerSection`·`SWViewerField`·`SWViewerSwitch`·`SWViewerSlider`·`SWViewerInput`·`SWViewerButton` - 신규: 뷰어에 없는 패널 콘텐츠 → 소비 프로젝트 컴포넌트를 `SWViewerPanel`의 `children`에, 안쪽은 `SWViewerField` + `SWViewerInput` 등, 외형은 `--hm-sw-viewer-*` 토큰 -- 하지 않음: `SWHeader`·`SWPopup`을 뷰어 화면에 섞기, 로고가 없다고 임의 문자·아이콘 넣기, 연결할 명령이 없는 메뉴를 가짜 동작으로 만들기(제외 또는 `disabled` + 미연결 보고) +- 하지 않음: `SWHeader`·`SWPopup`을 뷰어 화면에 섞기, 로고(홈) 메뉴(`SWHomeMenu`·`SWRecentFiles`·`homeMenu`)를 뷰어 화면에 넣거나 비슷하게 만들기(홈 메뉴는 일반 모드 전용), 로고가 없다고 임의 문자·아이콘 넣기, 연결할 명령이 없는 메뉴를 가짜 동작으로 만들기(제외 또는 `disabled` + 미연결 보고) ```tsx import { SWViewerHeader, SWViewerPanel, SWViewerSection, SWViewerField, SWViewerSwitch, type SWViewerHeaderGroup } from "@hm-design/sw" diff --git a/docs/sw/figma-additional/ai-home-menu-guide.md b/docs/sw/figma-additional/ai-home-menu-guide.md new file mode 100644 index 0000000..35a8313 --- /dev/null +++ b/docs/sw/figma-additional/ai-home-menu-guide.md @@ -0,0 +1,73 @@ +# AI 가이드 초안 — SW 로고 클릭 메뉴 (`SWHomeMenu`) + +> 상태: **통합 전 초안**입니다(Task B 2단계, 2026-10-19). 통합 승인 후 `packages/sw/ai/COMPONENT_CATALOG.md`·`COMPOSITION_PATTERNS.md`·`DESIGN_RULES.md`로 옮깁니다. 지금은 `@hm-design/sw` 진입점에서 export되지 않으므로 소스 경로 `packages/sw/src/components/sw-home-menu`를 사용합니다. +> 기준: Figma `rj6wpsfk24lOWvWiVRAANP` 26:10591(메뉴), 26:11355…26:11631(타일 15개), 26:12604…(섹션 제목), 662:67267·662:67331·662:67471(최근파일 하위 패널). 구현: `SWHomeMenu.tsx`, `SWRecentFiles.tsx`, `theme/sw-home-menu.css`. + +## 1. 무엇인가 + +- SW Header의 **로고(홈) 버튼을 누르면 Header 위에 겹쳐 나타나는 2단 메뉴**입니다. 기본은 숨김이고, 로고를 다시 누르면 닫힙니다. +- 구성: 섹션(제목 badge + 타일 그룹) 여러 개 → 섹션마다 80 × 46 타일 여러 개. 타일 하나가 하위 패널(예: 최근파일 목록)을 열 수 있습니다. +- 운영체제 파일 선택창이 아닙니다. "찾아열기" 같은 항목의 실제 동작(파일 대화상자 등)은 host가 `onSelect`에서 수행합니다. + +## 2. 최소 사용법 + +```tsx +import { SWHeader, SWTheme } from "@hm-design/sw" +import { SWHomeMenu, type SWHomeMenuSectionData } from "@hm-design/sw" // 통합 후 경로 + +const sections: SWHomeMenuSectionData[] = [ + { id: "file", title: "작업중인 파일", items: [ + { id: "save", label: "저장", icon: , toggle: false, onSelect: () => host.save() }, + { id: "export", label: "내보내기", icon: }, + ] }, +] + +function App() { + const [open, setOpen] = useState(false) + return ( +
+ setOpen(v => !v)} /* 기존 props */ /> + {/* 통합 전: host가 위치를 지정합니다(Header 객체 수정 영역 왼쪽 - 2px, 창 영역 왼쪽까지). */} +
+ +
+
+ ) +} +``` + +## 3. 데이터 규칙 (새 메뉴를 만들 때) + +| 하고 싶은 것 | 방법 | +|---|---| +| 항목 추가 | 섹션 `items`에 `{ id, label, icon }`을 추가합니다. 폭·구분선·모서리·섹션 폭은 자동입니다 | +| 섹션 추가 | `{ id, title, items }`를 추가합니다. 제목 badge 폭은 글자 + 46px로 자동입니다 | +| 숨김 | `hidden: true`. 자리를 남기지 않습니다 | +| 비활성 | `disabled: true`. 기존 SW 규칙대로 opacity .4이며 Hover가 없습니다 | +| 실행만 하는 버튼 | `toggle: false`. Active(Variant3)가 되지 않습니다 | +| 켜고 끄는 버튼 | 기본값(`toggle` 생략)입니다. 클릭하면 Active, 다시 클릭하면 Default입니다 | +| Active 제어 | `activeIds` + `onActiveChange`(controlled) 또는 `defaultActiveIds`. 하나만 켜려면 `selection="single"` | +| 하위 패널 | `panel: `. 패널은 한 번에 하나만 열리고 열린 동안 하단 강조가 전체 외곽선이 됩니다 | +| 아이콘 | `currentColor` SVG 하나를 권장합니다(Default `#B6B4AF`, Hover·Active `#FF5C00` 자동). 색이 고정된 이미지 쌍이면 `hoverIcon`을 함께 줍니다 | +| 이벤트 | 항목 `onSelect(event)` → 메뉴 `onItemSelect(event)`. `event.active`는 클릭 후 상태입니다 | + +## 4. 상태와 닫기 (Figma 기준 + 접근성 보완) + +| 동작 | 결과 | 근거 | +|---|---|---| +| 로고 클릭 | 열기 / 다시 클릭하면 닫기 | Figma btn_home ON_CLICK → OVERLAY, 재클릭 닫기는 사용자 확정 | +| 타일 Hover | Variant2: 주황 gradient 1px 테두리, 아이콘·글자 `#FF5C00`, 1px 위·왼쪽 이동 | Figma Default ON_HOVER → V2 | +| 타일 클릭 | Variant3(Active, V2와 같은 모양) → 다시 클릭하면 Default | Figma V2 → V3 → Default | +| 메뉴 빈 곳 클릭 | 닫기 | Figma Group ON_CLICK → CLOSE (`closeOnBackgroundClick`) | +| Escape | 열린 패널을 먼저 닫고, 다시 누르면 메뉴를 닫은 뒤 로고로 Focus 복귀 | Figma 없음 · 접근성 (`closeOnEscape`) | +| 메뉴 밖 클릭 | 기본은 닫지 않음 | Figma overlay에 바깥 동작 없음 (`closeOnOutsideClick`) | +| ←/→/Home/End | 타일 사이 이동. 열린 패널 타일에서 ↓를 누르면 패널로 이동, ↑/↓로 행 이동, Enter로 파일 열기 | Figma 없음 · 접근성 | +| 최근파일 행 선택 | `onFileOpen(file)` 후 메뉴 닫기(`closeOnOpen`) | Figma 없음 · 검토 대상 | + +## 5. 하지 말 것 + +- 타일·섹션·제목을 Figma 화면별로 따로 만들지 않습니다. 모든 메뉴는 `sections` 데이터 하나로 표현합니다. +- `hm-sw-home-menu*` class를 소비 코드에서 붙여 외형을 만들지 않습니다(`className`은 확장용입니다). +- 새 색·크기를 임의로 정하지 않습니다. 필요한 값은 `--hm-sw-home-menu-*`·`--hm-sw-recent-files-*` 토큰을 `style`로 덮어씁니다. +- Font Weight는 400/500/700만 씁니다(타일 라벨·파일명 700, 섹션 제목 400). +- 홈 버튼이나 창 영역을 메뉴 안에 다시 그리지 않습니다. 그것은 `SWHeader`가 담당합니다. diff --git a/docs/sw/figma-additional/analysis-report.md b/docs/sw/figma-additional/analysis-report.md new file mode 100644 index 0000000..ef3d28f --- /dev/null +++ b/docs/sw/figma-additional/analysis-report.md @@ -0,0 +1,259 @@ +# 작업 B 1단계 — Figma 추가 디자인 분석·설계 보고 (2026-10-19) + +> **2단계 이후 정정(우선 적용):** [2단계 보고](./stage2-report.md)를 기준으로 봅니다. 아래 1단계 본문은 당시 기록으로 남겨 둡니다. +> - 로고 클릭 = 2단 Header 메뉴, 기본 숨김, 재클릭 닫힘(사용자 최종 정정). +> - 662:67267은 Figma 주석 "최근파일" 상태 화면입니다. 최근파일 목록 662:67331과 2뎁스 미리보기 662:67471이 함께 붙으며, 두 노드는 `SWRecentFiles`로 구현했습니다. +> - V3 = 클릭으로 켜지고 다시 클릭하면 꺼지는 Active 상태입니다(사용자 지시). +> - 아이콘 prop은 `iconHover`가 아니라 `hoverIcon`입니다(Task A `SWToolButton`과 이름을 맞춤). +> - `accent`의 기본값은 `"auto"`입니다(패널이 열린 동안 outline). + +> 상태: **분석·설계 보고만 작성했습니다(코드 수정 없음)**. 구현, Commit, Push는 하지 않았고 2단계는 사용자 승인 후 시작합니다. +> 대상: Figma `rj6wpsfk24lOWvWiVRAANP`, 속성Bar `26:10492`와 로고 클릭 노드 21개. 기준 브랜치는 `claude/sw-figma-logo-menu-36832b`(HEAD `5faa1f1`, `feature/sw-package`와 동일)입니다. +> 수집 자료: [figma-nodes.json](./figma-nodes.json)(노드별 메타데이터·디자인 컨텍스트 정규화·Prototype 연결), [screenshots/](./screenshots/)(노드 22개 PNG, 1x). + +## 0. 수집 방법과 한계 + +| 항목 | 내용 | 상태 | +|---|---|---| +| Figma 접근 | 공식 Figma MCP(`get_metadata`, `get_design_context`, `get_variable_defs`, `get_screenshot`)를 사용했습니다. `figma-design-to-code` 스킬을 먼저 불러왔습니다. 인증이 필요한 `plugin:figma:figma` 서버는 사용하지 않았습니다. | 완료 | +| 세부 속성 | 읽기 전용 `use_figma`(Plugin API)로 reactions, gradient stop, stroke, effect, font, 변형 간 diff를 확인했습니다. 캔버스는 수정하지 않았습니다. | 완료 | +| 디자인 컨텍스트 저장 | React/Tailwind 원문 대신 구현에 필요한 값만 `figma-nodes.json`에 정규화했습니다. 원문은 같은 node id로 다시 받을 수 있습니다. | 정규화본만 저장 | +| Asset | `get_design_context`의 asset URL은 2026-10-26에 만료됩니다. 이번 단계에서는 asset을 받지 않았고, 2단계에서 다시 받습니다. | 미수집 | +| Storybook 비교 | `localhost:6024`에서 이미 실행 중인 Storybook의 `SW/Header/Overview` 속성Bar를 측정했습니다. 그 서버가 어느 checkout에서 실행되는지는 확인하지 못했습니다. Pane 폭은 390px, DPR은 1.5였습니다. | 실측 1회, 출처 미확인 | +| 형제 노트 | 공유 노트 폴더에 다른 세션의 노트가 없었습니다. 작업 A의 계획은 사용자 메모리의 확정 기록 기준으로 대조했습니다. | 확인 | + +## 1. 노드별 표 (22개) + +"로고 클릭 화면 21개"는 실제로 **화면 상태 2개**와 **구성 컴포넌트 19개**(섹션 제목 4개, 버튼 세트 15개 × 상태 3개)입니다. 다섯 번째 섹션 제목 `tit_마이세팅`(26:12628, "My Setting")은 요청 목록에 없지만 화면에서 사용되므로 참고로 함께 정리했습니다. + +| # | Node | 이름 / 유형 | 크기 | 역할 | 상태·Prototype | +|---|---|---|---|---|---| +| 1 | 26:10492 | 속성Bar / FRAME (`header_green` → `선택한것` 26:10491 하위) | 1222×28 | 객체 속성 편집 strip | input ON_HOVER → hover(26:11659) | +| 2 | 26:10591 | 헤더/꾸러미 ver2/home on / COMPONENT | 1920×77 | **로고 클릭 overlay 본체** | btn_home ON_CLICK → OVERLAY(TOP_LEFT, 배경 없음), 메뉴 그룹 ON_CLICK → CLOSE | +| 3 | 662:67267 | 같은 이름 / FRAME | 1920×77(렌더 1935×193) | 2의 정적 사본. 팝업가이드 Variant5(K 미리보기)와 다른 하단 강조 | hover만 있음(open/close 없음) | +| 4 | 26:12604 | tit_작업중인파일 | 124×19 | 섹션 제목 "작업중인 파일" | 없음 | +| 5 | 26:12610 | tit_다른파일열기 | 123×19 | "다른파일 열기" | 없음 | +| 6 | 26:12622 | tit_파일손상시 | 111×19 | "파일 손상시" | 없음 | +| 7 | 26:12616 | tit_궁금하면 | 95×19 | "궁금하면" | 없음 | +| 8 | 26:11355 | btn_저장 / COMPONENT_SET | 3×(80×46) | 저장 · save · 그룹 첫 버튼 | D→hover V2, V2 click→V3, V3 click→D | +| 9 | 26:11371 | 복사저장 | 〃 | save_as · 중간 | 〃 | +| 10 | 26:11387 | 내보내기 | 〃 | file_open · 중간 | 〃 | +| 11 | 26:11403 | 도면묶기 | 〃 | inventory_2 · 마지막(구분선 없음) | 〃 | +| 12 | 26:11416 | 찾아열기 | 〃 | folder_open · 첫 버튼. 아이콘 top 5 | 〃. 구분선 gradient가 다름 | +| 13 | 26:11450 | 최근파일 | 〃 | 시계 붙은 파일 아이콘 · 중간 | **V2→V3 클릭 reaction 없음**. 구분선 gradient가 다름 | +| 14 | 26:11485 | 새파일 | 〃 | insert_drive_file · 마지막 | 〃 | +| 15 | 26:11507 | 복구하기 | 〃 | rotate_left · 첫 버튼 | 〃 | +| 16 | 26:11529 | 임시파일 | 〃 | file_copy · 마지막 | 〃 | +| 17 | 26:11542 | 디스플레이 | 〃 | monitor 24×22 · 첫 버튼. 라벨 "Display..."(원문에서 이미 말줄임) | 〃 | +| 18 | 26:11558 | 저장하기 | 〃 | 설정 저장 · 중간. gap 2 | 〃 | +| 19 | 26:11586 | 불러오기 | 〃 | save_alt · 마지막 | 〃 | +| 20 | 26:11599 | 설명보기 | 〃 | content_paste · 첫 버튼 | 〃 | +| 21 | 26:11615 | 문의하기 | 〃 | question_answer · 중간 | 〃 | +| 22 | 26:11631 | 소프트웨어 정보 | 〃 | 라벨 "S/W정보" · 마지막 | **V3가 button이 아니고 Default로 돌아가는 reaction 없음** | + +## 2. 속성Bar 차이표 (Figma 26:10492 ↔ 현재 구현·Storybook) + +비교 기준은 `packages/sw/src/theme/sw.css`(`.hm-sw-property-bar*`, `.hm-sw-header__input`), `SWHeaderPropertyBar.tsx`, Storybook `SW/Header/Overview` 실측입니다. **실제 차이가 있는 항목만** 적었습니다. 수정 위치는 모두 기존 공유 파일인 `sw.css`이므로 **통합 단계 항목**입니다. + +| # | 항목 | Figma | 현재 구현 / Storybook | 영향 | 수정 위치 | +|---|---|---|---|---|---| +| P1 | 테두리 색 | 좌·우·하 1px **세로 gradient**(`--gra-border-green`): `#08251C` 0% → `#208769` 37.1% → `#08241C` 80.5% → `#051612` 100%(위→아래) | 단색 `1px solid #08251C`. Storybook computed도 `rgb(8,37,28)` 단색 | 중간 높이의 초록 하이라이트(`#208769`)가 없음 | **통합 단계** `sw.css` `.hm-sw-property-bar`(gradient border는 기존 hover border 기법 재사용 검토) | +| P2 | 객체명 글자 외곽선 | 검정 1.3px Stroke + `#FFC600` 0.3px. 기존 정책상 검정 외곽선만 적용 | `text-shadow: none`. 외곽선 목록(`sw.css` 약 1472–1477행)에 `.hm-sw-property-bar__object`가 없음 | 노란 글자 가장자리가 Figma보다 흐림 | **통합 단계** `sw.css`, `--hm-sw-header-text-outline` 적용 | +| P3 | 라벨 글자 외곽선 | 14px 라벨에 검정 1px Stroke | `text-shadow: none` | 라벨 대비가 약함 | **통합 단계** `sw.css`, 1px 외곽선(`--hm-sw-header-label-outline`) 적용 검토 | +| P4 | 라벨 박스 폭 | 고정 텍스트 박스(반지름 46, 지름·원주·면적 30), 가운데 정렬. 박스 안 좌 1.4–2.1px, 우 1.8–2.8px 여백 | 자연 폭(예: "원주" 26.9px). 라벨→입력 간격이 Figma보다 약 2–3px 좁음. 콘텐츠 폭은 527.6px로 Figma 538px보다 짧음 | 글꼴 대체(Dotum → Noto Sans KR) 영향과 섞여 있음 | **검토 대상**(§5 R-P1). 고친다면 통합 단계 `sw.css` | +| P5 | 세로 위치 | 내용 Frame top 4px(20px 행) | 실측 top 3.5px(bar 875.2 → field 878.7, 27px 영역 가운데 정렬) | 0.5px | **검토 대상**(§5 R-P2) | + +**의도된 차이(수정하지 않음):** 바 폭은 Figma 1222px 고정 대신 콘텐츠 폭입니다(2026-10-19 사용자 확정). 글꼴은 Dotum Regular + Stroke 대신 Noto Sans KR이며 객체명·값은 700입니다(기존 Typography 정책). 입력 폭은 Figma 고정 58/66px 대신 값 길이를 따릅니다. 필드 순서와 객체명 문구는 Story fixture 데이터입니다. +**일치(차이 없음):** 높이 28, 배경 `#271F13`, 아래 radius 6, inset shadow `0 4 4 rgba(0,0,0,.6)`, 객체명 90px·`#FFC600`, 필드 간격 16·라벨-입력 6, 라벨 `#F6F4F2`·자간 4%, 입력 `#E60403`·자간 2%·padding 2/4/2/6·radius 2. 입력 상태 Default(면 없음) / hover(24px, 1px .25) / on(`#0F0D0A`, 1px .3)과 hover reaction도 같습니다. 아이콘은 Figma와 구현 모두 없습니다. +**미검증:** 1920px 폭 실측, Hover·편집 상태 Storybook 실측, P1–P3를 고친 뒤의 렌더 비교. + +## 3. 로고 클릭 화면 분석 + +### 3.1 화면 구성 (26:10591 기준, 1920 디자인) + +``` +y 0 ─ border-top 2px #5F4B0F ─────────────────────────────────────────────────── + [btn_home 80] (기존 Header가 비쳐 보임: 문서 제목 등) [섹션 5개, x377–1678] [창 영역 240: 인쇄·K pill | 창이동 | – | ×] +y 46 ─ border-bottom 2px #5F4B0F ─────────────── +y 47 ─ 하단 강조 strip 30px(섹션 뒤, 아래로 보이는 주황 gradient) +y 77 ─ 메뉴 끝(Header 48px보다 29px 아래로 내려옴) +``` + +- **Overlay**: 로고 클릭 시 `home on` 전체가 기존 Header 위에 TOP_LEFT로 겹칩니다(배경 없음). `bg black`과 `document_tit`가 숨겨져 있어 그 부분은 기존 Header가 그대로 보입니다. 즉 **새로 그려지는 것은 섹션 메뉴(x375–1680)이고**, 홈·창 영역은 기존 Header와 같은 컴포넌트 사본입니다. +- **섹션**(5개): 제목 badge(19px, Union 도형) + 버튼 그룹 box(46px) + 섹션 면(75px). 섹션 폭 = 버튼 수 × 80 + 좌우 padding(10, 첫·마지막 섹션은 한쪽 11)입니다. + - 작업중인 파일: 저장 · 복사저장 · 내보내기 · 도면묶기 + - 다른파일 열기: 찾아열기 · 최근파일 · 새파일 + - 파일 손상시: 복구하기 · 임시파일 + - My Setting: Display... · 저장하기 · 불러오기 + - 궁금하면: 설명보기 · 문의하기 · S/W정보 +- **버튼**: 80×46, 아이콘 18px(31,6), 라벨 14px(top 25). 마지막 버튼을 뺀 버튼 오른쪽에 1×44 gradient 구분선이 있습니다. + +### 3.2 공통 영역과 화면별 차이 + +| 구분 | 내용 | +|---|---| +| 공통(두 화면 동일) | 섹션 5개·버튼 15개·제목·구분선·면 gradient, 홈 버튼, 창 영역(인쇄·K·창이동·최소·종료), border-top/bottom `#5F4B0F` | +| 26:10591만 | 하단 강조 = 섹션별 사각형 5개(`#FEC501` + `#5F4B0F → #FF5100` gradient), btn_home 클릭 → open, 메뉴 클릭 → close | +| 662:67267만 | 하단 강조 = 메뉴 전체 1305×30에 2px gradient stroke(`#FF5100 → #5F4B0F`, fill 숨김), 팝업가이드 Variant5(K 미리보기 209×186, "다중인쇄/도면관리") 표시, open/close reaction 없음, btn_home 배경 asset이 다름 | +| 버튼 세트 공통 | Default / Variant2 / Variant3. **V2와 V3는 시각 속성이 같습니다**(Plugin API로 하위 노드 전체를 비교했고 위치만 다름) | +| 버튼별 차이 | 아이콘 asset과 위치(찾아열기 top 5, Display 24×22), 라벨 박스 폭(33–70), 그룹 내 위치에 따른 hover radius(첫 3 0 0 3 / 중간 0 / 마지막 0 3 3 0), 구분선 유무(마지막 없음), 찾아열기·최근파일만 구분선 gradient가 다름, 저장하기·S/W정보만 flex gap 2 | + +### 3.3 상태 + +| 상태 | Figma 근거 | 시각 | +|---|---|---| +| Default | 각 세트 Default | 면 없음, 아이콘 회색, 라벨 `#F6F4F2` + 검정 외곽선 | +| Hover | Default ON_HOVER → V2 | 1px INSIDE 주황 세로 gradient 테두리(`#DA6813` 8.5% / `#FFBB89` 37.9% / `#E5690D` 71.9% / `#AE3607` 92.8%), 아이콘·라벨 `#FF5C00`, 아이콘·라벨 1px 위·왼쪽 이동 | +| Pressed / 선택(?) | V2 ON_CLICK → V3, V3 ON_CLICK → Default | V2와 동일. 의미는 미정(§5 R-3) | +| Open / Close | btn_home ON_CLICK → OVERLAY, 메뉴 영역 ON_CLICK → CLOSE | — | +| Focus / Disabled / 키보드 | **Figma에 없음** | §5 검토 대상 | + +### 3.4 전환 관계 (Prototype) + +``` +[기존 Header] --btn_home click--> [home on overlay 26:10591] +[home on] --메뉴 영역(Group 2882) click--> CLOSE → [기존 Header] +버튼: Default --hover--> V2 --click--> V3 --click--> Default (최근파일: V2에서 끝, S/W정보: V3에서 끝) +팝업가이드: Default --hover--> Variant5(K 미리보기) ※ 기존 SWHeaderKGuide와 같은 대상 +``` + +Figma에는 메뉴 밖 클릭, Escape, 로고 재클릭으로 닫기, 각 버튼의 실제 동작(파일 대화상자, 최근 파일 목록 등)이 정의되어 있지 않습니다(§5). + +## 4. 공통 컴포넌트 구조·공개 API 초안 + +### 4.1 재사용 우선순위 판단 + +| 단계 | 후보 | 판단 | +|---|---|---| +| 기존 SW | `SWHeaderHome`(`onHomeClick`), `SWHeaderKGuide`, 창 제어, `useSWHeaderDropdown`의 닫기 계약(Escape·바깥 클릭·Tab 이탈·Focus 복귀), 텍스트 외곽선·focus 토큰, `SWTheme` | **재사용.** Header 쪽은 그대로 두고 메뉴만 새로 만듭니다. 홈·창 영역을 다시 그리지 않습니다 | +| 작업 A 계획 | `SWToolButton`(pill/text/document), `SWToolGroup`(selection), `SWPopup*` | §4.4 참고. 그대로 쓸 수 있는 appearance가 없습니다 | +| shadcn / Radix | Popover, NavigationMenu | `@hm-design/sw`는 `@hm-design/ui`·Radix에 의존하지 않습니다(독립 패키지). 새 의존성은 **별도 승인 대상**이므로 기존 SW hook 방식을 따릅니다 | +| 최소 Custom | 섹션 badge, 그룹 box, 80×46 타일 버튼 | 시각 요소만 새로 만듭니다(Figma 근거 있음) | + +### 4.2 구조 + +``` + overlay 패널(region/dialog 역할은 §5 R-6), open 상태·닫기 계약 + 섹션 면 + 제목 badge(폭은 글자에 맞춤) + 그룹 box + 80×46 타일 button. 마지막 항목은 구분선 자동 생략, 첫/마지막 hover radius 자동 +``` + +데이터형(`sections`)과 조합형(`children`) 중 하나만 써도 21개를 모두 표현할 수 있습니다. 위치·첫/마지막 여부·구분선·섹션 폭은 **항목 수에서 자동 계산**합니다. 따라서 AI가 항목만 추가해도 같은 스타일이 적용됩니다. + +### 4.3 공개 API 초안 + +```ts +export interface SWHomeMenuItemData { + id: string + label: string // 한 줄, 넘치면 말줄임 + title (기존 규칙) + icon?: ReactNode // currentColor SVG 권장: Default 회색 → Hover #FF5C00을 CSS가 처리 + iconHover?: ReactNode // 색 고정 이미지 쌍일 때만(기존 close/close-hover 방식) + disabled?: boolean // 시각은 검토 대상(R-4) + hidden?: boolean // 미렌더, 자리 없음(작업 A 숨김 정책과 맞춤) + title?: string // tooltip/전체 이름 + "aria-label"?: string + closeOnSelect?: boolean // 기본 true (Figma: 메뉴 클릭 → CLOSE) + onSelect?: (item: SWHomeMenuItemData) => void +} +export interface SWHomeMenuSectionData { + id: string + title: string + items: readonly SWHomeMenuItemData[] + hidden?: boolean +} +export interface SWHomeMenuProps extends Omit, "onSelect"> { + sections?: readonly SWHomeMenuSectionData[] // 또는 children() + open?: boolean // controlled + defaultOpen?: boolean + onOpenChange?: (open: boolean) => void + onItemSelect?: (item: SWHomeMenuItemData, section: SWHomeMenuSectionData) => void + /** 닫힐 때 Focus를 돌려줄 대상(기본: 연결된 홈 버튼). 통합 단계에서 SWHeader가 자동 연결 */ + returnFocusRef?: RefObject +} +export function SWHomeMenu(props: SWHomeMenuProps): JSX.Element +export function SWHomeMenuSection(props: { title: string; children: ReactNode; className?: string }): JSX.Element +export function SWHomeMenuItem(props: ButtonHTMLAttributes & { label: string; icon?: ReactNode; iconHover?: ReactNode }): JSX.Element +``` + +- **텍스트·아이콘·메뉴·이벤트·상태는 모두 외부에서 지정합니다.** 패키지에는 CAD 동작이 없습니다. Figma의 15개 메뉴는 Storybook fixture(또는 선택형 기본 아이콘 세트, §6 A-2)로만 제공합니다. +- **독립 단계 연결 방식(SWHeader 무수정):** ` setOpen(v => !v)} />`와 ``를 같은 상대 위치 컨테이너 안에 둡니다. 위치는 host가 `style`로 지정합니다. +- **통합 단계 연결 방식(안):** `SWHeader`에 `homeMenu?: SWHomeMenuProps | ReactNode`를 추가합니다. 홈 버튼에 `aria-expanded`/`aria-controls`를 붙이고, 객체 영역 시작 x에 앵커하며, 열림 중 홈 버튼 상태를 표시합니다. 작업 A의 `leading` 슬롯·파일 열기 배치와 같은 파일을 수정하므로 통합 단계에서만 합니다. +- **CSS:** 새 파일 `packages/sw/src/theme/sw-home-menu.css`에 `.hm-sw-home-menu*`만 둡니다. 새 토큰은 `--hm-sw-home-menu-*`이고, 기존 `--hm-sw-header-text-outline`·`--hm-sw-header-label-outline`·`--hm-sw-header-focus-color`·font 토큰은 그대로 읽습니다. 전역 선택자와 Dark 분기는 두지 않습니다. 단독 사용 시 `` 안에서 렌더합니다. +- **Font Weight:** 버튼 라벨 700(기존 "값·제목·토글 700"과 Figma 'Dotum/bold' 명칭), 제목 badge 12px 400(Stroke 없는 검정 글자)을 제안합니다. 600은 쓰지 않습니다. 최종값은 §5 R-5에서 확인합니다. + +### 4.4 작업 A와 겹치는 부분 + +| 작업 A 항목 | 겹침 | 제안 | +|---|---|---| +| `SWToolButton` appearance pill/text/document | 80×46 세로 아이콘+라벨 타일은 승인된 appearance에 없습니다 | B는 `SWHomeMenuItem`을 독립으로 만듭니다. 통합 단계에서 `SWToolButton appearance="tile"`로 합칠지 정합니다(**별도 승인 대상** A-1) | +| `SWToolGroup` selection="single" | 메뉴에는 선택 상태가 없습니다(V3 의미 미정) | 사용하지 않습니다. 키보드 이동 규칙만 맞춥니다 | +| `SWPopup`/`Section`/`Row` | 밝은 속성창 Popup과 시각·역할이 다릅니다 | 재사용하지 않습니다. 이름이 비슷한 `Section`은 namespace(`SWHomeMenuSection`)로 구분합니다 | +| `hiddenControls`·`show*` | 항목 숨김 개념이 같습니다 | 항목·섹션 `hidden`(미렌더, 자리 없음)으로 A와 같은 의미를 씁니다 | +| `documentOpenPlacement`, 문서 New/Open | "찾아열기·새파일"이 `onDocumentOpen`/`onDocumentNew`와 중복될 수 있습니다 | **검토 대상**(R-7). 컴포넌트는 콜백만 받습니다 | +| `leading` 슬롯·파일 열기 배치·반응형 | 메뉴 시작 x(Figma 375 = 문서 제목 끝)가 바뀝니다 | 통합 단계에서 실제 DOM 위치로 앵커합니다(x 하드코딩 금지) | +| 속성Bar(`.hm-sw-property-bar`) | 같은 49px 아래 overlay 영역을 씁니다(메뉴는 77px까지) | z-index·동시 표시는 R-8 | + +## 5. 검토 대상 (Figma에 없는 동작 — 확정하지 않음) + +| ID | 항목 | 제안(미확정) | +|---|---|---| +| R-1 | 메뉴 닫기: 바깥 클릭·Escape·로고 재클릭·Tab 이탈 | 기존 SW Dropdown 계약과 같게 처리하고 Focus는 홈 버튼으로 복귀 | +| R-2 | 항목 클릭 후 닫힘 | Figma CLOSE를 따라 기본 닫힘, `closeOnSelect`로 변경 | +| R-3 | V3(클릭 후)의 의미: 누름(pressed) 순간 표시인지, 유지되는 선택 상태인지. 최근파일·S/W정보의 reaction 누락 | 누름(`:active`) 표시로만 구현하고 유지 상태는 만들지 않음 | +| R-4 | Disabled·Focus-visible 시각 | 기존 SW 규칙(opacity .4, focus 2px `--hm-sw-header-focus-color`) | +| R-5 | 라벨·제목 Font Weight(700/400), Stroke 적용 범위 | §4.3 제안 | +| R-6 | 접근성 역할: `role="menu"` + 화살표 이동 vs region + button + Tab | button 목록 + 섹션 `aria-labelledby`, 화살표 이동은 작업 A 규칙과 맞춤 | +| R-7 | 찾아열기·새파일과 기존 `onDocumentOpen`/`onDocumentNew` 관계, 최근파일 하위 목록 여부 | 컴포넌트는 콜백만 받고, 연결은 host 또는 통합 단계에서 결정 | +| R-8 | 속성Bar·Dropdown·K 미리보기와의 z-index와 동시 표시 | 메뉴가 열리면 다른 Dropdown을 닫고 속성Bar보다 위에 표시 | +| R-9 | 1920 미만 반응형(메뉴 1305px) | 가용 폭 안 내부 가로 스크롤(속성Bar 정책과 동일). 섹션 접기·줄바꿈은 새 디자인이 필요해 A-4로 분리 | +| R-10 | 하단 강조 strip 두 가지(섹션별 vs 전체 2px) 중 기준 | 기본 디자인 컴포넌트인 26:10591(섹션별) | +| R-11 | home on의 border-top/bottom `#5F4B0F`와 홈 버튼 배경 asset이 기존 Header와 다른지 | 2단계에서 기존 `home-bg*.svg`·Header 선과 대조한 뒤 보고 | +| R-P1 | 속성Bar 라벨 고정 박스 여백(P4) | 글꼴 대체 영향이라 유지 권장 | +| R-P2 | 속성Bar 세로 0.5px(P5) | 유지 권장 | + +## 6. 별도 승인 대상 (새 디자인 판단 또는 승인 범위 초과) + +| ID | 항목 | 이유 | +|---|---|---| +| A-1 | `SWToolButton`에 `tile` appearance 추가 또는 `SWHomeMenuItem` 별도 유지 | 작업 A에서 확정된 공개 API 변경 | +| A-2 | Figma 메뉴 아이콘 15개(+hover 15개)를 패키지 기본 asset으로 제공할지, Story fixture로만 둘지 | 공개 asset·번들 크기 증가 | +| A-3 | `SWHeader`에 `homeMenu` prop·홈 버튼 열림 상태 추가 | 기존 Header API·스타일 변경(통합 단계) | +| A-4 | 좁은 폭에서 섹션 접기·More 이동 등 새 반응형 디자인 | Figma에 없는 디자인 | +| A-5 | Radix 등 새 dependency 사용 | 현재 `@hm-design/sw`에는 런타임 의존성이 없음 | +| A-6 | 속성Bar P1–P3 수정 | 기존 공유 CSS 변경이며, 사용자 확정 디자인 범위 안인지 확인 필요 | + +## 7. 파일 경계 + +| 구분 | 파일 | 내용 | +|---|---|---| +| **B 독립(신규만)** | `packages/sw/src/components/sw-home-menu/**` | `SWHomeMenu.tsx`, `SWHomeMenuSection.tsx`, `SWHomeMenuItem.tsx`, `types.ts`, `index.ts`, (A-2 승인 시) `assets/` | +| | `packages/sw/src/theme/sw-home-menu.css` | `.hm-sw-home-menu*` 스타일·토큰 | +| | `src/sw/sw-home-menu.stories.tsx` | Figma 21개 재현, 단독, 동적 데이터, Header 조합(host wiring) Story. Story CSS는 새 파일만 | +| | `docs/sw/figma-additional/**` | 이 보고서, 수집 자료, 2단계 검증 기록 | +| **통합 단계로 미룸** | `packages/sw/src/index.ts`, 테마 진입 CSS(`sw.css` import 체인) | export·CSS 연결(2단계 Story는 상대 경로 import로 확인) | +| | `packages/sw/src/components/sw-header/**`, `packages/sw/src/theme/sw.css` | `homeMenu` 연결(A-3), 속성Bar P1–P3(A-6) | +| | `build.mjs`, `package.json` | asset·CSS 번들 포함 | +| | `packages/sw/ai/**`, `packages/sw/README.md`, `docs/sw/sw-header-*.md` | AI 가이드·카탈로그·사용법. 2단계에서는 초안을 `docs/sw/figma-additional/`에 둠 | +| | 기존 stories(`src/sw/sw-header*.stories.tsx`, `sw-header-overview.tsx`, `sw-stories.css`) | 수정하지 않음 | + +## 8. 2단계 구현·검증 계획 (승인 후) + +**구현 순서** +1. Asset 재수집(만료 전) → A-2 결정에 따라 경로 확정 → 섹션 badge·그룹 box·구분선·타일 CSS +2. `SWHomeMenuItem` → `SWHomeMenuSection` → `SWHomeMenu`(open 계약, R-1·R-2 결정 반영) +3. Story `SW/Home Menu`: Figma 재현, 단독, 동적, Header 조합 +4. AI 가이드 초안(`docs/sw/figma-additional/ai-home-menu-draft.md`) → 통합 단계에서 `packages/sw/ai/`로 이동 + +**검증 범위**(실행하지 않은 항목은 미검증으로 기록) + +| 범위 | 방법 | 기준 | +|---|---|---| +| Figma 비교 | 1920 viewport, Figma 스크린샷과 같은 배율 비교 + 요소 실측 | 섹션 x·폭(340/260/180/260/261), 높이 75·46·19, 색·gradient·shadow | +| 21개 재현 | 제목 5개(참고 1개 포함), 버튼 15개 × Default/Hover/Pressed 상태 Story | 노드별 체크리스트 | +| 단독 사용 | `` 안 `SWHomeMenu`만 렌더 | Header 없이 동작·스타일 유지, 전역 CSS 누수 없음 | +| 동적 콘텐츠 | 항목 추가·삭제·숨김, 긴 라벨, 아이콘 없음, 섹션 1개·6개, 비동기 갱신 | 폭·구분선·radius 자동 계산, 말줄임 | +| Header/Popup 조합 | `onHomeClick` host wiring, 속성Bar·Dropdown·K 가이드 동시 상태 | 닫기 계약, Focus 복귀, z-index(R-8) | +| 반응형 | 1920/1440/1280/1080/900/768/640/390 | 가로 넘침 없이 내부 스크롤(R-9) | +| Storybook | 기존 SW Story 회귀 없음 | 기존 Story 무수정 확인 | +| AI 가이드 | 문서만으로 새 메뉴 항목·섹션 생성 시나리오 1건 | 임의 값 없이 같은 스타일 | +| 독립 React 19 소비 프로젝트 | 통합 단계 build 후 packed tarball 설치 | 타입·CSS·asset 로드. **dist·export 연결이 통합 단계라 2단계에서는 미검증 예정** | diff --git a/docs/sw/figma-additional/figma-nodes.json b/docs/sw/figma-additional/figma-nodes.json new file mode 100644 index 0000000..374037c --- /dev/null +++ b/docs/sw/figma-additional/figma-nodes.json @@ -0,0 +1,115 @@ +{ + "source": { + "fileKey": "rj6wpsfk24lOWvWiVRAANP", + "collectedAt": "2026-10-19", + "tools": "공식 Figma MCP get_metadata / get_design_context / get_variable_defs / get_screenshot + 읽기 전용 use_figma(Plugin API: reactions, fills, strokes, effects, fonts)", + "page": "2. 헤더 (SECTION) — 속성Bar만 header_green 26:10332의 'Property 1=선택한것' 26:10491 하위", + "note": "get_design_context의 React/Tailwind 원문은 화면 재현용 참고 코드라 그대로 저장하지 않고, 구현에 필요한 값만 아래에 정규화했습니다. 원문은 같은 node id로 다시 받을 수 있습니다. 응답에 들어 있던 asset URL은 2026-10-26에 만료되므로 2단계에서 다시 받아야 합니다. 스크린샷은 screenshots/.png (1x)입니다." + }, + "nodes": [ + { + "id": "26:10492", "name": "속성Bar", "type": "FRAME", "size": [1222, 28], + "screenshot": "screenshots/26-10492_property-bar.png", + "variables": { "--accent-yellow": "#FFC600", "--text-brown100": "#F6F4F2", "--text-red": "#E60403", "--gra-border-green": "(gradient, 값 없음)" }, + "metadata": "Rectangle 7541 1222x28 + Frame(top 4, h 20) = 객체명 Dotum_14_bold 90x16 + Frame(gap 16) x4 [라벨 Dotum_regular_14 (46|30)x16 + gap 6 + input 58|66x20]", + "designContext": { + "background": "#271F13", + "border": "좌·우·하 1px (상 0) GRADIENT_LINEAR 위→아래 #08251C 0% / #208769 37.1% / #08241C 80.5% / #051612 100%", + "radius": "0 0 6 6", + "effect": "INNER_SHADOW 0 4 4 rgba(0,0,0,.6)", + "object": "90px 가운데 정렬, Dotum Regular 14 / 4%, #FFC600, 아래층 Stroke 검정 1.3px + 위층 #FFC600 0.3px", + "label": "Dotum Regular 14 / 4%, #F6F4F2, Stroke 검정 1px, 고정 폭 텍스트 박스(46 또는 30) 가운데 정렬", + "fieldGap": 16, "labelInputGap": 6, + "input": "component set 'input'(26:11656) Default 26:11657 58x20 pad 2/4/2/6 r2 면·테두리 없음 / hover 26:11659 58x24 1px rgba(212,203,189,.25) / on 26:11661 58x24 #0F0D0A + 1px .3. 값 Dotum Regular 14 / 2%, 검정 1.3 + #E60403 0.3" + }, + "reactions": ["input 4개: ON_HOVER → CHANGE_TO input hover(26:11659)"] + }, + { + "id": "26:10591", "name": "헤더/꾸러미 ver2/home on", "type": "COMPONENT", "size": [1920, 77], + "screenshot": "screenshots/26-10591_home-on.png", + "role": "로고(btn_home) 클릭 시 열리는 overlay 자체(TOP_LEFT, 배경 없음, 바깥 클릭 상호작용 없음)", + "variables": { "--text-brown100": "#F6F4F2", "--gra-border-brown1": "(gradient)", "--gra-border-brown2": "(gradient)", "--accent-border-yellow": "(gradient)" }, + "hiddenLayers": ["bg balck 1920x48", "Rectangle 6671 310x48", "header/document_tit 310x48"], + "metadata": "창 영역 240x48(x1680) · 최소/종료 32x48 x2 · pill(인쇄 + 팝업가이드) 85x42 · 창이동 motion 88x48 · border-top/bottom 1920x2 #5F4B0F · btn_home 80x48 · Group 2882 x375 1305x77 = 하단 강조 strip(y47, 30px, 섹션별 사각형 5개) + 섹션 5개(x377 1301x75)", + "sections": [ + { "frame": "Frame 2408", "width": 340, "padding": "5 10 5 11", "title": "tit_작업중인파일 26:12604 124x19", "group": "g_작업중인파일 320x46", "items": ["btn_저장 26:11355", "복사저장 26:11371", "내보내기 26:11387", "도면묶기 26:11403"] }, + { "frame": "Frame 2409", "width": 260, "padding": "5 10", "title": "tit_다른파일열기 26:12610 123x19", "group": "g_다른파일열기 240x46", "items": ["찾아열기 26:11416", "최근파일 26:11450", "새파일 26:11485"] }, + { "frame": "Frame 2410", "width": 180, "padding": "5 10", "title": "tit_파일손상시 26:12622 111x19", "group": "g_파일손상시 160x46", "items": ["복구하기 26:11507", "임시파일 26:11529"] }, + { "frame": "Frame 2411", "width": 260, "padding": "5 10", "title": "tit_마이세팅 26:12628 107x19 (요청 목록 밖, 'My Setting')", "group": "Frame 2407 240x46", "items": ["디스플레이 26:11542", "저장하기 26:11558", "불러오기 26:11586"] }, + { "frame": "Frame 2412", "width": 261, "padding": "5 10 5 11", "title": "tit_궁금하면 26:12616 95x19", "group": "g_궁금하면 240x46", "items": ["설명보기 26:11599", "문의하기 26:11615", "소프트웨어 정보 26:11631"] } + ], + "designContext": { + "section": "h75, 1px #081813, radius 0 0 3 3, fill 2중 gradient(세로 #18150E 0 / #262015 21.3% / #332B1C 47% / #38301F 75% / #18150E 100% + 가장자리 어둡게 #16120A 0 / 투명 54.5% / #16120A 100%), 안쪽 1px #20190E 사각형", + "group": "h46, 1px GRADIENT stroke(#886D35 0 / #423625 8.8% / #F3DBA8 26.2% / #0E0B06 83.8% / #574B30 100%), radius 3, fill gradient(#19160E 2% / #38301F 43.7% / #463C29 67.7% / #2F281A 100%), DROP_SHADOW 0 2 radius 4 rgba(0,0,0,.6)", + "title": "Union 도형(위아래 반전) 19px, fill gradient #887757 → #A8997C 75.6% → #C3B79E, stroke 1px #7B6332 → #9F8D68, DROP_SHADOW 0 -2 radius 4 rgba(0,0,0,.4), 글자 Dotum Regular 12 / 2% #000 가운데, group 위에 -1px 겹침", + "bottomStrip": "y47 h30, 섹션별 사각형(343/263/181/262/264, -2px 겹침, radius 0 0 3 3) fill #FEC501 + GRADIENT #5F4B0F → #FF5100", + "headerLines": "border-top 0-2px, border-bottom 46-48px, #5F4B0F 1920px" + }, + "reactions": [ + "btn_home 26:10652 ON_CLICK → OVERLAY 26:10591", + "Group 2882(메뉴 전체) ON_CLICK → CLOSE", + "메뉴 버튼 15개 ON_HOVER → 각 Variant2", + "header/btn_최소최대화·btn_종료 ON_HOVER → hover", + "Component 743(인쇄) ON_HOVER → hover 26:224", + "꾸러미ver2/팝업가이드 ON_HOVER → Variant5 26:426 (209x186, SMART_ANIMATE)", + "창이동 motion ON_HOVER → 26:10258 SMART_ANIMATE", + "header/document_tit(숨김) MOUSE_ENTER → OVERLAY 26:10667 hover" + ] + }, + { + "id": "662:67267", "name": "헤더/꾸러미 ver2/home on", "type": "FRAME", "size": [1920, 77], "renderBounds": [1935, 193], + "screenshot": "screenshots/662-67267_home-on-popup-guide.png", + "role": "26:10591과 같은 구성의 독립 Frame. 팝업가이드가 Variant5(K 미리보기 209x186) 상태이고 하단 강조가 다름", + "diffFrom_26:10591": [ + "하단 strip: 섹션별 사각형 4개 숨김, Rectangle 6991만 1305x30, fill(#FF5100) 숨김 + 2px GRADIENT stroke #FF5100 → #5F4B0F", + "꾸러미ver2/팝업가이드 = Variant5 (검정 미리보기, '다중인쇄/도면관리')", + "btn_home 클릭·메뉴 CLOSE reaction 없음 (정적 상태 화면)", + "btn_home 배경 asset이 26:10591과 다른 파일(a80fd vs 9931a)" + ], + "reactions": ["창 버튼·인쇄·창이동·메뉴 버튼 15개 ON_HOVER만 (26:10591과 같은 대상의 다른 사본 id)"] + }, + { "id": "26:12604", "name": "tit_작업중인파일", "type": "COMPONENT", "size": [124, 19], "text": "작업중인 파일", "textBox": [78, 14], "screenshot": "screenshots/26-12604_tit-working-file.png" }, + { "id": "26:12610", "name": "tit_다른파일열기", "type": "COMPONENT", "size": [123, 19], "text": "다른파일 열기", "textBox": [78, 14], "screenshot": "screenshots/26-12610_tit-open-other.png" }, + { "id": "26:12622", "name": "tit_파일손상시", "type": "COMPONENT", "size": [111, 19], "text": "파일 손상시", "textBox": [66, 14], "screenshot": "screenshots/26-12622_tit-file-damaged.png" }, + { "id": "26:12616", "name": "tit_궁금하면", "type": "COMPONENT", "size": [95, 19], "text": "궁금하면", "textBox": [49, 14], "screenshot": "screenshots/26-12616_tit-curious.png" } + ], + "titleWidthRule": "제목 폭 = 글자 폭 + 약 46px(좌우 약 23px). 5개 모두 같은 Union 도형을 폭만 늘린 것", + "buttonSets": { + "common": { + "type": "COMPONENT_SET 120x218, variants 'Property 1' = Default / Variant2 / Variant3, 각 80x46", + "default": "면 없음, 아이콘 18x18 at (31,6) 회색 #B6B4AF 계열 SVG, 라벨 Dotum Regular 14 / 4% #F6F4F2 + 검정 1.3 / 자기 색 0.3 Stroke, top 25 가운데", + "variant2": "1px INSIDE GRADIENT stroke 위→아래 #DA6813 8.5% / #FFBB89 37.9% / #E5690D 71.9% / #AE3607 92.8%, 아이콘 hover SVG(#FF5C00), 라벨 #FF5C00, 아이콘·라벨 1px 위·왼쪽 이동(31,6→30,5 / top 25→24), radius = 그룹 첫 버튼 3 0 0 3, 마지막 0 3 3 0, 중간 0", + "variant3": "Variant2와 시각 속성 동일(Plugin API 전체 하위 노드 비교 결과 위치 y만 다름)", + "divider": "마지막 버튼을 뺀 버튼 오른쪽(-1px, hover -2px)에 1x44 세로선 GRADIENT(#886D35/#423625/#F3DBA8/#0E0B06/#574B30) + DROP_SHADOW -1 0 radius 2 #000", + "prototype": "Default ON_HOVER → Variant2, Variant2 ON_CLICK → Variant3, Variant3 ON_CLICK → Default" + }, + "items": [ + { "set": "26:11355", "name": "btn_저장", "label": "저장", "icon": "save", "position": "first", "variants": ["26:11356", "26:11361", "26:11366"], "screenshot": "screenshots/26-11355_btn-save.png", "note": "Default에 숨김(visible=false) 노란 gradient stroke 존재" }, + { "set": "26:11371", "name": "복사저장", "label": "복사저장", "icon": "save_as", "position": "middle", "variants": ["26:11372", "26:11377", "26:11382"], "screenshot": "screenshots/26-11371_btn-save-copy.png" }, + { "set": "26:11387", "name": "내보내기", "label": "내보내기", "icon": "file_open", "position": "middle", "variants": ["26:11388", "26:11393", "26:11398"], "screenshot": "screenshots/26-11387_btn-export.png" }, + { "set": "26:11403", "name": "도면묶기", "label": "도면묶기", "icon": "inventory_2", "position": "last", "variants": ["26:11404", "26:11408", "26:11412"], "screenshot": "screenshots/26-11403_btn-bundle.png" }, + { "set": "26:11416", "name": "찾아열기", "label": "찾아열기", "icon": "folder_open (top 5)", "position": "first", "variants": ["26:11417", "26:11428", "26:11439"], "screenshot": "screenshots/26-11416_btn-find-open.png", "note": "구분선 gradient가 다른 버튼과 다름(0deg 갈색 #493927 계열)" }, + { "set": "26:11450", "name": "최근파일", "label": "최근파일", "icon": "insert_drive_file(시계 포함)", "position": "middle", "variants": ["26:11451", "26:11462", "26:11473"], "screenshot": "screenshots/26-11450_btn-recent.png", "note": "구분선 gradient 2중(갈색 + 초록). Variant2 → Variant3 클릭 reaction 없음" }, + { "set": "26:11485", "name": "새파일", "label": "새파일", "icon": "insert_drive_file", "position": "last", "variants": ["26:11486", "26:11493", "26:11500"], "screenshot": "screenshots/26-11485_btn-new-file.png" }, + { "set": "26:11507", "name": "복구하기", "label": "복구하기", "icon": "rotate_left", "position": "first", "variants": ["26:11508", "26:11515", "26:11522"], "screenshot": "screenshots/26-11507_btn-recover.png" }, + { "set": "26:11529", "name": "임시파일", "label": "임시파일", "icon": "file_copy", "position": "last", "variants": ["26:11530", "26:11534", "26:11538"], "screenshot": "screenshots/26-11529_btn-temp-file.png" }, + { "set": "26:11542", "name": "디스플레이", "label": "Display...", "icon": "monitor 24x22 at (29,6)", "position": "first", "variants": ["26:11543", "26:11548", "26:11553"], "screenshot": "screenshots/26-11542_btn-display.png", "note": "라벨 박스 70px, Figma 원문 자체가 '...' 말줄임" }, + { "set": "26:11558", "name": "저장하기", "label": "저장하기", "icon": "설정 저장(그룹 아이콘 16.3x16.5)", "position": "middle", "variants": ["26:11559", "26:11568", "26:11577"], "screenshot": "screenshots/26-11558_btn-setting-save.png", "note": "flex gap 2px" }, + { "set": "26:11586", "name": "불러오기", "label": "불러오기", "icon": "save_alt", "position": "last", "variants": ["26:11587", "26:11591", "26:11595"], "screenshot": "screenshots/26-11586_btn-setting-load.png" }, + { "set": "26:11599", "name": "설명보기", "label": "설명보기", "icon": "content_paste", "position": "first", "variants": ["26:11600", "26:11605", "26:11610"], "screenshot": "screenshots/26-11599_btn-help.png" }, + { "set": "26:11615", "name": "문의하기", "label": "문의하기", "icon": "question_answer", "position": "middle", "variants": ["26:11616", "26:11621", "26:11626"], "screenshot": "screenshots/26-11615_btn-inquiry.png" }, + { "set": "26:11631", "name": "소프트웨어 정보", "label": "S/W정보", "icon": "정보(Frame 2405)", "position": "last", "variants": ["26:11632", "26:11639", "26:11646"], "screenshot": "screenshots/26-11631_btn-sw-info.png", "note": "Variant3가 button 형태가 아니며 Default로 돌아가는 클릭 reaction 없음" } + ] + }, + "supplementary": { + "note": "요청 21개 밖, 2단계 재확인(2026-10-19)에서 찾은 노드. 같은 SECTION '2. 헤더'의 주석 '최근파일'(26:11784) 아래 662:67267과 함께 배치. 서로 연결된 prototype reaction 없음(drop ON_CLICK의 action 비어 있음).", + "nodes": [ + { "id": "662:67331", "name": "최근파일", "type": "FRAME", "size": [354, 750], "screenshot": "screenshots/662-67331_recent-files.png", + "position": "662:67267 기준 x 808, y 77 (최근파일 타일 왼쪽 + 1, 메뉴 바로 아래)", + "designContext": "frame 1px #DA6813 좌·우·하, radius 0 0 3 3 / drop 354x750 #27241D, 1px #27241D, radius 0 0 4 4, shadow 0 2 4 rgba(0,0,0,.25) + inset 0 4 8 rgba(0,0,0,.4) / row 'header/최근파일/list' 50px, px 8, gap 8 (배지 없는 행 px 45) / icon_dualmonitor 29x28 (84a46 왼쪽 노랑, 9967e 오른쪽 노랑) / 이름 Dotum 14 4% #F6F4F2 (Stroke 2층) / 경로 12 4% #D4CBBD 60% / Hover 행 #62533D + 이름 #FF5C00" }, + { "id": "662:67471", "name": "파일출력 2뎁스", "type": "FRAME", "size": [310, 270], "screenshot": "screenshots/662-67471_file-preview-2depth.png", + "position": "최근파일 오른쪽 +1, Hover 행 top +1", + "designContext": "#62533D, 1px #62533D 상·우·하, radius 0 3 4 0, drop-shadow 0 2 1 rgba(0,0,0,.5), inset 2 0 2.5 rgba(0,0,0,.5), py 4 gap 4 / 경로 14px #FF5C00 (아래층 #D7D2B0) / image 918 310x244 (crop 158.67% x 191.87%, -25.97% / -52.46%)" } + ] + } +} diff --git a/docs/sw/figma-additional/integration-plan.md b/docs/sw/figma-additional/integration-plan.md new file mode 100644 index 0000000..f967c8e --- /dev/null +++ b/docs/sw/figma-additional/integration-plan.md @@ -0,0 +1,40 @@ +# Task A + B 통합 계획 — 로고 클릭 2단 Header 메뉴 (초안, 2026-10-19) + +> 상태: **미승인 계획**입니다. Task B는 신규 파일만 작성했고 아래 공유 파일은 아직 수정하지 않았습니다. 통합은 사용자 별도 승인 후 진행합니다. +> 근거: [2단계 보고](./stage2-report.md), Task A 현황(읽기 전용 확인, 미커밋): SWHeader `leading` 슬롯, `documentOpenPlacement`, CSS 변수 `--hm-sw-header-leading-width`, `components/sw-tool/`. + +## 1. 순서 + +1. Task A 변경을 먼저 확정한 뒤, 그 위에 Task B 신규 파일을 merge합니다. B 파일은 A 파일과 겹치지 않습니다. +2. export 연결 → 3. SWHeader 연결 → 4. 속성Bar 수정(선택) → 5. 문서·AI → 6. 검증. + +## 2. 작업 목록과 적용 방법 + +| # | 파일 | 변경 | 적용 방법 | +|---|---|---|---| +| I-1 | `packages/sw/src/index.ts` | 공개 export | `export * from "./components/sw-home-menu"` 한 줄. CSS는 `SWHomeMenu.tsx`·`SWRecentFiles.tsx`에서 import하므로 index에 CSS import를 추가하지 않습니다(`sideEffects` 때문에 index에서만 import하면 빌드에서 빠지는 것을 확인함) | +| I-2 | `components/sw-header/types.ts` | Header prop | `homeMenu?: Omit`, `homeMenuOpen?`, `defaultHomeMenuOpen?`(false), `onHomeMenuOpenChange?(open, reason)`. 미전달이면 기존 동작과 같습니다(하위 호환) | +| I-3 | `components/sw-header/SWHeader.tsx` | 연결 | `homeMenu`가 있을 때만 홈 클릭으로 열림을 토글합니다. 기존 `onHomeClick`은 항상 먼저 호출합니다. 메뉴는 `
` 안의 absolute 레이어(`top: 0`)로 렌더링하고, `returnFocusRef`는 홈 버튼입니다. 메뉴가 열리면 기존 필드 Dropdown(`activeMenu`)을 닫습니다 | +| I-4 | 같은 파일 | 앵커 | 시작 x = 객체 수정 영역 `getBoundingClientRect().left − header.left − 2px`, 폭 = 창 영역 left − 그 값입니다. 고정 375px을 쓰지 않습니다. Task A `leading` 슬롯이 있으면 `--hm-sw-header-leading-width`만큼 객체 영역이 이동하므로 **DOM 실측을 기준으로 하고 변수는 보조로 씁니다**. 기존 속성Bar `barOffset` 측정 방식과 같은 패턴입니다 | +| I-5 | `components/sw-header/components/SWHeaderHome.tsx` | 접근성 | `aria-expanded`·`aria-controls`(메뉴 id)를 추가합니다. Figma에 열림 시각 변화가 없으므로 스타일은 바꾸지 않습니다 | +| I-6 | `theme/sw.css` | z-index | 메뉴 레이어를 속성Bar 앵커(z 2)보다 위, 기존 Dropdown 패널과 같은 층에 둡니다. 동시에 열리지 않게 I-3에서 닫습니다 | +| I-7 | `theme/sw.css` (선택, A-6 승인 필요) | 속성Bar | P1: 좌·우·하 테두리를 세로 gradient `#08251C 0% / #208769 37.1% / #08241C 80.5% / #051612 100%`로 바꿉니다(기존 hover-ring mask 기법). P2: `.hm-sw-property-bar__object`에 `--hm-sw-header-text-outline`. P3: 라벨에 `--hm-sw-header-label-outline` | +| I-8 | `theme/sw.css` (검토) | home on 상·하단 선 | Figma 열림 상태의 1920 전폭 `#5F4B0F` 2px 선(y 0–2, 46–48)을 `.hm-sw-header[data-home-menu-open]`에서만 적용할지 사용자가 확인해야 합니다 | +| I-9 | `build.mjs`, `package.json` | 번들 | 변경이 필요 없을 것으로 예상합니다. `dist/styles.css`에 `.hm-sw-home-menu`가 포함되는지, `title-badge.svg`가 inline 또는 asset으로 나오는지 build 후 확인합니다 | +| I-10 | `packages/sw/ai/**`, `README.md`, `docs/sw/sw-header-usage.md` | 문서 | [AI 가이드 초안](./ai-home-menu-guide.md)을 COMPONENT_CATALOG·COMPOSITION_PATTERNS·DESIGN_RULES로 옮기고, `homeMenu` prop 사용 예를 추가합니다 | +| I-11 | 기존 stories | 예시 | `src/sw/sw-home-menu.stories.tsx`의 소스 경로 import를 `@hm-design/sw`로 바꿉니다. host wiring 예시는 I-3 이후 `SWHeader homeMenu` 예시로 대체합니다 | + +## 3. Task A와 맞출 결정 (사용자 확인) + +- `SWToolButton`에 `tile` appearance를 둘지, `SWHomeMenuItem`을 별도로 유지할지(A-1). +- 토글 이름: A는 `pressed`, B는 `active`/`activeIds`(별칭 추가 여부). +- `documentOpenPlacement` 기본값 `"menu"`는 메뉴와 독립적입니다. 찾아열기·새파일은 host가 `onDocumentOpen`·`onDocumentNew`와 같은 handler를 연결합니다(내부 결합 없음). +- Figma 아이콘 15쌍을 패키지 asset으로 둘지 여부(A-2). 현재는 Story fixture에만 있습니다. + +## 4. 통합 검증 + +1920·1440·1080·768·390 폭에서 확인합니다. +- 로고 열기·재클릭 닫기, 그리고 `leading`·문서 Dropdown(New/Open)과 겹치지 않는지. +- 기존 Header·속성Bar·Dropdown·K 가이드 회귀 없음. +- `tsc`, library build, packed tarball을 React 19 소비 프로젝트에 설치했을 때 동작하는지. +- Storybook 전체 Story(포트 충돌 주의). diff --git a/docs/sw/figma-additional/screenshots/26-10492_property-bar.png b/docs/sw/figma-additional/screenshots/26-10492_property-bar.png new file mode 100644 index 0000000..7632167 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-10492_property-bar.png differ diff --git a/docs/sw/figma-additional/screenshots/26-10591_home-on.png b/docs/sw/figma-additional/screenshots/26-10591_home-on.png new file mode 100644 index 0000000..2aee93c Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-10591_home-on.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11355_btn-save.png b/docs/sw/figma-additional/screenshots/26-11355_btn-save.png new file mode 100644 index 0000000..fc14c8b Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11355_btn-save.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11371_btn-save-copy.png b/docs/sw/figma-additional/screenshots/26-11371_btn-save-copy.png new file mode 100644 index 0000000..cba730f Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11371_btn-save-copy.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11387_btn-export.png b/docs/sw/figma-additional/screenshots/26-11387_btn-export.png new file mode 100644 index 0000000..f3197db Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11387_btn-export.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11403_btn-bundle.png b/docs/sw/figma-additional/screenshots/26-11403_btn-bundle.png new file mode 100644 index 0000000..58a6938 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11403_btn-bundle.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11416_btn-find-open.png b/docs/sw/figma-additional/screenshots/26-11416_btn-find-open.png new file mode 100644 index 0000000..4c4eab9 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11416_btn-find-open.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11450_btn-recent.png b/docs/sw/figma-additional/screenshots/26-11450_btn-recent.png new file mode 100644 index 0000000..2292127 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11450_btn-recent.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11485_btn-new-file.png b/docs/sw/figma-additional/screenshots/26-11485_btn-new-file.png new file mode 100644 index 0000000..7413ef6 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11485_btn-new-file.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11507_btn-recover.png b/docs/sw/figma-additional/screenshots/26-11507_btn-recover.png new file mode 100644 index 0000000..50a2f19 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11507_btn-recover.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11529_btn-temp-file.png b/docs/sw/figma-additional/screenshots/26-11529_btn-temp-file.png new file mode 100644 index 0000000..ad8b87f Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11529_btn-temp-file.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11542_btn-display.png b/docs/sw/figma-additional/screenshots/26-11542_btn-display.png new file mode 100644 index 0000000..74ce37f Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11542_btn-display.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11558_btn-setting-save.png b/docs/sw/figma-additional/screenshots/26-11558_btn-setting-save.png new file mode 100644 index 0000000..252929d Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11558_btn-setting-save.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11586_btn-setting-load.png b/docs/sw/figma-additional/screenshots/26-11586_btn-setting-load.png new file mode 100644 index 0000000..f315d4e Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11586_btn-setting-load.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11599_btn-help.png b/docs/sw/figma-additional/screenshots/26-11599_btn-help.png new file mode 100644 index 0000000..f797136 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11599_btn-help.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11615_btn-inquiry.png b/docs/sw/figma-additional/screenshots/26-11615_btn-inquiry.png new file mode 100644 index 0000000..8288ee8 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11615_btn-inquiry.png differ diff --git a/docs/sw/figma-additional/screenshots/26-11631_btn-sw-info.png b/docs/sw/figma-additional/screenshots/26-11631_btn-sw-info.png new file mode 100644 index 0000000..7855e9e Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-11631_btn-sw-info.png differ diff --git a/docs/sw/figma-additional/screenshots/26-12604_tit-working-file.png b/docs/sw/figma-additional/screenshots/26-12604_tit-working-file.png new file mode 100644 index 0000000..437d007 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-12604_tit-working-file.png differ diff --git a/docs/sw/figma-additional/screenshots/26-12610_tit-open-other.png b/docs/sw/figma-additional/screenshots/26-12610_tit-open-other.png new file mode 100644 index 0000000..1c16c83 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-12610_tit-open-other.png differ diff --git a/docs/sw/figma-additional/screenshots/26-12616_tit-curious.png b/docs/sw/figma-additional/screenshots/26-12616_tit-curious.png new file mode 100644 index 0000000..b239023 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-12616_tit-curious.png differ diff --git a/docs/sw/figma-additional/screenshots/26-12622_tit-file-damaged.png b/docs/sw/figma-additional/screenshots/26-12622_tit-file-damaged.png new file mode 100644 index 0000000..ed3e869 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/26-12622_tit-file-damaged.png differ diff --git a/docs/sw/figma-additional/screenshots/662-67267_home-on-popup-guide.png b/docs/sw/figma-additional/screenshots/662-67267_home-on-popup-guide.png new file mode 100644 index 0000000..efebf12 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/662-67267_home-on-popup-guide.png differ diff --git a/docs/sw/figma-additional/screenshots/662-67331_recent-files.png b/docs/sw/figma-additional/screenshots/662-67331_recent-files.png new file mode 100644 index 0000000..ab32fa6 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/662-67331_recent-files.png differ diff --git a/docs/sw/figma-additional/screenshots/662-67471_file-preview-2depth.png b/docs/sw/figma-additional/screenshots/662-67471_file-preview-2depth.png new file mode 100644 index 0000000..8e9f208 Binary files /dev/null and b/docs/sw/figma-additional/screenshots/662-67471_file-preview-2depth.png differ diff --git a/docs/sw/figma-additional/stage2-qa/compare-left-2x.png b/docs/sw/figma-additional/stage2-qa/compare-left-2x.png new file mode 100644 index 0000000..4dffb69 Binary files /dev/null and b/docs/sw/figma-additional/stage2-qa/compare-left-2x.png differ diff --git a/docs/sw/figma-additional/stage2-qa/compare-property-bar-2x.png b/docs/sw/figma-additional/stage2-qa/compare-property-bar-2x.png new file mode 100644 index 0000000..4b59c55 Binary files /dev/null and b/docs/sw/figma-additional/stage2-qa/compare-property-bar-2x.png differ diff --git a/docs/sw/figma-additional/stage2-qa/compare-recent-files.png b/docs/sw/figma-additional/stage2-qa/compare-recent-files.png new file mode 100644 index 0000000..17fa71c Binary files /dev/null and b/docs/sw/figma-additional/stage2-qa/compare-recent-files.png differ diff --git a/docs/sw/figma-additional/stage2-qa/compare-right-2x.png b/docs/sw/figma-additional/stage2-qa/compare-right-2x.png new file mode 100644 index 0000000..30bdd66 Binary files /dev/null and b/docs/sw/figma-additional/stage2-qa/compare-right-2x.png differ diff --git a/docs/sw/figma-additional/stage2-qa/react19-consumer.png b/docs/sw/figma-additional/stage2-qa/react19-consumer.png new file mode 100644 index 0000000..7438580 Binary files /dev/null and b/docs/sw/figma-additional/stage2-qa/react19-consumer.png differ diff --git a/docs/sw/figma-additional/stage2-qa/responsive-1080.png b/docs/sw/figma-additional/stage2-qa/responsive-1080.png new file mode 100644 index 0000000..10a3920 Binary files /dev/null and b/docs/sw/figma-additional/stage2-qa/responsive-1080.png differ diff --git a/docs/sw/figma-additional/stage2-qa/responsive-1920.png b/docs/sw/figma-additional/stage2-qa/responsive-1920.png new file mode 100644 index 0000000..3ffbe26 Binary files /dev/null and b/docs/sw/figma-additional/stage2-qa/responsive-1920.png differ diff --git a/docs/sw/figma-additional/stage2-qa/responsive-390.png b/docs/sw/figma-additional/stage2-qa/responsive-390.png new file mode 100644 index 0000000..7d4e65c Binary files /dev/null and b/docs/sw/figma-additional/stage2-qa/responsive-390.png differ diff --git a/docs/sw/figma-additional/stage2-report.md b/docs/sw/figma-additional/stage2-report.md new file mode 100644 index 0000000..8e3b3af --- /dev/null +++ b/docs/sw/figma-additional/stage2-report.md @@ -0,0 +1,129 @@ +# 작업 B 2단계 — 로고 클릭 2단 Header 메뉴 구현·검증 보고 (2026-10-19) + +> 기준: 사용자 최종 정정(로고 클릭 = 2단 Header 메뉴, 기본 숨김, 재클릭 닫힘), [1단계 분석](./analysis-report.md), Figma `rj6wpsfk24lOWvWiVRAANP`. +> 범위: Task B worktree `claude/sw-figma-logo-menu-36832b`(HEAD `5faa1f1`)의 **신규 파일만** 수정했습니다. Task A 공유 파일은 수정하지 않았고, Commit·Push·Merge·Publish도 하지 않았습니다. + +## 0. 해석 변경 이력 + +| 시점 | 해석 | 최종 | +|---|---|---| +| 1단계 | 로고 클릭 → `home on` 2단 메뉴 overlay | **유지(최종 정정과 일치)** | +| 2단계 중간 요청 | 로고 클릭 → "파일 열기 창" | Figma 재확인 결과 앱 내부 UI이며 OS 파일 선택창 호출 구조가 아닙니다. 이후 사용자 최종 정정으로 2단 메뉴로 돌아왔습니다 | +| 재확인으로 바뀐 점 | 662:67267을 단순 "하단 강조 outline 변형"으로 본 것 | 실제로는 Figma 주석 **"최근파일" 상태 화면**입니다. 최근파일이 열려 메뉴 전체에 주황 외곽선이 생기고, 그 아래 최근파일 목록(662:67331)과 2뎁스 미리보기(662:67471)가 붙습니다. 두 노드는 요청한 21개 목록 밖이라 **선택 기능**(`panel` + `SWRecentFiles`)으로 구현했습니다 | + +## 1. 구현 컴포넌트 + +| 파일(모두 신규) | 내용 | +|---|---| +| `packages/sw/src/components/sw-home-menu/SWHomeMenu.tsx` | `SWHomeMenu`(메뉴·열림·Active·닫기·키보드), `SWHomeMenuSection`(제목 badge + 그룹), `SWHomeMenuItem`(80×46 타일, Default / Variant2 / Variant3), `useSWHomeMenuClose` | +| `…/sw-home-menu/SWRecentFiles.tsx` | 선택 하위 패널: 최근파일 목록 354px, 행 50px, 2뎁스 미리보기 310×270 | +| `…/sw-home-menu/types.ts`, `index.ts` | 공개 타입·export | +| `…/sw-home-menu/assets/title-badge.svg` | Figma tit_* Union 도형(9-slice로 폭 가변) | +| `packages/sw/src/theme/sw-home-menu.css` | `.hm-sw-home-menu*`, `.hm-sw-recent-files*` 스타일과 `--hm-sw-home-menu-*`·`--hm-sw-recent-files-*` 토큰. 기존 SW 토큰(글꼴, 외곽선, focus, 행 Hover)을 그대로 읽습니다 | +| `src/sw/sw-home-menu.stories.tsx`, `sw-home-menu-fixture.tsx`, `sw-home-menu.css`, `src/sw/assets/home-menu/**` | Storybook `SW/Home Menu`(Figma 재현, Header 조합, 3 Variant, 데이터 변경, 단독, 최근파일, 속성Bar 비교, 비교 캔버스). Figma 아이콘 30개·미리보기 이미지는 **Story fixture 전용**입니다 | +| `docs/sw/figma-additional/ai-home-menu-guide.md`, `stage2-report.md`, `stage2-qa/**`, `screenshots/662-67331·662-67471` | AI 가이드 초안, 이 보고서, 검증 스크린샷 | + +## 2. Figma 노드 대응 (22 + 참고 3) + +| Node | 대응 | 상태 | +|---|---|---| +| 26:10492 속성Bar | 기존 `SWHeaderPropertyBar`(수정 없음). Story `속성Bar 비교`에서 Figma 값으로 비교 | 차이 3건은 통합 단계(§8) | +| 26:10591 home on | `SWHomeMenu` + `accent="auto"`(패널 없음 → 섹션별 강조) | 재현 | +| 662:67267 home on(최근파일 상태) | 최근파일 타일 Active + 패널 → `accent` 자동 외곽선. K 미리보기는 기존 `SWHeaderKGuide` Hover | 재현 | +| 26:12604 / 12610 / 12622 / 12616 (+26:12628 참고) | `SWHomeMenuSection.title` (badge 공통 1개) | 재현 | +| 26:11355 … 26:11631 버튼 세트 15개 | `SWHomeMenuItem` 1개 + Story 데이터 15건. Default / V2(Hover) / V3(Active) | 재현 | +| 662:67331 최근파일 / 662:67471 2뎁스 (참고) | `SWRecentFiles` (`panel`로 연결) | 재현(선택 기능) | + +## 3. 공개 API + +```ts +/) + open? defaultOpen?=false onOpenChange?(open, reason: "escape"|"background"|"outside"|"select"|"file") + activeIds? defaultActiveIds? onActiveChange?(ids, event) selection?: "multiple"|"single" + onItemSelect?(event) closeOnBackgroundClick?=true closeOnSelect?=false closeOnEscape?=true closeOnOutsideClick?=false + autoFocus?=true returnFocusRef? accent?: "auto"|"sections"|"outline" /> +SWHomeMenuItemData { id, label, icon?, hoverIcon?, toggle?=true, panel?, panelLabel?, disabled?, hidden?, title?, aria-label?, onSelect? } +SWHomeMenuSectionData { id, title, items, hidden? } + +SWFileEntry { id, name, path?, badge?, preview?, previewTitle?, disabled?, title? } +``` + +- 텍스트·아이콘·항목·이벤트·Active·하위 패널은 모두 외부 데이터입니다. 패키지에는 메뉴 항목이나 CAD 동작이 들어 있지 않습니다. +- 단독 사용: `` 안에 둡니다. 메뉴 밖에서 쓰는 `SWHomeMenuItem`도 `active`·`onActiveChange`로 동작합니다. +- Header 연동(통합 전): 기존 `SWHeader onHomeClick`으로 `open`을 토글합니다. 위치는 host가 Header DOM(객체 수정 영역 왼쪽 − 2px부터 창 영역 왼쪽까지)에서 측정합니다. + +## 4. Figma 디자인 일치 + +1x 캡처는 headless Chromium의 1920px 화면에서 Figma 스크린샷과 2배 확대로 비교했습니다(`stage2-qa/compare-*.png`). + +| 항목 | 결과 | +|---|---| +| 위치·크기 | 1920에서 메뉴 left 375, 폭 1305, 높이 77이며 섹션 폭은 340/260/180/260/261입니다. 그룹 46, 타일 80×46, 아이콘 18 슬롯(31,6), 라벨 top 25 **일치** | +| 색·gradient·그림자 | 섹션 면·안쪽 선, 그룹 테두리 gradient(위→아래)·면(아래→위)·그림자, 구분선, 주황 Hover 테두리, 하단 강조 2종 **일치**(Plugin API 값과 gradientTransform 방향 반영) | +| 아이콘 | Figma SVG 30개(Default·Hover)를 그대로 사용하고, 위치 보정 값은 fixture에 둠 **일치** | +| 최근파일·미리보기 | 354 폭, 행 50, 배경 `#27241D`, 주황 테두리, Hover 행 `#62533D` + `#FF5C00`, 미리보기 310×270 **일치**(DPR 1.5 화면에서는 테두리 반올림으로 269.3) | +| 의도된 차이 | 글꼴은 Dotum → Noto Sans KR이고, 타일 라벨·파일명은 700(기존 SW 정책)이라 Figma보다 굵습니다. 섹션 제목은 400이며 Figma보다 가늘고 badge가 7px 좁습니다(116.6 vs 124). 첫 섹션 면 gradient stop은 나머지 4개 기준으로 통일했습니다. 찾아열기·최근파일 구분선의 다른 gradient는 공통 구분선으로 통일했습니다 | +| Header 소유 차이 | home on의 1920 전폭 상·하단 `#5F4B0F` 2px 선은 Header 소유라 미구현(통합 검토) | + +## 5. 상태 전환·Overlay 테스트 (Storybook 6031, 실제 실행) + +| 테스트 | 결과 | +|---|---| +| 기본 숨김 | PASS (`hiddenByDefault: true`, consumer DOM에도 없음) | +| 로고 클릭 열기 / 재클릭 닫기 | PASS | +| Hover → V2 (실제 마우스) | PASS (테두리 opacity 1, `#FF5C00`, Hover 아이콘 표시, -1px 이동) | +| 클릭 → V3, 재클릭 → Default | PASS (`aria-pressed` true/false) | +| 메뉴 빈 곳 클릭 닫기 / Escape 닫기 + 로고 Focus 복귀 | PASS | +| ←/→/Home/End, Tab Focus 2px 윤곽선, Enter 실행 | PASS (실제 키 입력) | +| 최근파일: 열기 → 외곽선 강조, `aria-expanded`, 재클릭 닫기, ↓로 목록 진입, 행 Hover·Focus 미리보기, Enter/클릭 → `onFileOpen` + 메뉴 닫기, 다시 열면 Default | PASS | +| Escape 단계(패널 → 메뉴) | PASS | +| 데이터 변경(추가·삭제·숨김·disabled·긴 라벨·섹션 추가·single·accent) | PASS | +| 반응형 1920/1440/1080/768/390 | PASS: 로고·창 영역과 겹치지 않고 메뉴 안에서 가로 스크롤. 좁은 폭 접기 디자인은 없음(별도 승인) | +| 타입 | PASS: `tsc` SW 패키지, Story, 독립 consumer | +| 독립 React 19.3 consumer(Vite 빌드, 소스 import) | PASS: 렌더, 기본 숨김, CSS·SVG 번들 포함 | + +참고: 브라우저 pane은 background page라 ResizeObserver 측정을 할 수 없어, 반응형은 headless Chromium으로 확인했습니다. 메뉴 CSS를 `index.ts`에서만 import하면 `sideEffects` 설정 때문에 빌드에서 빠지는 것을 발견했고, 사용하는 컴포넌트 파일에서 import하도록 고쳤습니다. + +## 6. AI 재사용 + +[AI 가이드 초안](./ai-home-menu-guide.md) 기준입니다. 새 메뉴는 `sections` 데이터만으로 같은 스타일이 적용되고, 폭·구분선·모서리·badge 폭이 자동으로 계산됩니다. 소비 프로젝트에서 새 섹션 2개·항목 5개(currentColor 아이콘, `toggle:false`, 패널)를 만든 결과가 같은 스타일로 렌더링되는 것을 확인했습니다(`stage2-qa/react19-consumer.png`). AI 가이드를 `packages/sw/ai/`로 옮기는 작업은 통합 단계입니다. + +## 7. Task A와의 중복·충돌 + +| 항목 | 내용 | 조치 | +|---|---|---| +| `SWToolButton` (pill/text/document) | 80×46 타일 appearance가 없어 중복 구현은 아닙니다 | 통합 때 `tile` appearance로 합칠지 결정(별도 승인) | +| 아이콘 prop 이름 | A `hoverIcon` | B도 `hoverIcon`으로 맞춤 | +| 토글 상태 이름 | A `pressed` / B `active`·`activeIds` | 메뉴는 여러 항목 상태라 `activeIds` 유지. 통합 때 별칭 검토 | +| CSS | A `hm-sw-tool__*` / B `hm-sw-home-menu__*`, `hm-sw-recent-files__*` | 충돌 없음 | +| `documentOpenPlacement` | 사용자 최종 지시: 기본 `"menu"`(Open은 문서 Dropdown 안), 로고 옆 독립 Open 없음 | B 메뉴는 이 값과 무관합니다. B Story의 Header(5faa1f1)에는 독립 Open이 없습니다 | +| `leading` 슬롯 | 객체 수정 영역 시작 x가 바뀝니다 | B는 DOM 측정이라 하드코딩 없음 | +| 찾아열기·새파일 ↔ `onDocumentOpen`·`onDocumentNew` | 동작이 중복될 수 있습니다 | 컴포넌트는 콜백만 받습니다. host가 같은 handler를 연결하는 방식을 권장합니다(통합 문서에 기재) | + +## 8. 통합 시 수정할 공유 파일 + +| 파일 | 변경 | +|---|---| +| `packages/sw/src/index.ts` | `export * from "./components/sw-home-menu"` | +| `components/sw-header/SWHeader.tsx`, `types.ts` | (안) `homeMenu?: SWHomeMenuProps`, `homeMenuOpen`/`defaultHomeMenuOpen`/`onHomeMenuOpenChange`. 홈 버튼 `aria-expanded`·`aria-controls`, 객체 수정 영역 −2px ~ 창 영역 앵커, 열릴 때 다른 Dropdown 닫기, 기존 `onHomeClick` 유지(하위 호환) | +| `components/sw-header/components/SWHeaderHome.tsx` | 열림 상태 전달(시각 변화는 Figma에 없음) | +| `theme/sw.css` | 속성Bar P1 gradient 테두리, P2·P3 객체명·라벨 외곽선. home on 상·하단 `#5F4B0F` 선 적용 여부(검토) | +| `build.mjs`, `package.json` | 새 CSS가 `styles.css`에 포함되는지 확인(컴포넌트 import 방식이라 변경 불필요 예상, 미검증) | +| `packages/sw/ai/**`, `README.md`, `docs/sw/sw-header-usage.md` | AI 가이드 초안 반영 | +| 기존 stories | 필요하면 Header Overview에 메뉴 연결 | + +## 9. 판정 + +**PARTIAL** — 독립 구현과 검증은 PASS입니다. 다만 공유 파일 연동(공개 export, `SWHeader` 내장 연결, 속성Bar 수정)은 승인 범위상 통합 단계로 남았습니다. + +미검증 항목: +- 패키지 진입점(`@hm-design/sw`) export와 `build.mjs` dist의 `styles.css` 포함 여부. tarball 소비 검증도 하지 않았습니다(통합 단계). +- Task A 최신 Header(leading·documentOpenPlacement 반영본)와의 실제 조합. B는 5faa1f1 기준 Header로만 검증했습니다. +- Firefox·Safari 렌더링(Chromium만 확인). +- 속성Bar P1–P3를 수정한 뒤의 비교. +- 스크린리더 실제 낭독. + +검토 대상: V3의 의미(유지 토글 vs 순간 누름; 현재는 사용자 지시대로 유지 토글), 파일 열기 후 닫기 기본값, 최근파일 패널 열기 방식(Figma 연결 없음 → 클릭), 빈 목록 문구, 좁은 폭 디자인, Header 상·하단 선. + +로컬 검증 환경(커밋 대상 아님): worktree `node_modules` junction(→ HMDesign-SW), `.storybook-task-b/`(신규 Story만 로드하는 설정과 웹폰트 fs.allow), `.claude/launch.json`. 실행 중인 Storybook 포트는 6031입니다. 정리 여부는 사용자가 결정합니다. diff --git a/docs/sw/handover-2026-10-19.md b/docs/sw/handover-2026-10-19.md new file mode 100644 index 0000000..c2e758a --- /dev/null +++ b/docs/sw/handover-2026-10-19.md @@ -0,0 +1,81 @@ +# SW 패키지 인수인계 (2026-10-19) + +> PC 변경 후 `@hm-design/sw` 작업을 이어가기 위한 기록입니다. 아래 검증 결과는 기존 보고서의 기록이며, 이 문서 작성 시 다시 실행하지 않았습니다. + +## 1. 저장소와 브랜치 + +- 원격: `https://gitea.hmac.kr/b25027/HMDesign.git` (`origin`) +- 작업 브랜치: **`feature/sw-home-menu`** (이 문서 직전 Commit `3cfbfc0`, 원격과 동기화) +- 병합 대상: `feature/sw-package` (`b434f27`) — **아직 병합하지 않음(사용자 승인 대기)** +- 패키지 버전: `@hm-design/sw` 0.2.0 + +`feature/sw-package` 이후 `feature/sw-home-menu`에만 있는 Commit: + +| Commit | 내용 | +| --- | --- | +| `1472e51` | feat(sw): 홈 메뉴를 SWHeader에 통합(Task A + B) | +| `3a5e29f` | Merge `integration/sw-home-menu` → `feature/sw-home-menu` (충돌 해결, 일반 모드 전용 지침) | +| `3cfbfc0` | fix(sw): SW 팝업 본문 thin 스크롤바 | + +## 2. 완료 작업 + +- **홈(로고) 메뉴**: `SWHomeMenu` / `SWHomeMenuSection` / `SWHomeMenuItem` / `SWRecentFiles` Export, `SWHeader`의 `homeMenu` / `homeMenuOpen` / `defaultHomeMenuOpen` / `onHomeMenuOpenChange`. 기본 숨김, 로고 클릭으로 토글, Escape 스택·문서/필드 Dropdown과 상호 닫힘, 로고 `aria-expanded` / `aria-controls`. +- **적용 범위**: SW **일반 모드 전용**. 뷰어 모드(`SWViewer*`) 코드·Story는 변경하지 않았고 AI 지침에서 뷰어 모드 사용을 금지했습니다. +- **배치 보정**: `controls` 안에 파일명이 있을 때 메뉴가 파일명 오른쪽에서 시작합니다. +- **팝업 스크롤바**: `SWPopup`, `SWViewerPanel`, 속성 창이 공유하는 `.hm-sw-property__body`와 그 안의 스크롤 영역에 thin `#9A9284` / `#E0DACE` 적용(`--hm-sw-popup-scrollbar-thumb` / `-track`), `packages/sw/ai/DESIGN_RULES.md`에 기록. +- **AI 지침**: AI_USAGE, COMPONENT_CATALOG(§5 홈 메뉴, §9 뷰어), COMPOSITION_PATTERNS(8 홈 메뉴), DESIGN_RULES(§12 홈 메뉴), VIEWER.md, 공통 AI_GUIDE 갱신. +- **Storybook**: `SW/Home Menu`(공개 `@hm-design/sw` import 사용), 통합 Story. + +상세: [통합 보고서](sw-home-menu-integration-2026-10-19.md), [Merge 보고서](sw-home-menu-merge-2026-10-19.md). + +## 3. 검증 결과 (기존 기록) + +| 항목 | 결과 | 출처 | +| --- | --- | --- | +| SW typecheck / `tsc -b` / SW build / Storybook build | PASS | Merge 보고서 | +| AI 문서(`check:ai-docs`, `ai-docs.check.mjs`) | PASS / 32/32 | Merge 보고서 | +| 홈 메뉴 Storybook(`home-menu-integration.browser.mjs`) | 22/22 | Merge 보고서 | +| 기존 Header·Popup 기능 | 89/0 | Merge 보고서 | +| 뷰어 Story 기능(`viewer.browser.mjs`) | 70/70 | Merge 보고서 | +| Merge 전 대비 픽셀(Header·Popup 39장, 전체 Story 48장) | 동일 | Merge 보고서(배치 보정 전 측정) | +| 로컬 소비 앱(0.2.0 tarball) | typecheck·build PASS, 브라우저 14/14 | Merge 보고서 | +| 팝업 스크롤바(`3cfbfc0`) | **미검증** — 검증 기록 없음 | — | + +미검증(Merge 보고서 NOT VERIFIED 포함): + +- 배치 보정 이후 Header·Popup·Viewer 픽셀 회귀 재실행 +- Firefox·Safari, SW + HM UI CSS 동시 사용, Registry Publish, 독립 React 19 tarball 소비 설치 +- 참고 DWG/DXF 뷰어 대비 비교, 삭제된 `SW/Tool` 섹션 회귀 +- 팝업 스크롤바의 브라우저 표시 확인 + +## 4. 미완료 작업 + +1. `feature/sw-home-menu` → `feature/sw-package` 병합 (사용자 승인 후) +2. 팝업 스크롤바 시각 확인과 배치 보정 이후 픽셀 회귀 재실행 +3. 홈 메뉴 글자: Figma Dotum 14/12px vs HM Noto Sans KR — 디자인 승인 대기 +4. 소비 앱의 미연결 타일 12개(저장·내보내기 등)는 뷰어 앱에 기능이 없어 `toggle: false` 상태, 로고 이미지(`logoSrc`) 미지정 +5. 로컬 전용 WIP `wip/sw-header-composition-unverified`(`1b2c391`, 미검증 Header composition 초안)는 원격에 없음 — 필요 시 기존 PC에서 별도 Push + +## 5. 새 PC 설정 + +기존 환경: Node 22.x, npm 10.x, Git 2.5x, npm workspaces. + +```bash +git clone https://gitea.hmac.kr/b25027/HMDesign.git HMDesign +cd HMDesign +git switch feature/sw-home-menu +npm install +npm run storybook # http://localhost:6024 +``` + +자주 쓰는 명령: + +```bash +npm run typecheck -w @hm-design/sw +npm run build -w @hm-design/sw +npm run check:ai-docs +npm run build-storybook +``` + +- Commit은 기존 Git 사용자 정보로 작성하고 AI/Claude 서명(Co-Authored-By 등)을 넣지 않습니다. +- 작업 전 `CLAUDE.md`, `AGENTS.md`, `packages/sw/ai/` 지침과 위 보고서를 먼저 읽습니다. diff --git a/docs/sw/home-menu-action-buttons-qa-2026-10-19/1080-recent-active.png b/docs/sw/home-menu-action-buttons-qa-2026-10-19/1080-recent-active.png new file mode 100644 index 0000000..025192c Binary files /dev/null and b/docs/sw/home-menu-action-buttons-qa-2026-10-19/1080-recent-active.png differ diff --git a/docs/sw/home-menu-action-buttons-qa-2026-10-19/1080-text-after-clicks.png b/docs/sw/home-menu-action-buttons-qa-2026-10-19/1080-text-after-clicks.png new file mode 100644 index 0000000..3d15fdd Binary files /dev/null and b/docs/sw/home-menu-action-buttons-qa-2026-10-19/1080-text-after-clicks.png differ diff --git a/docs/sw/home-menu-action-buttons-qa-2026-10-19/1920-after-clicks.png b/docs/sw/home-menu-action-buttons-qa-2026-10-19/1920-after-clicks.png new file mode 100644 index 0000000..439e0e1 Binary files /dev/null and b/docs/sw/home-menu-action-buttons-qa-2026-10-19/1920-after-clicks.png differ diff --git a/docs/sw/home-menu-action-buttons-qa-2026-10-19/1920-recent-open.png b/docs/sw/home-menu-action-buttons-qa-2026-10-19/1920-recent-open.png new file mode 100644 index 0000000..4f65ee9 Binary files /dev/null and b/docs/sw/home-menu-action-buttons-qa-2026-10-19/1920-recent-open.png differ diff --git a/docs/sw/home-menu-action-buttons-qa-2026-10-19/report.json b/docs/sw/home-menu-action-buttons-qa-2026-10-19/report.json new file mode 100644 index 0000000..c9e34bf --- /dev/null +++ b/docs/sw/home-menu-action-buttons-qa-2026-10-19/report.json @@ -0,0 +1,219 @@ +{ + "checks": [ + { + "name": "1920 tiles: 14 action tiles — no Active / aria-pressed / ring after the click", + "ok": true, + "data": [] + }, + { + "name": "Hover kept: Variant2 (ring + #FF5C00) while the pointer is on the tile", + "ok": true, + "data": { + "active": null, + "pressed": null, + "expanded": null, + "mark": "\"\"", + "ring": "1", + "color": "rgb(255, 92, 0)", + "bg": "rgba(0, 0, 0, 0)" + } + }, + { + "name": "Pressed: Variant3 only while held (Space down), Default after release", + "ok": true, + "data": { + "held": { + "active": null, + "pressed": null, + "expanded": null, + "mark": "\"\"", + "ring": "1", + "color": "rgb(255, 92, 0)", + "bg": "rgba(0, 0, 0, 0)" + }, + "released": { + "active": null, + "pressed": null, + "expanded": null, + "mark": "\"\"", + "ring": "0", + "color": "rgb(246, 244, 242)", + "bg": "rgba(0, 0, 0, 0)" + } + } + }, + { + "name": "최근파일 tile: Variant3 (Active, aria-expanded) while the list is open; re-click closes list and Active", + "ok": true, + "data": { + "rOpen": { + "tile": { + "active": "true", + "pressed": null, + "expanded": "true", + "mark": "\"\"", + "ring": "1", + "color": "rgb(255, 92, 0)", + "bg": "rgba(0, 0, 0, 0)" + }, + "list": true + }, + "rClosed": { + "tile": { + "active": null, + "pressed": null, + "expanded": "false", + "mark": "\"\"", + "ring": "0", + "color": "rgb(246, 244, 242)", + "bg": "rgba(0, 0, 0, 0)" + }, + "list": false + } + } + }, + { + "name": "최근파일: Escape closes the list → Active off", + "ok": true, + "data": { + "tile": { + "active": null, + "pressed": null, + "expanded": "false", + "mark": "\"\"", + "ring": "0", + "color": "rgb(246, 244, 242)", + "bg": "rgba(0, 0, 0, 0)" + }, + "list": false + } + }, + { + "name": "최근파일: opening a file closes the menu; reopening starts with 최근파일 off", + "ok": true, + "data": { + "afterFile": false, + "reopened": { + "active": null, + "pressed": null, + "expanded": "false", + "mark": "\"\"", + "ring": "0", + "color": "rgb(246, 244, 242)", + "bg": "rgba(0, 0, 0, 0)" + } + } + }, + { + "name": "home button keeps Home On while the menu is open", + "ok": true, + "data": true + }, + { + "name": "More tile keeps its Variant3 while its dropdown is open", + "ok": true, + "data": { + "active": "true", + "ring": "1", + "expanded": "true" + } + }, + { + "name": "1080 More text menu: 10 action rows — no Active, no ✓, no brown row after the click (dropdown stays open)", + "ok": true, + "data": { + "rowLeft": [], + "stillOpen": true + } + }, + { + "name": "text row Hover kept (#62533D + #FF5C00)", + "ok": true, + "data": { + "active": null, + "pressed": null, + "expanded": null, + "mark": "\"\"", + "ring": null, + "color": "rgb(255, 92, 0)", + "bg": "rgb(98, 83, 61)" + } + }, + { + "name": "text row Pressed only while held, nothing after release", + "ok": true, + "data": { + "rowHeld": { + "active": null, + "pressed": null, + "expanded": null, + "mark": "\"\"", + "ring": null, + "color": "rgb(255, 92, 0)", + "bg": "rgb(98, 83, 61)" + }, + "rowReleased": { + "active": null, + "pressed": null, + "expanded": null, + "mark": "\"\"", + "ring": null, + "color": "rgb(246, 244, 242)", + "bg": "rgba(0, 0, 0, 0)" + } + } + }, + { + "name": "최근파일 row: list opens; More stays Variant3; reopened dropdown shows 최근파일 Active with › (no ✓)", + "ok": true, + "data": { + "listOpen": true, + "moreWhileList": "true", + "rRow": { + "active": "true", + "pressed": null, + "expanded": "true", + "mark": "\"›\"", + "ring": null, + "color": "rgb(255, 92, 0)", + "bg": "rgb(98, 83, 61)" + } + } + }, + { + "name": "Escape (dropdown, then list): list closed → 최근파일 row and More off", + "ok": true, + "data": { + "rAfter": { + "list": false, + "more": null + }, + "rRow2": { + "active": null, + "pressed": null, + "expanded": "false", + "mark": "\"›\"", + "ring": null, + "color": "rgb(246, 244, 242)", + "bg": "rgba(0, 0, 0, 0)" + } + } + }, + { + "name": "More tile off once its dropdown and the list are closed", + "ok": true, + "data": null + }, + { + "name": "callbacks: action tile / text row → onItemSelect(active=false) without onActiveChange; 최근파일 → onActiveChange([recent]) + onItemSelect(active=true)", + "ok": true, + "data": "onItemSelect(open / recent, active=true)\nonActiveChange([recent])\nonItemSelect(setting / display, active=false)\nonItemSelect(working / save, active=false)\nonHomeMenuOpenChange(true, home)" + }, + { + "name": "no page errors", + "ok": true, + "data": [] + } + ], + "errors": [] +} \ No newline at end of file diff --git a/docs/sw/home-menu-integration-qa/baseline-improvement/integrated-improvement-result.json b/docs/sw/home-menu-integration-qa/baseline-improvement/integrated-improvement-result.json new file mode 100644 index 0000000..a4c6cad --- /dev/null +++ b/docs/sw/home-menu-integration-qa/baseline-improvement/integrated-improvement-result.json @@ -0,0 +1,1286 @@ +{ + "browser": "155.0.8059.80", + "checks": [ + { + "name": "menu (default): no Open next to the logo", + "status": "PASS" + }, + { + "name": "menu (default): dropdown footer keeps + New and Open", + "status": "PASS" + }, + { + "name": "header: Open takes the file name place right of the logo (same junction offset, 48px)", + "status": "PASS", + "data": { + "home": { + "x": 360, + "y": 851.5, + "w": 80, + "h": 48, + "right": 440 + }, + "openBox": { + "x": 425, + "y": 851.5, + "w": 58.265625, + "h": 48, + "right": 483.265625 + }, + "junction": -15 + } + }, + { + "name": "header: file name follows Open without overlap", + "status": "PASS", + "data": { + "openBox": { + "x": 425, + "y": 851.5, + "w": 58.265625, + "h": 48, + "right": 483.265625 + }, + "docBox": { + "x": 485.265625, + "y": 851.5, + "w": 249.734375, + "h": 48, + "right": 735 + } + } + }, + { + "name": "header: Open uses hm-sw-header__document-button (same surface, color, weight as the file name)", + "status": "PASS", + "data": { + "styles": { + "cls": "hm-sw-header__document-button", + "bg": "linear-gradient(rgb(8, 24, 19) 0%, rgb(9", + "color": "rgb(240, 247, 245)", + "weight": "700", + "padL": "5px", + "borderL": "0px", + "borderR": "1px" + }, + "fileStyles": { + "bg": "linear-gradient(rgb(8, 24, 19) 0%, rgb(9", + "color": "rgb(240, 247, 245)", + "weight": "700", + "padL": "12px" + } + } + }, + { + "name": "D-1: file name after Open starts with 12px padding", + "status": "PASS", + "data": { + "bg": "linear-gradient(rgb(8, 24, 19) 0%, rgb(9", + "color": "rgb(240, 247, 245)", + "weight": "700", + "padL": "12px" + } + }, + { + "name": "header: Open hover turns only the text #FFC600", + "status": "PASS" + }, + { + "name": "header: dropdown footer has + New only (no duplicate Open)", + "status": "PASS" + }, + { + "name": "header: Open calls onDocumentOpen", + "status": "PASS" + }, + { + "name": "documentOpenLabel is the Open text", + "status": "PASS" + }, + { + "name": "responsive 1920: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 2280, + "barRight": 2280, + "overlap": false, + "open": 58.265625, + "doc": 249.734375, + "layer": 234, + "more": false + } + }, + { + "name": "responsive 1920: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 1920: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 1800: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 2160, + "barRight": 2160, + "overlap": false, + "open": 58.265625, + "doc": 190, + "layer": 234, + "more": false + } + }, + { + "name": "responsive 1800: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 1800: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 1440: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1800, + "barRight": 1800, + "overlap": false, + "open": 58.265625, + "doc": 310, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 1440: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 1440: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 1180: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1540, + "barRight": 1540, + "overlap": false, + "open": 58.265625, + "doc": 120, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 1180: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 1180: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 1080: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1440, + "barRight": 1440, + "overlap": false, + "open": 58.265625, + "doc": 120, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 1080: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 1080: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 900: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 1260, + "barRight": 1260, + "overlap": false, + "open": 58.265625, + "doc": 120, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 900: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 900: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 768: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 1128, + "barRight": 1128, + "overlap": false, + "open": 58.265625, + "doc": 178.734375, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 768: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 768: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 640: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1000, + "barRight": 1000, + "overlap": false, + "open": 58.265625, + "doc": 96, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 640: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 640: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 520: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 880, + "barRight": 880, + "overlap": false, + "open": 0, + "doc": 103, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 520: Open moved into More and works there", + "status": "PASS", + "data": { + "open": 0, + "inMore": true + } + }, + { + "name": "responsive 520: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 390: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 750, + "barRight": 750, + "overlap": false, + "open": 0, + "doc": 96, + "layer": 113, + "more": true + } + }, + { + "name": "responsive 390: Open moved into More and works there", + "status": "PASS", + "data": { + "open": 0, + "inMore": true + } + }, + { + "name": "resize: collapsed Open returns once when the header grows (measured, with hysteresis)", + "status": "PASS", + "data": [ + [ + 520, + 0 + ], + [ + 560, + 0 + ], + [ + 600, + 1 + ], + [ + 640, + 1 + ], + [ + 680, + 1 + ], + [ + 720, + 1 + ], + [ + 760, + 1 + ], + [ + 820, + 1 + ], + [ + 900, + 1 + ], + [ + 1080, + 1 + ] + ] + }, + { + "name": "hidden documentNew: footer keeps Open on its right side", + "status": "PASS", + "data": { + "footer": { + "x": 424, + "y": 442.5, + "w": 310, + "h": 40, + "right": 734 + }, + "action": { + "x": 675.96875, + "y": 451, + "w": 50.03125, + "h": 24, + "right": 726 + } + } + }, + { + "name": "hidden documentNew + documentOpen: no footer", + "status": "PASS" + }, + { + "name": "hidden layerFreeze / layerLock: field draws the bulb only, two empty 20px places", + "status": "PASS", + "data": [ + { + "empty": false, + "w": 20 + }, + { + "empty": true, + "w": 20 + }, + { + "empty": true, + "w": 20 + } + ] + }, + { + "name": "hidden layerFreeze / layerLock: rows have no snowflake / lock button, places kept", + "status": "PASS", + "data": [ + { + "buttons": [ + "hm-sw-header__layer-toggle--visibility", + "hm-sw-header__layer-item" + ], + "empty": 2, + "name": 931 + }, + { + "buttons": [ + "hm-sw-header__layer-toggle--visibility", + "hm-sw-header__layer-item" + ], + "empty": 2, + "name": 931 + }, + { + "buttons": [ + "hm-sw-header__layer-toggle--visibility", + "hm-sw-header__layer-item" + ], + "empty": 2, + "name": 931 + } + ] + }, + { + "name": "hidden layer states: the bulb still reports its callback", + "status": "PASS" + }, + { + "name": "composed: Open right of the logo at the same junction offset as SWHeader", + "status": "PASS", + "data": { + "cHome": { + "x": 360, + "y": 6118.5, + "w": 80, + "h": 48, + "right": 440 + }, + "cOpen": { + "x": 425, + "y": 6118.5, + "w": 58.265625, + "h": 48, + "right": 483.265625 + } + } + }, + { + "name": "composed: file name after Open has 12px padding", + "status": "PASS" + }, + { + "name": "composed: Open callback", + "status": "PASS" + }, + { + "name": "composed: showOpen={false} removes Open from the dropdown", + "status": "PASS" + }, + { + "name": "composed responsive 1920: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 1800: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 1440: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 1180: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 1080: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 900: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 768: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 768: 파일 열기 reachable in More", + "status": "PASS" + }, + { + "name": "composed responsive 640: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 640: 파일 열기 reachable in More", + "status": "PASS" + }, + { + "name": "composed responsive 520: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 520: 파일 열기 reachable in More", + "status": "PASS" + }, + { + "name": "composed responsive 390: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 390: 파일 열기 reachable in More", + "status": "PASS" + }, + { + "name": "tool: Model / Layout is a radio group", + "status": "PASS" + }, + { + "name": "tool: arrow key moves focus and selects Layout", + "status": "PASS" + }, + { + "name": "tool: 2.5D toggle reports and shows pressed (#FFC600)", + "status": "PASS" + }, + { + "name": "tool: text buttons are the 속성Bar toggle look (700, 19px row, 12px caption)", + "status": "PASS", + "data": { + "text": { + "weight": "700", + "h": 19 + }, + "ref": "12px" + } + }, + { + "name": "tool: pill button is 40 x 38 with the yellow ring and hover icon", + "status": "PASS", + "data": { + "pillBox": { + "x": 1467.234375, + "y": 336, + "w": 40, + "h": 38, + "right": 1507.234375 + }, + "hover": { + "ring": "1", + "icon": "hidden", + "hoverIcon": "visible" + } + } + }, + { + "name": "tool: pill click callback", + "status": "PASS" + }, + { + "name": "tool: pill accessible name from its text", + "status": "PASS" + }, + { + "name": "tool: document look keeps the logo junction in a composed bar", + "status": "PASS", + "data": { + "tHome": { + "x": 360, + "y": 491.5, + "w": 80, + "h": 48, + "right": 440 + }, + "tOpen": { + "x": 425, + "y": 491.5, + "w": 58.265625, + "h": 48, + "right": 483.265625 + } + } + }, + { + "name": "popup: SWPopup frames match the property window frame (314, surface, border, radius, title)", + "status": "PASS", + "data": [ + { + "w": 314, + "bg": "rgb(228, 219, 201)", + "border": "rgb(166, 125, 3)", + "radius": "4px", + "shadow": "rgb(0, 0, 0) 0px 0px 0px 1px inset", + "title": "rgb(255, 198, 0)", + "weight": "700", + "titlebar": 30, + "role": "dialog", + "modal": "false" + }, + { + "w": 314, + "bg": "rgb(228, 219, 201)", + "border": "rgb(166, 125, 3)", + "radius": "4px", + "shadow": "rgb(0, 0, 0) 0px 0px 0px 1px inset", + "title": "rgb(255, 198, 0)", + "weight": "700", + "titlebar": 30, + "role": "dialog", + "modal": "false" + }, + { + "w": 314, + "bg": "rgb(228, 219, 201)", + "border": "rgb(166, 125, 3)", + "radius": "4px", + "shadow": "rgb(0, 0, 0) 0px 0px 0px 1px inset", + "title": "rgb(255, 198, 0)", + "weight": "700", + "titlebar": 30, + "role": "dialog", + "modal": "false" + } + ] + }, + { + "name": "popup content: SWHeaderInput rows commit through the host callbacks", + "status": "PASS" + }, + { + "name": "popup content: SWPopupRow is the property row (72px label, 32px row, 28px box)", + "status": "PASS", + "data": { + "label": "72px", + "minH": "32px", + "box": "28px" + } + }, + { + "name": "popup content: HM UI Switch works inside", + "status": "PASS" + }, + { + "name": "popup content: HM UI Select (portal) works inside", + "status": "PASS" + }, + { + "name": "popup content: HM UI Slider works inside", + "status": "PASS", + "data": "Callback: name=평면도-02 → scale=50 → snap=false → unit=cm → opacity=70" + }, + { + "name": "popup content: HM UI Button works inside", + "status": "PASS" + }, + { + "name": "popup dropdown: SW layer dropdown opens right under its field (fixed overlay) and is not clipped", + "status": "PASS", + "data": { + "fieldBox": { + "x": 387, + "y": 548.5, + "w": 234, + "h": 38, + "right": 621 + }, + "menuBox": { + "x": 387, + "y": 586.5, + "w": 234, + "h": 160, + "right": 621 + }, + "hit": true + } + }, + { + "name": "popup dropdown: selection callback, list closes, popup stays", + "status": "PASS" + }, + { + "name": "popup dropdown: SW color dropdown becomes a fixed overlay", + "status": "PASS" + }, + { + "name": "popup dropdown: color chip callback", + "status": "PASS" + }, + { + "name": "popup dropdown: Escape closes the dropdown only", + "status": "PASS" + }, + { + "name": "object popup: read-only rows", + "status": "PASS" + }, + { + "name": "object popup: number row commits", + "status": "PASS" + }, + { + "name": "object popup: compact row uses the 41px hug field", + "status": "PASS", + "data": { + "cls": "hm-sw-header__input hm-sw-property__compact", + "w": 26.53125 + } + }, + { + "name": "property panel + children: children follow the property groups in the same body", + "status": "PASS", + "data": [ + "공통", + "메모" + ] + }, + { + "name": "property panel + children: child content callback", + "status": "PASS" + }, + { + "name": "popup: close button calls onClose", + "status": "PASS" + }, + { + "name": "short popup: dropdown extends past the popup and stays fully visible (no clipping)", + "status": "PASS", + "data": { + "bBox": { + "x": 706, + "y": 264.5, + "w": 314, + "h": 110, + "right": 1020 + }, + "menuB": { + "x": 717, + "y": 363.5, + "w": 234, + "h": 160, + "right": 951 + }, + "bHit": true + } + }, + { + "name": "several popups: Escape in a dropdown closes only the dropdown", + "status": "PASS" + }, + { + "name": "several popups: Escape on an edited input cancels the edit only", + "status": "PASS" + }, + { + "name": "several popups: Escape inside a popup closes that popup only", + "status": "PASS", + "data": "Callback: close(a)" + }, + { + "name": "several popups: Escape outside closes only the top popup (last used: B)", + "status": "PASS", + "data": "Callback: close(a) → close(b)" + }, + { + "name": "several popups: the popup used last becomes the top", + "status": "PASS", + "data": "Callback: close(a) → close(b) → close(a)" + }, + { + "name": "long content: the body scrolls inside the frame and the last row is reachable", + "status": "PASS", + "data": { + "scroll": { + "sh": 1000, + "ch": 328, + "overflow": "auto" + }, + "lastVisible": true + } + }, + { + "name": "no browser console or page errors", + "status": "PASS", + "data": [] + } + ], + "errors": [], + "data": { + "junction": -15, + "responsive": [ + { + "width": 1920, + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 2280, + "barRight": 2280, + "overlap": false, + "open": 58.265625, + "doc": 249.734375, + "layer": 234, + "more": false, + "inMore": null + }, + { + "width": 1800, + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 2160, + "barRight": 2160, + "overlap": false, + "open": 58.265625, + "doc": 190, + "layer": 234, + "more": false, + "inMore": null + }, + { + "width": 1440, + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1800, + "barRight": 1800, + "overlap": false, + "open": 58.265625, + "doc": 310, + "layer": 234, + "more": true, + "inMore": null + }, + { + "width": 1180, + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1540, + "barRight": 1540, + "overlap": false, + "open": 58.265625, + "doc": 120, + "layer": 234, + "more": true, + "inMore": null + }, + { + "width": 1080, + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1440, + "barRight": 1440, + "overlap": false, + "open": 58.265625, + "doc": 120, + "layer": 234, + "more": true, + "inMore": null + }, + { + "width": 900, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 1260, + "barRight": 1260, + "overlap": false, + "open": 58.265625, + "doc": 120, + "layer": 234, + "more": true, + "inMore": null + }, + { + "width": 768, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 1128, + "barRight": 1128, + "overlap": false, + "open": 58.265625, + "doc": 178.734375, + "layer": 234, + "more": true, + "inMore": null + }, + { + "width": 640, + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1000, + "barRight": 1000, + "overlap": false, + "open": 58.265625, + "doc": 96, + "layer": 234, + "more": true, + "inMore": null + }, + { + "width": 520, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 880, + "barRight": 880, + "overlap": false, + "open": 0, + "doc": 103, + "layer": 234, + "more": true, + "inMore": true + }, + { + "width": 390, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 750, + "barRight": 750, + "overlap": false, + "open": 0, + "doc": 96, + "layer": 113, + "more": true, + "inMore": true + } + ], + "hysteresis": [ + [ + 520, + 0 + ], + [ + 560, + 0 + ], + [ + 600, + 1 + ], + [ + 640, + 1 + ], + [ + 680, + 1 + ], + [ + 720, + 1 + ], + [ + 760, + 1 + ], + [ + 820, + 1 + ], + [ + 900, + 1 + ], + [ + 1080, + 1 + ] + ], + "composedResponsive": [ + { + "width": 1920, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + }, + { + "width": 1800, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + }, + { + "width": 1440, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + }, + { + "width": 1180, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + }, + { + "width": 1080, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + }, + { + "width": 900, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + }, + { + "width": 768, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + }, + { + "width": 640, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + }, + { + "width": 520, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + }, + { + "width": 390, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + } + ], + "popupFrames": [ + { + "w": 314, + "bg": "rgb(228, 219, 201)", + "border": "rgb(166, 125, 3)", + "radius": "4px", + "shadow": "rgb(0, 0, 0) 0px 0px 0px 1px inset", + "title": "rgb(255, 198, 0)", + "weight": "700", + "titlebar": 30, + "role": "dialog", + "modal": "false" + }, + { + "w": 314, + "bg": "rgb(228, 219, 201)", + "border": "rgb(166, 125, 3)", + "radius": "4px", + "shadow": "rgb(0, 0, 0) 0px 0px 0px 1px inset", + "title": "rgb(255, 198, 0)", + "weight": "700", + "titlebar": 30, + "role": "dialog", + "modal": "false" + }, + { + "w": 314, + "bg": "rgb(228, 219, 201)", + "border": "rgb(166, 125, 3)", + "radius": "4px", + "shadow": "rgb(0, 0, 0) 0px 0px 0px 1px inset", + "title": "rgb(255, 198, 0)", + "weight": "700", + "titlebar": 30, + "role": "dialog", + "modal": "false" + } + ] + }, + "status": "PASS" +} diff --git a/docs/sw/home-menu-integration-qa/baseline-visual/capture.json b/docs/sw/home-menu-integration-qa/baseline-visual/capture.json new file mode 100644 index 0000000..7454952 --- /dev/null +++ b/docs/sw/home-menu-integration-qa/baseline-visual/capture.json @@ -0,0 +1,34 @@ +{ + "browser": "155.0.8059.80", + "shots": [ + "overview-1920.png", + "detail-buttons-1920.png", + "interactive-states-1920.png", + "window-move-motion-1920.png", + "logo-slot-1920.png", + "document-dropdown-1920.png", + "responsive-more-1920.png", + "k-guide-1920.png", + "property-panel-compare-1920.png", + "composed-controls-1920.png", + "overview-1800.png", + "overview-1440.png", + "overview-1180.png", + "overview-1080.png", + "overview-900.png", + "overview-768.png", + "overview-640.png", + "overview-520.png", + "overview-390.png", + "responsive-more-1800.png", + "responsive-more-1440.png", + "responsive-more-1180.png", + "responsive-more-1080.png", + "responsive-more-900.png", + "responsive-more-768.png", + "responsive-more-640.png", + "responsive-more-520.png", + "responsive-more-390.png" + ], + "errors": [] +} \ No newline at end of file diff --git a/docs/sw/home-menu-integration-qa/final-improvement/integrated-improvement-result.json b/docs/sw/home-menu-integration-qa/final-improvement/integrated-improvement-result.json new file mode 100644 index 0000000..a4c6cad --- /dev/null +++ b/docs/sw/home-menu-integration-qa/final-improvement/integrated-improvement-result.json @@ -0,0 +1,1286 @@ +{ + "browser": "155.0.8059.80", + "checks": [ + { + "name": "menu (default): no Open next to the logo", + "status": "PASS" + }, + { + "name": "menu (default): dropdown footer keeps + New and Open", + "status": "PASS" + }, + { + "name": "header: Open takes the file name place right of the logo (same junction offset, 48px)", + "status": "PASS", + "data": { + "home": { + "x": 360, + "y": 851.5, + "w": 80, + "h": 48, + "right": 440 + }, + "openBox": { + "x": 425, + "y": 851.5, + "w": 58.265625, + "h": 48, + "right": 483.265625 + }, + "junction": -15 + } + }, + { + "name": "header: file name follows Open without overlap", + "status": "PASS", + "data": { + "openBox": { + "x": 425, + "y": 851.5, + "w": 58.265625, + "h": 48, + "right": 483.265625 + }, + "docBox": { + "x": 485.265625, + "y": 851.5, + "w": 249.734375, + "h": 48, + "right": 735 + } + } + }, + { + "name": "header: Open uses hm-sw-header__document-button (same surface, color, weight as the file name)", + "status": "PASS", + "data": { + "styles": { + "cls": "hm-sw-header__document-button", + "bg": "linear-gradient(rgb(8, 24, 19) 0%, rgb(9", + "color": "rgb(240, 247, 245)", + "weight": "700", + "padL": "5px", + "borderL": "0px", + "borderR": "1px" + }, + "fileStyles": { + "bg": "linear-gradient(rgb(8, 24, 19) 0%, rgb(9", + "color": "rgb(240, 247, 245)", + "weight": "700", + "padL": "12px" + } + } + }, + { + "name": "D-1: file name after Open starts with 12px padding", + "status": "PASS", + "data": { + "bg": "linear-gradient(rgb(8, 24, 19) 0%, rgb(9", + "color": "rgb(240, 247, 245)", + "weight": "700", + "padL": "12px" + } + }, + { + "name": "header: Open hover turns only the text #FFC600", + "status": "PASS" + }, + { + "name": "header: dropdown footer has + New only (no duplicate Open)", + "status": "PASS" + }, + { + "name": "header: Open calls onDocumentOpen", + "status": "PASS" + }, + { + "name": "documentOpenLabel is the Open text", + "status": "PASS" + }, + { + "name": "responsive 1920: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 2280, + "barRight": 2280, + "overlap": false, + "open": 58.265625, + "doc": 249.734375, + "layer": 234, + "more": false + } + }, + { + "name": "responsive 1920: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 1920: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 1800: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 2160, + "barRight": 2160, + "overlap": false, + "open": 58.265625, + "doc": 190, + "layer": 234, + "more": false + } + }, + { + "name": "responsive 1800: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 1800: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 1440: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1800, + "barRight": 1800, + "overlap": false, + "open": 58.265625, + "doc": 310, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 1440: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 1440: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 1180: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1540, + "barRight": 1540, + "overlap": false, + "open": 58.265625, + "doc": 120, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 1180: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 1180: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 1080: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1440, + "barRight": 1440, + "overlap": false, + "open": 58.265625, + "doc": 120, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 1080: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 1080: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 900: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 1260, + "barRight": 1260, + "overlap": false, + "open": 58.265625, + "doc": 120, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 900: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 900: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 768: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 1128, + "barRight": 1128, + "overlap": false, + "open": 58.265625, + "doc": 178.734375, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 768: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 768: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 640: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1000, + "barRight": 1000, + "overlap": false, + "open": 58.265625, + "doc": 96, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 640: Open shown next to the logo", + "status": "PASS", + "data": { + "open": 58.265625, + "inMore": null + } + }, + { + "name": "responsive 640: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 520: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 880, + "barRight": 880, + "overlap": false, + "open": 0, + "doc": 103, + "layer": 234, + "more": true + } + }, + { + "name": "responsive 520: Open moved into More and works there", + "status": "PASS", + "data": { + "open": 0, + "inMore": true + } + }, + { + "name": "responsive 520: layer field keeps its Figma width (234) while Open is shown", + "status": "PASS", + "data": 234 + }, + { + "name": "responsive 390: 49px, no overflow or overlap, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 750, + "barRight": 750, + "overlap": false, + "open": 0, + "doc": 96, + "layer": 113, + "more": true + } + }, + { + "name": "responsive 390: Open moved into More and works there", + "status": "PASS", + "data": { + "open": 0, + "inMore": true + } + }, + { + "name": "resize: collapsed Open returns once when the header grows (measured, with hysteresis)", + "status": "PASS", + "data": [ + [ + 520, + 0 + ], + [ + 560, + 0 + ], + [ + 600, + 1 + ], + [ + 640, + 1 + ], + [ + 680, + 1 + ], + [ + 720, + 1 + ], + [ + 760, + 1 + ], + [ + 820, + 1 + ], + [ + 900, + 1 + ], + [ + 1080, + 1 + ] + ] + }, + { + "name": "hidden documentNew: footer keeps Open on its right side", + "status": "PASS", + "data": { + "footer": { + "x": 424, + "y": 442.5, + "w": 310, + "h": 40, + "right": 734 + }, + "action": { + "x": 675.96875, + "y": 451, + "w": 50.03125, + "h": 24, + "right": 726 + } + } + }, + { + "name": "hidden documentNew + documentOpen: no footer", + "status": "PASS" + }, + { + "name": "hidden layerFreeze / layerLock: field draws the bulb only, two empty 20px places", + "status": "PASS", + "data": [ + { + "empty": false, + "w": 20 + }, + { + "empty": true, + "w": 20 + }, + { + "empty": true, + "w": 20 + } + ] + }, + { + "name": "hidden layerFreeze / layerLock: rows have no snowflake / lock button, places kept", + "status": "PASS", + "data": [ + { + "buttons": [ + "hm-sw-header__layer-toggle--visibility", + "hm-sw-header__layer-item" + ], + "empty": 2, + "name": 931 + }, + { + "buttons": [ + "hm-sw-header__layer-toggle--visibility", + "hm-sw-header__layer-item" + ], + "empty": 2, + "name": 931 + }, + { + "buttons": [ + "hm-sw-header__layer-toggle--visibility", + "hm-sw-header__layer-item" + ], + "empty": 2, + "name": 931 + } + ] + }, + { + "name": "hidden layer states: the bulb still reports its callback", + "status": "PASS" + }, + { + "name": "composed: Open right of the logo at the same junction offset as SWHeader", + "status": "PASS", + "data": { + "cHome": { + "x": 360, + "y": 6118.5, + "w": 80, + "h": 48, + "right": 440 + }, + "cOpen": { + "x": 425, + "y": 6118.5, + "w": 58.265625, + "h": 48, + "right": 483.265625 + } + } + }, + { + "name": "composed: file name after Open has 12px padding", + "status": "PASS" + }, + { + "name": "composed: Open callback", + "status": "PASS" + }, + { + "name": "composed: showOpen={false} removes Open from the dropdown", + "status": "PASS" + }, + { + "name": "composed responsive 1920: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 1800: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 1440: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 1180: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 1080: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 900: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 768: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 768: 파일 열기 reachable in More", + "status": "PASS" + }, + { + "name": "composed responsive 640: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 640: 파일 열기 reachable in More", + "status": "PASS" + }, + { + "name": "composed responsive 520: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 520: 파일 열기 reachable in More", + "status": "PASS" + }, + { + "name": "composed responsive 390: 49px, no overflow, nothing past the edge", + "status": "PASS", + "data": { + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + } + }, + { + "name": "composed responsive 390: 파일 열기 reachable in More", + "status": "PASS" + }, + { + "name": "tool: Model / Layout is a radio group", + "status": "PASS" + }, + { + "name": "tool: arrow key moves focus and selects Layout", + "status": "PASS" + }, + { + "name": "tool: 2.5D toggle reports and shows pressed (#FFC600)", + "status": "PASS" + }, + { + "name": "tool: text buttons are the 속성Bar toggle look (700, 19px row, 12px caption)", + "status": "PASS", + "data": { + "text": { + "weight": "700", + "h": 19 + }, + "ref": "12px" + } + }, + { + "name": "tool: pill button is 40 x 38 with the yellow ring and hover icon", + "status": "PASS", + "data": { + "pillBox": { + "x": 1467.234375, + "y": 336, + "w": 40, + "h": 38, + "right": 1507.234375 + }, + "hover": { + "ring": "1", + "icon": "hidden", + "hoverIcon": "visible" + } + } + }, + { + "name": "tool: pill click callback", + "status": "PASS" + }, + { + "name": "tool: pill accessible name from its text", + "status": "PASS" + }, + { + "name": "tool: document look keeps the logo junction in a composed bar", + "status": "PASS", + "data": { + "tHome": { + "x": 360, + "y": 491.5, + "w": 80, + "h": 48, + "right": 440 + }, + "tOpen": { + "x": 425, + "y": 491.5, + "w": 58.265625, + "h": 48, + "right": 483.265625 + } + } + }, + { + "name": "popup: SWPopup frames match the property window frame (314, surface, border, radius, title)", + "status": "PASS", + "data": [ + { + "w": 314, + "bg": "rgb(228, 219, 201)", + "border": "rgb(166, 125, 3)", + "radius": "4px", + "shadow": "rgb(0, 0, 0) 0px 0px 0px 1px inset", + "title": "rgb(255, 198, 0)", + "weight": "700", + "titlebar": 30, + "role": "dialog", + "modal": "false" + }, + { + "w": 314, + "bg": "rgb(228, 219, 201)", + "border": "rgb(166, 125, 3)", + "radius": "4px", + "shadow": "rgb(0, 0, 0) 0px 0px 0px 1px inset", + "title": "rgb(255, 198, 0)", + "weight": "700", + "titlebar": 30, + "role": "dialog", + "modal": "false" + }, + { + "w": 314, + "bg": "rgb(228, 219, 201)", + "border": "rgb(166, 125, 3)", + "radius": "4px", + "shadow": "rgb(0, 0, 0) 0px 0px 0px 1px inset", + "title": "rgb(255, 198, 0)", + "weight": "700", + "titlebar": 30, + "role": "dialog", + "modal": "false" + } + ] + }, + { + "name": "popup content: SWHeaderInput rows commit through the host callbacks", + "status": "PASS" + }, + { + "name": "popup content: SWPopupRow is the property row (72px label, 32px row, 28px box)", + "status": "PASS", + "data": { + "label": "72px", + "minH": "32px", + "box": "28px" + } + }, + { + "name": "popup content: HM UI Switch works inside", + "status": "PASS" + }, + { + "name": "popup content: HM UI Select (portal) works inside", + "status": "PASS" + }, + { + "name": "popup content: HM UI Slider works inside", + "status": "PASS", + "data": "Callback: name=평면도-02 → scale=50 → snap=false → unit=cm → opacity=70" + }, + { + "name": "popup content: HM UI Button works inside", + "status": "PASS" + }, + { + "name": "popup dropdown: SW layer dropdown opens right under its field (fixed overlay) and is not clipped", + "status": "PASS", + "data": { + "fieldBox": { + "x": 387, + "y": 548.5, + "w": 234, + "h": 38, + "right": 621 + }, + "menuBox": { + "x": 387, + "y": 586.5, + "w": 234, + "h": 160, + "right": 621 + }, + "hit": true + } + }, + { + "name": "popup dropdown: selection callback, list closes, popup stays", + "status": "PASS" + }, + { + "name": "popup dropdown: SW color dropdown becomes a fixed overlay", + "status": "PASS" + }, + { + "name": "popup dropdown: color chip callback", + "status": "PASS" + }, + { + "name": "popup dropdown: Escape closes the dropdown only", + "status": "PASS" + }, + { + "name": "object popup: read-only rows", + "status": "PASS" + }, + { + "name": "object popup: number row commits", + "status": "PASS" + }, + { + "name": "object popup: compact row uses the 41px hug field", + "status": "PASS", + "data": { + "cls": "hm-sw-header__input hm-sw-property__compact", + "w": 26.53125 + } + }, + { + "name": "property panel + children: children follow the property groups in the same body", + "status": "PASS", + "data": [ + "공통", + "메모" + ] + }, + { + "name": "property panel + children: child content callback", + "status": "PASS" + }, + { + "name": "popup: close button calls onClose", + "status": "PASS" + }, + { + "name": "short popup: dropdown extends past the popup and stays fully visible (no clipping)", + "status": "PASS", + "data": { + "bBox": { + "x": 706, + "y": 264.5, + "w": 314, + "h": 110, + "right": 1020 + }, + "menuB": { + "x": 717, + "y": 363.5, + "w": 234, + "h": 160, + "right": 951 + }, + "bHit": true + } + }, + { + "name": "several popups: Escape in a dropdown closes only the dropdown", + "status": "PASS" + }, + { + "name": "several popups: Escape on an edited input cancels the edit only", + "status": "PASS" + }, + { + "name": "several popups: Escape inside a popup closes that popup only", + "status": "PASS", + "data": "Callback: close(a)" + }, + { + "name": "several popups: Escape outside closes only the top popup (last used: B)", + "status": "PASS", + "data": "Callback: close(a) → close(b)" + }, + { + "name": "several popups: the popup used last becomes the top", + "status": "PASS", + "data": "Callback: close(a) → close(b) → close(a)" + }, + { + "name": "long content: the body scrolls inside the frame and the last row is reachable", + "status": "PASS", + "data": { + "scroll": { + "sh": 1000, + "ch": 328, + "overflow": "auto" + }, + "lastVisible": true + } + }, + { + "name": "no browser console or page errors", + "status": "PASS", + "data": [] + } + ], + "errors": [], + "data": { + "junction": -15, + "responsive": [ + { + "width": 1920, + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 2280, + "barRight": 2280, + "overlap": false, + "open": 58.265625, + "doc": 249.734375, + "layer": 234, + "more": false, + "inMore": null + }, + { + "width": 1800, + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 2160, + "barRight": 2160, + "overlap": false, + "open": 58.265625, + "doc": 190, + "layer": 234, + "more": false, + "inMore": null + }, + { + "width": 1440, + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1800, + "barRight": 1800, + "overlap": false, + "open": 58.265625, + "doc": 310, + "layer": 234, + "more": true, + "inMore": null + }, + { + "width": 1180, + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1540, + "barRight": 1540, + "overlap": false, + "open": 58.265625, + "doc": 120, + "layer": 234, + "more": true, + "inMore": null + }, + { + "width": 1080, + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1440, + "barRight": 1440, + "overlap": false, + "open": 58.265625, + "doc": 120, + "layer": 234, + "more": true, + "inMore": null + }, + { + "width": 900, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 1260, + "barRight": 1260, + "overlap": false, + "open": 58.265625, + "doc": 120, + "layer": 234, + "more": true, + "inMore": null + }, + { + "width": 768, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 1128, + "barRight": 1128, + "overlap": false, + "open": 58.265625, + "doc": 178.734375, + "layer": 234, + "more": true, + "inMore": null + }, + { + "width": 640, + "height": 49, + "barOverflow": 0, + "areaOverflow": 1, + "headerRight": 1000, + "barRight": 1000, + "overlap": false, + "open": 58.265625, + "doc": 96, + "layer": 234, + "more": true, + "inMore": null + }, + { + "width": 520, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 880, + "barRight": 880, + "overlap": false, + "open": 0, + "doc": 103, + "layer": 234, + "more": true, + "inMore": true + }, + { + "width": 390, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "headerRight": 750, + "barRight": 750, + "overlap": false, + "open": 0, + "doc": 96, + "layer": 113, + "more": true, + "inMore": true + } + ], + "hysteresis": [ + [ + 520, + 0 + ], + [ + 560, + 0 + ], + [ + 600, + 1 + ], + [ + 640, + 1 + ], + [ + 680, + 1 + ], + [ + 720, + 1 + ], + [ + 760, + 1 + ], + [ + 820, + 1 + ], + [ + 900, + 1 + ], + [ + 1080, + 1 + ] + ], + "composedResponsive": [ + { + "width": 1920, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + }, + { + "width": 1800, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + }, + { + "width": 1440, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + }, + { + "width": 1180, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + }, + { + "width": 1080, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + }, + { + "width": 900, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 1, + "more": 0, + "clipped": false, + "right": 0 + }, + { + "width": 768, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + }, + { + "width": 640, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + }, + { + "width": 520, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + }, + { + "width": 390, + "height": 49, + "barOverflow": 0, + "areaOverflow": 0, + "open": 0, + "more": 1, + "clipped": false, + "right": 0 + } + ], + "popupFrames": [ + { + "w": 314, + "bg": "rgb(228, 219, 201)", + "border": "rgb(166, 125, 3)", + "radius": "4px", + "shadow": "rgb(0, 0, 0) 0px 0px 0px 1px inset", + "title": "rgb(255, 198, 0)", + "weight": "700", + "titlebar": 30, + "role": "dialog", + "modal": "false" + }, + { + "w": 314, + "bg": "rgb(228, 219, 201)", + "border": "rgb(166, 125, 3)", + "radius": "4px", + "shadow": "rgb(0, 0, 0) 0px 0px 0px 1px inset", + "title": "rgb(255, 198, 0)", + "weight": "700", + "titlebar": 30, + "role": "dialog", + "modal": "false" + }, + { + "w": 314, + "bg": "rgb(228, 219, 201)", + "border": "rgb(166, 125, 3)", + "radius": "4px", + "shadow": "rgb(0, 0, 0) 0px 0px 0px 1px inset", + "title": "rgb(255, 198, 0)", + "weight": "700", + "titlebar": 30, + "role": "dialog", + "modal": "false" + } + ] + }, + "status": "PASS" +} diff --git a/docs/sw/home-menu-integration-qa/final-visual/capture.json b/docs/sw/home-menu-integration-qa/final-visual/capture.json new file mode 100644 index 0000000..7454952 --- /dev/null +++ b/docs/sw/home-menu-integration-qa/final-visual/capture.json @@ -0,0 +1,34 @@ +{ + "browser": "155.0.8059.80", + "shots": [ + "overview-1920.png", + "detail-buttons-1920.png", + "interactive-states-1920.png", + "window-move-motion-1920.png", + "logo-slot-1920.png", + "document-dropdown-1920.png", + "responsive-more-1920.png", + "k-guide-1920.png", + "property-panel-compare-1920.png", + "composed-controls-1920.png", + "overview-1800.png", + "overview-1440.png", + "overview-1180.png", + "overview-1080.png", + "overview-900.png", + "overview-768.png", + "overview-640.png", + "overview-520.png", + "overview-390.png", + "responsive-more-1800.png", + "responsive-more-1440.png", + "responsive-more-1180.png", + "responsive-more-1080.png", + "responsive-more-900.png", + "responsive-more-768.png", + "responsive-more-640.png", + "responsive-more-520.png", + "responsive-more-390.png" + ], + "errors": [] +} \ No newline at end of file diff --git a/docs/sw/home-menu-integration-qa/home-menu/capture-default-1920.png b/docs/sw/home-menu-integration-qa/home-menu/capture-default-1920.png new file mode 100644 index 0000000..24b9845 Binary files /dev/null and b/docs/sw/home-menu-integration-qa/home-menu/capture-default-1920.png differ diff --git a/docs/sw/home-menu-integration-qa/home-menu/header-composition-open.png b/docs/sw/home-menu-integration-qa/home-menu/header-composition-open.png new file mode 100644 index 0000000..fb9c775 Binary files /dev/null and b/docs/sw/home-menu-integration-qa/home-menu/header-composition-open.png differ diff --git a/docs/sw/home-menu-integration-qa/home-menu/responsive-390.png b/docs/sw/home-menu-integration-qa/home-menu/responsive-390.png new file mode 100644 index 0000000..e9f6f87 Binary files /dev/null and b/docs/sw/home-menu-integration-qa/home-menu/responsive-390.png differ diff --git a/docs/sw/home-menu-integration-qa/home-menu/responsive-768.png b/docs/sw/home-menu-integration-qa/home-menu/responsive-768.png new file mode 100644 index 0000000..912d0a8 Binary files /dev/null and b/docs/sw/home-menu-integration-qa/home-menu/responsive-768.png differ diff --git a/docs/sw/home-menu-integration-qa/home-menu/result.json b/docs/sw/home-menu-integration-qa/home-menu/result.json new file mode 100644 index 0000000..89bc362 --- /dev/null +++ b/docs/sw/home-menu-integration-qa/home-menu/result.json @@ -0,0 +1,363 @@ +{ + "browser": "155.0.8059.80", + "checks": [ + { + "name": "Storybook SW titles: Header, Tool, Popup, Home Menu; no SW/Header/Options", + "status": "PASS", + "data": [ + "SW/Header", + "SW/Home Menu", + "SW/Popup", + "SW/Tool" + ] + }, + { + "name": "menu at Figma x 375, width 1305, height 77 (measured, no fixed x); header stays 49", + "status": "PASS", + "data": { + "left": 375, + "width": 1305, + "height": 77, + "headerHeight": 49, + "sections": [ + 340, + 260, + 180, + 260, + 261 + ], + "tiles": 15, + "tileSizes": [ + "80x46" + ], + "titles": 5, + "badgeInlined": true, + "icons": 30, + "iconsLoaded": 30 + } + }, + { + "name": "5 sections 340/260/180/260/261, 15 tiles 80x46, 5 titles", + "status": "PASS", + "data": { + "left": 375, + "width": 1305, + "height": 77, + "headerHeight": 49, + "sections": [ + 340, + 260, + 180, + 260, + 261 + ], + "tiles": 15, + "tileSizes": [ + "80x46" + ], + "titles": 5, + "badgeInlined": true, + "icons": 30, + "iconsLoaded": 30 + } + }, + { + "name": "title badge SVG and 30 tile icons render", + "status": "PASS", + "data": { + "left": 375, + "width": 1305, + "height": 77, + "headerHeight": 49, + "sections": [ + 340, + 260, + 180, + 260, + 261 + ], + "tiles": 15, + "tileSizes": [ + "80x46" + ], + "titles": 5, + "badgeInlined": true, + "icons": 30, + "iconsLoaded": 30 + } + }, + { + "name": "hidden by default (not in DOM), logo aria-expanded=false", + "status": "PASS" + }, + { + "name": "logo click opens, aria-expanded=true, aria-controls → menu id", + "status": "PASS" + }, + { + "name": "tile Hover: label #FF5C00", + "status": "PASS", + "data": "rgb(255, 92, 0)" + }, + { + "name": "tile click → Active (aria-pressed true), re-click → Default", + "status": "PASS", + "data": "true" + }, + { + "name": "logo re-click closes; onHomeClick never called while homeMenu is set", + "status": "PASS", + "data": "onHomeMenuOpenChange(false, home)\nonItemSelect(working / save, active=false)\nonActiveChange([])\nonItemSelect(working / save, active=true)\nonActiveChange([save])\nonHomeMenuOpenChange(true, home)" + }, + { + "name": "Escape inside closes the menu and returns focus to the logo", + "status": "PASS" + }, + { + "name": "click on the menu background closes it (Figma CLOSE)", + "status": "PASS" + }, + { + "name": "recent panel opens (outline accent); Escape closes the panel, then the menu", + "status": "PASS", + "data": { + "panelOpen": true, + "panelFirst": true + } + }, + { + "name": "opening the document dropdown closes the menu (reason document); New / Open stay in the dropdown", + "status": "PASS", + "data": "C0020101-006-평면및종단면도(06)\nC0020101-007-횡단면도\n+ New\nOpen" + }, + { + "name": "opening the menu closes the document dropdown", + "status": "PASS" + }, + { + "name": "no separate Open button next to the logo (documentOpenPlacement=\"menu\")", + "status": "PASS" + }, + { + "name": "focus outside: Escape closes the most recent (menu), then the popup", + "status": "PASS", + "data": { + "step1": { + "menu": 0, + "popup": 1 + }, + "step2": { + "menu": 0, + "popup": 0 + } + } + }, + { + "name": "popup opened after the menu: Escape outside closes the popup first, menu stays", + "status": "PASS", + "data": { + "menu": 1, + "popup": 0 + } + }, + { + "name": "Escape inside the popup closes only the popup", + "status": "PASS", + "data": { + "menu": 1, + "popup": 0 + } + }, + { + "name": "Escape inside the menu closes only the menu (popup stays), focus → logo", + "status": "PASS", + "data": { + "menu": 0, + "popup": 1, + "focusHome": true + } + }, + { + "name": "every width: menu starts at object area −2px, ends at the window area, covers neither logo nor file name, header 49, no page scroll", + "status": "PASS", + "data": [ + { + "width": 1920, + "headerHeight": 49, + "start": 0, + "endGap": 0, + "coversHome": false, + "coversDocument": false, + "menuWidth": 1305, + "scrolls": false, + "pageScroll": false + }, + { + "width": 1440, + "headerHeight": 49, + "start": 0, + "endGap": 0, + "coversHome": false, + "coversDocument": false, + "menuWidth": 825, + "scrolls": true, + "pageScroll": false + }, + { + "width": 1080, + "headerHeight": 49, + "start": 0, + "endGap": 0, + "coversHome": false, + "coversDocument": false, + "menuWidth": 639, + "scrolls": true, + "pageScroll": false + }, + { + "width": 768, + "headerHeight": 49, + "start": 0, + "endGap": 0, + "coversHome": false, + "coversDocument": false, + "menuWidth": 288, + "scrolls": true, + "pageScroll": false + }, + { + "width": 520, + "headerHeight": 49, + "start": 0, + "endGap": 0, + "coversHome": false, + "coversDocument": false, + "menuWidth": 288, + "scrolls": true, + "pageScroll": false + }, + { + "width": 390, + "headerHeight": 49, + "start": 0, + "endGap": 0, + "coversHome": false, + "coversDocument": false, + "menuWidth": 165, + "scrolls": true, + "pageScroll": false + } + ] + }, + { + "name": "without homeMenu: logo click calls onHomeClick, renders no menu, no aria-expanded", + "status": "PASS", + "data": [ + "[SWHeader Overview] onHomeClick" + ] + }, + { + "name": "no page / console errors", + "status": "PASS", + "data": [] + } + ], + "errors": [], + "data": { + "titles": [ + "SW/Header", + "SW/Home Menu", + "SW/Popup", + "SW/Tool" + ], + "geometry": { + "left": 375, + "width": 1305, + "height": 77, + "headerHeight": 49, + "sections": [ + 340, + 260, + 180, + 260, + 261 + ], + "tiles": 15, + "tileSizes": [ + "80x46" + ], + "titles": 5, + "badgeInlined": true, + "icons": 30, + "iconsLoaded": 30 + }, + "responsive": [ + { + "width": 1920, + "headerHeight": 49, + "start": 0, + "endGap": 0, + "coversHome": false, + "coversDocument": false, + "menuWidth": 1305, + "scrolls": false, + "pageScroll": false + }, + { + "width": 1440, + "headerHeight": 49, + "start": 0, + "endGap": 0, + "coversHome": false, + "coversDocument": false, + "menuWidth": 825, + "scrolls": true, + "pageScroll": false + }, + { + "width": 1080, + "headerHeight": 49, + "start": 0, + "endGap": 0, + "coversHome": false, + "coversDocument": false, + "menuWidth": 639, + "scrolls": true, + "pageScroll": false + }, + { + "width": 768, + "headerHeight": 49, + "start": 0, + "endGap": 0, + "coversHome": false, + "coversDocument": false, + "menuWidth": 288, + "scrolls": true, + "pageScroll": false + }, + { + "width": 520, + "headerHeight": 49, + "start": 0, + "endGap": 0, + "coversHome": false, + "coversDocument": false, + "menuWidth": 288, + "scrolls": true, + "pageScroll": false + }, + { + "width": 390, + "headerHeight": 49, + "start": 0, + "endGap": 0, + "coversHome": false, + "coversDocument": false, + "menuWidth": 165, + "scrolls": true, + "pageScroll": false + } + ] + } +} \ No newline at end of file diff --git a/docs/sw/home-menu-integration-qa/visual-diff/compare-result.json b/docs/sw/home-menu-integration-qa/visual-diff/compare-result.json new file mode 100644 index 0000000..0bb1d0e --- /dev/null +++ b/docs/sw/home-menu-integration-qa/visual-diff/compare-result.json @@ -0,0 +1,146 @@ +{ + "total": 28, + "same": 28, + "results": [ + { + "file": "composed-controls-1920.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "detail-buttons-1920.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "document-dropdown-1920.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "interactive-states-1920.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "k-guide-1920.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "logo-slot-1920.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "overview-1080.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "overview-1180.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "overview-1440.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "overview-1800.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "overview-1920.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "overview-390.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "overview-520.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "overview-640.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "overview-768.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "overview-900.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "property-panel-compare-1920.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "responsive-more-1080.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "responsive-more-1180.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "responsive-more-1440.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "responsive-more-1800.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "responsive-more-1920.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "responsive-more-390.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "responsive-more-520.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "responsive-more-640.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "responsive-more-768.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "responsive-more-900.png", + "status": "SAME", + "changed": 0 + }, + { + "file": "window-move-motion-1920.png", + "status": "SAME", + "changed": 0 + } + ] +} \ No newline at end of file diff --git a/docs/sw/home-menu-joint-qa-2026-10-19/after-1024.png b/docs/sw/home-menu-joint-qa-2026-10-19/after-1024.png new file mode 100644 index 0000000..789041a Binary files /dev/null and b/docs/sw/home-menu-joint-qa-2026-10-19/after-1024.png differ diff --git a/docs/sw/home-menu-joint-qa-2026-10-19/after-1440.png b/docs/sw/home-menu-joint-qa-2026-10-19/after-1440.png new file mode 100644 index 0000000..4e87fec Binary files /dev/null and b/docs/sw/home-menu-joint-qa-2026-10-19/after-1440.png differ diff --git a/docs/sw/home-menu-joint-qa-2026-10-19/after-1920.png b/docs/sw/home-menu-joint-qa-2026-10-19/after-1920.png new file mode 100644 index 0000000..60ef404 Binary files /dev/null and b/docs/sw/home-menu-joint-qa-2026-10-19/after-1920.png differ diff --git a/docs/sw/home-menu-joint-qa-2026-10-19/after-390.png b/docs/sw/home-menu-joint-qa-2026-10-19/after-390.png new file mode 100644 index 0000000..3bd1348 Binary files /dev/null and b/docs/sw/home-menu-joint-qa-2026-10-19/after-390.png differ diff --git a/docs/sw/home-menu-joint-qa-2026-10-19/after-768.png b/docs/sw/home-menu-joint-qa-2026-10-19/after-768.png new file mode 100644 index 0000000..8fd16c5 Binary files /dev/null and b/docs/sw/home-menu-joint-qa-2026-10-19/after-768.png differ diff --git a/docs/sw/home-menu-joint-qa-2026-10-19/compare-joint.png b/docs/sw/home-menu-joint-qa-2026-10-19/compare-joint.png new file mode 100644 index 0000000..f2a68cc Binary files /dev/null and b/docs/sw/home-menu-joint-qa-2026-10-19/compare-joint.png differ diff --git a/docs/sw/home-menu-joint-qa-2026-10-19/geometry.json b/docs/sw/home-menu-joint-qa-2026-10-19/geometry.json new file mode 100644 index 0000000..d6b2901 --- /dev/null +++ b/docs/sw/home-menu-joint-qa-2026-10-19/geometry.json @@ -0,0 +1,271 @@ +{ + "results": [ + { + "vw": 1920, + "menu": { + "x": 375, + "y": 0, + "width": 1305, + "height": 77, + "top": 0, + "right": 1680, + "bottom": 77, + "left": 375 + }, + "panel": { + "x": 808, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 1162, + "bottom": 829, + "left": 808 + }, + "list": { + "x": 808, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 1162, + "bottom": 829, + "left": 808 + }, + "accent": "outline", + "listBorder": [ + "0px", + "1px", + "rgb(218, 104, 19)" + ], + "accentBox": { + "top": "47px", + "height": "30px", + "padding": "2px", + "radius": "3px" + }, + "joint": [], + "pageScroll": 0 + }, + { + "vw": 1440, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "panel": { + "x": 808, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 1162, + "bottom": 829, + "left": 808 + }, + "list": { + "x": 808, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 1162, + "bottom": 829, + "left": 808 + }, + "accent": "outline", + "listBorder": [ + "0px", + "1px", + "rgb(218, 104, 19)" + ], + "accentBox": { + "top": "47px", + "height": "30px", + "padding": "2px", + "radius": "3px" + }, + "joint": [], + "pageScroll": 0 + }, + { + "vw": 1024, + "menu": { + "x": 364, + "y": 0, + "width": 484, + "height": 77, + "top": 0, + "right": 848, + "bottom": 77, + "left": 364 + }, + "panel": { + "x": 670, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 1024, + "bottom": 829, + "left": 670 + }, + "list": { + "x": 670, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 1024, + "bottom": 829, + "left": 670 + }, + "accent": "outline", + "listBorder": [ + "0px", + "1px", + "rgb(218, 104, 19)" + ], + "accentBox": { + "top": "47px", + "height": "30px", + "padding": "2px", + "radius": "3px" + }, + "joint": [ + [ + 845, + 1024, + 75, + 77, + "linear-gradient(0deg, rgb(255, 81, 0) 0%" + ] + ], + "pageScroll": 0 + }, + { + "vw": 768, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "panel": { + "x": 414, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 768, + "bottom": 829, + "left": 414 + }, + "list": { + "x": 414, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 768, + "bottom": 829, + "left": 414 + }, + "accent": "outline", + "listBorder": [ + "0px", + "1px", + "rgb(218, 104, 19)" + ], + "accentBox": { + "top": "47px", + "height": "30px", + "padding": "2px", + "radius": "3px" + }, + "joint": [ + [ + 589, + 768, + 75, + 77, + "linear-gradient(0deg, rgb(255, 81, 0) 0%" + ] + ], + "pageScroll": 0 + }, + { + "vw": 390, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "panel": { + "x": 36, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 390, + "bottom": 829, + "left": 36 + }, + "list": { + "x": 36, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 390, + "bottom": 829, + "left": 36 + }, + "accent": "outline", + "listBorder": [ + "0px", + "1px", + "rgb(218, 104, 19)" + ], + "accentBox": { + "top": "47px", + "height": "30px", + "padding": "2px", + "radius": "3px" + }, + "joint": [ + [ + 36, + 164, + 75, + 77, + "linear-gradient(0deg, rgb(255, 81, 0) 0%" + ], + [ + 323, + 390, + 75, + 77, + "linear-gradient(0deg, rgb(255, 81, 0) 0%" + ] + ], + "pageScroll": 0 + } + ], + "errors": [] +} \ No newline at end of file diff --git a/docs/sw/home-menu-joint-qa-2026-10-19/joint-1024.png b/docs/sw/home-menu-joint-qa-2026-10-19/joint-1024.png new file mode 100644 index 0000000..019c1d0 Binary files /dev/null and b/docs/sw/home-menu-joint-qa-2026-10-19/joint-1024.png differ diff --git a/docs/sw/home-menu-joint-qa-2026-10-19/joint-390.png b/docs/sw/home-menu-joint-qa-2026-10-19/joint-390.png new file mode 100644 index 0000000..7d94f89 Binary files /dev/null and b/docs/sw/home-menu-joint-qa-2026-10-19/joint-390.png differ diff --git a/docs/sw/home-menu-joint-qa-2026-10-19/joint-768.png b/docs/sw/home-menu-joint-qa-2026-10-19/joint-768.png new file mode 100644 index 0000000..caba431 Binary files /dev/null and b/docs/sw/home-menu-joint-qa-2026-10-19/joint-768.png differ diff --git a/docs/sw/home-menu-merge-qa/consumer-after-1920.png b/docs/sw/home-menu-merge-qa/consumer-after-1920.png new file mode 100644 index 0000000..3c30509 Binary files /dev/null and b/docs/sw/home-menu-merge-qa/consumer-after-1920.png differ diff --git a/docs/sw/home-menu-merge-qa/consumer-closed-1920.png b/docs/sw/home-menu-merge-qa/consumer-closed-1920.png new file mode 100644 index 0000000..578275f Binary files /dev/null and b/docs/sw/home-menu-merge-qa/consumer-closed-1920.png differ diff --git a/docs/sw/home-menu-merge-qa/consumer-open-hover-1920.png b/docs/sw/home-menu-merge-qa/consumer-open-hover-1920.png new file mode 100644 index 0000000..67e7227 Binary files /dev/null and b/docs/sw/home-menu-merge-qa/consumer-open-hover-1920.png differ diff --git a/docs/sw/home-menu-merge-qa/consumer-recent-1920.png b/docs/sw/home-menu-merge-qa/consumer-recent-1920.png new file mode 100644 index 0000000..22daf72 Binary files /dev/null and b/docs/sw/home-menu-merge-qa/consumer-recent-1920.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/768-1-recent.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/768-1-recent.png new file mode 100644 index 0000000..78d81d2 Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/768-1-recent.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/768-2-more.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/768-2-more.png new file mode 100644 index 0000000..126b84e Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/768-2-more.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/768-3-recent.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/768-3-recent.png new file mode 100644 index 0000000..78d81d2 Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/768-3-recent.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/compare-more-placement.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/compare-more-placement.png new file mode 100644 index 0000000..a5f7047 Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/compare-more-placement.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/place-1080.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/place-1080.png new file mode 100644 index 0000000..575236b Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/place-1080.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/place-1440.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/place-1440.png new file mode 100644 index 0000000..19b675e Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/place-1440.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/place-1920.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/place-1920.png new file mode 100644 index 0000000..439e0e1 Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/place-1920.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/place-390.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/place-390.png new file mode 100644 index 0000000..ef78300 Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/place-390.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/place-768.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/place-768.png new file mode 100644 index 0000000..ac9eea9 Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/place-768.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/report.json b/docs/sw/home-menu-more-placement-qa-2026-10-19/report.json new file mode 100644 index 0000000..a11ee62 --- /dev/null +++ b/docs/sw/home-menu-more-placement-qa-2026-10-19/report.json @@ -0,0 +1,3064 @@ +{ + "checks": [ + { + "name": "1920: full Figma row (5 groups), More hidden", + "ok": true, + "data": { + "vw": 1920, + "open": true, + "rowCount": 5, + "more": false, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": null, + "menuTail": null, + "rowPad": 2, + "tileInset": null, + "badgeInset": null, + "dropLeftToTile": null, + "menu": { + "x": 375, + "y": 0, + "width": 1305, + "height": 77, + "top": 0, + "right": 1680, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1680, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1920, + "bottom": 48, + "left": 1680 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + }, + { + "name": "narrower: More directly after the last shown group (gap 0) — or at the row start when no group fits", + "ok": true, + "data": [ + [ + 1920, + 5, + null + ], + [ + 1440, + 2, + 0 + ], + [ + 1080, + 1, + 0 + ], + [ + 768, + 0, + 0 + ], + [ + 390, + 0, + 0 + ], + [ + 390, + 0, + 0 + ], + [ + 768, + 0, + 0 + ], + [ + 1080, + 1, + 0 + ], + [ + 1440, + 2, + 0 + ], + [ + 1920, + 5, + null + ] + ] + }, + { + "name": "background unchanged: the More section surface fills the rest, menu ends at the window area", + "ok": true, + "data": [ + [ + 1920, + null, + 1680, + 1680 + ], + [ + 1440, + 2, + 1200, + 1200 + ], + [ + 1080, + 2, + 840, + 840 + ], + [ + 768, + 2, + 592, + 592 + ], + [ + 390, + 2, + 326, + 326 + ], + [ + 390, + 2, + 326, + 326 + ], + [ + 768, + 2, + 592, + 592 + ], + [ + 1080, + 2, + 840, + 840 + ], + [ + 1440, + 2, + 1200, + 1200 + ], + [ + 1920, + null, + 1680, + 1680 + ] + ] + }, + { + "name": "⋯ tile and badge at the start of the More section (section padding 10 + border 1), right after the last group", + "ok": true, + "data": [ + [ + 1920, + null, + null + ], + [ + 1440, + 11, + 11 + ], + [ + 1080, + 11, + 11 + ], + [ + 768, + 11, + 11 + ], + [ + 390, + 11, + 11 + ], + [ + 390, + 11, + 11 + ], + [ + 768, + 11, + 11 + ], + [ + 1080, + 11, + 11 + ], + [ + 1440, + 11, + 11 + ], + [ + 1920, + null, + null + ] + ] + }, + { + "name": "More follows the group count both ways (same split down and up)", + "ok": true, + "data": [ + [ + 1920, + 5 + ], + [ + 1440, + 2 + ], + [ + 1080, + 1 + ], + [ + 768, + 0 + ], + [ + 390, + 0 + ], + [ + 390, + 0 + ], + [ + 768, + 0 + ], + [ + 1080, + 1 + ], + [ + 1440, + 2 + ], + [ + 1920, + 5 + ] + ] + }, + { + "name": "no horizontal scroll; menu stays left of the window area", + "ok": true, + "data": [ + [ + 1920, + 0, + 1680, + 1680 + ], + [ + 1440, + 0, + 1200, + 1200 + ], + [ + 1080, + 0, + 840, + 840 + ], + [ + 768, + 0, + 592, + 592 + ], + [ + 390, + 0, + 326, + 326 + ], + [ + 390, + 0, + 326, + 326 + ], + [ + 768, + 0, + 592, + 592 + ], + [ + 1080, + 0, + 840, + 840 + ], + [ + 1440, + 0, + 1200, + 1200 + ], + [ + 1920, + 0, + 1680, + 1680 + ] + ] + }, + { + "name": "Home On + #5F4B0F lines kept", + "ok": true, + "data": [ + [ + 1920, + true + ], + [ + 1440, + true + ], + [ + 1080, + true + ], + [ + 768, + true + ], + [ + 390, + true + ], + [ + 390, + true + ], + [ + 768, + true + ], + [ + 1080, + true + ], + [ + 1440, + true + ], + [ + 1920, + true + ] + ] + }, + { + "name": "1440: 최근파일 open → list only (no dropdown), ON on 최근파일", + "ok": true, + "data": { + "vw": 1440, + "open": true, + "rowCount": 2, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + }, + { + "name": "1440: More while the list is open → list closed first, dropdown open under the ⋯ tile, no overlap", + "ok": true, + "data": { + "vw": 1440, + "open": true, + "rowCount": 2, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + }, + { + "name": "1440: 최근파일 again → dropdown closed, list open", + "ok": true, + "data": { + "vw": 1440, + "open": true, + "rowCount": 2, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + }, + { + "name": "1440: preview kept, inside the viewport, no page scroll", + "ok": true, + "data": { + "left": 497, + "right": 807, + "page": 0 + } + }, + { + "name": "1440: keyboard Enter on More with the list open → list closed, dropdown open; Escape closes the dropdown, menu stays", + "ok": true, + "data": { + "s4": { + "vw": 1440, + "open": true, + "rowCount": 2, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + "s5": { + "vw": 1440, + "open": true, + "rowCount": 2, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + } + }, + { + "name": "1080: 최근파일 open → list only (no dropdown), ON on 최근파일", + "ok": true, + "data": { + "vw": 1080, + "open": true, + "rowCount": 1, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "joints": 1, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + }, + { + "name": "1080: More while the list is open → list closed first, dropdown open under the ⋯ tile, no overlap", + "ok": true, + "data": { + "vw": 1080, + "open": true, + "rowCount": 1, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + }, + { + "name": "1080: 최근파일 again → dropdown closed, list open", + "ok": true, + "data": { + "vw": 1080, + "open": true, + "rowCount": 1, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "joints": 1, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + }, + { + "name": "1080: preview kept, inside the viewport, no page scroll", + "ok": true, + "data": { + "left": 244, + "right": 554, + "page": 0 + } + }, + { + "name": "1080: keyboard Enter on More with the list open → list closed, dropdown open; Escape closes the dropdown, menu stays", + "ok": true, + "data": { + "s4": { + "vw": 1080, + "open": true, + "rowCount": 1, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + "s5": { + "vw": 1080, + "open": true, + "rowCount": 1, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + } + }, + { + "name": "768: 최근파일 open → list only (no dropdown), ON on 최근파일", + "ok": true, + "data": { + "vw": 768, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "joints": 1, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + }, + { + "name": "768: More while the list is open → list closed first, dropdown open under the ⋯ tile, no overlap", + "ok": true, + "data": { + "vw": 768, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + }, + { + "name": "768: 최근파일 again → dropdown closed, list open", + "ok": true, + "data": { + "vw": 768, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "joints": 1, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + }, + { + "name": "768: preview kept, inside the viewport, no page scroll", + "ok": true, + "data": { + "left": 7, + "right": 317, + "page": 0 + } + }, + { + "name": "768: keyboard Enter on More with the list open → list closed, dropdown open; Escape closes the dropdown, menu stays", + "ok": true, + "data": { + "s4": { + "vw": 768, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + "s5": { + "vw": 768, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + } + }, + { + "name": "390: 최근파일 open → list only (no dropdown), ON on 최근파일", + "ok": true, + "data": { + "vw": 390, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "joints": 2, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + }, + { + "name": "390: More while the list is open → list closed first, dropdown open under the ⋯ tile, no overlap", + "ok": true, + "data": { + "vw": 390, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + }, + { + "name": "390: 최근파일 again → dropdown closed, list open", + "ok": true, + "data": { + "vw": 390, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "joints": 2, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + }, + { + "name": "390: preview kept, inside the viewport, no page scroll", + "ok": false, + "data": { + "left": -275, + "right": 35, + "page": 0 + } + }, + { + "name": "390: keyboard Enter on More with the list open → list closed, dropdown open; Escape closes the dropdown, menu stays", + "ok": true, + "data": { + "s4": { + "vw": 390, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + "s5": { + "vw": 390, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + } + }, + { + "name": "never both popups at once, never overlapping (every step)", + "ok": true, + "data": [ + [ + "1440 최근파일 open", + true, + false + ], + [ + "1440 More over open list", + false, + true + ], + [ + "1440 최근파일 again", + true, + false + ], + [ + "1440 Enter on More over open list", + false, + true + ], + [ + "1440 Escape", + false, + false + ], + [ + "1080 More open", + false, + true + ], + [ + "1080 최근파일 open", + true, + false + ], + [ + "1080 More over open list", + false, + true + ], + [ + "1080 최근파일 again", + true, + false + ], + [ + "1080 Enter on More over open list", + false, + true + ], + [ + "1080 Escape", + false, + false + ], + [ + "768 More open", + false, + true + ], + [ + "768 최근파일 open", + true, + false + ], + [ + "768 More over open list", + false, + true + ], + [ + "768 최근파일 again", + true, + false + ], + [ + "768 Enter on More over open list", + false, + true + ], + [ + "768 Escape", + false, + false + ], + [ + "390 More open", + false, + true + ], + [ + "390 최근파일 open", + true, + false + ], + [ + "390 More over open list", + false, + true + ], + [ + "390 최근파일 again", + true, + false + ], + [ + "390 Enter on More over open list", + false, + true + ], + [ + "390 Escape", + false, + false + ] + ] + }, + { + "name": "connector line where the list reaches past the menu (768 / 390 list steps)", + "ok": true, + "data": [ + [ + "1440 최근파일 open", + 0 + ], + [ + "1440 최근파일 again", + 0 + ], + [ + "1080 최근파일 open", + 1 + ], + [ + "1080 최근파일 again", + 1 + ], + [ + "768 최근파일 open", + 1 + ], + [ + "768 최근파일 again", + 1 + ], + [ + "390 최근파일 open", + 2 + ], + [ + "390 최근파일 again", + 2 + ] + ] + }, + { + "name": "no page scroll at any step", + "ok": true, + "data": [ + [ + "1440 최근파일 open", + 0 + ], + [ + "1440 More over open list", + 0 + ], + [ + "1440 최근파일 again", + 0 + ], + [ + "1440 Enter on More over open list", + 0 + ], + [ + "1440 Escape", + 0 + ], + [ + "1080 More open", + 0 + ], + [ + "1080 최근파일 open", + 0 + ], + [ + "1080 More over open list", + 0 + ], + [ + "1080 최근파일 again", + 0 + ], + [ + "1080 Enter on More over open list", + 0 + ], + [ + "1080 Escape", + 0 + ], + [ + "768 More open", + 0 + ], + [ + "768 최근파일 open", + 0 + ], + [ + "768 More over open list", + 0 + ], + [ + "768 최근파일 again", + 0 + ], + [ + "768 Enter on More over open list", + 0 + ], + [ + "768 Escape", + 0 + ], + [ + "390 More open", + 0 + ], + [ + "390 최근파일 open", + 0 + ], + [ + "390 More over open list", + 0 + ], + [ + "390 최근파일 again", + 0 + ], + [ + "390 Enter on More over open list", + 0 + ], + [ + "390 Escape", + 0 + ] + ] + }, + { + "name": "no page errors", + "ok": true, + "data": [] + } + ], + "place": [ + { + "vw": 1920, + "open": true, + "rowCount": 5, + "more": false, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": null, + "menuTail": null, + "rowPad": 2, + "tileInset": null, + "badgeInset": null, + "dropLeftToTile": null, + "menu": { + "x": 375, + "y": 0, + "width": 1305, + "height": 77, + "top": 0, + "right": 1680, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1680, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1920, + "bottom": 48, + "left": 1680 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "vw": 1440, + "open": true, + "rowCount": 2, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "vw": 1080, + "open": true, + "rowCount": 1, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "vw": 768, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "vw": 390, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "vw": 390, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "vw": 768, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "vw": 1080, + "open": true, + "rowCount": 1, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "vw": 1440, + "open": true, + "rowCount": 2, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "vw": 1920, + "open": true, + "rowCount": 5, + "more": false, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": null, + "menuTail": null, + "rowPad": 2, + "tileInset": null, + "badgeInset": null, + "dropLeftToTile": null, + "menu": { + "x": 375, + "y": 0, + "width": 1305, + "height": 77, + "top": 0, + "right": 1680, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1680, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1920, + "bottom": 48, + "left": 1680 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + ], + "steps": [ + { + "label": "1440 최근파일 open", + "vw": 1440, + "open": true, + "rowCount": 2, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "1440 More over open list", + "vw": 1440, + "open": true, + "rowCount": 2, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "1440 최근파일 again", + "vw": 1440, + "open": true, + "rowCount": 2, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "1440 Enter on More over open list", + "vw": 1440, + "open": true, + "rowCount": 2, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "1440 Escape", + "vw": 1440, + "open": true, + "rowCount": 2, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "1080 More open", + "vw": 1080, + "open": true, + "rowCount": 1, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "1080 최근파일 open", + "vw": 1080, + "open": true, + "rowCount": 1, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "joints": 1, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "1080 More over open list", + "vw": 1080, + "open": true, + "rowCount": 1, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "1080 최근파일 again", + "vw": 1080, + "open": true, + "rowCount": 1, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "joints": 1, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "1080 Enter on More over open list", + "vw": 1080, + "open": true, + "rowCount": 1, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "1080 Escape", + "vw": 1080, + "open": true, + "rowCount": 1, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "768 More open", + "vw": 768, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "768 최근파일 open", + "vw": 768, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "joints": 1, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "768 More over open list", + "vw": 768, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "768 최근파일 again", + "vw": 768, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "joints": 1, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "768 Enter on More over open list", + "vw": 768, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "768 Escape", + "vw": 768, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "390 More open", + "vw": 390, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "390 최근파일 open", + "vw": 390, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "joints": 2, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "390 More over open list", + "vw": 390, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "390 최근파일 again", + "vw": 390, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": true, + "overlap": false, + "recentActive": "true", + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "joints": 2, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "390 Enter on More over open list", + "vw": 390, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": true, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": "true", + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": 0, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + }, + { + "label": "390 Escape", + "vw": 390, + "open": true, + "rowCount": 0, + "more": true, + "dropShown": false, + "list": false, + "overlap": false, + "recentActive": null, + "moreActive": null, + "gapToMore": 0, + "menuTail": 2, + "rowPad": 2, + "tileInset": 11, + "badgeInset": 11, + "dropLeftToTile": null, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "joints": 0, + "homeOn": true, + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "rowScroll": 0, + "pageScroll": 0 + } + ], + "errors": [] +} \ No newline at end of file diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-1280.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-1280.png new file mode 100644 index 0000000..d75b07e Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-1280.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-1920.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-1920.png new file mode 100644 index 0000000..439e0e1 Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-1920.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-390.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-390.png new file mode 100644 index 0000000..ef78300 Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-390.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-520.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-520.png new file mode 100644 index 0000000..81aa1c2 Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-520.png differ diff --git a/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-960.png b/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-960.png new file mode 100644 index 0000000..fdc5198 Binary files /dev/null and b/docs/sw/home-menu-more-placement-qa-2026-10-19/row-after-960.png differ diff --git a/docs/sw/home-menu-more-qa-2026-10-19/1080-closed.png b/docs/sw/home-menu-more-qa-2026-10-19/1080-closed.png new file mode 100644 index 0000000..3b9de3b Binary files /dev/null and b/docs/sw/home-menu-more-qa-2026-10-19/1080-closed.png differ diff --git a/docs/sw/home-menu-more-qa-2026-10-19/1080-more-hover.png b/docs/sw/home-menu-more-qa-2026-10-19/1080-more-hover.png new file mode 100644 index 0000000..a51592d Binary files /dev/null and b/docs/sw/home-menu-more-qa-2026-10-19/1080-more-hover.png differ diff --git a/docs/sw/home-menu-more-qa-2026-10-19/1080-more-open.png b/docs/sw/home-menu-more-qa-2026-10-19/1080-more-open.png new file mode 100644 index 0000000..3cb26b2 Binary files /dev/null and b/docs/sw/home-menu-more-qa-2026-10-19/1080-more-open.png differ diff --git a/docs/sw/home-menu-more-qa-2026-10-19/1920-back.png b/docs/sw/home-menu-more-qa-2026-10-19/1920-back.png new file mode 100644 index 0000000..c5dcf7a Binary files /dev/null and b/docs/sw/home-menu-more-qa-2026-10-19/1920-back.png differ diff --git a/docs/sw/home-menu-more-qa-2026-10-19/768-recent-from-more.png b/docs/sw/home-menu-more-qa-2026-10-19/768-recent-from-more.png new file mode 100644 index 0000000..c7a010b Binary files /dev/null and b/docs/sw/home-menu-more-qa-2026-10-19/768-recent-from-more.png differ diff --git a/docs/sw/home-menu-more-qa-2026-10-19/page-1024.png b/docs/sw/home-menu-more-qa-2026-10-19/page-1024.png new file mode 100644 index 0000000..a5337cc Binary files /dev/null and b/docs/sw/home-menu-more-qa-2026-10-19/page-1024.png differ diff --git a/docs/sw/home-menu-more-qa-2026-10-19/page-390.png b/docs/sw/home-menu-more-qa-2026-10-19/page-390.png new file mode 100644 index 0000000..6c1b0aa Binary files /dev/null and b/docs/sw/home-menu-more-qa-2026-10-19/page-390.png differ diff --git a/docs/sw/home-menu-more-qa-2026-10-19/report.json b/docs/sw/home-menu-more-qa-2026-10-19/report.json new file mode 100644 index 0000000..0150fde --- /dev/null +++ b/docs/sw/home-menu-more-qa-2026-10-19/report.json @@ -0,0 +1,3588 @@ +{ + "checks": [ + { + "name": "all widths: 5 groups = row + More, order kept", + "ok": true, + "data": [ + [ + 1920, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [] + ], + [ + 1680, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시" + ], + [ + "My Setting", + "궁금하면" + ] + ], + [ + 1440, + [ + "작업중인 파일", + "다른파일 열기" + ], + [ + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1280, + [ + "작업중인 파일", + "다른파일 열기" + ], + [ + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1180, + [ + "작업중인 파일", + "다른파일 열기" + ], + [ + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1080, + [ + "작업중인 파일" + ], + [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 960, + [ + "작업중인 파일" + ], + [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 768, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 640, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 520, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 390, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 390, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 520, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 640, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 768, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 960, + [ + "작업중인 파일" + ], + [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1080, + [ + "작업중인 파일" + ], + [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1180, + [ + "작업중인 파일", + "다른파일 열기" + ], + [ + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1280, + [ + "작업중인 파일", + "다른파일 열기" + ], + [ + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1440, + [ + "작업중인 파일", + "다른파일 열기" + ], + [ + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1680, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시" + ], + [ + "My Setting", + "궁금하면" + ] + ], + [ + 1920, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [] + ] + ] + }, + { + "name": "1920: all 5 groups in the row, no More", + "ok": true, + "data": { + "vw": 1920, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "more": false, + "hidden": [], + "panelOpen": false, + "panelVisibility": null, + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 1305, + "height": 77, + "top": 0, + "right": 1680, + "bottom": 77, + "left": 375 + }, + "moreRect": null, + "moreButton": null, + "panelRect": null, + "win": { + "x": 1680, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1920, + "bottom": 48, + "left": 1680 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + } + }, + { + "name": "narrower: groups move into More (fewer in the row as the width shrinks)", + "ok": true, + "data": [ + [ + 1920, + 5 + ], + [ + 1680, + 3 + ], + [ + 1440, + 2 + ], + [ + 1280, + 2 + ], + [ + 1180, + 2 + ], + [ + 1080, + 1 + ], + [ + 960, + 1 + ], + [ + 768, + 0 + ], + [ + 640, + 0 + ], + [ + 520, + 0 + ], + [ + 390, + 0 + ] + ] + }, + { + "name": "wider again: same split as on the way down (automatic return)", + "ok": true, + "data": [ + [ + 390, + 0 + ], + [ + 520, + 0 + ], + [ + 640, + 0 + ], + [ + 768, + 0 + ], + [ + 960, + 1 + ], + [ + 1080, + 1 + ], + [ + 1180, + 2 + ], + [ + 1280, + 2 + ], + [ + 1440, + 2 + ], + [ + 1680, + 3 + ], + [ + 1920, + 5 + ] + ] + }, + { + "name": "no horizontal scroll anywhere (menu row, page)", + "ok": true, + "data": [ + [ + 1920, + 0, + 0, + "hidden" + ], + [ + 1680, + 0, + 0, + "hidden" + ], + [ + 1440, + 0, + 0, + "hidden" + ], + [ + 1280, + 0, + 0, + "hidden" + ], + [ + 1180, + 0, + 0, + "hidden" + ], + [ + 1080, + 0, + 0, + "hidden" + ], + [ + 960, + 0, + 0, + "hidden" + ], + [ + 768, + 0, + 0, + "hidden" + ], + [ + 640, + 0, + 0, + "hidden" + ], + [ + 520, + 0, + 0, + "hidden" + ], + [ + 390, + 0, + 0, + "hidden" + ], + [ + 390, + 0, + 0, + "hidden" + ], + [ + 520, + 0, + 0, + "hidden" + ], + [ + 640, + 0, + 0, + "hidden" + ], + [ + 768, + 0, + 0, + "hidden" + ], + [ + 960, + 0, + 0, + "hidden" + ], + [ + 1080, + 0, + 0, + "hidden" + ], + [ + 1180, + 0, + 0, + "hidden" + ], + [ + 1280, + 0, + 0, + "hidden" + ], + [ + 1440, + 0, + 0, + "hidden" + ], + [ + 1680, + 0, + 0, + "hidden" + ], + [ + 1920, + 0, + 0, + "hidden" + ] + ] + }, + { + "name": "menu (incl. More) stays left of the window area", + "ok": true, + "data": [ + [ + 1920, + 1680, + 1680 + ], + [ + 1680, + 1440, + 1440 + ], + [ + 1440, + 1200, + 1200 + ], + [ + 1280, + 1040, + 1040 + ], + [ + 1180, + 940, + 940 + ], + [ + 1080, + 840, + 840 + ], + [ + 960, + 784, + 784 + ], + [ + 768, + 592, + 592 + ], + [ + 640, + 464, + 464 + ], + [ + 520, + 456, + 456 + ], + [ + 390, + 326, + 326 + ], + [ + 390, + 326, + 326 + ], + [ + 520, + 456, + 456 + ], + [ + 640, + 464, + 464 + ], + [ + 768, + 592, + 592 + ], + [ + 960, + 784, + 784 + ], + [ + 1080, + 840, + 840 + ], + [ + 1180, + 940, + 940 + ], + [ + 1280, + 1040, + 1040 + ], + [ + 1440, + 1200, + 1200 + ], + [ + 1680, + 1440, + 1440 + ], + [ + 1920, + 1680, + 1680 + ] + ] + }, + { + "name": "with More: the menu still reaches the window area (covers the object area as the full menu)", + "ok": true, + "data": [ + [ + 1920, + 1680, + 1680 + ], + [ + 1680, + 1440, + 1440 + ], + [ + 1440, + 1200, + 1200 + ], + [ + 1280, + 1040, + 1040 + ], + [ + 1180, + 940, + 940 + ], + [ + 1080, + 840, + 840 + ], + [ + 960, + 784, + 784 + ], + [ + 768, + 592, + 592 + ], + [ + 640, + 464, + 464 + ], + [ + 520, + 456, + 456 + ], + [ + 390, + 326, + 326 + ], + [ + 390, + 326, + 326 + ], + [ + 520, + 456, + 456 + ], + [ + 640, + 464, + 464 + ], + [ + 768, + 592, + 592 + ], + [ + 960, + 784, + 784 + ], + [ + 1080, + 840, + 840 + ], + [ + 1180, + 940, + 940 + ], + [ + 1280, + 1040, + 1040 + ], + [ + 1440, + 1200, + 1200 + ], + [ + 1680, + 1440, + 1440 + ], + [ + 1920, + 1680, + 1680 + ] + ] + }, + { + "name": "More label = hidden count", + "ok": true, + "data": [ + "2개 그룹", + "3개 그룹", + "3개 그룹", + "3개 그룹", + "4개 그룹", + "4개 그룹", + "5개 그룹", + "5개 그룹", + "5개 그룹", + "5개 그룹", + "5개 그룹", + "5개 그룹", + "5개 그룹", + "5개 그룹", + "4개 그룹", + "4개 그룹", + "3개 그룹", + "3개 그룹", + "3개 그룹", + "2개 그룹" + ] + }, + { + "name": "Home On kept while open (logo border + #5F4B0F lines)", + "ok": true, + "data": [ + [ + 1920, + true, + "1" + ], + [ + 1680, + true, + "1" + ], + [ + 1440, + true, + "1" + ], + [ + 1280, + true, + "1" + ], + [ + 1180, + true, + "1" + ], + [ + 1080, + true, + "1" + ], + [ + 960, + true, + "1" + ], + [ + 768, + true, + "1" + ], + [ + 640, + true, + "1" + ], + [ + 520, + true, + "1" + ], + [ + 390, + true, + "1" + ], + [ + 390, + true, + "1" + ], + [ + 520, + true, + "1" + ], + [ + 640, + true, + "1" + ], + [ + 768, + true, + "1" + ], + [ + 960, + true, + "1" + ], + [ + 1080, + true, + "1" + ], + [ + 1180, + true, + "1" + ], + [ + 1280, + true, + "1" + ], + [ + 1440, + true, + "1" + ], + [ + 1680, + true, + "1" + ], + [ + 1920, + true, + "1" + ] + ] + }, + { + "name": "1080: More closed by default, dropdown not visible", + "ok": true, + "data": { + "vw": 1080, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "moreRect": { + "x": 543, + "y": 0, + "width": 295, + "height": 75, + "top": 0, + "right": 838, + "bottom": 75, + "left": 543 + }, + "moreButton": { + "x": 748, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 828, + "bottom": 69, + "left": 748 + }, + "panelRect": { + "x": 567, + "y": 79, + "width": 271, + "height": 322, + "top": 79, + "right": 838, + "bottom": 401, + "left": 567 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + } + }, + { + "name": "More click opens the dropdown under More (right edges aligned, inside the viewport)", + "ok": true, + "data": { + "vw": 1080, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "true", + "moreActive": "true", + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": true, + "panelVisibility": "visible", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "moreRect": { + "x": 543, + "y": 0, + "width": 295, + "height": 75, + "top": 0, + "right": 838, + "bottom": 75, + "left": 543 + }, + "moreButton": { + "x": 748, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 828, + "bottom": 69, + "left": 748 + }, + "panelRect": { + "x": 567, + "y": 79, + "width": 271, + "height": 322, + "top": 79, + "right": 838, + "bottom": 401, + "left": 567 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + } + }, + { + "name": "hidden tile Hover = Variant2 (ring + #FF5C00)", + "ok": true, + "data": { + "hover": true, + "ring": "1", + "color": "rgb(255, 92, 0)" + } + }, + { + "name": "hidden tile click = Variant3, dropdown stays open", + "ok": true, + "data": { + "active": "true", + "log": null, + "open": true + } + }, + { + "name": "Escape: closes the More dropdown only (menu stays open)", + "ok": true, + "data": { + "vw": 1080, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "moreRect": { + "x": 543, + "y": 0, + "width": 295, + "height": 75, + "top": 0, + "right": 838, + "bottom": 75, + "left": 543 + }, + "moreButton": { + "x": 748, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 828, + "bottom": 69, + "left": 748 + }, + "panelRect": { + "x": 567, + "y": 79, + "width": 271, + "height": 322, + "top": 79, + "right": 838, + "bottom": 401, + "left": 567 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + } + }, + { + "name": "second Escape closes the menu → Home On off", + "ok": true, + "data": { + "vw": 1080, + "open": false, + "homeOn": false, + "homeHover": "0", + "lineTop": "rgba(0, 0, 0, 0)", + "lineBottom": "rgba(0, 0, 0, 0)", + "row": [], + "more": false, + "hidden": [], + "panelOpen": false, + "panelVisibility": null, + "rowScroll": null, + "rowOverflowY": null, + "pageScroll": 0, + "menu": null, + "moreRect": null, + "moreButton": null, + "panelRect": null, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + } + }, + { + "name": "logo click reopens with the same split", + "ok": true, + "data": { + "vw": 1080, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "moreRect": { + "x": 543, + "y": 0, + "width": 295, + "height": 75, + "top": 0, + "right": 838, + "bottom": 75, + "left": 543 + }, + "moreButton": { + "x": 748, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 828, + "bottom": 69, + "left": 748 + }, + "panelRect": { + "x": 567, + "y": 79, + "width": 271, + "height": 322, + "top": 79, + "right": 838, + "bottom": 401, + "left": 567 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + } + }, + { + "name": "768: 다른파일 열기 is inside More", + "ok": true, + "data": { + "vw": 768, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "moreRect": { + "x": 306, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 590, + "bottom": 75, + "left": 306 + }, + "moreButton": { + "x": 500, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 580, + "bottom": 69, + "left": 500 + }, + "panelRect": { + "x": 240, + "y": 79, + "width": 350, + "height": 401, + "top": 79, + "right": 590, + "bottom": 480, + "left": 240 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + } + }, + { + "name": "최근파일 in More: list opens under the More tile, dropdown closes, More = Variant3, inside the viewport", + "ok": true, + "data": { + "vw": 768, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": "true", + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "moreRect": { + "x": 306, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 590, + "bottom": 75, + "left": 306 + }, + "moreButton": { + "x": 500, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 580, + "bottom": 69, + "left": 500 + }, + "panelRect": { + "x": 240, + "y": 79, + "width": 350, + "height": 401, + "top": 79, + "right": 590, + "bottom": 480, + "left": 240 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": { + "x": 414, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 768, + "bottom": 829, + "left": 414 + }, + "subFromMore": false + } + }, + { + "name": "Escape closes the 최근파일 list first, menu stays", + "ok": true, + "data": { + "vw": 768, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "moreRect": { + "x": 306, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 590, + "bottom": 75, + "left": 306 + }, + "moreButton": { + "x": 500, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 580, + "bottom": 69, + "left": 500 + }, + "panelRect": { + "x": 240, + "y": 79, + "width": 350, + "height": 401, + "top": 79, + "right": 590, + "bottom": 480, + "left": 240 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + } + }, + { + "name": "widen to 1920 with the dropdown open: all groups back in the row, More removed", + "ok": true, + "data": { + "vw": 1920, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "more": false, + "hidden": [], + "panelOpen": false, + "panelVisibility": null, + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 1305, + "height": 77, + "top": 0, + "right": 1680, + "bottom": 77, + "left": 375 + }, + "moreRect": null, + "moreButton": null, + "panelRect": null, + "win": { + "x": 1680, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1920, + "bottom": 48, + "left": 1680 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + } + }, + { + "name": "no page errors", + "ok": true, + "data": [] + } + ], + "down": [ + { + "vw": 1920, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "more": false, + "hidden": [], + "panelOpen": false, + "panelVisibility": null, + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 1305, + "height": 77, + "top": 0, + "right": 1680, + "bottom": 77, + "left": 375 + }, + "moreRect": null, + "moreButton": null, + "panelRect": null, + "win": { + "x": 1680, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1920, + "bottom": 48, + "left": 1680 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1680, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시" + ], + "more": true, + "moreLabel": "2개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 1065, + "height": 77, + "top": 0, + "right": 1440, + "bottom": 77, + "left": 375 + }, + "moreRect": { + "x": 1157, + "y": 0, + "width": 281, + "height": 75, + "top": 0, + "right": 1438, + "bottom": 75, + "left": 1157 + }, + "moreButton": { + "x": 1348, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 1428, + "bottom": 69, + "left": 1348 + }, + "panelRect": { + "x": 1167, + "y": 79, + "width": 271, + "height": 164, + "top": 79, + "right": 1438, + "bottom": 243, + "left": 1167 + }, + "win": { + "x": 1440, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1680, + "bottom": 48, + "left": 1440 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1440, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기" + ], + "more": true, + "moreLabel": "3개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "moreRect": { + "x": 977, + "y": 0, + "width": 221, + "height": 75, + "top": 0, + "right": 1198, + "bottom": 75, + "left": 977 + }, + "moreButton": { + "x": 1108, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 1188, + "bottom": 69, + "left": 1108 + }, + "panelRect": { + "x": 927, + "y": 79, + "width": 271, + "height": 243, + "top": 79, + "right": 1198, + "bottom": 322, + "left": 927 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1280, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기" + ], + "more": true, + "moreLabel": "3개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 315, + "y": 0, + "width": 725, + "height": 77, + "top": 0, + "right": 1040, + "bottom": 77, + "left": 315 + }, + "moreRect": { + "x": 917, + "y": 0, + "width": 121, + "height": 75, + "top": 0, + "right": 1038, + "bottom": 75, + "left": 917 + }, + "moreButton": { + "x": 948, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 1028, + "bottom": 69, + "left": 948 + }, + "panelRect": { + "x": 767, + "y": 79, + "width": 271, + "height": 243, + "top": 79, + "right": 1038, + "bottom": 322, + "left": 767 + }, + "win": { + "x": 1040, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1280, + "bottom": 48, + "left": 1040 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1180, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기" + ], + "more": true, + "moreLabel": "3개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 215, + "y": 0, + "width": 725, + "height": 77, + "top": 0, + "right": 940, + "bottom": 77, + "left": 215 + }, + "moreRect": { + "x": 817, + "y": 0, + "width": 121, + "height": 75, + "top": 0, + "right": 938, + "bottom": 75, + "left": 817 + }, + "moreButton": { + "x": 848, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 928, + "bottom": 69, + "left": 848 + }, + "panelRect": { + "x": 667, + "y": 79, + "width": 271, + "height": 243, + "top": 79, + "right": 938, + "bottom": 322, + "left": 667 + }, + "win": { + "x": 940, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1180, + "bottom": 48, + "left": 940 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1080, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "moreRect": { + "x": 543, + "y": 0, + "width": 295, + "height": 75, + "top": 0, + "right": 838, + "bottom": 75, + "left": 543 + }, + "moreButton": { + "x": 748, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 828, + "bottom": 69, + "left": 748 + }, + "panelRect": { + "x": 567, + "y": 79, + "width": 271, + "height": 322, + "top": 79, + "right": 838, + "bottom": 401, + "left": 567 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 960, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 300, + "y": 0, + "width": 484, + "height": 77, + "top": 0, + "right": 784, + "bottom": 77, + "left": 300 + }, + "moreRect": { + "x": 642, + "y": 0, + "width": 140, + "height": 75, + "top": 0, + "right": 782, + "bottom": 75, + "left": 642 + }, + "moreButton": { + "x": 692, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 772, + "bottom": 69, + "left": 692 + }, + "panelRect": { + "x": 511, + "y": 79, + "width": 271, + "height": 322, + "top": 79, + "right": 782, + "bottom": 401, + "left": 511 + }, + "win": { + "x": 784, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 960, + "bottom": 48, + "left": 784 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 768, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "moreRect": { + "x": 306, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 590, + "bottom": 75, + "left": 306 + }, + "moreButton": { + "x": 500, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 580, + "bottom": 69, + "left": 500 + }, + "panelRect": { + "x": 240, + "y": 79, + "width": 350, + "height": 401, + "top": 79, + "right": 590, + "bottom": 480, + "left": 240 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 640, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 176, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 464, + "bottom": 77, + "left": 176 + }, + "moreRect": { + "x": 178, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 462, + "bottom": 75, + "left": 178 + }, + "moreButton": { + "x": 372, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 452, + "bottom": 69, + "left": 372 + }, + "panelRect": { + "x": 112, + "y": 79, + "width": 350, + "height": 401, + "top": 79, + "right": 462, + "bottom": 480, + "left": 112 + }, + "win": { + "x": 464, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 640, + "bottom": 48, + "left": 464 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 520, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 168, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 456, + "bottom": 77, + "left": 168 + }, + "moreRect": { + "x": 170, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 454, + "bottom": 75, + "left": 170 + }, + "moreButton": { + "x": 364, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 444, + "bottom": 69, + "left": 364 + }, + "panelRect": { + "x": 104, + "y": 79, + "width": 350, + "height": 401, + "top": 79, + "right": 454, + "bottom": 480, + "left": 104 + }, + "win": { + "x": 456, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 520, + "bottom": 48, + "left": 456 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 390, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "moreRect": { + "x": 163, + "y": 0, + "width": 161, + "height": 75, + "top": 0, + "right": 324, + "bottom": 75, + "left": 163 + }, + "moreButton": { + "x": 234, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 314, + "bottom": 69, + "left": 234 + }, + "panelRect": { + "x": 0, + "y": 79, + "width": 350, + "height": 401, + "top": 79, + "right": 350, + "bottom": 480, + "left": 0 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + } + ], + "up": [ + { + "vw": 390, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "moreRect": { + "x": 163, + "y": 0, + "width": 161, + "height": 75, + "top": 0, + "right": 324, + "bottom": 75, + "left": 163 + }, + "moreButton": { + "x": 234, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 314, + "bottom": 69, + "left": 234 + }, + "panelRect": { + "x": 0, + "y": 79, + "width": 350, + "height": 401, + "top": 79, + "right": 350, + "bottom": 480, + "left": 0 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 520, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 168, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 456, + "bottom": 77, + "left": 168 + }, + "moreRect": { + "x": 170, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 454, + "bottom": 75, + "left": 170 + }, + "moreButton": { + "x": 364, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 444, + "bottom": 69, + "left": 364 + }, + "panelRect": { + "x": 104, + "y": 79, + "width": 350, + "height": 401, + "top": 79, + "right": 454, + "bottom": 480, + "left": 104 + }, + "win": { + "x": 456, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 520, + "bottom": 48, + "left": 456 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 640, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 176, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 464, + "bottom": 77, + "left": 176 + }, + "moreRect": { + "x": 178, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 462, + "bottom": 75, + "left": 178 + }, + "moreButton": { + "x": 372, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 452, + "bottom": 69, + "left": 372 + }, + "panelRect": { + "x": 112, + "y": 79, + "width": 350, + "height": 401, + "top": 79, + "right": 462, + "bottom": 480, + "left": 112 + }, + "win": { + "x": 464, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 640, + "bottom": 48, + "left": 464 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 768, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "moreRect": { + "x": 306, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 590, + "bottom": 75, + "left": 306 + }, + "moreButton": { + "x": 500, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 580, + "bottom": 69, + "left": 500 + }, + "panelRect": { + "x": 240, + "y": 79, + "width": 350, + "height": 401, + "top": 79, + "right": 590, + "bottom": 480, + "left": 240 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 960, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 300, + "y": 0, + "width": 484, + "height": 77, + "top": 0, + "right": 784, + "bottom": 77, + "left": 300 + }, + "moreRect": { + "x": 642, + "y": 0, + "width": 140, + "height": 75, + "top": 0, + "right": 782, + "bottom": 75, + "left": 642 + }, + "moreButton": { + "x": 692, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 772, + "bottom": 69, + "left": 692 + }, + "panelRect": { + "x": 511, + "y": 79, + "width": 271, + "height": 322, + "top": 79, + "right": 782, + "bottom": 401, + "left": 511 + }, + "win": { + "x": 784, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 960, + "bottom": 48, + "left": 784 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1080, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "moreRect": { + "x": 543, + "y": 0, + "width": 295, + "height": 75, + "top": 0, + "right": 838, + "bottom": 75, + "left": 543 + }, + "moreButton": { + "x": 748, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 828, + "bottom": 69, + "left": 748 + }, + "panelRect": { + "x": 567, + "y": 79, + "width": 271, + "height": 322, + "top": 79, + "right": 838, + "bottom": 401, + "left": 567 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1180, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기" + ], + "more": true, + "moreLabel": "3개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 215, + "y": 0, + "width": 725, + "height": 77, + "top": 0, + "right": 940, + "bottom": 77, + "left": 215 + }, + "moreRect": { + "x": 817, + "y": 0, + "width": 121, + "height": 75, + "top": 0, + "right": 938, + "bottom": 75, + "left": 817 + }, + "moreButton": { + "x": 848, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 928, + "bottom": 69, + "left": 848 + }, + "panelRect": { + "x": 667, + "y": 79, + "width": 271, + "height": 243, + "top": 79, + "right": 938, + "bottom": 322, + "left": 667 + }, + "win": { + "x": 940, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1180, + "bottom": 48, + "left": 940 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1280, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기" + ], + "more": true, + "moreLabel": "3개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 315, + "y": 0, + "width": 725, + "height": 77, + "top": 0, + "right": 1040, + "bottom": 77, + "left": 315 + }, + "moreRect": { + "x": 917, + "y": 0, + "width": 121, + "height": 75, + "top": 0, + "right": 1038, + "bottom": 75, + "left": 917 + }, + "moreButton": { + "x": 948, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 1028, + "bottom": 69, + "left": 948 + }, + "panelRect": { + "x": 767, + "y": 79, + "width": 271, + "height": 243, + "top": 79, + "right": 1038, + "bottom": 322, + "left": 767 + }, + "win": { + "x": 1040, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1280, + "bottom": 48, + "left": 1040 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1440, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기" + ], + "more": true, + "moreLabel": "3개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "moreRect": { + "x": 977, + "y": 0, + "width": 221, + "height": 75, + "top": 0, + "right": 1198, + "bottom": 75, + "left": 977 + }, + "moreButton": { + "x": 1108, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 1188, + "bottom": 69, + "left": 1108 + }, + "panelRect": { + "x": 927, + "y": 79, + "width": 271, + "height": 243, + "top": 79, + "right": 1198, + "bottom": 322, + "left": 927 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1680, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시" + ], + "more": true, + "moreLabel": "2개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "My Setting", + "궁금하면" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 1065, + "height": 77, + "top": 0, + "right": 1440, + "bottom": 77, + "left": 375 + }, + "moreRect": { + "x": 1157, + "y": 0, + "width": 281, + "height": 75, + "top": 0, + "right": 1438, + "bottom": 75, + "left": 1157 + }, + "moreButton": { + "x": 1348, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 1428, + "bottom": 69, + "left": 1348 + }, + "panelRect": { + "x": 1167, + "y": 79, + "width": 271, + "height": 164, + "top": 79, + "right": 1438, + "bottom": 243, + "left": 1167 + }, + "win": { + "x": 1440, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1680, + "bottom": 48, + "left": 1440 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1920, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "more": false, + "hidden": [], + "panelOpen": false, + "panelVisibility": null, + "rowScroll": 0, + "rowOverflowY": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 1305, + "height": 77, + "top": 0, + "right": 1680, + "bottom": 77, + "left": 375 + }, + "moreRect": null, + "moreButton": null, + "panelRect": null, + "win": { + "x": 1680, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1920, + "bottom": 48, + "left": 1680 + }, + "homeRect": { + "x": 0, + "y": 0, + "width": 80, + "height": 48, + "top": 0, + "right": 80, + "bottom": 48, + "left": 0 + }, + "sub": null, + "subFromMore": null + } + ], + "errors": [] +} \ No newline at end of file diff --git a/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-active.png b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-active.png new file mode 100644 index 0000000..e074efd Binary files /dev/null and b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-active.png differ diff --git a/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-closed.png b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-closed.png new file mode 100644 index 0000000..3b9de3b Binary files /dev/null and b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-closed.png differ diff --git a/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-hover.png b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-hover.png new file mode 100644 index 0000000..b9b9fe1 Binary files /dev/null and b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-hover.png differ diff --git a/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-open.png b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-open.png new file mode 100644 index 0000000..7dd8275 Binary files /dev/null and b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-open.png differ diff --git a/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-recent-preview.png b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-recent-preview.png new file mode 100644 index 0000000..3bc7c34 Binary files /dev/null and b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-1080-recent-preview.png differ diff --git a/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-768-recent-more.png b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-768-recent-more.png new file mode 100644 index 0000000..b5d015d Binary files /dev/null and b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-768-recent-more.png differ diff --git a/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-768-recent.png b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-768-recent.png new file mode 100644 index 0000000..2138405 Binary files /dev/null and b/docs/sw/home-menu-more-text-qa-2026-10-19/narrow-768-recent.png differ diff --git a/docs/sw/home-menu-more-text-qa-2026-10-19/report.json b/docs/sw/home-menu-more-text-qa-2026-10-19/report.json new file mode 100644 index 0000000..b50f4cc --- /dev/null +++ b/docs/sw/home-menu-more-text-qa-2026-10-19/report.json @@ -0,0 +1,4471 @@ +{ + "checks": [ + { + "name": "all widths: 5 groups = Figma row + More text groups, order kept", + "ok": true, + "data": [ + [ + 1920, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [] + ], + [ + 1680, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시" + ], + [ + "My Setting", + "궁금하면" + ] + ], + [ + 1440, + [ + "작업중인 파일", + "다른파일 열기" + ], + [ + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1280, + [ + "작업중인 파일", + "다른파일 열기" + ], + [ + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1180, + [ + "작업중인 파일", + "다른파일 열기" + ], + [ + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1080, + [ + "작업중인 파일" + ], + [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 960, + [ + "작업중인 파일" + ], + [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 768, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 640, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 520, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 390, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 390, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 520, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 640, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 768, + [], + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 960, + [ + "작업중인 파일" + ], + [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1080, + [ + "작업중인 파일" + ], + [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1180, + [ + "작업중인 파일", + "다른파일 열기" + ], + [ + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1280, + [ + "작업중인 파일", + "다른파일 열기" + ], + [ + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1440, + [ + "작업중인 파일", + "다른파일 열기" + ], + [ + "파일 손상시", + "My Setting", + "궁금하면" + ] + ], + [ + 1680, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시" + ], + [ + "My Setting", + "궁금하면" + ] + ], + [ + 1920, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [] + ] + ] + }, + { + "name": "1920: all 5 groups in the row, no More", + "ok": true, + "data": { + "vw": 1920, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "rowTilesOnly": true, + "more": false, + "hidden": [], + "hiddenItems": [], + "panelTiles": 0, + "dividers": [], + "panelOpen": false, + "panelVisibility": null, + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 1305, + "height": 77, + "top": 0, + "right": 1680, + "bottom": 77, + "left": 375 + }, + "moreRect": null, + "moreButton": null, + "panelRect": null, + "win": { + "x": 1680, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1920, + "bottom": 48, + "left": 1680 + }, + "sub": null, + "subFromMore": null + } + }, + { + "name": "narrower: groups move into More; wider: they return (same split both ways)", + "ok": true, + "data": [ + [ + 1920, + 5 + ], + [ + 1680, + 3 + ], + [ + 1440, + 2 + ], + [ + 1280, + 2 + ], + [ + 1180, + 2 + ], + [ + 1080, + 1 + ], + [ + 960, + 1 + ], + [ + 768, + 0 + ], + [ + 640, + 0 + ], + [ + 520, + 0 + ], + [ + 390, + 0 + ], + [ + 390, + 0 + ], + [ + 520, + 0 + ], + [ + 640, + 0 + ], + [ + 768, + 0 + ], + [ + 960, + 1 + ], + [ + 1080, + 1 + ], + [ + 1180, + 2 + ], + [ + 1280, + 2 + ], + [ + 1440, + 2 + ], + [ + 1680, + 3 + ], + [ + 1920, + 5 + ] + ] + }, + { + "name": "row keeps the Figma tiles; dropdown has no tiles or icons", + "ok": true, + "data": [ + [ + 1920, + true, + 0 + ], + [ + 1680, + true, + 0 + ], + [ + 1440, + true, + 0 + ], + [ + 1280, + true, + 0 + ], + [ + 1180, + true, + 0 + ], + [ + 1080, + true, + 0 + ], + [ + 960, + true, + 0 + ], + [ + 768, + true, + 0 + ], + [ + 640, + true, + 0 + ], + [ + 520, + true, + 0 + ], + [ + 390, + true, + 0 + ], + [ + 390, + true, + 0 + ], + [ + 520, + true, + 0 + ], + [ + 640, + true, + 0 + ], + [ + 768, + true, + 0 + ], + [ + 960, + true, + 0 + ], + [ + 1080, + true, + 0 + ], + [ + 1180, + true, + 0 + ], + [ + 1280, + true, + 0 + ], + [ + 1440, + true, + 0 + ], + [ + 1680, + true, + 0 + ], + [ + 1920, + true, + 0 + ] + ] + }, + { + "name": "text groups: title + every item of that group as text, in order", + "ok": true, + "data": [ + [ + 1920, + [], + [] + ], + [ + 1680, + [ + "My Setting", + "궁금하면" + ], + [ + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 1440, + [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 1280, + [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 1180, + [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 1080, + [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 960, + [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 768, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 640, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 520, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 390, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 390, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 520, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 640, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 768, + [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 960, + [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 1080, + [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 1180, + [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 1280, + [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 1440, + [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + [ + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 1680, + [ + "My Setting", + "궁금하면" + ], + [ + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ] + ], + [ + 1920, + [], + [] + ] + ] + }, + { + "name": "divider between groups (1px top border on every group after the first)", + "ok": true, + "data": [ + [], + [ + "0px", + "1px" + ], + [ + "0px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px" + ], + [ + "0px", + "1px", + "1px" + ], + [ + "0px", + "1px" + ], + [] + ] + }, + { + "name": "no horizontal scroll (menu row, page)", + "ok": true, + "data": [ + [ + 1920, + 0, + 0 + ], + [ + 1680, + 0, + 0 + ], + [ + 1440, + 0, + 0 + ], + [ + 1280, + 0, + 0 + ], + [ + 1180, + 0, + 0 + ], + [ + 1080, + 0, + 0 + ], + [ + 960, + 0, + 0 + ], + [ + 768, + 0, + 0 + ], + [ + 640, + 0, + 0 + ], + [ + 520, + 0, + 0 + ], + [ + 390, + 0, + 0 + ], + [ + 390, + 0, + 0 + ], + [ + 520, + 0, + 0 + ], + [ + 640, + 0, + 0 + ], + [ + 768, + 0, + 0 + ], + [ + 960, + 0, + 0 + ], + [ + 1080, + 0, + 0 + ], + [ + 1180, + 0, + 0 + ], + [ + 1280, + 0, + 0 + ], + [ + 1440, + 0, + 0 + ], + [ + 1680, + 0, + 0 + ], + [ + 1920, + 0, + 0 + ] + ] + }, + { + "name": "Home On kept while open (logo border + #5F4B0F lines)", + "ok": true, + "data": [ + [ + 1920, + true + ], + [ + 1680, + true + ], + [ + 1440, + true + ], + [ + 1280, + true + ], + [ + 1180, + true + ], + [ + 1080, + true + ], + [ + 960, + true + ], + [ + 768, + true + ], + [ + 640, + true + ], + [ + 520, + true + ], + [ + 390, + true + ], + [ + 390, + true + ], + [ + 520, + true + ], + [ + 640, + true + ], + [ + 768, + true + ], + [ + 960, + true + ], + [ + 1080, + true + ], + [ + 1180, + true + ], + [ + 1280, + true + ], + [ + 1440, + true + ], + [ + 1680, + true + ], + [ + 1920, + true + ] + ] + }, + { + "name": "More click opens the text menu under More (right edges aligned, inside the viewport)", + "ok": true, + "data": { + "vw": 1080, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "true", + "moreActive": "true", + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px" + ], + "panelOpen": true, + "panelVisibility": "visible", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "moreRect": { + "x": 543, + "y": 0, + "width": 295, + "height": 75, + "top": 0, + "right": 838, + "bottom": 75, + "left": 543 + }, + "moreButton": { + "x": 748, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 828, + "bottom": 69, + "left": 748 + }, + "panelRect": { + "x": 658, + "y": 79, + "width": 180, + "height": 471, + "top": 79, + "right": 838, + "bottom": 550, + "left": 658 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "sub": null, + "subFromMore": null + } + }, + { + "name": "text menu uses SW tokens (brown dropdown #27241D / #000 / 3px, title 12px 700 #D4CBBD, rows 14px 700 #F6F4F2 30px 12px, Noto Sans KR)", + "ok": true, + "data": { + "panelBg": "rgb(39, 36, 29)", + "panelBorder": "rgb(0, 0, 0)", + "radius": "3px", + "title": [ + "12px", + "700", + "rgb(212, 203, 189)" + ], + "item": [ + "14px", + "700", + "rgb(246, 244, 242)", + "30px", + "12px" + ], + "family": "\"Noto Sans KR\"" + } + }, + { + "name": "text row Hover: #62533D row, #FF5C00 text (SW brown row hover)", + "ok": true, + "data": { + "hover": true, + "bg": "rgb(98, 83, 61)", + "color": "rgb(255, 92, 0)" + } + }, + { + "name": "text row click: Active (aria-pressed, ✓, orange on brown), dropdown stays open, same callbacks as the tile", + "ok": true, + "data": { + "act": { + "active": "true", + "pressed": "true", + "mark": "\"✓\"", + "bg": "rgb(98, 83, 61)", + "color": "rgb(255, 92, 0)", + "open": true, + "log": "" + }, + "before": "" + } + }, + { + "name": "second click: back to default", + "ok": true, + "data": null + }, + { + "name": "Escape closes only the dropdown (focus on More)", + "ok": true, + "data": { + "s": { + "vw": 1080, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "moreRect": { + "x": 543, + "y": 0, + "width": 295, + "height": 75, + "top": 0, + "right": 838, + "bottom": 75, + "left": 543 + }, + "moreButton": { + "x": 748, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 828, + "bottom": 69, + "left": 748 + }, + "panelRect": { + "x": 658, + "y": 79, + "width": 180, + "height": 471, + "top": 79, + "right": 838, + "bottom": 550, + "left": 658 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "sub": null, + "subFromMore": null + }, + "focused": "MORE" + } + }, + { + "name": "keyboard: ArrowDown on More opens on the first row, ArrowDown next, ArrowUp back to More", + "ok": true, + "data": [ + "find-open", + "recent", + "MORE" + ] + }, + { + "name": "keyboard: Enter on 최근파일 opens the list under More, focus back on More", + "ok": true, + "data": { + "s": { + "vw": 1080, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": "true", + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "moreRect": { + "x": 543, + "y": 0, + "width": 295, + "height": 75, + "top": 0, + "right": 838, + "bottom": 75, + "left": 543 + }, + "moreButton": { + "x": 748, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 828, + "bottom": 69, + "left": 748 + }, + "panelRect": { + "x": 658, + "y": 79, + "width": 180, + "height": 471, + "top": 79, + "right": 838, + "bottom": 550, + "left": 658 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "sub": { + "x": 726, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 1080, + "bottom": 829, + "left": 726 + }, + "subFromMore": false + }, + "f": "MORE" + } + }, + { + "name": "keyboard path: no page scroll with the list (and a hovered preview) open", + "ok": true, + "data": 0 + }, + { + "name": "1080: 2-depth preview flips to the left of the list (no room on the right), inside the viewport, no page scroll", + "ok": true, + "data": { + "side": "left", + "left": 415, + "right": 725, + "page": 0 + } + }, + { + "name": "Escape closes the list, menu stays", + "ok": true, + "data": { + "vw": 1080, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "moreRect": { + "x": 543, + "y": 0, + "width": 295, + "height": 75, + "top": 0, + "right": 838, + "bottom": 75, + "left": 543 + }, + "moreButton": { + "x": 748, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 828, + "bottom": 69, + "left": 748 + }, + "panelRect": { + "x": 658, + "y": 79, + "width": 180, + "height": 471, + "top": 79, + "right": 838, + "bottom": 550, + "left": 658 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "sub": null, + "subFromMore": null + } + }, + { + "name": "최근파일 row (›, aria-expanded) opens the existing list under More, dropdown closes, More = Variant3, no page scroll", + "ok": true, + "data": { + "recentRow": { + "mark": "\"›\"", + "expanded": "false" + }, + "s": { + "vw": 768, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "rowTilesOnly": true, + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": "true", + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "moreRect": { + "x": 306, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 590, + "bottom": 75, + "left": 306 + }, + "moreButton": { + "x": 500, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 580, + "bottom": 69, + "left": 500 + }, + "panelRect": { + "x": 410, + "y": 79, + "width": 180, + "height": 624, + "top": 79, + "right": 590, + "bottom": 703, + "left": 410 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "sub": { + "x": 414, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 768, + "bottom": 829, + "left": 414 + }, + "subFromMore": false + } + } + }, + { + "name": "the 최근파일 list is the existing SWRecentFiles (15 rows)", + "ok": true, + "data": 15 + }, + { + "name": "reopened More: 최근파일 row shows Active while its list is open", + "ok": true, + "data": { + "active": "true", + "expanded": "true", + "bg": "rgb(98, 83, 61)" + } + }, + { + "name": "widen to 1920: all groups back in the Figma row, More removed", + "ok": true, + "data": { + "vw": 1920, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "rowTilesOnly": true, + "more": false, + "hidden": [], + "hiddenItems": [], + "panelTiles": 0, + "dividers": [], + "panelOpen": false, + "panelVisibility": null, + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 1305, + "height": 77, + "top": 0, + "right": 1680, + "bottom": 77, + "left": 375 + }, + "moreRect": null, + "moreButton": null, + "panelRect": null, + "win": { + "x": 1680, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1920, + "bottom": 48, + "left": 1680 + }, + "sub": { + "x": 808, + "y": 77, + "width": 354, + "height": 752, + "top": 77, + "right": 1162, + "bottom": 829, + "left": 808 + }, + "subFromMore": false + } + }, + { + "name": "text row click fires the same callbacks as the tile (onActiveChange + onItemSelect with section)", + "ok": true, + "data": "onItemSelect(open / find-open, active=true)\nonActiveChange([find-open])\nonHomeMenuOpenChange(true, home)" + }, + { + "name": "no page errors", + "ok": true, + "data": [] + } + ], + "down": [ + { + "vw": 1920, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "rowTilesOnly": true, + "more": false, + "hidden": [], + "hiddenItems": [], + "panelTiles": 0, + "dividers": [], + "panelOpen": false, + "panelVisibility": null, + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 1305, + "height": 77, + "top": 0, + "right": 1680, + "bottom": 77, + "left": 375 + }, + "moreRect": null, + "moreButton": null, + "panelRect": null, + "win": { + "x": 1680, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1920, + "bottom": 48, + "left": 1680 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1680, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "2개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 1065, + "height": 77, + "top": 0, + "right": 1440, + "bottom": 77, + "left": 375 + }, + "moreRect": { + "x": 1157, + "y": 0, + "width": 281, + "height": 75, + "top": 0, + "right": 1438, + "bottom": 75, + "left": 1157 + }, + "moreButton": { + "x": 1348, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 1428, + "bottom": 69, + "left": 1348 + }, + "panelRect": { + "x": 1258, + "y": 79, + "width": 180, + "height": 255, + "top": 79, + "right": 1438, + "bottom": 334, + "left": 1258 + }, + "win": { + "x": 1440, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1680, + "bottom": 48, + "left": 1440 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1440, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "3개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "moreRect": { + "x": 977, + "y": 0, + "width": 221, + "height": 75, + "top": 0, + "right": 1198, + "bottom": 75, + "left": 977 + }, + "moreButton": { + "x": 1108, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 1188, + "bottom": 69, + "left": 1108 + }, + "panelRect": { + "x": 1018, + "y": 79, + "width": 180, + "height": 348, + "top": 79, + "right": 1198, + "bottom": 427, + "left": 1018 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1280, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "3개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 315, + "y": 0, + "width": 725, + "height": 77, + "top": 0, + "right": 1040, + "bottom": 77, + "left": 315 + }, + "moreRect": { + "x": 917, + "y": 0, + "width": 121, + "height": 75, + "top": 0, + "right": 1038, + "bottom": 75, + "left": 917 + }, + "moreButton": { + "x": 948, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 1028, + "bottom": 69, + "left": 948 + }, + "panelRect": { + "x": 858, + "y": 79, + "width": 180, + "height": 348, + "top": 79, + "right": 1038, + "bottom": 427, + "left": 858 + }, + "win": { + "x": 1040, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1280, + "bottom": 48, + "left": 1040 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1180, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "3개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 215, + "y": 0, + "width": 725, + "height": 77, + "top": 0, + "right": 940, + "bottom": 77, + "left": 215 + }, + "moreRect": { + "x": 817, + "y": 0, + "width": 121, + "height": 75, + "top": 0, + "right": 938, + "bottom": 75, + "left": 817 + }, + "moreButton": { + "x": 848, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 928, + "bottom": 69, + "left": 848 + }, + "panelRect": { + "x": 758, + "y": 79, + "width": 180, + "height": 348, + "top": 79, + "right": 938, + "bottom": 427, + "left": 758 + }, + "win": { + "x": 940, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1180, + "bottom": 48, + "left": 940 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1080, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "moreRect": { + "x": 543, + "y": 0, + "width": 295, + "height": 75, + "top": 0, + "right": 838, + "bottom": 75, + "left": 543 + }, + "moreButton": { + "x": 748, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 828, + "bottom": 69, + "left": 748 + }, + "panelRect": { + "x": 658, + "y": 79, + "width": 180, + "height": 471, + "top": 79, + "right": 838, + "bottom": 550, + "left": 658 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 960, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 300, + "y": 0, + "width": 484, + "height": 77, + "top": 0, + "right": 784, + "bottom": 77, + "left": 300 + }, + "moreRect": { + "x": 642, + "y": 0, + "width": 140, + "height": 75, + "top": 0, + "right": 782, + "bottom": 75, + "left": 642 + }, + "moreButton": { + "x": 692, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 772, + "bottom": 69, + "left": 692 + }, + "panelRect": { + "x": 602, + "y": 79, + "width": 180, + "height": 471, + "top": 79, + "right": 782, + "bottom": 550, + "left": 602 + }, + "win": { + "x": 784, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 960, + "bottom": 48, + "left": 784 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 768, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "rowTilesOnly": true, + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "moreRect": { + "x": 306, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 590, + "bottom": 75, + "left": 306 + }, + "moreButton": { + "x": 500, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 580, + "bottom": 69, + "left": 500 + }, + "panelRect": { + "x": 410, + "y": 79, + "width": 180, + "height": 624, + "top": 79, + "right": 590, + "bottom": 703, + "left": 410 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 640, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "rowTilesOnly": true, + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 176, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 464, + "bottom": 77, + "left": 176 + }, + "moreRect": { + "x": 178, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 462, + "bottom": 75, + "left": 178 + }, + "moreButton": { + "x": 372, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 452, + "bottom": 69, + "left": 372 + }, + "panelRect": { + "x": 282, + "y": 79, + "width": 180, + "height": 624, + "top": 79, + "right": 462, + "bottom": 703, + "left": 282 + }, + "win": { + "x": 464, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 640, + "bottom": 48, + "left": 464 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 520, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "rowTilesOnly": true, + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 168, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 456, + "bottom": 77, + "left": 168 + }, + "moreRect": { + "x": 170, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 454, + "bottom": 75, + "left": 170 + }, + "moreButton": { + "x": 364, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 444, + "bottom": 69, + "left": 364 + }, + "panelRect": { + "x": 274, + "y": 79, + "width": 180, + "height": 624, + "top": 79, + "right": 454, + "bottom": 703, + "left": 274 + }, + "win": { + "x": 456, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 520, + "bottom": 48, + "left": 456 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 390, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "rowTilesOnly": true, + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "moreRect": { + "x": 163, + "y": 0, + "width": 161, + "height": 75, + "top": 0, + "right": 324, + "bottom": 75, + "left": 163 + }, + "moreButton": { + "x": 234, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 314, + "bottom": 69, + "left": 234 + }, + "panelRect": { + "x": 144, + "y": 79, + "width": 180, + "height": 624, + "top": 79, + "right": 324, + "bottom": 703, + "left": 144 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "sub": null, + "subFromMore": null + } + ], + "up": [ + { + "vw": 390, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "rowTilesOnly": true, + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 161, + "y": 0, + "width": 165, + "height": 77, + "top": 0, + "right": 326, + "bottom": 77, + "left": 161 + }, + "moreRect": { + "x": 163, + "y": 0, + "width": 161, + "height": 75, + "top": 0, + "right": 324, + "bottom": 75, + "left": 163 + }, + "moreButton": { + "x": 234, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 314, + "bottom": 69, + "left": 234 + }, + "panelRect": { + "x": 144, + "y": 79, + "width": 180, + "height": 624, + "top": 79, + "right": 324, + "bottom": 703, + "left": 144 + }, + "win": { + "x": 326, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 390, + "bottom": 48, + "left": 326 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 520, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "rowTilesOnly": true, + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 168, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 456, + "bottom": 77, + "left": 168 + }, + "moreRect": { + "x": 170, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 454, + "bottom": 75, + "left": 170 + }, + "moreButton": { + "x": 364, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 444, + "bottom": 69, + "left": 364 + }, + "panelRect": { + "x": 274, + "y": 79, + "width": 180, + "height": 624, + "top": 79, + "right": 454, + "bottom": 703, + "left": 274 + }, + "win": { + "x": 456, + "y": 0, + "width": 64, + "height": 48, + "top": 0, + "right": 520, + "bottom": 48, + "left": 456 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 640, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "rowTilesOnly": true, + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 176, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 464, + "bottom": 77, + "left": 176 + }, + "moreRect": { + "x": 178, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 462, + "bottom": 75, + "left": 178 + }, + "moreButton": { + "x": 372, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 452, + "bottom": 69, + "left": 372 + }, + "panelRect": { + "x": 282, + "y": 79, + "width": 180, + "height": 624, + "top": 79, + "right": 462, + "bottom": 703, + "left": 282 + }, + "win": { + "x": 464, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 640, + "bottom": 48, + "left": 464 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 768, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [], + "rowTilesOnly": true, + "more": true, + "moreLabel": "5개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "저장", + "복사저장", + "내보내기", + "도면묶기" + ], + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 304, + "y": 0, + "width": 288, + "height": 77, + "top": 0, + "right": 592, + "bottom": 77, + "left": 304 + }, + "moreRect": { + "x": 306, + "y": 0, + "width": 284, + "height": 75, + "top": 0, + "right": 590, + "bottom": 75, + "left": 306 + }, + "moreButton": { + "x": 500, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 580, + "bottom": 69, + "left": 500 + }, + "panelRect": { + "x": 410, + "y": 79, + "width": 180, + "height": 624, + "top": 79, + "right": 590, + "bottom": 703, + "left": 410 + }, + "win": { + "x": 592, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 768, + "bottom": 48, + "left": 592 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 960, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 300, + "y": 0, + "width": 484, + "height": 77, + "top": 0, + "right": 784, + "bottom": 77, + "left": 300 + }, + "moreRect": { + "x": 642, + "y": 0, + "width": 140, + "height": 75, + "top": 0, + "right": 782, + "bottom": 75, + "left": 642 + }, + "moreButton": { + "x": 692, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 772, + "bottom": 69, + "left": 692 + }, + "panelRect": { + "x": 602, + "y": 79, + "width": 180, + "height": 471, + "top": 79, + "right": 782, + "bottom": 550, + "left": 602 + }, + "win": { + "x": 784, + "y": 0, + "width": 176, + "height": 48, + "top": 0, + "right": 960, + "bottom": 48, + "left": 784 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1080, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "4개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "찾아열기", + "최근파일", + "새파일" + ], + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 201, + "y": 0, + "width": 639, + "height": 77, + "top": 0, + "right": 840, + "bottom": 77, + "left": 201 + }, + "moreRect": { + "x": 543, + "y": 0, + "width": 295, + "height": 75, + "top": 0, + "right": 838, + "bottom": 75, + "left": 543 + }, + "moreButton": { + "x": 748, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 828, + "bottom": 69, + "left": 748 + }, + "panelRect": { + "x": 658, + "y": 79, + "width": 180, + "height": 471, + "top": 79, + "right": 838, + "bottom": 550, + "left": 658 + }, + "win": { + "x": 840, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1080, + "bottom": 48, + "left": 840 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1180, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "3개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 215, + "y": 0, + "width": 725, + "height": 77, + "top": 0, + "right": 940, + "bottom": 77, + "left": 215 + }, + "moreRect": { + "x": 817, + "y": 0, + "width": 121, + "height": 75, + "top": 0, + "right": 938, + "bottom": 75, + "left": 817 + }, + "moreButton": { + "x": 848, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 928, + "bottom": 69, + "left": 848 + }, + "panelRect": { + "x": 758, + "y": 79, + "width": 180, + "height": 348, + "top": 79, + "right": 938, + "bottom": 427, + "left": 758 + }, + "win": { + "x": 940, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1180, + "bottom": 48, + "left": 940 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1280, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "3개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 315, + "y": 0, + "width": 725, + "height": 77, + "top": 0, + "right": 1040, + "bottom": 77, + "left": 315 + }, + "moreRect": { + "x": 917, + "y": 0, + "width": 121, + "height": 75, + "top": 0, + "right": 1038, + "bottom": 75, + "left": 917 + }, + "moreButton": { + "x": 948, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 1028, + "bottom": 69, + "left": 948 + }, + "panelRect": { + "x": 858, + "y": 79, + "width": 180, + "height": 348, + "top": 79, + "right": 1038, + "bottom": 427, + "left": 858 + }, + "win": { + "x": 1040, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1280, + "bottom": 48, + "left": 1040 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1440, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "3개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "파일 손상시", + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "복구하기", + "임시파일" + ], + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 825, + "height": 77, + "top": 0, + "right": 1200, + "bottom": 77, + "left": 375 + }, + "moreRect": { + "x": 977, + "y": 0, + "width": 221, + "height": 75, + "top": 0, + "right": 1198, + "bottom": 75, + "left": 977 + }, + "moreButton": { + "x": 1108, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 1188, + "bottom": 69, + "left": 1108 + }, + "panelRect": { + "x": 1018, + "y": 79, + "width": 180, + "height": 348, + "top": 79, + "right": 1198, + "bottom": 427, + "left": 1018 + }, + "win": { + "x": 1200, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1440, + "bottom": 48, + "left": 1200 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1680, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시" + ], + "rowTilesOnly": true, + "more": true, + "moreLabel": "2개 그룹", + "moreExpanded": "false", + "moreActive": null, + "hidden": [ + "My Setting", + "궁금하면" + ], + "hiddenItems": [ + [ + "Display...", + "저장하기", + "불러오기" + ], + [ + "설명보기", + "문의하기", + "S/W정보" + ] + ], + "panelTiles": 0, + "dividers": [ + "0px", + "1px" + ], + "panelOpen": false, + "panelVisibility": "hidden", + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 1065, + "height": 77, + "top": 0, + "right": 1440, + "bottom": 77, + "left": 375 + }, + "moreRect": { + "x": 1157, + "y": 0, + "width": 281, + "height": 75, + "top": 0, + "right": 1438, + "bottom": 75, + "left": 1157 + }, + "moreButton": { + "x": 1348, + "y": 23, + "width": 80, + "height": 46, + "top": 23, + "right": 1428, + "bottom": 69, + "left": 1348 + }, + "panelRect": { + "x": 1258, + "y": 79, + "width": 180, + "height": 255, + "top": 79, + "right": 1438, + "bottom": 334, + "left": 1258 + }, + "win": { + "x": 1440, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1680, + "bottom": 48, + "left": 1440 + }, + "sub": null, + "subFromMore": null + }, + { + "vw": 1920, + "open": true, + "homeOn": true, + "homeHover": "1", + "lineTop": "rgb(95, 75, 15)", + "lineBottom": "rgb(95, 75, 15)", + "row": [ + "작업중인 파일", + "다른파일 열기", + "파일 손상시", + "My Setting", + "궁금하면" + ], + "rowTilesOnly": true, + "more": false, + "hidden": [], + "hiddenItems": [], + "panelTiles": 0, + "dividers": [], + "panelOpen": false, + "panelVisibility": null, + "rowScroll": 0, + "rowOverflowX": "hidden", + "pageScroll": 0, + "menu": { + "x": 375, + "y": 0, + "width": 1305, + "height": 77, + "top": 0, + "right": 1680, + "bottom": 77, + "left": 375 + }, + "moreRect": null, + "moreButton": null, + "panelRect": null, + "win": { + "x": 1680, + "y": 0, + "width": 240, + "height": 48, + "top": 0, + "right": 1920, + "bottom": 48, + "left": 1680 + }, + "sub": null, + "subFromMore": null + } + ], + "errors": [] +} \ No newline at end of file diff --git a/docs/sw/home-menu-more-text-qa-2026-10-19/wide-1920.png b/docs/sw/home-menu-more-text-qa-2026-10-19/wide-1920.png new file mode 100644 index 0000000..439e0e1 Binary files /dev/null and b/docs/sw/home-menu-more-text-qa-2026-10-19/wide-1920.png differ diff --git a/docs/sw/home-on-qa-2026-10-19/compare-full.png b/docs/sw/home-on-qa-2026-10-19/compare-full.png new file mode 100644 index 0000000..b0a8a00 Binary files /dev/null and b/docs/sw/home-on-qa-2026-10-19/compare-full.png differ diff --git a/docs/sw/home-on-qa-2026-10-19/compare-left.png b/docs/sw/home-on-qa-2026-10-19/compare-left.png new file mode 100644 index 0000000..5cff03b Binary files /dev/null and b/docs/sw/home-on-qa-2026-10-19/compare-left.png differ diff --git a/docs/sw/home-on-qa-2026-10-19/compare-right.png b/docs/sw/home-on-qa-2026-10-19/compare-right.png new file mode 100644 index 0000000..57c9837 Binary files /dev/null and b/docs/sw/home-on-qa-2026-10-19/compare-right.png differ diff --git a/docs/sw/sw-header-design-spec.md b/docs/sw/sw-header-design-spec.md index 6e72f2a..3970b6e 100644 --- a/docs/sw/sw-header-design-spec.md +++ b/docs/sw/sw-header-design-spec.md @@ -517,6 +517,18 @@ Composed Controls의 기존 레이어·색상·상세보기 예제는 보존하 검증(2026-10-16, Storybook `SW / Header / Responsive`, 18개 폭): 1920 / 1800 / 1799 / 1770 / 1600 / 1440 / 1280 / 1180 / 1179 / 1080 / 1079 / 900 / 899 / 768 / 640 / 639 / 560 / 390에서 헤더 가로 스크롤 0, 요소 겹침 0, 객체 수정 면 밖으로 넘침 0. 필드 값·라벨 잘림은 390px의 레이어명 1건뿐입니다. 각 폭에서 더보기 항목 선택 시 Callback이 호출되고, 선택 상태가 반영되며, 메뉴가 닫히는 것을 확인했습니다(속성Bar·속성창 체크 전환, 인쇄·팝업 가이드 Callback 포함). 실제 Viewport 1799 / 1079 / 390에서도 같은 결과입니다. +### 12.1 실측 More — 실제 사용 가능한 공간 기준 (2026-10-19) + +2026-10-19 사용자 요청("고정된 화면 너비만 기준으로 처리하지 말고 실제 사용 가능한 공간을 기준으로")에 따라 위 Breakpoint 위에 실측 단계를 더했습니다. Breakpoint 표는 그대로이며, 기본 구성(추가 요소 없음)의 배치는 바뀌지 않습니다. + +- 측정 대상: 객체 수정 영역의 in-flow 내용. 측정하는 동안(`data-measuring`, 같은 Layout Effect 안에서 설정·해제, 그려지지 않음) 영역 안 요소는 줄거나 늘지 않고 auto margin도 0이므로 실제로 필요한 폭이 드러납니다. 구성형(`controls`) 파일명은 기본 디자인의 최소 파일명 폭(96px)으로 계산합니다. +- 이동 순서: Breakpoint 단계 순서 그대로 선·문자·치수스타일 → 그리기모드(라벨만 숨김) → 속성 블록(상세보기·속성Bar·속성창, 기본 구성에서는 한 덩어리) → 색상 → 인쇄·K(구성형만, 기본 구성에서는 창 영역이라 Breakpoint 유지). 같은 단계는 오른쪽부터. 대표 칸(레이어 또는 More에서 고른 필드)은 이동하지 않습니다. 로고 오른쪽 Open(`documentOpenPlacement="header"`)은 가장 먼저 옮겨지고 가장 늦게 돌아옵니다. +- 복귀: 옮긴 직후 그 이동으로 생긴 공간(More 버튼 등장·여백 변화 포함)을 한 번 측정해 두고, 남은 공간이 그만큼 생기면 역순으로 원래 자리에 돌아옵니다(경계에서 깜박임 없음). +- 메뉴를 열고 닫아도 위치·폭은 바뀌지 않습니다. Dropdown·로고 메뉴·More 목록·Tooltip은 positioned 층이라 측정에서 제외됩니다. +- 한계: `leading`·`tools`처럼 호스트가 넣은 요소는 More로 옮기지 않습니다(More 항목이 없음). 그 요소만으로도 공간이 부족하면 기존처럼 대표 필드가 줄어듭니다. + +상세 검증: [홈 메뉴 통합·실측 More 보고](./sw-header-home-menu-responsive-2026-10-19.md). + ## 13. 컴포넌트 분리 기준 - 공개: `SWHeader`(전체), `SWHeaderHome`, `SWHeaderDocumentTitle`, `SWHeaderLayerControl`, `SWHeaderLayerMenu`(레이어 필드 + Dropdown, §5.2), `SWHeaderColorMenu` · `SWHeaderLineStyleMenu` · `SWHeaderTextStyleMenu` · `SWHeaderDimensionStyleMenu`(§5.3), `SWHeaderLinePreview` · `swHeaderLinePatterns`, `SWHeaderInput` · `parseSWHeaderColor` · `parseSWHeaderNumber`(§5.5), `SWHeaderColorControl`, `SWHeaderLineStyle`, `SWHeaderTextStyle`, `SWHeaderDimensionStyle`, `SWHeaderProperties`, `SWHeaderActions`, `SWHeaderWindowControls`, `SWTheme`(단독 사용 시 토큰 범위). @@ -540,6 +552,7 @@ Composed Controls의 기존 레이어·색상·상세보기 예제는 보존하 | `--hm-sw-header-arrow-color` | `#47AF91` | 파일명 화살표 | | `--hm-sw-header-hover` | `rgba(255,255,255,.08)` | 더보기 메뉴 항목 Hover 배경 | | `--hm-sw-header-hover-border-gradient` / `-hover-border-width` | Figma 홈 hover gradient / 1px | Hover 테두리(§11.1) | +| `--hm-sw-header-home-on-line-color` / `-home-on-line-width` | `#5F4B0F` / 2px | Home On(로고 메뉴 열림, Figma 662:67267): Header 전폭 상·하단 선. 로고는 Hover 테두리 유지 | | `--hm-sw-header-document-menu-width` / `-document-menu-background` / `-document-menu-border-color` / `-document-menu-border-width` | 310px / `#103127` / `#041611` / 1px | 문서 Dropdown(§5.1) | | `--hm-sw-header-document-menu-shadow` / `-document-menu-inset-shadow` / `-document-menu-divider-color` | `0 2px 4px rgba(0,0,0,.25)` / `inset 0 4px 8px rgba(0,0,0,.4)` / `rgba(194,217,210,.2)` | 문서 Dropdown(§5.1) | | `--hm-sw-header-document-list-max-height` | 320px | 목록 내부 스크롤 시작 높이(구현값) | diff --git a/docs/sw/sw-header-home-menu-responsive-2026-10-19.md b/docs/sw/sw-header-home-menu-responsive-2026-10-19.md new file mode 100644 index 0000000..3e769da --- /dev/null +++ b/docs/sw/sw-header-home-menu-responsive-2026-10-19.md @@ -0,0 +1,76 @@ +# SW Header 홈 메뉴 통합 · 실측 More (2026-10-19) + +> 브랜치 `feature/sw-home-menu`(기준 `c542bdc`, 작업 전 미커밋 `packages/sw/src/theme/sw-viewer.css` 3줄 보존). **Commit·Push 하지 않았습니다(승인 대기).** +> 검증: Storybook 개발 서버(포트 6025, 6024는 다른 세션이 사용 중)와 Claude 내장 브라우저(Chromium). 이 PC에는 기존 `*.browser.mjs`가 쓰는 Playwright 런타임이 없어 그 스크립트는 실행하지 않았습니다. + +## 1. 요청과 결과 + +| 요청 | 결과 | +|---|---| +| `SW / Home Menu` 기능·디자인을 `SW / Header`로 통합 | `SW / Header` → `Home Menu`(`sw-header--home-menu`) 한 페이지에 로고 클릭 열기/닫기·이벤트 기록, 헤더 폭 조절, Figma 26:10591 비교, Default/Hover/Active, 최근파일 하위 패널, 속성창·SWPopup·Escape 통합. `Overview` 로고도 같은 홈 메뉴를 엶 | +| 홈 버튼 클릭 → 열림, 다시 클릭 → 닫힘 | 기존 `SWHeader homeMenu` 동작 그대로(코드 변경 없음). 5개 섹션·15개 타일·Hover·하위 패널 유지 | +| SW 일반 모드 전용 | `SWViewer*` 코드·Story 변경 없음. 뷰어 Story에 홈 메뉴 0개 | +| 반응형 더보기: 실제 사용 가능한 공간 기준, 넓어지면 원위치, 순서·기능 유지 | `SWHeader` 실측 More 추가(아래 §2). Breakpoint는 그대로 | +| 메뉴 열고 닫을 때 헤더 요소 위치·폭 유지 | 측정에서 positioned 층(Dropdown·홈 메뉴·More 목록·Tooltip) 제외. 열기/닫기 전후 좌표 동일 확인 | +| `SW / Home Menu` 사이드바 제거, 컴포넌트·Export·스타일·AI 지침 유지 | Story 파일을 `sw-header-home-menu.stories.tsx`로 옮기고 title `SW/Header`. `SWHomeMenu`·`SWRecentFiles`·Export·`sw-home-menu.css`(패키지)·AI 지침 삭제 없음 | + +## 2. 실측 More 동작 + +- 기존 Breakpoint(1800 / 1180 / 1080 / 900 / 640 / 520)를 먼저 적용하고, 그 위에서 객체 수정 영역의 실제 남은 공간을 측정합니다. +- 측정: Layout Effect 안에서 `data-measuring`을 잠깐 붙여(그려지지 않음) 영역 안 요소가 줄거나 늘지 않고 auto margin이 0인 상태의 in-flow 폭을 읽습니다. 구성형 파일명은 최소 96px로 계산합니다. +- 이동 순서: Open(로고 오른쪽) → 선·문자·치수스타일 → 그리기모드 → 속성 블록 → 색상 → (구성형) 인쇄·K. 같은 단계는 오른쪽부터. 대표 칸은 이동하지 않습니다. +- 복귀: 옮긴 직후 생긴 공간을 한 번 측정해 두고 그만큼 공간이 생기면 역순으로 복귀. 기본 구성은 아무것도 옮기지 않으면 기존 CSS 전용 배치를 그대로 씁니다. +- 공개 API 변경 없음(추가 Prop 없음). 내부 상태·`data-squeezed` 속성·CSS만 추가. + +## 3. 변경 파일 + +| 파일 | 내용 | +|---|---| +| `packages/sw/src/components/sw-header/SWHeader.tsx` | 실측 More(측정 함수·이동 순서·상태·Layout Effect), Open 이동 판정을 같은 측정으로 통일 | +| `packages/sw/src/theme/sw.css` | `data-measuring` 측정 규칙, 옮겨진 그리기모드·속성 블록 자리 보정 | +| `src/sw/sw-home-menu.stories.tsx` → `src/sw/sw-header-home-menu.stories.tsx` | title `SW/Header`, 대표 Story `Home Menu`, 나머지 `verification` 태그(`sw-header--home-menu-*`) | +| `src/sw/sw-header.stories.tsx` | `Overview`에 홈 메뉴 연결, `Responsive More`에 "실제 사용 가능한 공간 기준" 섹션 | +| `src/sw/sw-header-overview.tsx` | 선택 `homeMenuSections` Prop | +| `src/sw/sw-home-menu.css`, `src/sw/sw-stories.css` | Story 전용 폭 조절 컨트롤 배치 | +| `packages/sw/tests/home-menu-integration.browser.mjs`, `packages/sw/tests/storybook-inventory.mjs` | 새 Story ID·제목 기대값, 이동 ID 표 | +| `docs/sw/sw-header-design-spec.md` §12.1, `docs/sw/sw-header-usage.md`, `packages/sw/README.md`, `packages/sw/ai/DESIGN_RULES.md` §7, `packages/sw/ai/COMPONENT_CATALOG.md` | 실측 More·Storybook 위치 | + +보존: `packages/sw/src/theme/sw-viewer.css`의 작업 전 미커밋 변경(`.hm-sw-viewer-menu-root { display: contents; }`)은 손대지 않았습니다. 과거 검증 보고서는 수정하지 않았습니다. + +## 4. 검증 + +| 항목 | 결과 | 방법 | +|---|---|---| +| SW typecheck / 앱 `tsc -b` / SW build | PASS | `npm run typecheck -w @hm-design/sw`, `npx tsc -b`, `npm run build -w @hm-design/sw` | +| AI 문서 | PASS / 32/32 | `npm run check:ai-docs`, `node packages/sw/tests/ai-docs.check.mjs` | +| Storybook 메뉴 | PASS | `index.json`: SW title = Header·Popup·Viewer(`SW/Home Menu` 없음), `sw-header--home-menu` 표시, 홈 메뉴 하위 14개 `verification` | +| 기존 Header Story 배치 회귀 | PASS(기본 구성 변화 없음) | 작업 전 dist로 기록한 요소 좌표·폭과 비교: Overview·Interactive States·Logo Slot·Document Dropdown·Responsive More(19폭)·K Guide·Hidden Sub Controls 동일. 차이는 `Document Open`(§5)뿐 | +| 이동한 홈 메뉴 Story 배치 | PASS 18/18 | 옛 `sw-home-menu--*`와 새 `sw-header--home-menu-*` 6개 × 1920/1280/768 좌표 동일(메뉴 x·폭 포함) | +| 홈 메뉴 열기/닫기 | PASS | 로고 클릭 → 메뉴 1·섹션 5·타일 15·`aria-expanded=true`·Focus 메뉴 안, 재클릭 → 닫힘, `onHomeClick` 미호출, 열기/닫기 전후 Header 좌표 동일. `Overview`에서도 열기/닫기 확인 | +| Hover·하위 패널·Escape | PASS | 실제 포인터 Hover 시 라벨 `#FF5C00`, 최근파일 → 하위 패널·outline 강조, Escape 1회 패널만 닫힘, 2회 메뉴 닫힘·로고로 Focus | +| 좁은 화면 더보기 · 폭 변경 재배치 | PASS | `Responsive More` 실측 섹션(로고 오른쪽 버튼 2개 + 도구 1개): 1920→390 축소 시 치수 → 문자 → 그리기모드 → 속성 블록 → 색상 순 이동, 겹침·가로 스크롤 0(520까지), 390→1920 확대 시 역순 복귀, 추가 요소 끄면 기본 CSS 배치로 복귀 | +| 더보기 안 메뉴 선택 · 팝업 | PASS | 1180: More 목록 = 선/문자/치수스타일·속성Bar·속성창(순서 유지). 속성창 → 팝업(`role=dialog`) 열림·Focus 안, Escape 닫힘·More로 Focus 복귀. 선스타일 → 대표 칸·Dropdown 열림·Focus, 레이어는 More로 | +| 헤더 요소 위치·폭 유지 | PASS | More 열기, 속성창 열기/닫기, 홈 메뉴, 레이어 Dropdown, 문서 Dropdown 각각 전후 좌표 동일 | +| SW 뷰어 모드 영향 | PASS | 뷰어 코드·Story diff 없음, `SW/Viewer` 3개 Story 렌더 오류 0·홈 메뉴 0 | +| Storybook production build | PASS | `npm run build-storybook`(인덱스 358개, SW title = Header·Popup·Viewer, `SW/Header` 27개) | + +참고: 내장 브라우저 창이 숨겨진 상태라 ResizeObserver가 프레임이 그려질 때만 실행됩니다. 폭 변경 검증은 각 단계마다 화면 프레임을 갱신한 뒤 측정했습니다. + +## 5. 의도된 배치 변화 (`Document Open` Story) + +로고 오른쪽 Open을 쓰는 기본 구성은 작업 전 아래 폭에서 실제로 겹쳤습니다(기존 판정이 `scrollWidth`만 봐서 감지 못함). 이제 Open(필요하면 메뉴 1개)이 More로 이동합니다. + +| 프레임 | 작업 전 | 작업 후 | +|---|---|---| +| 1800 | 치수스타일이 속성 블록과 겹침 | Open·치수스타일 → More | +| 1180 / 1080 | 색상이 More와 겹침 | Open → More | +| 900 | 색상이 More와 3px 겹침 | Open → More | +| 640 | 레이어가 More와 겹침 | Open → More | +| 구성형 768 | Open이 More에 있음 | Open 표시(파일명 200px ≥ 최소 96px) | + +## 6. NOT VERIFIED · 한계 + +- 기존 Playwright 스크립트(`home-menu-integration.browser.mjs` 등): 이 PC에 런타임 없음. ID만 갱신했고 실행하지 않았습니다. +- Firefox·Safari, 실제 소비 앱(`HMDesignSwTest`) 재검증, 픽셀 단위 스크린샷 비교(좌표·폭 비교로 대신함). +- 호스트 요소(`leading`·`tools`)는 More로 옮기지 않습니다. 390px에 로고 오른쪽 버튼 2개 + 도구를 함께 넣으면 대표 필드가 0까지 줄고 도구와 More가 겹칩니다(옮길 메뉴가 더 없음). +- 기존 동작 관찰(이번 변경과 무관, 수정하지 않음): 홈 메뉴에서 Escape로 닫을 때 Story 기록에 `onHomeMenuOpenChange(false, escape)`·`onActiveChange([])`가 2회씩 남습니다. 이전 Story(`sw-header--home-menu-header-composition`, 구 `sw-home-menu--header-composition`)에서도 같습니다. diff --git a/docs/sw/sw-header-usage.md b/docs/sw/sw-header-usage.md index 915884b..4283dae 100644 --- a/docs/sw/sw-header-usage.md +++ b/docs/sw/sw-header-usage.md @@ -371,6 +371,7 @@ import { SWHeaderInput, parseSWHeaderNumber, SWTheme } from "@hm-design/sw" - 레이어는 그동안 더보기로 이동하며, 더보기 → 레이어로 원래 배치로 돌아갑니다. 이미 화면에 있는 필드는 더보기에 나오지 않습니다. - 전환은 UI 상태입니다. 데이터 Callback은 호출되지 않고, 필드 클릭과 같은 `on*Open` 1회와 `on*MenuOpenChange(true)`만 호출됩니다. 값은 그대로 유지됩니다. - 폭이 넓어져 그 필드가 다시 보이는 단계에서는 1920 기준 배치로 돌아갑니다(Breakpoint 1800 / 1180 / 1080 / 900 / 640 / 520은 그대로). +- 실측 More(2026-10-19): Breakpoint 위에서 객체 수정 영역의 실제 남은 공간도 측정합니다. `leading`·`tools`·긴 라벨·사이드 패널 등으로 공간이 모자라면 표시할 수 없는 메뉴만 더보기로 옮기고, 공간이 다시 생기면 원래 자리·순서로 돌려놓습니다. 메뉴를 열고 닫는 것만으로는 Header 요소의 위치·폭이 바뀌지 않습니다([명세 §12.1](./sw-header-design-spec.md#121-실측-more--실제-사용-가능한-공간-기준-2026-10-19)). - Dropdown 데이터(`colors` 등)가 없는 필드도 같은 방식으로 대표 칸에 표시됩니다(목록 없이 `on*Open`만). ## 8. 하위 컴포넌트 재사용 @@ -406,7 +407,7 @@ import type { CSSProperties } from "react" - 기존 뷰어 `Toolbar.tsx`의 파일명(`fileName`)은 `documentTitle`로, 패널 토글(`propsOpen` 등)은 `propertyPanelOpen` + `onPropertyPanelToggle`로 연결할 수 있습니다. - 뷰어의 파일 열기·샘플·Model/Layout 탭·2.5D·어두운 배경·로드 상태는 Figma SW Header에 없는 뷰어 전용 도구입니다. 필요하면 `tools` 슬롯에 호스트가 렌더링합니다(스타일은 호스트 책임). - 헤더 높이는 49px입니다. 고정 배치(`position: fixed`)는 `className`·`style`로 호스트에서 지정합니다. -- 반응형은 모두 헤더 자신의 폭(container query)을 기준으로 하므로 사이드 패널 때문에 헤더가 좁아져도 동작합니다. 단계(1800 / 1180 / 1080 / 900 / 640 / 520)는 [디자인 명세 §12](./sw-header-design-spec.md#12-반응형)를 따릅니다. +- 반응형은 모두 헤더 자신의 폭(container query)을 기준으로 하므로 사이드 패널 때문에 헤더가 좁아져도 동작합니다. 단계(1800 / 1180 / 1080 / 900 / 640 / 520)는 [디자인 명세 §12](./sw-header-design-spec.md#12-반응형)를 따르고, 그 위에서 실제 남은 공간을 측정해 부족한 메뉴만 더보기로 옮깁니다([§12.1](./sw-header-design-spec.md#121-실측-more--실제-사용-가능한-공간-기준-2026-10-19)). - 뷰어는 현재 `@hm-design/ui`의 SWHeader 패턴을 사용합니다. 이 패키지로 바꾸는 작업은 이번 범위가 아닙니다. ## 10.1 상호작용 상태 @@ -454,7 +455,9 @@ Tooltip은 45 × 17px, 검정 80% 배경과 흰색 12px/400 글자입니다. Too npm run storybook ``` -현재(2026-10-19) `SW / Header`에는 33개 Story가 있습니다. Story ID·분류·용도 전체 표는 [1차 정리 보고 §2](./sw-first-pass-cleanup-review-2026-10-19.md#2-storybook-전체-목록-및-분류)를 봅니다. 아래 문단은 Story를 추가한 시점별 설명입니다. +현재(2026-10-19, 홈 메뉴 통합 후) `SW / Header`에는 27개 Story가 있습니다(사이드바 기본 표시 12개 + `verification` 태그 15개). 이전 시점의 Story 표는 [1차 정리 보고 §2](./sw-first-pass-cleanup-review-2026-10-19.md#2-storybook-전체-목록-및-분류), 홈 메뉴 통합 후 목록은 [홈 메뉴 통합·실측 More 보고](./sw-header-home-menu-responsive-2026-10-19.md)를 봅니다. 아래 문단은 Story를 추가한 시점별 설명입니다. + +2026-10-19 홈 메뉴 통합: 기존 `SW / Home Menu` 메뉴는 사이드바에서 제거하고 `SW / Header`로 옮겼습니다. 사이드바에는 `Home Menu`(`sw-header--home-menu`: 로고 클릭 열기/닫기·이벤트 기록, 헤더 폭 조절, Figma 26:10591 비교, Default/Hover/Active, 최근파일 하위 패널, 속성창·SWPopup·Escape 통합) 하나만 표시합니다. Figma 비교 캔버스·Variant·데이터 변경·단독 사용·속성Bar 비교 등은 `sw-header--home-menu-*` ID의 `verification` 태그 Story로 남아 직접 URL과 사이드바 태그 필터로 엽니다. `Overview`의 로고도 같은 홈 메뉴를 엽니다. `Responsive More` 첫 섹션 "실제 사용 가능한 공간 기준"은 헤더 폭 Range와 로고 오른쪽 버튼·추가 도구·홈 메뉴 On/Off로 실측 More의 이동·복귀를 확인합니다. 홈 메뉴는 SW 일반 모드 전용이며 `SW / Viewer`에는 없습니다. `SW / Header` 아래 Story: Overview, Default, Controls, Interactive States(인쇄·팝업 가이드·최소화·종료 Default/Hover 비교와 Callback 기록 포함), Responsive, Composed Controls, Logo Slot(기본 임시 로고 / 사용자 지정 로고 / 로고 미전달), Document Dropdown(Default / Hover / Open / 선택 / 여러 문서 / 문서 없음 / 긴 파일명 / 좁은 화면), Layer Dropdown(Layer Default / Hover / Open(Figma 8행) / Row Hover / 전구·눈꽃·자물쇠 4상태 3배 확대 / 선택·Toggle Callback 기록과 상태표 / 여러 상태·현재 레이어 / 긴 레이어명 / 20개 스크롤 / 레이어 없음 / 레이어 상세 / 상태 표시 전용 / 좁은 화면 1440–390). Responsive Story는 헤더 폭 18개(1920–390, 각 단계 경계 전후 포함) 프레임을 나열합니다. 모든 단계가 헤더 폭 기준이므로 Viewport를 바꾸지 않아도 확인할 수 있습니다. @@ -633,3 +636,20 @@ Storybook: `Property Panel · 선택 없음 / 전체 선택 / 원 1개 / 모두 - `undefined`(미지정): Figma 원형 그림(기존 기본). `null` / `false`: 빈 영역 — 크기·치수 라벨 위치·패널 높이 유지. ReactNode: 외부 컴포넌트. 함수: `{ selection, group, properties }`(해당 그룹 항목)를 받아 렌더링 — 객체 유형별 교체에 사용합니다. - 내용은 영역 안에 맞춰지고(overflow hidden) 원주·지름·반지름·면적 입력은 그 위에 그대로 표시됩니다. 값은 `properties`로만 전달되며 형상 Slot과 독립입니다. 입력은 기존 SWHeaderInput 검증·Enter/Blur 확정·Escape 취소를 사용합니다. - 패키지는 CAD 계산·형상 렌더링 엔진을 포함하지 않습니다. Storybook의 사각형/점선 원 SVG는 Story 전용 샘플입니다. + +## 로고 클릭 메뉴 — `homeMenu` (2026-10-19) + +Figma 26:10591의 2단 Header 메뉴입니다. 기본 숨김, 로고 클릭으로 열고 다시 클릭하면 닫힙니다. + +```tsx + {}} /> // reason: home | escape | background | outside | select | file | document +``` + +- `sections`: `{ id, title, items: [{ id, label, icon, hoverIcon?, toggle?, panel?, disabled?, hidden?, onSelect? }] }[]`. 최근파일은 타일의 `panel: `(선택). `panel`이 없는 항목은 실행 버튼입니다(클릭 시 `onSelect`/`onItemSelect`, 클릭 후 ON 유지 없음). 최근파일만 목록이 열린 동안 Active이며, 유지형이 필요하면 `toggle: true`. +- 이벤트 우선순위: `homeMenu`가 있으면 로고 클릭은 메뉴 토글만 하고 `onHomeClick`은 호출되지 않습니다. `homeMenu`가 없으면 기존과 같이 `onHomeClick`만 호출됩니다. +- New / Open은 문서 Dropdown 안 그대로입니다(`documentOpenPlacement` 기본 `"menu"`). 메뉴가 열리면 필드·문서 Dropdown이 닫히고, 문서 Dropdown을 열면 메뉴가 닫힙니다. +- 위치: 객체 수정 영역 −2px ~ 창 영역(DOM 측정, 1920에서 x 375 · 폭 1305). 좁은 폭에서는 가로 스크롤 없이 들어가는 섹션만 표시하고 나머지는 끝의 더보기(⋯) 섹션으로 옮깁니다(Dropdown은 섹션 제목 + 기능 텍스트 목록, 타일과 같은 Hover·Active·클릭, 폭이 넓어지면 자동 복귀, 배지 문구 `homeMenu.moreLabel`). +- Escape: 하위 패널 → 메뉴 순서, 닫히면 로고로 Focus. 속성창·`SWPopup`과 같은 Escape 순서(Focus가 모두 밖이면 최근 사용 하나). +- 상세: 패키지 [카탈로그 5절](../../packages/sw/ai/COMPONENT_CATALOG.md), [통합 검증 기록](./sw-home-menu-integration-2026-10-19.md). diff --git a/docs/sw/sw-home-menu-integration-2026-10-19.md b/docs/sw/sw-home-menu-integration-2026-10-19.md new file mode 100644 index 0000000..102cc32 --- /dev/null +++ b/docs/sw/sw-home-menu-integration-2026-10-19.md @@ -0,0 +1,38 @@ +# SW Task A + B 통합 — 로고 클릭 메뉴 (2026-10-19) + +> 통합 Worktree `HMDesign-SW-Integration`, 브랜치 `integration/sw-home-menu`(기준 Task A `e8409ef`) + Task B `396539d`의 신규 파일 84개. 미커밋. + +## 결합 방식 + +- Task B 파일 84개는 모두 신규이며 Task A 파일과 겹치지 않아 Git 충돌이 없습니다(`5faa1f1` → `e8409ef` 조상 관계). +- 공유 파일 수정은 연결에 필요한 최소 범위입니다. + +| 파일 | 변경 | +|---|---| +| `packages/sw/src/index.ts` | `export * from "./components/sw-home-menu"` | +| `sw-header/types.ts`, `index.ts` | `homeMenu`, `homeMenuOpen`, `defaultHomeMenuOpen`, `onHomeMenuOpenChange`, 타입 `SWHeaderHomeMenu`, `SWHeaderHomeMenuChangeReason` | +| `sw-header/SWHeader.tsx` | `homeMenu`가 있을 때만: 로고 클릭 = 메뉴 토글(`onHomeClick` 미호출), DOM 측정 배치(객체 수정 영역 −2px ~ 창 영역), 메뉴와 문서·필드 Dropdown 상호 닫기. `homeMenu`가 없으면 기존 동작 그대로 | +| `components/SWHeaderHome.tsx` | `aria-expanded`·`aria-controls` 전달(시각 변화 없음) | +| `components/SWHeaderPropertyPanel.tsx` | 내부 `useSWPopupStack`에 `export`만 추가(패키지 공개 아님) | +| `theme/sw.css` | `.hm-sw-header__home-menu` 레이어 1줄(top 0, z-index 20) | +| `sw-home-menu/SWHomeMenu.tsx`(Task B) | 열린 동안 Popup Escape 스택에 합류(하위 패널 → 메뉴 순서는 그대로) | +| Story·Fixture(Task B) | `@hm-design/sw` 공식 Import, `SWHeader homeMenu` 사용, `통합 · Popup · Escape` Story 추가 | +| AI 문서·README·사용 가이드 | 카탈로그 5절, 조합 패턴 7절, 디자인 규칙 11절, 예제 G | + +## 검증 (실행 결과) + +| 항목 | 결과 | +|---|---| +| SW typecheck / 앱 `tsc -b` / SW build / Storybook build | PASS / PASS / PASS / PASS | +| `dist/styles.css` 홈 메뉴 스타일, `dist/index.d.ts` 공개 Export | 포함 / 포함 | +| AI 문서·공개 API 정합성(`ai-docs.check.mjs`) | 22/22 PASS | +| 기존 SW Story 28장 픽셀 비교(통합 전 기준선 대비, threshold 0) | 28/28 동일 | +| 기존 Header·Tool·Popup 기능 회귀(`integrated-improvement.browser.mjs`) | 96 PASS / 0 FAIL(통합 전과 동일) | +| 홈 메뉴 통합(`home-menu-integration.browser.mjs`) | 22/22 PASS | + +## 남은 항목 + +- 미실행: 독립 React 19 Tarball 소비 설치, SW + HM UI CSS 동시 사용, Figma 스크린샷 픽셀 비교(배치·크기는 DOM 실측으로만 확인), Firefox·Safari. +- 좁은 폭: (2026-10-19 후속 수정) 가로 스크롤 대신 측정형 더보기(⋯). 들어가는 섹션만 앞에서부터 Figma 타일로 표시하고 나머지는 더보기 Dropdown의 텍스트 메뉴(섹션 제목 + 항목, 구분선)로 이동, 폭이 넓어지면 복귀. 실측(capture-responsive): 1920 5개, 1680 3+더보기, 1440·1280·1180 2+더보기, 1080·960 1+더보기, 768 이하 더보기만. 메뉴 행·페이지 가로 스크롤 0. +- 디자인 승인 대기(미적용): 속성Bar 차이 3건, 폰트 차이. 열림 상태 Header 상·하단 `#5F4B0F` 선과 로고 Home On은 2026-10-19 사용자 요청으로 적용(Figma 662:67267). +- Task A의 기존 제한(넓은 `tools` + 390px에서 파일명·레이어 폭 0)은 이번 통합 범위 밖입니다. diff --git a/docs/sw/sw-home-menu-merge-2026-10-19.md b/docs/sw/sw-home-menu-merge-2026-10-19.md new file mode 100644 index 0000000..dcbc3c6 --- /dev/null +++ b/docs/sw/sw-home-menu-merge-2026-10-19.md @@ -0,0 +1,49 @@ +# 홈 메뉴 Merge — `integration/sw-home-menu` → `feature/sw-package` (2026-10-19) + +> 로컬 `git merge --no-commit --no-ff integration/sw-home-menu` (기준 `b434f27`, 대상 `1472e51`). **Merge Commit·Push는 하지 않았습니다(승인 대기).** + +## 적용 범위 (사용자 정정 반영) + +- 홈 메뉴(Figma 45개 노드, `SWHeader homeMenu` / `SWHomeMenu` / `SWRecentFiles`)는 **SW 일반 모드 전용**입니다. +- SW 뷰어 모드(`SWViewer*`)에는 홈 메뉴를 적용하지 않습니다. 뷰어 코드·Story는 변경하지 않았습니다(`sw-viewer` 소스에 홈 메뉴 참조 없음). +- AI 지침: AI_USAGE §0.2 표에 "로고(홈) 버튼 메뉴" 행(일반 = `homeMenu`, 뷰어 = 사용하지 않음), §0.3 혼합 금지 항목, 카탈로그 §5·DESIGN_RULES §12·PATTERNS 8의 "일반 모드 전용" 표기, VIEWER.md 잘못된 사용 행, 공통 AI_GUIDE 예시 B/B2. + +## 충돌 해결 + +| 파일 | 해결 | +|---|---| +| `packages/sw/src/index.ts` | 두 Export 모두 유지(`sw-home-menu`, `sw-viewer`) | +| `ai/AI_USAGE.md` | 뷰어 모드 문장 유지 + 홈 메뉴 문장 추가 | +| `ai/COMPONENT_CATALOG.md` | 홈 메뉴 §5 추가, 이후 6 타입·7 비공개·8 제약, **뷰어 §8 → §9**(참조 갱신: AI_USAGE, VIEWER.md, DESIGN_RULES §11) | +| `ai/COMPOSITION_PATTERNS.md` | 뷰어 7 유지, **홈 메뉴 7 → 8**, 하지 말 것 8 → 9 | +| `ai/DESIGN_RULES.md` | 뷰어 §11 유지, **홈 메뉴 §11 → §12** | + +`docs/sw/sw-home-menu-integration-2026-10-19.md`의 "패턴 7절, 디자인 규칙 11절"은 통합 당시 기록이라 그대로 둡니다(현재 번호는 위 표). + +## Merge 중 추가 수정 + +| 파일 | 내용 | 이유 | +|---|---|---| +| `sw-header/SWHeader.tsx` | 홈 메뉴 시작 위치 = max(객체 수정 영역, `controls` 안 파일명 오른쪽) − 2px | `controls`로 파일명이 객체 수정 영역 안에 있는 Header(실제 SW 화면)에서 메뉴가 파일명을 덮음(x 63 → 378). 기본 Header 배치는 동일(캡처 바이트 동일) | +| `tests/ai-docs.check.mjs` | `` `SWViewer*` `` 같은 와일드카드 표기를 Export 이름으로 보지 않음 | Merge 전 뷰어 문서에서도 실패하던 오탐 | +| `tests/home-menu-integration.browser.mjs` | Story 목록 기대값에서 `SW/Tool` 제외, `SW/Viewer` 포함 | `SW/Tool`은 뷰어 작업(7f42923)에서 사용자 요청으로 삭제됨 | + +## 검증 + +| 항목 | 결과 | +|---|---| +| SW typecheck / 앱 `tsc -b` / SW build / Storybook build | PASS / PASS / PASS / PASS | +| AI 문서(`check:ai-docs`, `ai-docs.check.mjs`) | PASS / 32/32 | +| 홈 메뉴 Storybook(`home-menu-integration.browser.mjs`, 배치 수정 후 재실행) | 22/22 | +| 기존 Header·Popup 기능(`integrated-improvement` options·popup) | 89/0 | +| 뷰어 Story 기능(`viewer.browser.mjs`, 참고 뷰어 없이) | 70/70 | +| Merge 전(b434f27) 대비 픽셀: Header·Popup 요소(`viewer-regression`) / SW Header·Popup·Viewer 전체 Story 48장(1440·768, threshold 0) | 39/39 / 48/48 동일 (배치 수정 전 측정, 수정은 메뉴가 열린 동안만 실행) | +| Figma 26:10591 | 현재 Figma 원본 = 저장 이미지(바이트 동일). 섹션 5·타일 15·크기 80×46·메뉴 1305×77·색·아이콘 일치. 글자는 Figma Dotum 14/12px vs HM Noto Sans KR(기존 "폰트 차이 · 디자인 승인 대기") | +| 실제 SW 화면(`D:\디자인시스템\HMDesignSwTest`, 0.2.0 로컬 tarball) | typecheck·build PASS, 브라우저 14/14(열기·다시 클릭 닫기·Hover `#FF5C00`·최근파일·Escape 순서·문서 Dropdown·속성 패널 토글). 콘솔 404 1건은 앱의 `/favicon.ico` 없음(기존) | + +## NOT VERIFIED + +- `SW/Tool` 섹션 회귀(Story 삭제됨), 참고 DWG/DXF 뷰어 대비 비교, Firefox·Safari, SW + HM UI CSS 동시 사용, Registry Publish. +- 배치 수정 후 Header·Popup·Viewer 픽셀 회귀 재실행(코드 경로상 메뉴가 닫혀 있으면 실행되지 않아 재사용). +- 실제 SW 화면의 미연결 타일 12개(저장·복사저장·내보내기·도면묶기·복구하기·임시파일·Display·저장하기·불러오기·설명보기·문의하기·S/W정보): 뷰어 앱에 해당 기능이 없어 실행 동작 없음(`toggle: false`, 툴팁 "뷰어에서 지원하지 않는 기능"). +- 실제 SW 화면은 `logoSrc`를 주지 않아 로고 면이 비어 있음(기존 상태). diff --git a/packages/org-chart-react/ai/AI_GUIDE.md b/packages/org-chart-react/ai/AI_GUIDE.md index 27d6194..b68d1e2 100644 --- a/packages/org-chart-react/ai/AI_GUIDE.md +++ b/packages/org-chart-react/ai/AI_GUIDE.md @@ -212,7 +212,7 @@ import { Button, Card, CardContent, FilterBar, FilterBarActions, FilterBarSearch ### 예시 B1 — SW 일반 모드 (편집 Header + 도구 막대 + 설정 Popup) - 읽기: `node_modules/@hm-design/sw/ai/` → AI_USAGE §0(일반 모드) → COMPOSITION_PATTERNS "6. 파일 열기 + 도구 막대", 예제 `ai/examples/ExampleF-ViewerToolbar.tsx`(파일 이름의 Viewer는 과거 명칭이며 일반 모드 `SWHeader` 예제) -- 재사용: `SWHeader`(`documentOpenPlacement="header"`, `controls`, `tools`), `SWToolGroup` + `SWToolButton`(Model/Layout 탭, Fit 등), `SWPopup` + `SWPopupSection` + `SWPopupRow` + `SWHeaderInput`(설정 Popup) +- 재사용: `SWHeader`(`documentOpenPlacement="header"`, `controls`, `tools`), `SWToolGroup` + `SWToolButton`(Model/Layout 탭, Fit 등), `SWPopup` + `SWPopupSection` + `SWPopupRow` + `SWHeaderInput`(설정 Popup), 로고(홈) 버튼 메뉴는 `SWHeader`의 `homeMenu` + `SWRecentFiles`(**일반 모드 전용**, 예제 `ExampleG-HomeMenu.tsx`) - 신규: SW에 없는 기능(예: 검색) → 소비 프로젝트 컴포넌트, `` 안, `--hm-sw-header-*` 토큰, 안쪽 입력은 `SWHeaderInput`(예제 `ExampleD-SearchExtension.tsx`) ```tsx @@ -225,7 +225,7 @@ import "@hm-design/sw/styles.css" - 읽기: `node_modules/@hm-design/sw/ai/` → AI_USAGE §0(뷰어 모드) → `VIEWER.md`, 예제 `ai/examples/ExampleH-ViewerMode.tsx` - 재사용: `SWViewerHeader`(`groups` 데이터: `button`·`toggle`·`menu`·`tabs`·`switch`·`custom` 항목, `onCommand`, `trailing`에 `SWViewerStatus`·`SWViewerHeaderButton`), Dropdown은 `type: "menu"` 항목의 `entries`(단독·우클릭은 `SWViewerMenu`), 팝업은 `SWViewerPanel` + `SWViewerSection`·`SWViewerField`·`SWViewerSwitch`·`SWViewerSlider`·`SWViewerInput`·`SWViewerButton` - 신규: 뷰어에 없는 패널 콘텐츠 → 소비 프로젝트 컴포넌트를 `SWViewerPanel`의 `children`에, 안쪽은 `SWViewerField` + `SWViewerInput` 등, 외형은 `--hm-sw-viewer-*` 토큰 -- 하지 않음: `SWHeader`·`SWPopup`을 뷰어 화면에 섞기, 로고가 없다고 임의 문자·아이콘 넣기, 연결할 명령이 없는 메뉴를 가짜 동작으로 만들기(제외 또는 `disabled` + 미연결 보고) +- 하지 않음: `SWHeader`·`SWPopup`을 뷰어 화면에 섞기, 로고(홈) 메뉴(`SWHomeMenu`·`SWRecentFiles`·`homeMenu`)를 뷰어 화면에 넣거나 비슷하게 만들기(홈 메뉴는 일반 모드 전용), 로고가 없다고 임의 문자·아이콘 넣기, 연결할 명령이 없는 메뉴를 가짜 동작으로 만들기(제외 또는 `disabled` + 미연결 보고) ```tsx import { SWViewerHeader, SWViewerPanel, SWViewerSection, SWViewerField, SWViewerSwitch, type SWViewerHeaderGroup } from "@hm-design/sw" diff --git a/packages/org-chart/ai/AI_GUIDE.md b/packages/org-chart/ai/AI_GUIDE.md index 27d6194..b68d1e2 100644 --- a/packages/org-chart/ai/AI_GUIDE.md +++ b/packages/org-chart/ai/AI_GUIDE.md @@ -212,7 +212,7 @@ import { Button, Card, CardContent, FilterBar, FilterBarActions, FilterBarSearch ### 예시 B1 — SW 일반 모드 (편집 Header + 도구 막대 + 설정 Popup) - 읽기: `node_modules/@hm-design/sw/ai/` → AI_USAGE §0(일반 모드) → COMPOSITION_PATTERNS "6. 파일 열기 + 도구 막대", 예제 `ai/examples/ExampleF-ViewerToolbar.tsx`(파일 이름의 Viewer는 과거 명칭이며 일반 모드 `SWHeader` 예제) -- 재사용: `SWHeader`(`documentOpenPlacement="header"`, `controls`, `tools`), `SWToolGroup` + `SWToolButton`(Model/Layout 탭, Fit 등), `SWPopup` + `SWPopupSection` + `SWPopupRow` + `SWHeaderInput`(설정 Popup) +- 재사용: `SWHeader`(`documentOpenPlacement="header"`, `controls`, `tools`), `SWToolGroup` + `SWToolButton`(Model/Layout 탭, Fit 등), `SWPopup` + `SWPopupSection` + `SWPopupRow` + `SWHeaderInput`(설정 Popup), 로고(홈) 버튼 메뉴는 `SWHeader`의 `homeMenu` + `SWRecentFiles`(**일반 모드 전용**, 예제 `ExampleG-HomeMenu.tsx`) - 신규: SW에 없는 기능(예: 검색) → 소비 프로젝트 컴포넌트, `` 안, `--hm-sw-header-*` 토큰, 안쪽 입력은 `SWHeaderInput`(예제 `ExampleD-SearchExtension.tsx`) ```tsx @@ -225,7 +225,7 @@ import "@hm-design/sw/styles.css" - 읽기: `node_modules/@hm-design/sw/ai/` → AI_USAGE §0(뷰어 모드) → `VIEWER.md`, 예제 `ai/examples/ExampleH-ViewerMode.tsx` - 재사용: `SWViewerHeader`(`groups` 데이터: `button`·`toggle`·`menu`·`tabs`·`switch`·`custom` 항목, `onCommand`, `trailing`에 `SWViewerStatus`·`SWViewerHeaderButton`), Dropdown은 `type: "menu"` 항목의 `entries`(단독·우클릭은 `SWViewerMenu`), 팝업은 `SWViewerPanel` + `SWViewerSection`·`SWViewerField`·`SWViewerSwitch`·`SWViewerSlider`·`SWViewerInput`·`SWViewerButton` - 신규: 뷰어에 없는 패널 콘텐츠 → 소비 프로젝트 컴포넌트를 `SWViewerPanel`의 `children`에, 안쪽은 `SWViewerField` + `SWViewerInput` 등, 외형은 `--hm-sw-viewer-*` 토큰 -- 하지 않음: `SWHeader`·`SWPopup`을 뷰어 화면에 섞기, 로고가 없다고 임의 문자·아이콘 넣기, 연결할 명령이 없는 메뉴를 가짜 동작으로 만들기(제외 또는 `disabled` + 미연결 보고) +- 하지 않음: `SWHeader`·`SWPopup`을 뷰어 화면에 섞기, 로고(홈) 메뉴(`SWHomeMenu`·`SWRecentFiles`·`homeMenu`)를 뷰어 화면에 넣거나 비슷하게 만들기(홈 메뉴는 일반 모드 전용), 로고가 없다고 임의 문자·아이콘 넣기, 연결할 명령이 없는 메뉴를 가짜 동작으로 만들기(제외 또는 `disabled` + 미연결 보고) ```tsx import { SWViewerHeader, SWViewerPanel, SWViewerSection, SWViewerField, SWViewerSwitch, type SWViewerHeaderGroup } from "@hm-design/sw" diff --git a/packages/sw/README.md b/packages/sw/README.md index 2de593d..6c0cdda 100644 --- a/packages/sw/README.md +++ b/packages/sw/README.md @@ -2,6 +2,8 @@ > **0.2.0 통합 개선(2026-10-19):** 패키지에 포함된 AI 안내 [ai/AI_USAGE.md](./ai/AI_USAGE.md)·[카탈로그](./ai/COMPONENT_CATALOG.md)가 공개 API의 기준입니다. 추가: `SWPopup` / `SWPopupSection` / `SWPopupRow`(속성창 외형 + `children` 자유 콘텐츠, 여러 Popup Escape 스택, Popup 안 Dropdown 고정 Overlay), `SWHeaderPropertyPanel`의 `children`·`title`·`autoFocus`와 선택형 `selection`/`properties`/`groups`, `SWToolButton` / `SWToolGroup`(기존 글자 토글·pill·파일명 면 재사용), `SWHeader`의 `documentOpenPlacement`(로고 오른쪽 Open, 실측 기반 More 이동)·`leading`, `hiddenControls`의 `documentNew`·`documentOpen`·`layerFreeze`·`layerLock`, `showNew`/`showOpen`/`showFreeze`/`showLock`. 모두 선택 Props이며 기존 화면은 그대로입니다. 빌드는 줄바꿈 정규화로 재현 가능하고 `dist/build-info.json`에 출처 Commit·도구 버전을 남깁니다. 검증 기록: 저장소 `docs/sw/sw-integrated-improvement-2026-10-19.md`. +> **로고 클릭 메뉴(2026-10-19):** `SWHomeMenu` / `SWHomeMenuSection` / `SWHomeMenuItem` / `SWRecentFiles`(Figma 26:10591 2단 Header 메뉴, 최근파일 하위 패널)와 `SWHeader`의 `homeMenu`·`homeMenuOpen`·`defaultHomeMenuOpen`·`onHomeMenuOpenChange`. 기본 숨김 → 로고 클릭 열기 → 다시 클릭 닫기, 위치는 Header DOM 측정. `homeMenu`가 있으면 로고 클릭은 `onHomeClick`을 호출하지 않습니다. 모두 선택 Props이며 주지 않으면 기존 화면 그대로입니다([카탈로그 5절](./ai/COMPONENT_CATALOG.md), [예제 G](./ai/examples/ExampleG-HomeMenu.tsx)). 검증 기록: 저장소 `docs/sw/sw-home-menu-integration-2026-10-19.md`. + > **현재 기준 색인(2026-10-19 1차 정리):** 아래 날짜별 안내는 작성 당시 기록입니다. 현재 기준은 [사용 가이드](../../docs/sw/sw-header-usage.md), [디자인 명세](../../docs/sw/sw-header-design-spec.md) 상단 색인, 속성 필드 13개 [검증 기록](../../docs/sw/sw-property-fields-verification-2026-10-19.md), 게이지·속성Bar [후속 4건 기록](../../docs/sw/sw-header-followup-four-design-fixes-verification-2026-10-19.md)·[Firefox 게이지 기록](../../docs/sw/sw-header-firefox-range-close-verification-2026-10-19.md)입니다. Storybook은 `SW / Header` 33개 Story이며 전체 목록과 2차 검토 대상은 [1차 정리 보고](../../docs/sw/sw-first-pass-cleanup-review-2026-10-19.md)에 있습니다. > **3차 구현(2026-10-16):** `hiddenControls`(로고 외 모든 구성요소 개별 제거, 로고 필수), `menuOrder`(레이어·색상·선/문자/치수스타일 순서), 속성창 `shapeContent` Slot, 속성창 4상태 개별·비교 Story를 추가했습니다. 미지정 시 기존 디자인과 같습니다. [사용법](../../docs/sw/sw-header-usage.md#구성요소-표시메뉴-순서속성창-4상태형상-slot-2026-10-16-3차), [3차 검증 기록](../../docs/sw/sw-header-composition-shape-verification-2026-10-16.md). @@ -42,6 +44,7 @@ import "@hm-design/sw/styles.css" /> ``` - 반응형 More: 좁은 헤더에서 더보기의 필드를 고르면 그 필드가 첫 칸(레이어 자리)에 표시되고 Dropdown이 바로 아래 열립니다. 레이어는 더보기에서 다시 고를 수 있으며, 전환은 UI 상태라 데이터 Callback을 호출하지 않습니다([명세 §5.4](../../docs/sw/sw-header-design-spec.md#54-반응형-more--대표-필드-전환-2026-10-16)). +- 실측 More(2026-10-19): Breakpoint 위에서 객체 수정 영역의 실제 남은 공간을 측정해 표시할 수 없는 메뉴만 More로 옮기고, 공간이 생기면 원래 자리·순서로 돌려놓습니다. 메뉴 열기·닫기는 Header 요소의 위치·폭을 바꾸지 않습니다([명세 §12.1](../../docs/sw/sw-header-design-spec.md#121-실측-more--실제-사용-가능한-공간-기준-2026-10-19)). Storybook의 홈 메뉴 예제는 `SW / Header` → `Home Menu`입니다. - Text Stroke: Figma에 Stroke가 있는 텍스트만 검정 외곽선(14·16px 1.3px, 12px 1px)을 표시합니다. 자기 색 0.3px Stroke는 2026-10-16 추가 수정으로 제거했습니다. 더보기·Tooltip·`+ New`/`Open`은 제외([명세 §6.1](../../docs/sw/sw-header-design-spec.md#61-text-stroke-2026-10-16)). - `SWHeaderInput`: 레이어 상세 등 상세 영역에서 쓰는 수정 가능 Input(Figma 26:11656, Default / Hover / 편집, caret `#E60403`). `value`(확정값) · `onValueChange`(임시값) · `onCommit`(Enter·Focus 이동, 유효 + 변경 시) · `onCancel`(Escape) · `valueType`(`text` / `number`) · `parse` · `readOnly` · `disabled`([명세 §5.5](../../docs/sw/sw-header-design-spec.md#55-레이어-상세-버튼--수정-가능한-input-2026-10-16)). - Peer: `react`, `react-dom` `^19.0.0`. 런타임 dependency는 없습니다. diff --git a/packages/sw/ai/AI_GUIDE.md b/packages/sw/ai/AI_GUIDE.md index 27d6194..b68d1e2 100644 --- a/packages/sw/ai/AI_GUIDE.md +++ b/packages/sw/ai/AI_GUIDE.md @@ -212,7 +212,7 @@ import { Button, Card, CardContent, FilterBar, FilterBarActions, FilterBarSearch ### 예시 B1 — SW 일반 모드 (편집 Header + 도구 막대 + 설정 Popup) - 읽기: `node_modules/@hm-design/sw/ai/` → AI_USAGE §0(일반 모드) → COMPOSITION_PATTERNS "6. 파일 열기 + 도구 막대", 예제 `ai/examples/ExampleF-ViewerToolbar.tsx`(파일 이름의 Viewer는 과거 명칭이며 일반 모드 `SWHeader` 예제) -- 재사용: `SWHeader`(`documentOpenPlacement="header"`, `controls`, `tools`), `SWToolGroup` + `SWToolButton`(Model/Layout 탭, Fit 등), `SWPopup` + `SWPopupSection` + `SWPopupRow` + `SWHeaderInput`(설정 Popup) +- 재사용: `SWHeader`(`documentOpenPlacement="header"`, `controls`, `tools`), `SWToolGroup` + `SWToolButton`(Model/Layout 탭, Fit 등), `SWPopup` + `SWPopupSection` + `SWPopupRow` + `SWHeaderInput`(설정 Popup), 로고(홈) 버튼 메뉴는 `SWHeader`의 `homeMenu` + `SWRecentFiles`(**일반 모드 전용**, 예제 `ExampleG-HomeMenu.tsx`) - 신규: SW에 없는 기능(예: 검색) → 소비 프로젝트 컴포넌트, `` 안, `--hm-sw-header-*` 토큰, 안쪽 입력은 `SWHeaderInput`(예제 `ExampleD-SearchExtension.tsx`) ```tsx @@ -225,7 +225,7 @@ import "@hm-design/sw/styles.css" - 읽기: `node_modules/@hm-design/sw/ai/` → AI_USAGE §0(뷰어 모드) → `VIEWER.md`, 예제 `ai/examples/ExampleH-ViewerMode.tsx` - 재사용: `SWViewerHeader`(`groups` 데이터: `button`·`toggle`·`menu`·`tabs`·`switch`·`custom` 항목, `onCommand`, `trailing`에 `SWViewerStatus`·`SWViewerHeaderButton`), Dropdown은 `type: "menu"` 항목의 `entries`(단독·우클릭은 `SWViewerMenu`), 팝업은 `SWViewerPanel` + `SWViewerSection`·`SWViewerField`·`SWViewerSwitch`·`SWViewerSlider`·`SWViewerInput`·`SWViewerButton` - 신규: 뷰어에 없는 패널 콘텐츠 → 소비 프로젝트 컴포넌트를 `SWViewerPanel`의 `children`에, 안쪽은 `SWViewerField` + `SWViewerInput` 등, 외형은 `--hm-sw-viewer-*` 토큰 -- 하지 않음: `SWHeader`·`SWPopup`을 뷰어 화면에 섞기, 로고가 없다고 임의 문자·아이콘 넣기, 연결할 명령이 없는 메뉴를 가짜 동작으로 만들기(제외 또는 `disabled` + 미연결 보고) +- 하지 않음: `SWHeader`·`SWPopup`을 뷰어 화면에 섞기, 로고(홈) 메뉴(`SWHomeMenu`·`SWRecentFiles`·`homeMenu`)를 뷰어 화면에 넣거나 비슷하게 만들기(홈 메뉴는 일반 모드 전용), 로고가 없다고 임의 문자·아이콘 넣기, 연결할 명령이 없는 메뉴를 가짜 동작으로 만들기(제외 또는 `disabled` + 미연결 보고) ```tsx import { SWViewerHeader, SWViewerPanel, SWViewerSection, SWViewerField, SWViewerSwitch, type SWViewerHeaderGroup } from "@hm-design/sw" diff --git a/packages/sw/ai/AI_USAGE.md b/packages/sw/ai/AI_USAGE.md index e21de45..e0504fc 100644 --- a/packages/sw/ai/AI_USAGE.md +++ b/packages/sw/ai/AI_USAGE.md @@ -7,8 +7,8 @@ | 문서 | 내용 | |---|---| | [AI_GUIDE.md](./AI_GUIDE.md) | HMDesign 공통 진입점(모든 HMDesign 패키지에 같은 사본) | -| [COMPONENT_CATALOG.md](./COMPONENT_CATALOG.md) | 공식 공개 컴포넌트(일반 모드: Header·개별 컨트롤·Popup·도구 막대 / 뷰어 모드 §8: `SWViewer*` 전체 Export)·Props·Callback·크기·CSS 의존성 | -| [DESIGN_RULES.md](./DESIGN_RULES.md) | SW 전용 토큰·Typography·간격·Hover/Focus/Selected·Overlay·Motion·반응형·Popup 외형·도구 버튼(일반 모드 §1~10), 뷰어 토큰·상태값 요약(§11) | +| [COMPONENT_CATALOG.md](./COMPONENT_CATALOG.md) | 공식 공개 컴포넌트(일반 모드: Header·개별 컨트롤·Popup·도구 막대·로고 클릭 메뉴 / 뷰어 모드 §9: `SWViewer*` 전체 Export)·Props·Callback·크기·CSS 의존성 | +| [DESIGN_RULES.md](./DESIGN_RULES.md) | SW 전용 토큰·Typography·간격·Hover/Focus/Selected·Overlay·Motion·반응형·Popup 외형·도구 버튼·로고 클릭 메뉴(일반 모드 §1~10·§12), 뷰어 토큰·상태값 요약(§11) | | [COMPOSITION_PATTERNS.md](./COMPOSITION_PATTERNS.md) | 완성형·간소화·기능 중심·확장 Header, Popup(자유 콘텐츠), 일반 모드 Header + 도구 막대(1~6), 뷰어 모드 기본 조합(7) | | [examples/](./examples) | 공개 API만 쓰는 예제. **일반 모드** A~F(E = 사용자 정의 Popup, F = 파일 열기 + 도구 막대. 독립 소비 프로젝트에서 Typecheck·Build·브라우저 검증. B·F 파일명의 "Viewer"는 과거 이름이며 일반 모드 `SWHeader` 구성), **뷰어 모드** H(`SWViewer*`) | | [VIEWER.md](./VIEWER.md) | **뷰어 모드 전용**: `SWViewerHeader`(데이터 메뉴·More·외곽선·로고 규칙), `SWViewerMenu`(Dropdown·서브메뉴·우클릭), `SWViewerPanel`(팝업 프레임 + 자유 콘텐츠). 일반 SW 모드는 `SWHeader`·`SWPopup`을 그대로 씁니다 | @@ -41,11 +41,12 @@ SW 패키지에는 Header·Popup 계열이 두 벌 있습니다. 화면마다 ** | Header | `SWHeader`, 또는 `` 안의 개별 컨트롤(`SWHeaderHome`, `SWHeaderDocumentTitle`, `SWHeaderLayerMenu`, `SWHeaderColorMenu`, `SWHeaderLineStyleMenu`, `SWHeaderTextStyleMenu`, `SWHeaderDimensionStyleMenu`, `SWHeaderActions`, `SWHeaderWindowControls`, `SWHeaderProperties` …) | `SWViewerHeader`(`groups` 데이터 + `trailing`), 오른쪽 끝·`custom` 버튼 `SWViewerHeaderButton`, 상태 `SWViewerStatus` | | Dropdown | 각 필드 Dropdown(`SWHeaderLayerMenu` …) | `type: "menu"` 항목, 단독·우클릭은 `SWViewerMenu` | | 팝업·설정창 | `SWPopup`(`titleActions`, `footer`) + `SWPopupSection` / `SWPopupRow` + `SWHeaderInput`, 속성창 `SWHeaderPropertyPanel`, 속성Bar `SWHeaderPropertyBar` | `SWViewerPanel`(이동·크기 조절·접기·`modal`, `headerActions`, `footer`) + `SWViewerSection` / `SWViewerField` / `SWViewerSwitch` / `SWViewerSlider` / `SWViewerInput` / `SWViewerButton` / `SWViewerBadge` / `SWViewerHint` | +| 로고(홈) 버튼 메뉴 | `SWHeader`의 `homeMenu`(`SWHomeMenu` 데이터, 최근파일 `SWRecentFiles`, Figma 26:10591). 기본 숨김 → 로고 클릭 열기 → 다시 클릭 닫기 | **사용하지 않음.** `SWViewerHeader`에는 홈 메뉴 Props가 없고 로고 클릭은 `onHomeClick`만 호출합니다. 파일 열기·샘플은 Header `groups`의 `button`·`menu` 항목 | | 버튼·탭·토글 | `SWToolButton` / `SWToolGroup` | Header 항목 `type: "button" \| "toggle" \| "tabs" \| "switch"`, 패널 안 `SWViewerButton` | | 아이콘 | 패키지 자산(필드 안 아이콘) | 프로그램 아이콘 16px, 직접 그린 아이콘은 `SWViewerIcon`으로 감쌈 | | 범위 | Header 밖 부품은 `` 안 | `SWViewerHeader`·`SWViewerMenu`·`SWViewerPanel`은 루트에 `hm-sw-theme`이 있어 `` 불필요. 패널 컨트롤은 `SWViewerPanel` 안 | | 토큰 | `--hm-sw-header-*`, Popup 콘텐츠 `--hm-sw-property-*` | `--hm-sw-viewer-*` + 공유 `--hm-sw-header-*`(아래 0.3) | -| 읽을 문서 | [COMPONENT_CATALOG.md](./COMPONENT_CATALOG.md) §1~7, [DESIGN_RULES.md](./DESIGN_RULES.md) §1~10, [COMPOSITION_PATTERNS.md](./COMPOSITION_PATTERNS.md) 1~6, 예제 A~F | [VIEWER.md](./VIEWER.md), [COMPONENT_CATALOG.md](./COMPONENT_CATALOG.md) §8, [DESIGN_RULES.md](./DESIGN_RULES.md) §11, [COMPOSITION_PATTERNS.md](./COMPOSITION_PATTERNS.md) 7, [예제 H](./examples/ExampleH-ViewerMode.tsx) | +| 읽을 문서 | [COMPONENT_CATALOG.md](./COMPONENT_CATALOG.md) §1~8, [DESIGN_RULES.md](./DESIGN_RULES.md) §1~10·§12, [COMPOSITION_PATTERNS.md](./COMPOSITION_PATTERNS.md) 1~6·8, 예제 A~G | [VIEWER.md](./VIEWER.md), [COMPONENT_CATALOG.md](./COMPONENT_CATALOG.md) §9, [DESIGN_RULES.md](./DESIGN_RULES.md) §11, [COMPOSITION_PATTERNS.md](./COMPOSITION_PATTERNS.md) 7, [예제 H](./examples/ExampleH-ViewerMode.tsx) | - **일반 모드 Header에 도구 막대를 더한 구성**(로고 옆 파일 열기 + Model/Layout·Fit·2.5D 버튼을 `SWHeader`에 추가)은 **일반 모드**입니다: `SWHeader`의 `documentOpenPlacement`·`leading`·`tools` + `SWToolButton` / `SWToolGroup`(PATTERNS 6, 예제 F). "뷰어"·"도면 보기" 화면을 요청받았다면 이 구성이 아니라 뷰어 모드(`SWViewer*`)를 씁니다. - 모드 진입·종료, 파일 처리, 도면 렌더링, 메뉴 명령 실행은 어느 모드든 **프로그램 담당**입니다. @@ -55,6 +56,7 @@ SW 패키지에는 Header·Popup 계열이 두 벌 있습니다. 화면마다 ** - **한 화면에 Header 하나.** `SWHeader`와 `SWViewerHeader`를 같은 화면에 함께 두지 않습니다. 두 모드를 오가는 프로그램은 상태를 유지한 채 Header 컴포넌트만 바꿉니다(VIEWER.md §1). - **뷰어 화면:** `SWHeader`에 뷰어 메뉴를 넣거나 `SWHeader`·`SWPopup`을 뷰어처럼 재스타일하지 않습니다. 뷰어 팝업은 `SWViewerPanel`입니다. - **일반 화면:** `SWViewerHeader`·`SWViewerMenu`·`SWViewerPanel`과 패널 컨트롤(`SWViewerSection` …)을 쓰지 않습니다. +- **로고(홈) 메뉴는 SW 일반 모드 전용:** `SWHomeMenu`·`SWHomeMenuSection`·`SWHomeMenuItem`·`SWRecentFiles`·`useSWHomeMenuClose`와 `SWHeader`의 `homeMenu`·`homeMenuOpen`·`defaultHomeMenuOpen`·`onHomeMenuOpenChange`는 일반 모드 `SWHeader` 화면에서만 씁니다. 뷰어 화면에는 홈 메뉴를 만들지 않고(`SWViewerHeader` 옆·`custom` 항목·`SWViewerPanel` 안에 넣거나 비슷하게 다시 만들지 않음), 뷰어 Header와 기능은 그대로 둡니다. - **토큰:** `--hm-sw-viewer-*` 토큰을 일반 모드 신규 UI에 쓰지 않고, 일반 모드 전용 모양(속성창 행 `SWPopupRow`, `SWToolButton`의 `pill`·`text` 모양, 일반 필드 Dropdown)을 뷰어 신규 UI에 가져오지 않습니다. 두 토큰은 같은 범위(`.hm-sw-header`, `.hm-sw-theme`)에 함께 선언되어 있어 기술적으로 읽히지만, 읽힌다는 것이 허용을 뜻하지 않습니다. - **공유 — 모드 혼합 아님(실제 코드가 공유하는 부분):** - `SWViewerPanel`은 내부에서 `SWPopup` 프레임(제목 막대·제목·닫기·테두리·면)을 렌더링합니다. 뷰어에서 `SWViewerPanel`을 쓰는 것은 일반 모드 혼합이 아닙니다. 단, 뷰어 화면에서 `SWPopup`을 직접 쓰지는 않습니다. @@ -76,8 +78,8 @@ SW 패키지에는 Header·Popup 계열이 두 벌 있습니다. 화면마다 ** ## 1. 작업 순서 (필수) -1. **먼저 검색한다.** §0에서 모드를 정하고, 요청 기능을 [COMPONENT_CATALOG.md](./COMPONENT_CATALOG.md)의 공개 컴포넌트(뷰어 모드는 §8과 [VIEWER.md](./VIEWER.md))에서 찾는다. -2. **있으면 재사용한다(1순위).** 뷰어 모드는 `SWViewerHeader`·`SWViewerMenu`·`SWViewerPanel`이다(VIEWER.md). 일반 모드에서 완성형 Header가 필요하면 `SWHeader` 하나만 쓴다. 기존 Props(`hiddenControls`, `menuOrder`, `controls`, `documentOpenPlacement`, `leading`, `tools`, 각 데이터 배열·Callback)로 해결되는지 먼저 본다. 팝업·설정창은 `SWPopup`, 버튼·탭·토글은 `SWToolButton` / `SWToolGroup`이다. +1. **먼저 검색한다.** §0에서 모드를 정하고, 요청 기능을 [COMPONENT_CATALOG.md](./COMPONENT_CATALOG.md)의 공개 컴포넌트(뷰어 모드는 §9와 [VIEWER.md](./VIEWER.md))에서 찾는다. +2. **있으면 재사용한다(1순위).** 뷰어 모드는 `SWViewerHeader`·`SWViewerMenu`·`SWViewerPanel`이다(VIEWER.md). 일반 모드에서 완성형 Header가 필요하면 `SWHeader` 하나만 쓴다. 기존 Props(`hiddenControls`, `menuOrder`, `controls`, `documentOpenPlacement`, `leading`, `tools`, 각 데이터 배열·Callback)로 해결되는지 먼저 본다. 팝업·설정창은 `SWPopup`, 버튼·탭·토글은 `SWToolButton` / `SWToolGroup`, 일반 모드 로고 클릭 2단 메뉴는 `SWHeader`의 `homeMenu`(`SWHomeMenu` 데이터, 최근파일은 `SWRecentFiles`)이다. `SWToolButton`과 `SWHomeMenuItem`은 역할이 다르다(도구 막대 버튼 / 메뉴 타일). 서로 대신 쓰지 않는다. - Popup 요청은 이렇게 판단한다: ① `SWPopup`이 프레임(외형·닫기·Escape·스크롤)을 제공한다 → ② 내용은 `children`으로 자유 구성(구조 제한 없음) → ③ 행 모양은 `SWPopupSection` / `SWPopupRow` + `SWHeaderInput` → ④ SW에 없는 컨트롤은 `@hm-design/ui`를 children에 → ⑤ 프레임을 다시 만들거나 없는 Props(`content`, `renderContent` 등)를 추측하지 않는다. 3. **없으면 조합한다(2순위).** 개별 공개 컴포넌트(`SWHeaderHome`, `SWHeaderDocumentTitle`, `SWHeaderLayerMenu` …)를 `` 안에 배치한다. 배치용 CSS만 소비 프로젝트에 작성한다([COMPOSITION_PATTERNS.md](./COMPOSITION_PATTERNS.md)). 4. **조합으로도 안 될 때만 새로 만든다(3순위).** 새 컴포넌트는 **소비 프로젝트**에 작성하고, 공개 컴포넌트(예: `SWHeaderInput`)를 내부에 재사용하며, 외형은 공개 토큰 `--hm-sw-header-*`만 읽는다([DESIGN_RULES.md](./DESIGN_RULES.md), 예제 D). 뷰어 모드의 새 UI는 `--hm-sw-viewer-*`(+ 공유 `--hm-sw-header-*` 면·외곽선, [DESIGN_RULES.md](./DESIGN_RULES.md) §11)를 읽고 Header 버튼·패널 버튼·입력은 `SWViewerHeaderButton`·`SWViewerButton`·`SWViewerField` + `SWViewerInput`을 재사용한다. 모드별 상세는 §0.4. 뷰어 화면에 일반 모드 컨트롤 모양을 섞지 않는다. diff --git a/packages/sw/ai/COMPONENT_CATALOG.md b/packages/sw/ai/COMPONENT_CATALOG.md index 79c75cc..de546f0 100644 --- a/packages/sw/ai/COMPONENT_CATALOG.md +++ b/packages/sw/ai/COMPONENT_CATALOG.md @@ -7,9 +7,9 @@ - **열림 상태:** Dropdown은 `open` / `onOpenChange`(Controlled)를 주지 않으면 내부 상태로 동작합니다. - **공통 키보드:** Click·Enter·Space 열기/닫기(Hover로는 열리지 않음), ArrowDown 열고 첫(현재) 항목 Focus, Arrow 이동, Escape·바깥 클릭·Tab 이탈 닫기(Escape는 Trigger로 Focus 복귀). - **검증 표시:** ✅ = 2026-10-19 독립 소비 프로젝트(Tarball 설치)에서 브라우저 검증, ◻ = 소비 검증 범위 밖(Storybook 검증 기록만 있음). -- **먼저 모드:** SW 일반 모드(편집) / SW 뷰어 모드(도면 보기)를 [AI_USAGE.md](./AI_USAGE.md) §0으로 정합니다. **뷰어 모드는 §8(`SWViewer*`)만** 쓰고, 아래 §1~4는 일반 모드용입니다. 두 모드를 한 화면에 섞지 않습니다. -- **무엇을 쓸까(일반 모드):** Header 전체 → `SWHeader`(1). Header 부품 조합 → 개별 컨트롤(2). 팝업·설정창·정보창 → `SWPopup`(3). 도구 막대·탭·토글 → `SWToolButton` / `SWToolGroup`(4). Slider·Switch·Badge·Progress·Dialog(모달)·Label·FilterBar는 SW에 없습니다 → `@hm-design/ui`를 그대로 씁니다(필요하면 `SWPopup` children 안에). -- **무엇을 쓸까(뷰어 모드):** Header → `SWViewerHeader`(`groups` + `trailing`), Dropdown·우클릭 → `SWViewerMenu`, 팝업·설정창·모달 → `SWViewerPanel` + `SWViewerSection`/`SWViewerField`/`SWViewerSwitch`/`SWViewerSlider`/`SWViewerInput`/`SWViewerButton`, 상태 → `SWViewerStatus`(8). +- **먼저 모드:** SW 일반 모드(편집) / SW 뷰어 모드(도면 보기)를 [AI_USAGE.md](./AI_USAGE.md) §0으로 정합니다. **뷰어 모드는 §9(`SWViewer*`)만** 쓰고, 아래 §1~8은 일반 모드용입니다. 두 모드를 한 화면에 섞지 않습니다. +- **무엇을 쓸까(일반 모드):** Header 전체 → `SWHeader`(1). Header 부품 조합 → 개별 컨트롤(2). 팝업·설정창·정보창 → `SWPopup`(3). 도구 막대·탭·토글 → `SWToolButton` / `SWToolGroup`(4). 로고 클릭 2단 메뉴·최근파일 → `SWHeader homeMenu` / `SWHomeMenu`(5). Slider·Switch·Badge·Progress·Dialog(모달)·Label·FilterBar는 SW에 없습니다 → `@hm-design/ui`를 그대로 씁니다(필요하면 `SWPopup` children 안에). +- **무엇을 쓸까(뷰어 모드):** Header → `SWViewerHeader`(`groups` + `trailing`), Dropdown·우클릭 → `SWViewerMenu`, 팝업·설정창·모달 → `SWViewerPanel` + `SWViewerSection`/`SWViewerField`/`SWViewerSwitch`/`SWViewerSlider`/`SWViewerInput`/`SWViewerButton`, 상태 → `SWViewerStatus`(9). ## 1. 완성형 템플릿 @@ -21,7 +21,8 @@ SW 공식 기준 Header(Figma 26:8944, 1920 × 49). 로고 · 파일 · 객체 | 필수 | `documentTitle: string` | | 구성 | `hiddenControls?: SWHeaderHideableControlId[]`(로고 외 부품 제거, `home` 제거 시 정적 로고. 하위 항목 `documentNew`·`documentOpen`·`layerFreeze`·`layerLock`도 제거 — 레이아웃 변화 없음), `menuOrder?: SWHeaderMenuId[]`(5개 메뉴끼리 순서), `controls?: SWHeaderControlConfig[]`(객체 영역 전체 allowlist·순서·label) | | 로고 오른쪽 | `documentOpenPlacement?: "menu" \| "header"`(기본 `menu` = 기존 Dropdown 하단. `header` = 로고 바로 오른쪽에 파일명과 같은 면의 Open 버튼, Dropdown의 Open은 숨김. 둘 다 `onDocumentOpen`·`documentOpenLabel`), `leading?: ReactNode`(Open 뒤·파일명 앞 추가 부품, 예: `SWToolButton appearance="document"`) | -| 로고 | `logo?: ReactNode`, `logoSrc?: string`, `logoAlt?: string`, `onHomeClick` | +| 로고 | `logo?: ReactNode`, `logoSrc?: string`, `logoAlt?: string`, `onHomeClick`(`homeMenu`가 없을 때만 호출) | +| 로고 클릭 메뉴 | `homeMenu?: SWHeaderHomeMenu`(= `SWHomeMenu` Props에서 열림 상태 제외, 5절), `homeMenuOpen`, `defaultHomeMenuOpen`(기본 false), `onHomeMenuOpenChange(open, reason: SWHeaderHomeMenuChangeReason)` | | 파일 | `documents`, `activeDocumentId`, `documentMenuOpen`, `onDocumentMenuOpenChange`, `onDocumentSelect`, `onDocumentClose`, `onDocumentNew`, `onDocumentOpen`, `onDocumentClick`, `documentIcon`, `documentNewLabel`, `documentOpenLabel` | | 레이어 | `layer`, `layers`, `activeLayerId`, `layerMenuOpen`, `onLayerMenuOpenChange`, `onLayerSelect`, `onLayerVisibilityChange`, `onLayerFreezeChange`, `onLayerLockChange`, `onLayerDetail`, `onLayerOpen` | | 색상 | `color`, `colors`, `userColors`, `colorMode`, `colorMenuOpen`, `onColorMenuOpenChange`, `onColorSelect`, `onColorModeChange`, `onColorInput`, `onColorPick`, `onColorDetail`, `onColorOpen` | @@ -34,7 +35,7 @@ SW 공식 기준 Header(Figma 26:8944, 1920 × 49). 로고 · 파일 · 객체 - 데이터 배열(`layers`, `colors`, `lineTypes`/`lineWeights`, `textStyles`, `dimensionStyles`, `documents`)을 주지 않으면 해당 필드는 Dropdown 없는 버튼입니다. - 반응형(More·대표 필드 전환·창 영역 축소)은 **`SWHeader` 안에서만** 동작합니다(CSS container `hm-sw-header`). 조합형 구성이 반응형이어야 하면 `controls` + `documentOpenPlacement` + `leading` + `tools`로 `SWHeader` 안에서 구성합니다(예제 F). - 로고 옆 Open은 실제 공간을 측정해 넘칠 때만 More로 이동하고, 그 시점보다 Open 폭만큼 넓어지면 돌아옵니다. Open이 보이는 동안 파일명이 먼저 줄고 레이어 필드는 Figma 폭을 유지합니다. - +- 메뉴도 고정 폭만이 아니라 실제 남은 공간을 기준으로 More에 옮기고 공간이 생기면 원래 자리·순서로 돌려놓습니다(Breakpoint는 그대로, 추가 Prop 없음). 메뉴를 열고 닫아도 Header 요소의 위치·폭은 바뀌지 않습니다. ```tsx setId(l.id)} onClose={closeWindow} /> ``` @@ -78,7 +79,7 @@ SW 공식 기준 Header(Figma 26:8944, 1920 × 49). 로고 · 파일 · 객체 ## 4. 도구 막대 — 기존 SW 버튼 3종 -**일반 모드** 도구 막대입니다. 새 디자인 값 없이 기존 SW 버튼 모양을 공개 버튼으로 씁니다(일반 모드 `SWHeader`에 더하는 Model/Layout, Fit, 2.5D, 파일 열기 등). 뷰어 모드 화면은 §8 `SWViewerHeader` 항목을 씁니다. `SWHeader`의 `tools`·`leading` 안이나 `` 안에 둡니다. +**일반 모드** 도구 막대입니다. 새 디자인 값 없이 기존 SW 버튼 모양을 공개 버튼으로 씁니다(일반 모드 `SWHeader`에 더하는 Model/Layout, Fit, 2.5D, 파일 열기 등). 뷰어 모드 화면은 §9 `SWViewerHeader` 항목을 씁니다. `SWHeader`의 `tools`·`leading` 안이나 `` 안에 둡니다. | 컴포넌트 | 용도 | 주요 Props | 모양(기존 기준) | 검증 | |---|---|---|---|---| @@ -86,17 +87,36 @@ SW 공식 기준 Header(Figma 26:8944, 1920 × 49). 로고 · 파일 · 객체 | `SWToolGroup` | 버튼 묶음 | `appearance`(`text` 기본 = 상세보기 묶음, `pill` = 인쇄·K pill), `label`(`text`의 12px 캡션·접근성 이름), `selection`(`single` = radiogroup, 화살표·Home·End로 이동·선택), `div` 속성 | 버튼 사이 1px 구분선(`text`), 내용 폭 pill | ✅ | - 탭(Model / Layout)은 별도 컴포넌트 없이 `SWToolGroup selection="single"` + `SWToolButton pressed`입니다. -- 일반 모드의 상태 표시(로드 상태 등) 전용 SW 디자인은 아직 없습니다(디자인 확정 후 검토). 뷰어 모드는 `SWViewerStatus`(§8)가 있으며 일반 모드 Header에 가져오지 않습니다. +- 일반 모드의 상태 표시(로드 상태 등) 전용 SW 디자인은 아직 없습니다(디자인 확정 후 검토). 뷰어 모드는 `SWViewerStatus`(§9)가 있으며 일반 모드 Header에 가져오지 않습니다. -## 5. 공개 타입 +## 5. 로고 클릭 메뉴 — Figma 2단 Header 메뉴 (SW 일반 모드 전용) -`SWHeaderProps`, 각 컴포넌트 Props(`SWHeaderHomeProps`, `SWHeaderDocumentTitleProps`, `SWHeaderLayerControlProps`, `SWHeaderLayerMenuProps`, `SWHeaderColorMenuProps`, `SWHeaderLineStyleMenuProps`, `SWHeaderTextStyleMenuProps`, `SWHeaderDimensionStyleMenuProps`, `SWHeaderInputProps`, `SWHeaderPropertiesProps`, `SWHeaderPropertyPanelProps`, `SWHeaderPropertyBarProps`, `SWHeaderActionsProps`, `SWHeaderWindowControlsProps`), `SWThemeProps`, `SWPopupProps`, `SWPopupSectionProps`, `SWPopupRowProps`, `SWToolButtonProps`, `SWToolButtonAppearance`, `SWToolGroupProps`, `SWHeaderMenuId`, `SWHeaderControlId`, `SWHeaderControlConfig`, `SWHeaderFrameControlId`, `SWHeaderSubControlId`, `SWHeaderHideableControlId`, `SWHeaderDocument`, `SWHeaderLayer`, `SWHeaderLayerValue`, `SWHeaderColorValue`, `SWHeaderColorOption`, `SWHeaderColorMode`, `SWHeaderColorInputValue`, `SWHeaderLineStyleValue`, `SWHeaderLineType`, `SWHeaderLineWeight`, `SWHeaderTextStyleValue`, `SWHeaderTextStyleOption`, `SWHeaderDimensionStyleValue`, `SWHeaderDimensionStyleOption`, `SWHeaderInputValueType`, `SWHeaderProperty`, `SWHeaderPropertyType`, `SWHeaderPropertyPicker`, `SWHeaderPropertyMenus`, `SWHeaderPropertyGroup`, `SWHeaderPropertySelection`, `SWHeaderPropertyShapeContent`, `SWHeaderPropertyShapeContext`. 뷰어 모드 타입은 §8. +> **SW 일반 모드(`SWHeader`)에서만 씁니다.** SW 뷰어 모드(§9 `SWViewer*`)에는 홈 메뉴가 없으며 이 절의 컴포넌트를 뷰어 화면에 넣지 않습니다([AI_USAGE.md](./AI_USAGE.md) §0.3). -## 6. 공개하지 않은 것 (사용 금지) +Figma 26:10591(home on), 타일 15종 26:11355 … 26:11631, 섹션 제목 26:12604 … 26:12622, 최근파일 상태 662:67267 · 목록 662:67331 · 2뎁스 미리보기 662:67471을 **공통 컴포넌트 4개**로 표현합니다. 메뉴 항목·아이콘·제목·Active·이벤트·최근파일은 모두 데이터입니다(패키지에는 항목·아이콘이 없음). 운영체제 파일 선택창이 아니며, "찾아열기" 등의 실제 동작은 호스트가 `onSelect`에서 수행합니다. -`SWHeaderMore`, `SWHeaderField`/`SWHeaderFieldText`, `SWHeaderKGuide`, `useSWHeaderDropdown`, `SWHeaderMenuDetail`, `SWHeaderColorChip`, `SWHeaderLayerRows`, `SWHeaderColorPanelBody`, `SWHeaderLineStyleColumns`, `SWPopupFrame`, `useSWFixedDropdownPosition`, 속성창 내부 Picker, `useSWHeaderOverlay` 등은 내부 구현입니다. 필요하면 공개 컴포넌트로 대체하거나, 부족한 API로 보고합니다. +| 컴포넌트 | 용도 | 주요 Props | 크기·동작 | 검증 | +|---|---|---|---|---| +| `SWHomeMenu` | 2단 메뉴 전체(섹션 여러 개). 보통 `SWHeader homeMenu`로 씀 | `sections`(`SWHomeMenuSectionData[]`) 또는 `children`, `open`/`defaultOpen`(false)/`onOpenChange(open, reason)`, `activeIds`/`defaultActiveIds`/`onActiveChange`, `selection`(`multiple` 기본 / `single`), `onItemSelect`, `closeOnBackgroundClick`(true), `closeOnSelect`(false), `closeOnEscape`(true), `closeOnOutsideClick`(false), `autoFocus`(true), `returnFocusRef`, `accent`(`auto`/`sections`/`outline`), `moreLabel`("더보기") | 높이 77(섹션 75 + 강조 2), 섹션 폭은 타일 수로 자동. 좁으면 들어가는 섹션만 표시하고 나머지는 더보기(⋯) Dropdown의 텍스트 메뉴(섹션 제목 + 항목, 같은 Active·Callback·하위 패널)로 이동(가로 스크롤 없음, 넓어지면 복귀) | ✅ | +| `SWHomeMenuSection` | 섹션(제목 badge + 타일 그룹) | `title`, `children` | badge 폭 = 글자 + 46px | ✅ | +| `SWHomeMenuItem` | 80 × 46 타일(Default / Hover / Active) | 데이터 `SWHomeMenuItemData`: `id`, `label`, `icon`, `hoverIcon`, `toggle`(기본: `panel` 있는 항목만 true = 패널이 열린 동안 Active, 나머지는 실행 버튼 = 클릭 후 ON 없음. true = 켜고 끄기 유지), `panel`, `panelLabel`, `disabled`, `hidden`, `title`, `onSelect`. 메뉴 밖 단독이면 `active`/`defaultActive`/`onActiveChange` | Hover·Active = 주황 gradient 1px 테두리 + `#FF5C00` 아이콘·글자 | ✅ | +| `SWRecentFiles` | 선택 하위 패널: 최근파일 목록 + 2뎁스 미리보기 | `files`(`SWFileEntry[]`: `id`, `name`, `path`, `badge`, `preview`, `previewTitle`, `disabled`), `onFileOpen`, `onFileHover`, `renderPreview`, `closeOnOpen`(true), `emptyText` | 폭 354, 행 50, 미리보기 310 × 270 | ✅ | -## 7. 알려진 단독 사용 제약 +- **Header 연결:** `SWHeader`의 `homeMenu`에 `SWHomeMenu` Props를 주면 됩니다. 기본 숨김, 로고 클릭 열기, 다시 클릭 닫기. 위치는 SWHeader가 실제 DOM으로 정합니다(객체 수정 영역 −2px ~ 창 영역, 고정 x 없음. `controls`에 `document`가 있으면 파일명 오른쪽 −2px부터). 로고·파일명·창 영역은 가리지 않습니다. +- **이벤트 우선순위:** `homeMenu`가 있으면 로고 클릭은 메뉴 열기·닫기만 하고 `onHomeClick`을 호출하지 않습니다(의도하지 않은 홈 이동 방지). 상태 알림은 `onHomeMenuOpenChange`(`reason`: `home`, `escape`, `background`, `outside`, `select`, `file`, `document`). +- **New / Open:** 기존 문서 Dropdown 안(`documentOpenPlacement="menu"` 기본) 그대로입니다. 메뉴의 "찾아열기"·"새파일"에 같은 동작이 필요하면 호스트가 `onDocumentOpen`·`onDocumentNew`와 같은 함수를 `onSelect`에 연결합니다. 메뉴가 열리면 필드 Dropdown·문서 Dropdown이 닫히고, 문서 Dropdown을 열면 메뉴가 닫힙니다(`reason: "document"`). +- **Escape·Focus:** 메뉴 안의 Escape는 열린 하위 패널 → 메뉴 순서로 하나씩 닫고, 메뉴가 닫히면 로고로 Focus를 돌립니다. 메뉴는 Popup Escape 순서(3절)에 함께 들어가므로 Focus가 메뉴·Popup 밖이면 가장 최근에 열거나 사용한 하나만 닫힙니다. Popup 안의 Escape는 그 Popup만 닫습니다. +- **하위 패널 닫기:** 패널 안 콘텐츠는 `useSWHomeMenuClose()`로 메뉴 전체를 닫을 수 있습니다(`SWRecentFiles`는 파일을 열면 자동). + +## 6. 공개 타입 + +`SWHeaderProps`, 각 컴포넌트 Props(`SWHeaderHomeProps`, `SWHeaderDocumentTitleProps`, `SWHeaderLayerControlProps`, `SWHeaderLayerMenuProps`, `SWHeaderColorMenuProps`, `SWHeaderLineStyleMenuProps`, `SWHeaderTextStyleMenuProps`, `SWHeaderDimensionStyleMenuProps`, `SWHeaderInputProps`, `SWHeaderPropertiesProps`, `SWHeaderPropertyPanelProps`, `SWHeaderPropertyBarProps`, `SWHeaderActionsProps`, `SWHeaderWindowControlsProps`), `SWThemeProps`, `SWPopupProps`, `SWPopupSectionProps`, `SWPopupRowProps`, `SWToolButtonProps`, `SWToolButtonAppearance`, `SWToolGroupProps`, `SWHeaderMenuId`, `SWHeaderControlId`, `SWHeaderControlConfig`, `SWHeaderFrameControlId`, `SWHeaderSubControlId`, `SWHeaderHideableControlId`, `SWHeaderDocument`, `SWHeaderLayer`, `SWHeaderLayerValue`, `SWHeaderColorValue`, `SWHeaderColorOption`, `SWHeaderColorMode`, `SWHeaderColorInputValue`, `SWHeaderLineStyleValue`, `SWHeaderLineType`, `SWHeaderLineWeight`, `SWHeaderTextStyleValue`, `SWHeaderTextStyleOption`, `SWHeaderDimensionStyleValue`, `SWHeaderDimensionStyleOption`, `SWHeaderInputValueType`, `SWHeaderProperty`, `SWHeaderPropertyType`, `SWHeaderPropertyPicker`, `SWHeaderPropertyMenus`, `SWHeaderPropertyGroup`, `SWHeaderPropertySelection`, `SWHeaderPropertyShapeContent`, `SWHeaderPropertyShapeContext`, `SWHeaderHomeMenu`, `SWHeaderHomeMenuChangeReason`, `SWHomeMenuProps`, `SWHomeMenuSectionProps`, `SWHomeMenuItemProps`, `SWHomeMenuItemData`, `SWHomeMenuSectionData`, `SWHomeMenuSelectEvent`, `SWHomeMenuCloseReason`, `SWHomeMenuAccent`, `SWRecentFilesProps`, `SWFileEntry`. 뷰어 모드 타입은 §9. + +## 7. 공개하지 않은 것 (사용 금지) + +`useSWPopupStack`, `SWHeaderMore`, `SWHeaderField`/`SWHeaderFieldText`, `SWHeaderKGuide`, `useSWHeaderDropdown`, `SWHeaderMenuDetail`, `SWHeaderColorChip`, `SWHeaderLayerRows`, `SWHeaderColorPanelBody`, `SWHeaderLineStyleColumns`, `SWPopupFrame`, `useSWFixedDropdownPosition`, 속성창 내부 Picker, `useSWHeaderOverlay` 등은 내부 구현입니다. 필요하면 공개 컴포넌트로 대체하거나, 부족한 API로 보고합니다. + +## 8. 알려진 단독 사용 제약 | 항목 | 내용 | 대응 | |---|---|---| @@ -107,7 +127,7 @@ SW 공식 기준 Header(Figma 26:8944, 1920 × 49). 로고 · 파일 · 객체 | Dropdown 위치 | `SWHeader` 안이면 헤더, 밖이면 뷰포트 안으로 좌우 보정. `SWPopup`·속성창 안이면 고정 위치 Overlay | Popup 밖에서는 부모에 `overflow: hidden`을 두지 않는다 | | 파일 열기 뒤 파일명 여백 | `SWToolButton appearance="document"` 바로 뒤의 파일명은 왼쪽 여백 12px(로고 아래가 아니므로) | 패키지 CSS가 처리. 소비 코드에서 조정하지 않음 | -## 8. 뷰어 모드 (`SWViewer*`) +## 9. 뷰어 모드 (`SWViewer*`) SW **뷰어 모드** 전용 Export입니다(2026-10-19 추가, 참고 DWG/DXF 뷰어 실측 기준). 모드 선택은 [AI_USAGE.md](./AI_USAGE.md) §0, Props 상세·상태·금지 사항은 [VIEWER.md](./VIEWER.md), 토큰은 [DESIGN_RULES.md](./DESIGN_RULES.md) §11, 조합은 [COMPOSITION_PATTERNS.md](./COMPOSITION_PATTERNS.md) 7과 [예제 H](./examples/ExampleH-ViewerMode.tsx)를 봅니다. 일반 모드 화면에서는 쓰지 않습니다. `SWViewerHeader`·`SWViewerMenu`·`SWViewerPanel`은 루트에 `hm-sw-theme`을 가지므로 ``가 필요 없습니다. diff --git a/packages/sw/ai/COMPOSITION_PATTERNS.md b/packages/sw/ai/COMPOSITION_PATTERNS.md index 549cb8b..d3cd61e 100644 --- a/packages/sw/ai/COMPOSITION_PATTERNS.md +++ b/packages/sw/ai/COMPOSITION_PATTERNS.md @@ -4,7 +4,7 @@ ## 0. 어떤 패턴을 고를까 -먼저 SW 모드를 정합니다([AI_USAGE.md](./AI_USAGE.md) §0). 1~6은 **SW 일반 모드**, 7은 **SW 뷰어 모드**이며 한 화면에서 섞지 않습니다. +먼저 SW 모드를 정합니다([AI_USAGE.md](./AI_USAGE.md) §0). 1~6과 8은 **SW 일반 모드**, 7은 **SW 뷰어 모드**이며 한 화면에서 섞지 않습니다. | 요청 | 모드 | 패턴 | |---|---|---| @@ -15,6 +15,7 @@ | SW Popup 디자인의 설정창·정보창·사용자 정의 폼 | 일반 | 5. Popup(외형 고정, 콘텐츠 자유) | | 일반 모드 `SWHeader`에 로고 옆 파일 열기·도구 막대(Model/Layout, Fit, 2.5D) 추가 | 일반 | 6. 파일 열기 + 도구 막대 | | 뷰어·DWG/DXF 보기·도면 뷰어·읽기 전용 화면(Header 메뉴, 패널, 모달, 불러오기 상태) | 뷰어 | 7. 뷰어 모드 기본 조합 | +| 일반 모드 `SWHeader`에서 로고를 누르면 열리는 2단 메뉴(저장·내보내기·찾아열기·최근파일 등) | 일반 | 8. 로고 클릭 메뉴 | ## 1. 완성형 SW Header — [ExampleA-DefaultHeader.tsx](./examples/ExampleA-DefaultHeader.tsx) @@ -174,7 +175,32 @@ const groups: SWViewerHeaderGroup[] = [ - 상태(파일명·패널 열림·탭 값)는 프로그램이 가지고, 명령은 각 Callback 또는 `onCommand` 한 곳에서 받는다. 도면 영역 높이·렌더러 크기는 앱 레이아웃 담당(VIEWER.md §7). - 없는 기능은 메뉴를 만들지 않거나 `disabled` + 미연결 보고. 패키지에 없는 UI는 [AI_USAGE.md](./AI_USAGE.md) §0.4 뷰어 열을 따른다. -## 8. 하지 말 것 +## 8. 로고 클릭 메뉴 (일반 모드) — [ExampleG-HomeMenu.tsx](./examples/ExampleG-HomeMenu.tsx) + +SW **일반 모드** `SWHeader` 전용입니다. 패턴 7(뷰어 모드)에는 홈 메뉴를 넣지 않습니다. + +```tsx +const sections: SWHomeMenuSectionData[] = [ + { id: "working", title: "작업중인 파일", items: [ + { id: "save", label: "저장", icon: , toggle: false, onSelect: save }, + ] }, + { id: "open", title: "다른 파일 열기", items: [ + { id: "find-open", label: "찾아열기", icon: , toggle: false, onSelect: openFile }, + { id: "recent", label: "최근파일", icon: , panel: }, + ] }, +] + log(open, reason)} /> +``` + +1. 카탈로그 §5의 데이터로 메뉴를 쓴다. 화면마다 타일·섹션·제목을 따로 만들지 않는다. +2. 메뉴 데이터 변경: 항목 추가·삭제는 `items` 배열, 숨김은 `hidden`, 비활성은 `disabled`, 실행만 하는 버튼은 `toggle: false`, 켜고 끄는 버튼은 기본값. Active를 직접 제어하려면 `homeMenu.activeIds` + `onActiveChange`. +3. 최근파일 패널은 선택 기능이다. 필요한 타일에만 `panel: `를 준다. 파일을 열면 메뉴가 닫힌다(`closeOnOpen`). +4. 로고 클릭은 메뉴만 연다. `onHomeClick`의 홈 이동은 `homeMenu`가 있으면 실행되지 않는다. 메뉴 항목에 홈 이동이 필요하면 항목 `onSelect`에서 한다. +5. New / Open은 문서 Dropdown에 그대로 둔다(`documentOpenPlacement` 기본 `"menu"`). 로고 오른쪽에 별도 Open 버튼을 두지 않는다. 메뉴의 찾아열기·새파일은 같은 handler를 연결한다. +6. 위치·폭은 `SWHeader`가 정한다. 소비 코드에서 메뉴 위치를 계산하거나 겹치는 wrapper를 만들지 않는다. + +## 9. 하지 말 것 - `hm-sw-*` class를 소비 코드에 쓰거나 CSS로 덮어쓰기 - `dist` 구현·`styles.css` 블록 복사로 같은 컴포넌트 재작성 diff --git a/packages/sw/ai/DESIGN_RULES.md b/packages/sw/ai/DESIGN_RULES.md index 887ca73..a54d0ae 100644 --- a/packages/sw/ai/DESIGN_RULES.md +++ b/packages/sw/ai/DESIGN_RULES.md @@ -5,7 +5,7 @@ - 토큰은 `.hm-sw-header`와 `.hm-sw-theme`(``)에만 정의됩니다. 새 컴포넌트는 그 안에 렌더링합니다. - SW는 `@hm-design/ui` 토큰을 쓰지 않습니다. UI 패키지 토큰을 복제하거나 섞지 않습니다. - Light/Dark 분기 없음. 전역 선택자(`html`, `body`, `*`) 없음. -- **모드:** §1~10은 SW **일반 모드**(`SWHeader`·`SWPopup`·`SWToolButton`) 기준입니다. SW **뷰어 모드**(`SWViewer*`)의 토큰·상태는 §11과 [VIEWER.md](./VIEWER.md)를 봅니다. 모드 선택·혼합 금지는 [AI_USAGE.md](./AI_USAGE.md) §0. +- **모드:** §1~10과 §12는 SW **일반 모드**(`SWHeader`·`SWPopup`·`SWToolButton`·`SWHomeMenu`) 기준입니다. SW **뷰어 모드**(`SWViewer*`)의 토큰·상태는 §11과 [VIEWER.md](./VIEWER.md)를 봅니다. 모드 선택·혼합 금지는 [AI_USAGE.md](./AI_USAGE.md) §0. ## 1. 크기·간격 @@ -83,6 +83,10 @@ Container `hm-sw-header` 기준 Breakpoint: **< 1800** 선/문자/치수스타일 → More, **< 1180** 그리기모드 숨김, **< 1080** 상세보기 → More·창 이동 24px(창 영역 176), **< 900** 색상 → More, **< 640** 인쇄·K → More·창 이동 숨김(창 영역 64), **< 520** 레이어 상태 아이콘 숨김. More에서 고른 필드는 첫 칸(레이어 자리)에 표시되고 Dropdown이 바로 열립니다(UI 상태만, 데이터 Callback 없음). +실측 More(2026-10-19): Breakpoint 위에서 객체 수정 영역의 실제 남은 공간을 측정해, `leading`·`tools`·긴 라벨 등으로 표시할 수 없는 메뉴만 같은 단계 순서(선/문자/치수 → 그리기모드 → 속성 블록 → 색상 → 구성형의 인쇄·K, 같은 단계는 오른쪽부터)로 More에 옮기고 공간이 생기면 역순으로 돌려놓습니다. 로고 옆 Open이 가장 먼저 옮겨집니다. 메뉴 열기·닫기는 Header 요소의 위치·폭을 바꾸지 않습니다. 호스트 요소(`leading`·`tools`)는 More로 옮기지 않으므로 폭이 좁은 화면에는 많이 넣지 않습니다. + +로고 클릭 메뉴는 좁은 폭에서는 가로 스크롤 없이 들어가는 섹션만 앞에서부터 보여 주고, 나머지는 끝의 더보기(⋯) 섹션으로 옮깁니다(2026-10-19 사용자 확정, Figma에 좁은 폭 디자인 없음). 더보기를 누르면 옮긴 섹션이 텍스트 메뉴(섹션 제목 + 기능 텍스트 목록, 그룹 사이 구분선)로 아래 Dropdown에 열리고, 폭이 넓어지면 원래 자리로 돌아갑니다. 화면에 남은 섹션은 Figma 타일 그대로입니다(§12). + 조합 Header(개별 컴포넌트)에는 이 규칙이 적용되지 않습니다. 필요한 컨트롤만 배치하고 폭 정책은 소비 앱이 정합니다. ## 8. Popup (속성창 프레임, `SWPopup` / `SWHeaderPropertyPanel`) @@ -95,6 +99,7 @@ Container `hm-sw-header` 기준 Breakpoint: **< 1800** 선/문자/치수스타 | 표면 / 테두리 / radius | `#E4DBC9` / 1px `#A67D03` / 4px, 안쪽 1px 검정 그림자 | `--hm-sw-property-surface`, `--hm-sw-property-border` | | 제목줄 | 30px, Figma 제목 아트, 제목 14px 700 `#FFC600` + 검정 외곽선, 닫기 44 × 30(Hover 자산) | `--hm-sw-header-selected-color` | | 본문 | padding 7px, 그룹 사이 8px | — | +| 본문 스크롤바 | `thin`, Thumb `#9A9284` / Track `#E0DACE`(DWG/DXF Viewer 패널과 동일). 본문과 그 안의 스크롤 영역에 적용, 페이지 스크롤바는 그대로 | `--hm-sw-popup-scrollbar-thumb`, `--hm-sw-popup-scrollbar-track` | | 그룹 면(`SWPopupSection`) | 제목 700 · 검정 70%, 내용 면 `#F1ECE1`, 1px `#585349`, radius 4px | `--hm-sw-property-content` | | 행(`SWPopupRow`) | 최소 32px, 라벨 72px 700 검정, 값 글자 `#E60403` 500, 단위 12px | `--hm-sw-property-label`, `--hm-sw-header-input-color` | | 값 상자 | 28px, Hover 1px `rgba(33,29,19,.4)`, 숫자 편집 On `#0F0D0A`(단위 흰색), Dropdown On `#211D13` | `--hm-sw-property-field-*` | @@ -148,4 +153,23 @@ Container `hm-sw-header` 기준 Breakpoint: **< 1800** 선/문자/치수스타 | 상태 표시 | `SWViewerStatus`: 글자 `--hm-sw-viewer-muted` 11px 400, `error`는 `--hm-sw-viewer-accent`, `loading` 아이콘 회전 | — | - **Typography(뷰어):** Header 항목 14px 500, 캡션·개수·상태 11px 400, 패널 필드 라벨 14px 500, Section 제목 12px 700, 패널 버튼·Badge 12px 500, Input 12px. Font Weight는 400/500/700만 씁니다. -- **뷰어 신규 컴포넌트 체크리스트:** ① VIEWER.md·§8 컴포넌트로 해결되는지 먼저 본다 ② 위 토큰을 `var(--…)`로만 읽고 일반 모드 전용 모양(§8 `SWPopupRow`, §9 `SWToolButton`)을 섞지 않는다 ③ 상태는 위 표대로 ④ 토큰에 없는 값은 결과 보고에 "AI 구성 값 — 디자인 확인 필요"로 적는다 ⑤ `hm-sw-viewer-*` class를 쓰거나 덮어쓰지 않는다. +- **뷰어 신규 컴포넌트 체크리스트:** ① VIEWER.md·카탈로그 §9 컴포넌트로 해결되는지 먼저 본다 ② 위 토큰을 `var(--…)`로만 읽고 일반 모드 전용 모양(§8 `SWPopupRow`, §9 `SWToolButton`)을 섞지 않는다 ③ 상태는 위 표대로 ④ 토큰에 없는 값은 결과 보고에 "AI 구성 값 — 디자인 확인 필요"로 적는다 ⑤ `hm-sw-viewer-*` class를 쓰거나 덮어쓰지 않는다. + +## 12. 로고 클릭 메뉴 (`SWHeader homeMenu` / `SWHomeMenu`, Figma 26:10591) — SW 일반 모드 전용 + +이 절의 값은 일반 모드 `SWHeader`의 홈 메뉴에만 씁니다. 뷰어 모드(§11)에는 홈 메뉴가 없으며 `--hm-sw-home-menu-*`·`--hm-sw-recent-files-*` 토큰을 뷰어 신규 UI에 쓰지 않습니다. + +| 항목 | 값 | 토큰 | +|---|---|---| +| 위치 | Header 맨 위(top 0), 객체 수정 영역 왼쪽 −2px ~ 창 영역 왼쪽(1920에서 x 375, 폭 1305). DOM 측정이며 고정 좌표 없음. `controls`로 파일명이 객체 수정 영역 안에 있으면 파일명 오른쪽 −2px부터 시작. 로고·파일명·창 영역은 가리지 않음. `z-index` 20(속성Bar 위, Dropdown 30·속성창 40 아래) | — | +| 크기 | 메뉴 높이 77(섹션 75 + 하단 강조 2), 그룹 46, 타일 80 × 46, 아이콘 18 슬롯, 섹션 폭은 타일 수로 자동 | — | +| 섹션 면 | 세로 gradient 면 + 1px `#081813` + 안쪽 1px `#20190E`, 아래 모서리 3px | `--hm-sw-home-menu-section-*` | +| 섹션 제목 | Figma tit_* badge(9-slice), 글자 400 검정 | `--hm-sw-home-menu-title-color` | +| 타일 상태 | Default 아이콘 `#B6B4AF` · Hover·Pressed(누르는 동안)·Active 주황 gradient 1px 테두리 + 아이콘·글자 `#FF5C00`, 1px 위·왼쪽 이동. 라벨 700. 최근파일 외 항목은 실행 버튼: 클릭 후 ON 유지 없음(2026-10-19 사용자 확정). Active 유지는 하위 패널 타일(최근파일, 목록이 열린 동안)과 더보기·홈 버튼(메뉴가 열린 동안)만. 유지형이 필요하면 `toggle: true` | `--hm-sw-home-menu-item-*`, `--hm-sw-home-menu-icon-color` | +| 하단 강조 | `sections` = 섹션마다 주황 띠, `outline` = 메뉴 전체 2px 외곽선(하위 패널이 열린 동안, `auto` 기본) | `--hm-sw-home-menu-accent-*` | +| 최근파일 패널 | 폭 354, 행 50, 배경 `#27241D`, 주황 테두리, 행 Hover `#62533D` + `#FF5C00`, 미리보기 310 × 270. 미리보기 위치: 목록 오른쪽(Figma) → 오른쪽에 공간이 없으면 왼쪽 → 좌우 모두 없으면(예: 390) 목록 위에 겹쳐 Hover 행 바로 아래(목록 왼쪽 1px 안쪽, 4면 테두리·radius 4, 크기·색 동일), 화면 아래 공간이 없으면 행 바로 위(2026-10-19 사용자 확정, Figma 없음). 가로 스크롤 없음 | `--hm-sw-recent-files-*` | +| 동작 | 기본 숨김 → 로고 클릭 열기 → 다시 클릭 닫기. 메뉴 빈 곳 클릭 닫기(Figma CLOSE). Escape: 하위 패널 → 메뉴, 닫히면 로고로 Focus. 메뉴 밖 클릭은 닫지 않음(Figma overlay 기준) | — | +| 좁은 폭 | 측정해 들어가는 섹션만 표시, 나머지는 끝의 더보기(⋯) 섹션(기존 섹션·타일 부품, 배지 `moreLabel` 기본 "더보기", 타일 "N개 그룹")으로 이동. 메뉴 배경·폭·높이·테두리·강조선은 그대로(더보기 섹션 면이 남는 폭을 채워 객체 수정 영역을 계속 덮음)이고, 더보기 배지·⋯ 타일만 마지막으로 표시된 섹션 바로 오른쪽에 붙음. 전체가 들어가는 폭에서는 더보기 숨김. 더보기 Dropdown과 최근파일 목록은 동시에 열리지 않음: 더보기를 열면 열린 목록을 먼저 닫고, Dropdown에서 최근파일을 고르면 Dropdown을 닫고 목록을 엶. Dropdown = 텍스트 메뉴(SW brown Dropdown: 배경 `#27241D`·테두리 `#000`·radius 3, 제목 12px 700 `#D4CBBD`, 행 30px·14px 700·좌우 12, 그룹 구분선 = 레이어 footer 선), ⋯ 타일 아래 왼쪽 정렬(화면 안으로 맞춤). 행 Hover = Pressed = Active = `#62533D` + `#FF5C00`. 일반 행은 클릭 후 ON·✓ 없음, 최근파일 행(›)만 목록이 열린 동안 Active. ✓는 `toggle: true` 행에만. 클릭·Callback·상태 규칙은 타일과 같음. ↓(더보기) = 첫 행, ↑/↓ 이동. Escape: Dropdown → 하위 패널 → 메뉴. 더보기 안 최근파일은 Dropdown을 닫고 더보기 타일 아래(화면 안으로 맞춤)에 기존 최근파일 목록으로 열림, 미리보기는 오른쪽에 공간이 없으면 왼쪽, 좌우 모두 없으면 목록 위 행 아래(최근파일 패널 행 참고). 목록이 메뉴 밖으로 나가는 부분은 메뉴 하단 강조선(2px, 같은 gradient)이 목록 상단으로 이어짐(실측 위치 기준, `--hm-sw-home-menu-accent-outline-width`). 가로 스크롤 없음 | `--hm-sw-home-menu-more-*` | + +- Home On(Figma 662:67267, 2026-10-19 사용자 확정): 메뉴가 열려 있는 동안 SWHeader가 자동으로 로고에 노란 Hover 테두리를 유지하고, Header 전폭 상·하단에 `#5F4B0F` 2px 선(`--hm-sw-header-home-on-line-color` / `-width`)을 그립니다. 닫으면 기본 상태로 돌아갑니다. 크기·위치 변화가 없고 SW 일반 모드 전용입니다(뷰어 모드에는 없음). 소비 코드에서 별도 class나 상태를 추가하지 않습니다. +- 새 색·크기는 위 토큰만 `style`로 덮어씁니다. `hm-sw-home-menu*` class를 소비 코드에 쓰지 않습니다. diff --git a/packages/sw/ai/VIEWER.md b/packages/sw/ai/VIEWER.md index 38a9d9d..24702f4 100644 --- a/packages/sw/ai/VIEWER.md +++ b/packages/sw/ai/VIEWER.md @@ -2,7 +2,7 @@ 기준: 2026-10-19, 참고 DWG/DXF 뷰어(`dwg-dxf-viewer-hm`) 상단 메뉴·팝업을 같은 해상도(1440 × 900)에서 실측해 패키지 컴포넌트로 옮긴 결과입니다. 아래 이름은 모두 `from "@hm-design/sw"` 공개 Export이고 CSS는 `@hm-design/sw/styles.css` 한 개입니다. 예제: [examples/ExampleH-ViewerMode.tsx](./examples/ExampleH-ViewerMode.tsx). -> **모드 선택 먼저:** 이 문서는 SW **뷰어 모드** 전용입니다. 화면이 뷰어 모드인지는 [AI_USAGE.md](./AI_USAGE.md) §0(설정 `HMDesign 사용 유형: SW 뷰어` → 요청 문구 → 불명확하면 질문)으로 정합니다. 전체 Export 목록은 [COMPONENT_CATALOG.md](./COMPONENT_CATALOG.md) §8, 토큰·상태 요약은 [DESIGN_RULES.md](./DESIGN_RULES.md) §11, 조합은 [COMPOSITION_PATTERNS.md](./COMPOSITION_PATTERNS.md) 7입니다. +> **모드 선택 먼저:** 이 문서는 SW **뷰어 모드** 전용입니다. 화면이 뷰어 모드인지는 [AI_USAGE.md](./AI_USAGE.md) §0(설정 `HMDesign 사용 유형: SW 뷰어` → 요청 문구 → 불명확하면 질문)으로 정합니다. 전체 Export 목록은 [COMPONENT_CATALOG.md](./COMPONENT_CATALOG.md) §9, 토큰·상태 요약은 [DESIGN_RULES.md](./DESIGN_RULES.md) §11, 조합은 [COMPOSITION_PATTERNS.md](./COMPOSITION_PATTERNS.md) 7입니다. > > **일반 모드 금지 사항(상호 참조):** 뷰어 화면에 `SWHeader`·`SWPopup`·`SWPopupSection`·`SWPopupRow`·`SWToolButton`·`SWToolGroup`·`SWHeaderPropertyPanel`을 쓰거나 재스타일하지 않고, 일반 모드 화면에 `SWViewer*`와 `--hm-sw-viewer-*` 토큰을 쓰지 않습니다. `SWViewerPanel`이 내부에서 `SWPopup` 프레임을 렌더링하는 것과 두 Header가 `--hm-sw-header-document-*`·`object-*`·`property-*`·외곽선 토큰을 공유하는 것은 패키지 구현이며 모드 혼합이 아닙니다([AI_USAGE.md](./AI_USAGE.md) §0.3). 패키지에 없는 뷰어 UI는 [AI_USAGE.md](./AI_USAGE.md) §0.4 뷰어 열을 따릅니다. @@ -96,6 +96,7 @@ const groups: SWViewerHeaderGroup[] = [ | 하지 말 것 | 이유 / 대신 | |---|---| | ``처럼 로고가 없다고 임의 문자·아이콘 넣기 | 로고는 프로그램이 정합니다. 없으면 생략 | +| 뷰어 화면에 로고(홈) 메뉴(`SWHomeMenu`·`SWRecentFiles`, `SWHeader homeMenu`) 넣기 또는 비슷한 2단 메뉴 직접 만들기 | 홈 메뉴는 SW 일반 모드 전용입니다. 뷰어 로고 클릭은 `onHomeClick`, 파일 열기·샘플은 `groups`의 `button`·`menu` 항목 | | 뷰어 Header를 `div` + `button`으로 다시 만들기, `hm-sw-viewer-*` class를 소비 코드에 붙이기 | 데이터(`groups`)와 `custom` / `trailing`으로 구성 | | Header 버튼 글자에 `-webkit-text-stroke`·`border`로 외곽선 만들기 | 외곽선은 패키지 토큰이 이미 적용합니다 | | 메뉴 색·간격을 `#123456`, `margin` 등 임의 값으로 덮기 | 토큰 `--hm-sw-viewer-*` / `--hm-sw-header-*`만 `style`로 조정(기본값 유지 권장) | diff --git a/packages/sw/ai/examples/ExampleG-HomeMenu.tsx b/packages/sw/ai/examples/ExampleG-HomeMenu.tsx new file mode 100644 index 0000000..71d3166 --- /dev/null +++ b/packages/sw/ai/examples/ExampleG-HomeMenu.tsx @@ -0,0 +1,62 @@ +// Example G — the logo (home) menu (Figma 26:10591): SWHeader `homeMenu` + sections data + the optional recent +// files panel. Hidden by default; a logo click opens it, a second click closes it. New / Open stay in the +// document dropdown. Every text, icon and action is the program's data; the package ships none. +import { useState } from "react" +import { + SWHeader, SWRecentFiles, + type SWFileEntry, type SWHomeMenuItemData, type SWHomeMenuSectionData, +} from "@hm-design/sw" +import { documents } from "./sample-data" + +// One currentColor icon per tile follows the state colors (Default #B6B4AF, Hover / Active #FF5C00). +const Icon = ({ d }: { d: string }) => ( + +) + +const recentFiles: SWFileEntry[] = [ + { id: "r1", name: "평면도_A.dwg", path: "D:\\Projects\\A" }, + { id: "r2", name: "종단면도_B.dwg", path: "D:\\Projects\\B" }, +] + +export function ExampleGHomeMenu({ onEvent }: { onEvent?: (name: string) => void }) { + const [activeDocumentId, setActiveDocumentId] = useState(documents[0].id) + const [extra, setExtra] = useState([]) + // The same handlers as the document dropdown: the menu adds entry points, never a second implementation. + const openFile = () => onEvent?.("document:open") + const newFile = () => onEvent?.("document:new") + + const sections: SWHomeMenuSectionData[] = [ + { id: "working", title: "작업중인 파일", items: [ + { id: "save", label: "저장", icon: , toggle: false, onSelect: () => onEvent?.("menu:save") }, + { id: "export", label: "내보내기", icon: , toggle: false, onSelect: () => onEvent?.("menu:export") }, + ] }, + { id: "open", title: "다른 파일 열기", items: [ + { id: "find-open", label: "찾아열기", icon: , toggle: false, onSelect: openFile }, + // Optional sub panel: the tile toggles it (Active = open), the menu shows the outline accent meanwhile. + { id: "recent", label: "최근파일", icon: , + panel: onEvent?.(`recent:${file.id}`)} />, panelLabel: "최근파일" }, + { id: "new-file", label: "새파일", icon: , toggle: false, onSelect: newFile }, + ...extra, + ] }, + ] + + return ( + <> + item.id === activeDocumentId)?.name ?? ""} + logoAlt="예제 SW" + documents={documents} + activeDocumentId={activeDocumentId} + onDocumentSelect={document => { setActiveDocumentId(document.id); onEvent?.(`document:${document.id}`) }} + onDocumentNew={newFile} + onDocumentOpen={openFile} + homeMenu={{ sections, onItemSelect: event => onEvent?.(`menu:select:${event.item.id}:${event.active}`) }} + onHomeMenuOpenChange={(open, reason) => onEvent?.(`menu:${open ? "open" : "close"}:${reason}`)} + /> + {/* Adding an item is a data change only: width, dividers and corners follow the new item count. */} + + + ) +} diff --git a/packages/sw/src/components/sw-header/SWHeader.tsx b/packages/sw/src/components/sw-header/SWHeader.tsx index b192deb..49284eb 100644 --- a/packages/sw/src/components/sw-header/SWHeader.tsx +++ b/packages/sw/src/components/sw-header/SWHeader.tsx @@ -20,7 +20,8 @@ import { SWHeaderPropertyPanel } from "./components/SWHeaderPropertyPanel" import { SWHeaderDimensionStyleMenu, SWHeaderTextStyleMenu } from "./components/SWHeaderStyleListMenus" import { SWHeaderWindowControls } from "./components/SWHeaderWindowControls" import { SWToolButton } from "../sw-tool/SWTool" -import type { SWHeaderControlId, SWHeaderControlConfig, SWHeaderFrameControlId, SWHeaderHideableControlId, SWHeaderMenuId, SWHeaderProps, SWHeaderSubControlId } from "./types" +import { SWHomeMenu } from "../sw-home-menu/SWHomeMenu" +import type { SWHeaderControlId, SWHeaderControlConfig, SWHeaderFrameControlId, SWHeaderHideableControlId, SWHeaderHomeMenuChangeReason, SWHeaderMenuId, SWHeaderProps, SWHeaderSubControlId } from "./types" const defaults = { layer: { name: "0" }, @@ -41,6 +42,34 @@ const frameControls: readonly SWHeaderFrameControlId[] = ["home", "windowMove", const subControls: readonly SWHeaderSubControlId[] = ["documentNew", "documentOpen", "layerFreeze", "layerLock"] const isMenu = (id: string): id is SWHeaderMenuId => id in menuSlot +/** + * Order in which visible parts move into More when the measured object area has no room left (on top of the + * breakpoints): the breakpoint tier order — line / text / dimension style, 그리기모드, the property block, color, + * print / K — and within a tier the rightmost part first. The representative field never moves. + */ +const squeezeRank: Partial> = { + lineStyle: 0, textStyle: 0, dimensionStyle: 0, drawingMode: 1, details: 2, propertyBar: 2, propertyPanel: 2, color: 3, print: 4, popupGuide: 4, +} + +/** + * Room left in the object area (negative: missing) when nothing in it shrinks, grows or takes free space through an + * auto margin (`data-measuring`, see sw.css "Measured More"). Read and reset in one layout effect, never painted. + * Only in-flow children count: dropdowns, tooltips and other positioned layers never change the result. + */ +function measureRoom(header: HTMLElement, area: HTMLElement) { + header.setAttribute("data-measuring", "") + const style = getComputedStyle(area) + const end = area.getBoundingClientRect().right - parseFloat(style.borderRightWidth) - parseFloat(style.paddingRight) + let used = area.getBoundingClientRect().left + parseFloat(style.borderLeftWidth) + parseFloat(style.paddingLeft) + for (const child of Array.from(area.children)) { + const childStyle = getComputedStyle(child) + if (childStyle.display === "none" || childStyle.position === "absolute" || childStyle.position === "fixed") continue + used = Math.max(used, child.getBoundingClientRect().right + parseFloat(childStyle.marginRight)) + } + header.removeAttribute("data-measuring") + return end - used +} + /** * Menu order: listed known ids first (duplicates and unknown ids ignored), missing ids after them in * the default order. Menus only swap places among the slots menus already take; other parts never move. @@ -135,6 +164,10 @@ export const SWHeader = forwardRef(function SWHeader onPropertyPanelOpenChange, disabled = false, tools, + homeMenu, + homeMenuOpen, + defaultHomeMenuOpen = false, + onHomeMenuOpenChange, logo, logoSrc, logoAlt, @@ -165,8 +198,9 @@ export const SWHeader = forwardRef(function SWHeader const enabled = (id: SWHeaderControlId) => configuration.some(item => item.id === id) // Default design with removed object parts: same structure and breakpoints, but the script decides what // moves into More (the CSS alone assumes every field is present). Untouched defaults stay CSS-only. - // Sub-items live inside a part and never change the layout mode. - const scripted = controls !== undefined || [...removed].some(id => !frameControls.includes(id as SWHeaderFrameControlId) && !subControls.includes(id as SWHeaderSubControlId)) + // Sub-items live inside a part and never change the layout mode. Parts measured into More also need the script. + const [squeezed, setSqueezed] = useState([]) + const scripted = controls !== undefined || squeezed.length > 0 || [...removed].some(id => !frameControls.includes(id as SWHeaderFrameControlId) && !subControls.includes(id as SWHeaderSubControlId)) const layerStates = { showFreeze: shown("layerFreeze"), showLock: shown("layerLock") } const presentRef = useRef(new Set(configuration.map(item => item.id))) presentRef.current = new Set(configuration.map(item => item.id)) @@ -209,6 +243,7 @@ export const SWHeader = forwardRef(function SWHeader const [headerWidth, setHeaderWidth] = useState(1920) + const [, setAreaWidth] = useState(0) const [barOffset, setBarOffset] = useState(0) // Open next to the logo (documentOpenPlacement="header") moves into More when the measured header has no room. const openInHeader = documentOpenPlacement === "header" && shown("documentOpen") @@ -223,6 +258,8 @@ export const SWHeader = forwardRef(function SWHeader const update = () => { const bounds = header.getBoundingClientRect() setHeaderWidth(bounds.width) + // The object area can change alone (leading content, file name, window area): it re-runs the measured More. + setAreaWidth(panelAnchorRef.current?.getBoundingClientRect().width ?? 0) setBarOffset((panelAnchorRef.current?.getBoundingClientRect().left ?? bounds.left) - bounds.left) } const observer = new ResizeObserver(update) @@ -232,8 +269,7 @@ export const SWHeader = forwardRef(function SWHeader return () => observer.disconnect() }, []) // Space for the parts right of the logo, measured: the file name gives way first (its CSS clamp subtracts - // --hm-sw-header-leading-width). Open moves into More only when the bar or object area really overflows, - // and returns once the header is wider than at that moment by the Open width (no flicker at the edge). + // --hm-sw-header-leading-width). Open and the other parts move into More by measurement (see "Measured More"). useLayoutEffect(() => { const header = fieldsRef.current?.closest(".hm-sw-header") if (!header) return @@ -243,29 +279,62 @@ export const SWHeader = forwardRef(function SWHeader if (value) header.style.setProperty("--hm-sw-header-leading-width", value) else header.style.removeProperty("--hm-sw-header-leading-width") } - if (!openInHeader) { - collapseRef.current = null - if (openCollapsed) setOpenCollapsed(false) - return - } - if (!openCollapsed) { - const bar = header.querySelector(":scope > .hm-sw-header__bar") - const overflow = [bar, panelAnchorRef.current].some(element => !!element && element.scrollWidth - element.clientWidth > 1) - const open = leadingRef.current?.querySelector("[data-document-open]") - if (overflow && open) { - collapseRef.current = { at: header.getBoundingClientRect().width, width: open.getBoundingClientRect().width + 2 } - setOpenCollapsed(true) - } - } else if (collapseRef.current && headerWidth >= collapseRef.current.at + collapseRef.current.width) { - setOpenCollapsed(false) - } + }) + + // Logo (home) menu: SWHeader owns its open state; a logo click toggles it instead of calling onHomeClick. + const homeMenuId = useId() + const homeButtonRef = useRef(null) + const [internalHomeOpen, setInternalHomeOpen] = useState(defaultHomeMenuOpen) + const homeOpen = !!homeMenu && shown("home") && (homeMenuOpen ?? internalHomeOpen) + const [internalDocumentOpen, setInternalDocumentOpen] = useState(false) + const documentOpenNow = documentMenuOpen ?? internalDocumentOpen + const setDocumentOpen = (next: boolean) => { + if (documentMenuOpen === undefined) setInternalDocumentOpen(next) + onDocumentMenuOpenChange?.(next) + } + const setHomeOpen = (next: boolean, reason: SWHeaderHomeMenuChangeReason) => { + if (homeMenuOpen === undefined) setInternalHomeOpen(next) + if (next !== homeOpen) onHomeMenuOpenChange?.(next, reason) + if (!next) return + // One header layer at a time: the menu covers the fields, so their dropdown and the document menu close. + if (openMenu) openers[openMenu].onOpenChange(false) + if (documentOpenNow) setDocumentOpen(false) + } + // Placement from the DOM (never a fixed x): 2px before the object area (Figma 375 vs 377 at 1920) up to the + // window area, so it follows the breakpoints, `leading`, the header Open and a narrowed file name. + const [homeBox, setHomeBox] = useState({ left: 0, width: 0 }) + useLayoutEffect(() => { + const header = fieldsRef.current?.closest(".hm-sw-header") + homeButtonRef.current = header?.querySelector(":scope > .hm-sw-header__bar > .hm-sw-header__home") ?? null + if (!homeOpen || !header || !panelAnchorRef.current) return + const origin = header.getBoundingClientRect() + // With `controls`, the file name sits inside the object area: start after it so it stays visible. + const documentRight = fieldsRef.current?.querySelector(':scope > [data-control="document"]:not([data-hidden])')?.getBoundingClientRect().right + const start = Math.max(panelAnchorRef.current.getBoundingClientRect().left, documentRight ?? -Infinity) + const end = header.querySelector(":scope > .hm-sw-header__bar > .hm-sw-header__window")?.getBoundingClientRect().left ?? origin.right + const next = { left: start - origin.left - 2, width: end - start + 2 } + if (Math.abs(next.left - homeBox.left) > 0.1 || Math.abs(next.width - homeBox.width) > 0.1) setHomeBox(next) }) const menuIds = configuration.map(item => item.id).filter((id): id is SWHeaderMenuId => id in menuSlot) const baseMenu = menuIds.includes("layer") ? "layer" : menuIds[0] const validPromoted = promoted && enabled(promoted) ? promoted : null - const isOverflow = (id: SWHeaderControlId) => id === "color" ? headerWidth < 900 : ["lineStyle", "textStyle", "dimensionStyle"].includes(id) ? headerWidth < 1800 : ["propertyBar", "propertyPanel", "details"].includes(id) ? headerWidth < 1080 : ["print", "popupGuide"].includes(id) ? headerWidth < 640 : false + const breakpointOverflow = (id: SWHeaderControlId) => id === "color" ? headerWidth < 900 : ["lineStyle", "textStyle", "dimensionStyle"].includes(id) ? headerWidth < 1800 : ["propertyBar", "propertyPanel", "details"].includes(id) ? headerWidth < 1080 : ["print", "popupGuide"].includes(id) ? headerWidth < 640 : id === "drawingMode" ? headerWidth < 1180 : false + // Measured More: the parts that can move (the default layout moves the property block as one part; print / K sit in + // the window area there and keep the breakpoint). Keys of the moved parts are kept in move order. + const squeezeGroups = (controls === undefined + ? [...menuIds.map(id => ({ key: id as string, ids: [id] as SWHeaderControlId[] })), { key: "drawingMode", ids: ["drawingMode"] as SWHeaderControlId[] }, + { key: "properties", ids: ["details", "propertyBar", "propertyPanel"] as SWHeaderControlId[] }] + : configuration.map(item => ({ key: item.id as string, ids: [item.id] }))) + .map((group, index) => ({ ...group, ids: group.ids.filter(id => enabled(id) && squeezeRank[id] !== undefined), index })) + .filter(group => group.ids.length > 0) + const squeezedIds = new Set(squeezeGroups.filter(group => squeezed.includes(group.key)).flatMap(group => group.ids)) + const isOverflow = (id: SWHeaderControlId) => breakpointOverflow(id) || squeezedIds.has(id) const representative = validPromoted && isOverflow(validPromoted) ? validPromoted : baseMenu const fieldHidden = (id: SWHeaderMenuId) => id !== representative && (isOverflow(id) || (id === baseMenu && representative !== baseMenu)) + // Next part to move: shown now, never the representative slot, lowest tier first, rightmost first within a tier. + const squeezeCandidates = squeezeGroups + .filter(group => !squeezed.includes(group.key) && !group.ids.some(id => id === baseMenu || id === validPromoted || (isMenu(id) ? fieldHidden(id) : isOverflow(id)))) + .sort((a, b) => (squeezeRank[a.ids[0]] ?? 0) - (squeezeRank[b.ids[0]] ?? 0) || b.index - a.index) // Removal is structural: close stale internal dropdown state silently, never send data callbacks. const controlKey = configuration.map(item => item.id).join(",") useEffect(() => { @@ -275,6 +344,51 @@ export const SWHeader = forwardRef(function SWHeader if (!enabled("propertyBar")) setInternalBarOpen(false) }, [controlKey, openMenu, promoted]) + // Measured More (2026-10-19): on top of the breakpoints, parts move into More while the object area has no room for + // them (leading content, tools, labels, a side panel) and return once the room they freed is back, so the header + // never relies on fixed widths alone. Open next to the logo moves first and returns last. One part per pass; the + // passes are synchronous layout effects, so only the final layout is painted. Opening a menu never moves a part: + // dropdowns and the logo menu are positioned layers, which the measurement ignores. + const squeezeRef = useRef(new Map()) + useLayoutEffect(() => { + const header = fieldsRef.current?.closest(".hm-sw-header") + const area = panelAnchorRef.current + // Wait for the measured header width (breakpoint state) to be rendered first. + if (!header || !area || Math.abs(header.getBoundingClientRect().width - headerWidth) > 0.5) return + if (!openInHeader) { + collapseRef.current = null + if (openCollapsed) return setOpenCollapsed(false) + } + // Parts removed from the configuration leave the list silently. + const valid = squeezed.filter(key => squeezeGroups.some(group => group.key === key)) + if (valid.length !== squeezed.length) return setSqueezed(valid) + const room = measureRoom(header, area) + const last = squeezed[squeezed.length - 1] + const metrics = last === undefined ? undefined : squeezeRef.current.get(last) + // The room a part frees is measured once, right after it moved (More appearing and padding changes included). + if (metrics && metrics.room === undefined) metrics.room = room - metrics.before + if (room < -0.5) { + const open = openShown ? leadingRef.current?.querySelector("[data-document-open]") : null + if (open) { + collapseRef.current = { at: header.getBoundingClientRect().width, width: open.getBoundingClientRect().width + 2 } + return setOpenCollapsed(true) + } + const next = squeezeCandidates[0] + if (next) { + squeezeRef.current.set(next.key, { before: room }) + setSqueezed([...squeezed, next.key]) + } + } else if (last !== undefined) { + if (room >= (metrics?.room ?? Infinity) - 0.5) { + squeezeRef.current.delete(last) + setSqueezed(squeezed.slice(0, -1)) + } + } else if (openCollapsed && collapseRef.current && headerWidth >= collapseRef.current.at + collapseRef.current.width) { + // Open returns once the header is wider than when it moved by the Open width (no flicker at the edge). + setOpenCollapsed(false) + } + }) + const hasMenu: Record = { layer: layers !== undefined, color: colors !== undefined, @@ -440,8 +554,9 @@ export const SWHeader = forwardRef(function SWHeader title={documentTitle} onClick={onDocumentClick} documents={documents} - menuOpen={documentMenuOpen} - onMenuOpenChange={onDocumentMenuOpenChange} + // With a logo menu SWHeader holds the document menu state, so the two never stay open together. + menuOpen={homeMenu ? documentOpenNow : documentMenuOpen} + onMenuOpenChange={homeMenu ? next => { setDocumentOpen(next); if (next && homeOpen) setHomeOpen(false, "document") } : onDocumentMenuOpenChange} onDocumentSelect={onDocumentSelect} activeDocumentId={activeDocumentId} onDocumentClose={onDocumentClose} @@ -477,27 +592,28 @@ export const SWHeader = forwardRef(function SWHeader }) return ( -
+
- + setHomeOpen(!homeOpen, "home") : onHomeClick} interactive={shown("home")} logo={logo} logoSrc={logoSrc} logoAlt={logoAlt} + aria-expanded={homeMenu && shown("home") ? homeOpen : undefined} aria-controls={homeOpen ? homeMenu?.id ?? homeMenuId : undefined} /> {hasLeading &&
{openShown && {documentOpenLabel ?? "Open"}} {leading}
} {controls === undefined && enabled("document") && documentNode} -
- {controls === undefined && enabled("drawingMode") && {drawingModeLabel}} +
+ {controls === undefined && enabled("drawingMode") && !squeezedIds.has("drawingMode") && {drawingModeLabel}}
{controls ? configuration.map(config => { - const hidden = config.id in menuSlot ? fieldHidden(config.id as SWHeaderMenuId) : isOverflow(config.id) || (config.id === "drawingMode" && headerWidth < 1180) + const hidden = config.id in menuSlot ? fieldHidden(config.id as SWHeaderMenuId) : isOverflow(config.id) return
{presence(config.id, configuredNodes[config.id])}
}) : scripted ? menuIds.map(id => (
{presence(id, fieldNodes[id])}
)) : menuIds.map(id => {fieldNodes[id]})} {tools}
- {moreItems.some(item => item.visible !== false) && } - {controls === undefined && } + {moreItems.some(item => item.visible !== false) && 0} />} + {controls === undefined && !squeezed.includes("properties") && }
{windowShown &&
{actionsShown && } @@ -505,6 +621,12 @@ export const SWHeader = forwardRef(function SWHeader
}
{barOpen && barData &&
} + {homeMenu && shown("home") && ( +
+ setHomeOpen(next, reason)} /> +
+ )} {panelOpen && propertyPanel && }
) diff --git a/packages/sw/src/components/sw-header/components/SWHeaderHome.tsx b/packages/sw/src/components/sw-header/components/SWHeaderHome.tsx index d379f30..a891e4e 100644 --- a/packages/sw/src/components/sw-header/components/SWHeaderHome.tsx +++ b/packages/sw/src/components/sw-header/components/SWHeaderHome.tsx @@ -15,13 +15,16 @@ export interface SWHeaderHomeProps { * SWHeader always shows the logo; only the home action can be removed. Default true. */ interactive?: boolean + /** Logo menu state (SWHeader `homeMenu`). The Home On look is drawn by SWHeader (`data-home-menu-open`, Figma 662:67267). */ + "aria-expanded"?: boolean + "aria-controls"?: string } /** * Home button. The slanted background and the logo slot position are the common SW design; * the logo itself belongs to each SW program, so no logo is rendered unless one is passed. */ -export function SWHeaderHome({ onClick, logoSrc, logo, logoAlt, interactive = true }: SWHeaderHomeProps) { +export function SWHeaderHome({ onClick, logoSrc, logo, logoAlt, interactive = true, "aria-expanded": expanded, "aria-controls": controls }: SWHeaderHomeProps) { const content = logo ?? (logoSrc ? : null) if (!interactive) return (
@@ -30,7 +33,7 @@ export function SWHeaderHome({ onClick, logoSrc, logo, logoAlt, interactive = tr
) return ( - + + )} + + {overflowCount > 0 && ( + // Always laid out (positioned before it shows), visible only while open. The moved sections draw as text + // groups (title + rows) with the same items: selection, Active, panels and callbacks are unchanged. + // A row with a sub panel (최근파일) closes the dropdown; its panel opens under More. +
{ + if (!(event.target as Element).closest(".hm-sw-home-menu__text-item[aria-expanded]")) return + setMoreOpen(false) + moreButtonRef.current?.focus() + }}> + {nodes.slice(rowCount)} +
+ )} + {openPanel && ( + // The accent continues over the panel's top edge where it reaches past the menu (outline accent only). + resolvedAccent === "outline" && joint.map(part => ( +