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:
1 parent
c542bdc282
commit
170a5c23ae
71 files changed
+12535
-150
No files matched your search
@@ -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;
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
/* Figma header/btn_home (26:10655) "hover" stroke: 1px, top -> bottom. */
|
||||
--hm-sw-header-hover-border-gradient: linear-gradient(180deg, #a67d03 0%, #f2cc0f 16.41%, #fadd4f 37.19%, #f2cc0f 62.03%, #926e03 87.88%);
|
||||
--hm-sw-header-hover-border-width: 1px;
|
||||
/* Figma 662:67267 "home on" (logo menu open): header border-top / border-bottom, 2px, full width. */
|
||||
--hm-sw-header-home-on-line-color: #5f4b0f;
|
||||
--hm-sw-header-home-on-line-width: 2px;
|
||||
|
||||
/* Figma header/document_tit (26:10662) document dropdown */
|
||||
--hm-sw-header-document-menu-width: 310px;
|
||||
@@ -1883,7 +1886,44 @@ div.hm-sw-header__menu-row { justify-content: space-between; gap: 8px; padding-l
|
||||
/* ...and the file name gives way only down to the default design's smallest width (96px, see the clamps above). */
|
||||
.hm-sw-header[data-leading="open"] .hm-sw-header__fields[data-configured] > .hm-sw-header__control[data-control="document"] { min-width: 96px; }
|
||||
|
||||
/* Measured More (SWHeader, 2026-10-19): on top of the breakpoints, parts move into More while the object area has no
|
||||
room for them and return when it has. data-measuring is set for one synchronous layout read and removed before
|
||||
paint: nothing in the object area shrinks, grows or takes free space through an auto margin, so the in-flow content
|
||||
shows the room it really needs. A configured file name counts with the smallest default file-name width (96px).
|
||||
!important: measurement only, it must win over every tier and representative-slot rule above. */
|
||||
.hm-sw-header[data-measuring] :is(.hm-sw-header__object-area, .hm-sw-header__fields, .hm-sw-header__control) > * { flex-grow: 0 !important; flex-shrink: 0 !important; }
|
||||
.hm-sw-header[data-measuring] .hm-sw-header__properties,
|
||||
.hm-sw-header[data-measuring] .hm-sw-header__object-area[data-squeezed~="properties"] > .hm-sw-header__more { margin-left: 0 !important; }
|
||||
@container hm-sw-header (max-width: 1079.98px) {
|
||||
.hm-sw-header[data-measuring] .hm-sw-header__more { margin-left: 0 !important; }
|
||||
}
|
||||
.hm-sw-header[data-measuring] .hm-sw-header__control[data-control="document"] { flex: 0 0 96px !important; min-width: 0 !important; }
|
||||
/* Measured parts take the place the breakpoints give them: without 그리기모드 the fields start 4px in (as < 1180),
|
||||
without the property block More sits at the end of the object area (as < 1080). */
|
||||
.hm-sw-header__object-area[data-squeezed~="drawingMode"]:not([data-configured]) > .hm-sw-header__fields { padding-left: 4px; }
|
||||
.hm-sw-header__object-area[data-squeezed~="properties"] > .hm-sw-header__more { margin-left: auto; margin-right: 4px; }
|
||||
|
||||
/* Logo (home) menu layer (SWHeader homeMenu, 2026-10-19). Top of the header, left / max-width measured from the
|
||||
object area (−2px) to the window area. Above the property bar anchor (2), under the dropdowns (30) and the
|
||||
property window (40). The logo, the file name and the window area stay visible beside it. */
|
||||
.hm-sw-header__home-menu { position: absolute; top: 0; z-index: 20; }
|
||||
|
||||
/* Home On (Figma 662:67267 btn_home + border-top / border-bottom, 2026-10-19): only while the logo menu is open.
|
||||
The logo keeps the yellow hover border (the Home On asset draws the same 1px inner gradient border) and the header
|
||||
gets the 2px #5F4B0F lines across its full width. Figma layer order: border-bottom under the menu (20) over the
|
||||
file name / window area, border-top over the menu, the logo over both. Lines are overlays: no size or position
|
||||
changes, and closing the menu removes them. SW normal mode only (SWViewerHeader has no logo menu). */
|
||||
.hm-sw-header[data-home-menu-open] .hm-sw-header__home-bg-hover { opacity: 1; }
|
||||
.hm-sw-header[data-home-menu-open] > .hm-sw-header__bar > .hm-sw-header__home { z-index: 22; }
|
||||
.hm-sw-header[data-home-menu-open]::before,
|
||||
.hm-sw-header[data-home-menu-open]::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: var(--hm-sw-header-home-on-line-width);
|
||||
background: var(--hm-sw-header-home-on-line-color);
|
||||
pointer-events: none;
|
||||
}
|
||||
.hm-sw-header[data-home-menu-open]::before { top: 0; z-index: 21; }
|
||||
.hm-sw-header[data-home-menu-open]::after { top: calc(var(--hm-sw-header-bar-height) - var(--hm-sw-header-home-on-line-width)); z-index: 1; }
|
||||
Reference in new issue
Block a user