feat(sw): integrate responsive home menu into header

- Merge SW / Home Menu Stories into SW / Header (sidebar: Home Menu; others verification-tagged)
- Home On: logo hover ring and header top/bottom #5F4B0F lines while the menu is open
- Measured More in SWHeader; home menu narrow widths use a More (...) section with a grouped
  text menu instead of horizontal scroll, placed right after the last visible section
- Action tiles no longer stay on after a click; 최근파일 stays Active only while its list is open
- More dropdown and recent files list never open together; list top joins the accent line
- Recent files preview falls back left / over the list at narrow widths (390px)
- Update Storybook, browser tests, docs, AI guides and QA evidence
This commit is contained in:
shkim4 committed 2026-10-19 22:46:28 +09:00
1 parent c542bdc282
commit 170a5c23ae
71 files changed
+12535 -150

No files matched your search

+148 -13
View File
@@ -26,6 +26,22 @@
/* Bottom accent: 26:10591 per-section strip (top → bottom) / 662:67267 2px outline (bottom → top). */
--hm-sw-home-menu-accent-strip: linear-gradient(180deg, #5f4b0f -6.4%, #ff5100 96.8%);
--hm-sw-home-menu-accent-outline: linear-gradient(0deg, #ff5100 0%, #5f4b0f 76.7%);
--hm-sw-home-menu-accent-outline-width: 2px;
--hm-sw-home-menu-accent-outline-height: 30px;
/* More dropdown (not in Figma): a text menu in the SW brown dropdown family (header/menu/레이어 26:10940, rows
header/dropdown/brown/row 26:10687): surface, border, radius, shadow, 30px rows, row hover; group title in the
최근파일 path color, groups split by the layer footer divider. */
--hm-sw-home-menu-more-background: var(--hm-sw-header-layer-menu-background);
--hm-sw-home-menu-more-border-color: var(--hm-sw-header-layer-menu-border-color);
--hm-sw-home-menu-more-radius: var(--hm-sw-header-layer-menu-radius);
--hm-sw-home-menu-more-shadow: var(--hm-sw-header-layer-menu-shadow);
--hm-sw-home-menu-more-offset: 2px;
--hm-sw-home-menu-more-min-width: 180px;
--hm-sw-home-menu-more-divider-color: var(--hm-sw-header-layer-footer-border-color);
--hm-sw-home-menu-more-title-color: var(--hm-sw-recent-files-path-color);
--hm-sw-home-menu-more-row-height: 30px;
--hm-sw-home-menu-more-row-hover-background: var(--hm-sw-header-layer-row-hover-background);
--hm-sw-home-menu-more-row-hover-color: var(--hm-sw-header-layer-row-hover-color);
/* Optional sub panel (Figma 최근파일 662:67331 / 파일출력 2뎁스 662:67471). */
--hm-sw-recent-files-width: 354px;
@@ -49,10 +65,108 @@
max-width: 100%;
/* 2px of the accent strip shows left, right and under the sections (menu 1305 x 77 in Figma). */
padding: 0 2px 2px;
/* Not in Figma (1920px only): narrower hosts scroll the menu horizontally, like the property bar. */
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: thin;
/* Not in Figma (1920px only): narrower hosts get the measured More section instead of a scroller (SWHomeMenu).
The clip only keeps the badge shadow and the strip inside the menu, as before; nothing is cut off. */
overflow: hidden;
}
/* Measurement pass (one synchronous read, removed before paint) and overflow: the menu takes all the room of its host
(clamped by max-width), so with More it still covers the whole area SWHeader gives it, as the full menu does. */
.hm-sw-home-menu:is([data-measuring], [data-overflow]) { width: 100000px; }
/* More fills the rest of the row with the section surface (the menu background stays as it is); only its badge and
⋯ tile sit right after the last shown section (2026-10-19 user correction: start, not end). */
.hm-sw-home-menu__section.hm-sw-home-menu__more { flex: 1 0 auto; align-items: flex-start; }
/* Natural tile widths (SWHomeMenu measure copy): laid out, invisible, zero-size clip (no scroll area, no hit area). */
.hm-sw-home-menu__measure {
position: absolute;
top: 0;
left: 0;
width: 0;
height: 0;
overflow: hidden;
visibility: hidden;
pointer-events: none;
}
.hm-sw-home-menu__measure-row { display: flex; align-items: flex-start; width: max-content; }
/* More (not in Figma): the section + tile parts above with a ⋯ icon. Its dropdown sits under the ⋯ tile, left edges aligned
(left set from the DOM): a text menu of the moved sections (title + rows). Above the sub panel; laid out while
closed so it is positioned before it shows. */
.hm-sw-home-menu__more-panel {
position: absolute;
z-index: 2;
top: calc(100% + var(--hm-sw-home-menu-more-offset));
display: flex;
flex-direction: column;
min-width: var(--hm-sw-home-menu-more-min-width);
max-width: calc(100vw - 16px);
padding: 4px 0;
border: 1px solid var(--hm-sw-home-menu-more-border-color);
border-radius: var(--hm-sw-home-menu-more-radius);
background: var(--hm-sw-home-menu-more-background);
box-shadow: var(--hm-sw-home-menu-more-shadow);
color: var(--hm-sw-home-menu-item-color);
}
.hm-sw-home-menu__more-panel:not([data-open]) { visibility: hidden; pointer-events: none; }
.hm-sw-home-menu__text-group { display: flex; flex-direction: column; padding: 4px 0; }
.hm-sw-home-menu__text-group + .hm-sw-home-menu__text-group { border-top: 1px solid var(--hm-sw-home-menu-more-divider-color); }
.hm-sw-home-menu__text-title {
padding: 4px 12px;
overflow: clip;
overflow-clip-margin: var(--hm-sw-header-text-outline-room);
color: var(--hm-sw-home-menu-more-title-color);
font-size: var(--hm-sw-header-label-size);
font-weight: 700;
line-height: 16px;
letter-spacing: 0.04em;
white-space: nowrap;
text-overflow: ellipsis;
text-shadow: var(--hm-sw-header-label-outline);
}
.hm-sw-home-menu__text-list { display: flex; flex-direction: column; }
/* Row = header/dropdown/brown/row: 30px, 12px in, 14px 700 with the menu text outline. */
.hm-sw-home-menu__text-item {
display: flex;
align-items: center;
gap: 12px;
height: var(--hm-sw-home-menu-more-row-height);
padding: 0 12px;
color: var(--hm-sw-home-menu-item-color);
font-size: var(--hm-sw-header-font-size);
font-weight: 700;
line-height: 16px;
letter-spacing: 0.04em;
white-space: nowrap;
text-align: left;
}
.hm-sw-home-menu__text-label {
flex: 1 1 auto;
min-width: 0;
overflow: clip;
overflow-clip-margin: var(--hm-sw-header-text-outline-room);
text-overflow: ellipsis;
text-shadow: var(--hm-sw-header-text-outline);
}
/* Indicator column: › for a row that opens a sub panel (최근파일); ✓ only for an opt-in toggle row (toggle: true). */
.hm-sw-home-menu__text-item::after { content: ""; flex: 0 0 14px; width: 14px; text-align: center; }
.hm-sw-home-menu__text-item[aria-pressed="true"]::after { content: "✓"; }
.hm-sw-home-menu__text-item[aria-expanded]::after { content: "›"; }
/* Hover = pressed = Active (the tiles' Variant2 = Variant3, the brown rows' hover = selected): brown row, orange
text. Action rows keep nothing after the click; only the 최근파일 row stays Active while its list is open. */
.hm-sw-home-menu__text-item:is(:hover, :active, [data-active="true"]):not(:disabled) {
background: var(--hm-sw-home-menu-more-row-hover-background);
color: var(--hm-sw-home-menu-more-row-hover-color);
}
/* Accent joint (narrow widths, 2026-10-19): where the sub panel reaches past the menu, the outline's bottom band runs
on over the panel's top edge — same 2px, same gradient slice (the outline gradient sized to its box, bottom), so
the menu's bottom line and the list's side borders meet without a gap. Left / width from the measured positions. */
.hm-sw-home-menu__joint {
position: absolute;
z-index: 1;
top: calc(100% - var(--hm-sw-home-menu-accent-outline-width));
height: var(--hm-sw-home-menu-accent-outline-width);
background: var(--hm-sw-home-menu-accent-outline) left bottom / 100% var(--hm-sw-home-menu-accent-outline-height) no-repeat;
pointer-events: none;
}
/* Sub panel under the menu, at its tile (position set from the DOM). */
.hm-sw-home-menu__panel { position: absolute; z-index: 1; top: 100%; }
@@ -104,8 +218,8 @@
top: 47px;
right: 0;
left: 0;
height: 30px;
padding: 2px;
height: var(--hm-sw-home-menu-accent-outline-height);
padding: var(--hm-sw-home-menu-accent-outline-width);
border-radius: 0 0 3px 3px;
background: var(--hm-sw-home-menu-accent-outline);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
@@ -238,16 +352,17 @@
text-shadow: var(--hm-sw-header-text-outline);
}
/* Variant2 (hover) = Variant3 (active): orange stroke, #FF5C00 icon and label, art 1px up-left. */
.hm-sw-home-menu__item:is(:hover:not(:disabled), [data-active="true"])::after { opacity: 1; }
.hm-sw-home-menu__item:is(:hover:not(:disabled), [data-active="true"]) {
/* Variant2 (hover) = Variant3 (pressed while held; stays only as Active of a panel tile / More): orange stroke,
#FF5C00 icon and label, art 1px up-left. Action tiles keep nothing after the click (2026-10-19). */
.hm-sw-home-menu__item:is(:hover:not(:disabled), :active:not(:disabled), [data-active="true"])::after { opacity: 1; }
.hm-sw-home-menu__item:is(:hover:not(:disabled), :active:not(:disabled), [data-active="true"]) {
--hm-sw-home-menu-icon-color: var(--hm-sw-home-menu-item-accent-color);
color: var(--hm-sw-home-menu-item-accent-color);
}
.hm-sw-home-menu__item:is(:hover:not(:disabled), [data-active="true"]) .hm-sw-home-menu__icon { transform: translate(-1px, -1px); }
.hm-sw-home-menu__item:is(:hover:not(:disabled), [data-active="true"]) .hm-sw-home-menu__label { top: 24px; }
.hm-sw-home-menu__item[data-has-hover-icon]:is(:hover:not(:disabled), [data-active="true"]) .hm-sw-home-menu__icon:not(.hm-sw-home-menu__icon--hover) { visibility: hidden; }
.hm-sw-home-menu__item[data-has-hover-icon]:is(:hover:not(:disabled), [data-active="true"]) .hm-sw-home-menu__icon--hover { visibility: visible; }
.hm-sw-home-menu__item:is(:hover:not(:disabled), :active:not(:disabled), [data-active="true"]) .hm-sw-home-menu__icon { transform: translate(-1px, -1px); }
.hm-sw-home-menu__item:is(:hover:not(:disabled), :active:not(:disabled), [data-active="true"]) .hm-sw-home-menu__label { top: 24px; }
.hm-sw-home-menu__item[data-has-hover-icon]:is(:hover:not(:disabled), :active:not(:disabled), [data-active="true"]) .hm-sw-home-menu__icon:not(.hm-sw-home-menu__icon--hover) { visibility: hidden; }
.hm-sw-home-menu__item[data-has-hover-icon]:is(:hover:not(:disabled), :active:not(:disabled), [data-active="true"]) .hm-sw-home-menu__icon--hover { visibility: visible; }
/* SWRecentFiles — Figma 최근파일 662:67331 (354 x 750: rows 50px) + 2-depth preview 662:67471 (310 x 270). */
.hm-sw-recent-files { position: relative; width: var(--hm-sw-recent-files-width); }
@@ -321,6 +436,26 @@
filter: drop-shadow(0 2px 1px rgba(0, 0, 0, 0.5));
pointer-events: none;
}
/* No room on the right (narrow widths): the same preview mirrored on the left of the list. */
.hm-sw-recent-files__preview[data-side="left"] {
right: calc(100% + 1px);
left: auto;
border-right: 0;
border-left: 1px solid var(--hm-sw-recent-files-preview-background);
border-radius: 3px 0 0 4px;
box-shadow: inset -2px 0 2.5px rgba(0, 0, 0, 0.5);
}
.hm-sw-recent-files__preview[data-side="left"] .hm-sw-recent-files__preview-body { border-radius: 0 0 0 4px; }
/* No room on either side (e.g. 390px): the same preview over the list, right under the row (above it when the
viewport has no room below). Not in Figma (2026-10-19 사용자 확정). */
.hm-sw-recent-files__preview:is([data-side="below"], [data-side="above"]) {
left: 1px;
border-left: 1px solid var(--hm-sw-recent-files-preview-background);
border-radius: 4px;
box-shadow: none;
}
.hm-sw-recent-files__preview[data-side="above"] { transform: translateY(-100%); }
.hm-sw-recent-files__preview:is([data-side="below"], [data-side="above"]) .hm-sw-recent-files__preview-body { border-radius: 0 0 4px 4px; }
.hm-sw-recent-files__preview-title {
width: 294px;
overflow: hidden;