Files
HMDesign/packages/sw/src/theme/sw-home-menu.css
T
shkim4 1472e51f47 feat(sw): integrate home menu into SWHeader (Task A + B)
Combine Task A (e8409ef, SW 0.2.0 integrated improvement) with Task B
(396539d, Figma-based SWHomeMenu / SWHomeMenuSection / SWHomeMenuItem /
SWRecentFiles). Task B's 84 new files are taken unchanged except for the
public-import Storybook update and joining the popup Escape stack.

- Export the home menu from @hm-design/sw
- SWHeader homeMenu / homeMenuOpen / defaultHomeMenuOpen /
  onHomeMenuOpenChange: hidden by default, the logo toggles it (onHomeClick
  is not called while homeMenu is set), placed from the measured header,
  closes with / closes the document and field dropdowns
- Logo aria-expanded / aria-controls; menu layer CSS (z-index 20)
- AI catalog / patterns / design rules, example G, README, usage guide
- Storybook SW/Home Menu uses @hm-design/sw; integration story

Verified: SW typecheck, tsc -b, SW build, Storybook build, AI docs 22/22,
28/28 existing SW shots pixel-identical, regression 96 PASS / 0 FAIL,
home menu checks 22/22. Not run: tarball consumer install.
2026-10-19 15:39:47 +09:00

336 lines
13 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* @hm-design/sw — Home menu (Figma rj6wpsfk24lOWvWiVRAANP 26:10591 "헤더/꾸러미 ver2/home on", tiles 26:11355 …).
Scoped to .hm-sw-home-menu; reads the shared SW tokens of .hm-sw-header / .hm-sw-theme (font, text outline,
focus). New values are Figma values (Plugin API, 2026-10-19), never global selectors. */
.hm-sw-home-menu {
/* Section surface (Frame 2409–2412; Frame 2408 has slightly different stops): bottom → top + edge shade. */
--hm-sw-home-menu-section-background:
linear-gradient(0deg, #16120a 0%, rgba(22, 18, 10, 0) 54.458%, #16120a 100%),
linear-gradient(0deg, #18150e 28.102%, #262015 41.084%, #332b1c 58.06%, #38301f 81.027%, #18150e 100%);
--hm-sw-home-menu-section-border-color: #081813;
--hm-sw-home-menu-section-inner-border-color: #20190e;
/* Tile group g_* : fill bottom → top, 1px stroke top → bottom, drop shadow 0 2 r4 60%. */
--hm-sw-home-menu-group-background: linear-gradient(0deg, #19160e 2%, #38301f 43.678%, #463c29 67.668%, #2f281a 100%);
--hm-sw-home-menu-group-border: linear-gradient(180deg, #886d35 0%, #423625 8.846%, #f3dba8 26.169%, #0e0b06 83.792%, #574b30 100%);
--hm-sw-home-menu-group-shadow: 0 2px 4px rgba(0, 0, 0, 0.6);
/* Tile divider 1 x 44 (same gradient as the group stroke) with -1 0 r2 black shadow. */
--hm-sw-home-menu-divider: var(--hm-sw-home-menu-group-border);
--hm-sw-home-menu-divider-shadow: -1px 0 2px #000;
/* Tile states: Variant2 / Variant3 stroke (INSIDE 1px, top → bottom), icon and label color. */
--hm-sw-home-menu-item-hover-border: linear-gradient(180deg, #da6813 8.5%, #ffbb89 37.9%, #e5690d 71.9%, #ae3607 92.8%);
--hm-sw-home-menu-item-color: var(--hm-sw-header-text-color);
--hm-sw-home-menu-item-accent-color: #ff5c00;
--hm-sw-home-menu-icon-color: #b6b4af;
/* Title badge (tit_* Union, 9-slice of the Figma SVG) */
--hm-sw-home-menu-title-color: #000;
/* 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%);
/* Optional sub panel (Figma 최근파일 662:67331 / 파일출력 2뎁스 662:67471). */
--hm-sw-recent-files-width: 354px;
--hm-sw-recent-files-max-height: 750px;
--hm-sw-recent-files-background: #27241d;
--hm-sw-recent-files-border-color: #da6813;
--hm-sw-recent-files-path-color: #d4cbbd;
--hm-sw-recent-files-row-hover-background: var(--hm-sw-header-layer-row-hover-background);
--hm-sw-recent-files-row-hover-color: var(--hm-sw-header-layer-row-hover-color);
--hm-sw-recent-files-preview-width: 310px;
--hm-sw-recent-files-preview-background: #62533d;
position: relative;
isolation: isolate;
width: max-content;
max-width: 100%;
}
.hm-sw-home-menu__sections {
display: flex;
align-items: flex-start;
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;
}
/* 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%; }
.hm-sw-home-menu__section {
position: relative;
display: flex;
flex: 0 0 auto;
flex-direction: column;
align-items: center;
height: 75px;
/* Figma: content 5px from the top and 10px from the sides, the 1px stroke included. */
padding: 4px 9px 0;
border: 1px solid var(--hm-sw-home-menu-section-border-color);
border-radius: 0 0 3px 3px;
background: var(--hm-sw-home-menu-section-background);
}
/* Frame 2412 (last): 261px, 11px left. Frame 2408 keeps 340px with its group centered. */
.hm-sw-home-menu__section:last-child { padding-left: 10px; }
/* Inner 1px #20190E (Rectangle 6977 / border, inset 1px). */
.hm-sw-home-menu__section::before {
content: "";
position: absolute;
inset: 0;
border: 1px solid var(--hm-sw-home-menu-section-inner-border-color);
border-radius: 0 0 2px 2px;
pointer-events: none;
}
/* 26:10591 Rectangle 6991–6995: 30px strip from y 47 behind the section, 2px visible under it. */
.hm-sw-home-menu[data-accent="sections"] .hm-sw-home-menu__section::after {
content: "";
position: absolute;
z-index: -1;
top: 46px;
right: -2px;
bottom: -3px;
left: -2px;
border-radius: 0 0 3px 3px;
background: var(--hm-sw-home-menu-accent-strip);
pointer-events: none;
}
.hm-sw-home-menu[data-accent="sections"] .hm-sw-home-menu__section:first-child::after { left: -3px; }
.hm-sw-home-menu[data-accent="sections"] .hm-sw-home-menu__section:last-child::after { right: -3px; }
/* 662:67267 Rectangle 6991: 1305 x 30 from y 47, 2px INSIDE gradient stroke. */
.hm-sw-home-menu[data-accent="outline"]::after {
content: "";
position: absolute;
z-index: -1;
top: 47px;
right: 0;
left: 0;
height: 30px;
padding: 2px;
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);
-webkit-mask-composite: xor;
mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
pointer-events: none;
}
/* tit_* : text + 23px each side; the Figma Union SVG (132 x 27 incl. its -2 r4 shadow) is 9-sliced. */
.hm-sw-home-menu__title {
position: relative;
z-index: 1;
display: flex;
flex: 0 0 auto;
align-items: center;
justify-content: center;
height: 19px;
margin-bottom: -1px;
padding: 1px 23px 0;
color: var(--hm-sw-home-menu-title-color);
font-size: var(--hm-sw-header-label-size);
font-weight: 400;
line-height: 14px;
letter-spacing: 0.02em;
white-space: nowrap;
}
.hm-sw-home-menu__title::before {
content: "";
position: absolute;
z-index: -1;
inset: -6px -4px -2px;
border-style: solid;
border-width: 0 30px;
border-image: var(--hm-sw-home-menu-title-art) 0 30 fill / 0 30px / 0 stretch;
pointer-events: none;
}
.hm-sw-home-menu__group {
position: relative;
display: flex;
flex: 0 0 auto;
height: 46px;
border-radius: 3px;
background: var(--hm-sw-home-menu-group-background);
box-shadow: var(--hm-sw-home-menu-group-shadow);
}
/* INSIDE stroke drawn over the edge: tiles keep their full 80 x 46 like Figma. */
.hm-sw-home-menu__group::before {
content: "";
position: absolute;
inset: 0;
padding: 1px;
border-radius: inherit;
background: var(--hm-sw-home-menu-group-border);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
pointer-events: none;
}
.hm-sw-home-menu__item {
position: relative;
flex: 0 0 80px;
width: 80px;
height: 46px;
color: var(--hm-sw-home-menu-item-color);
}
.hm-sw-home-menu__item:first-child { border-radius: 3px 0 0 3px; }
.hm-sw-home-menu__item:last-child { border-radius: 0 3px 3px 0; }
.hm-sw-home-menu__item:only-child { border-radius: 3px; }
/* Divider at the right edge of every tile but the last. */
.hm-sw-home-menu__item:not(:last-child)::before {
content: "";
position: absolute;
z-index: 2;
top: 1px;
right: -1px;
width: 1px;
height: 44px;
background: var(--hm-sw-home-menu-divider);
box-shadow: var(--hm-sw-home-menu-divider-shadow);
pointer-events: none;
}
/* Variant2 / Variant3 stroke. */
.hm-sw-home-menu__item::after {
content: "";
position: absolute;
z-index: 3;
inset: 0;
padding: 1px;
border-radius: inherit;
background: var(--hm-sw-home-menu-item-hover-border);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
opacity: 0;
pointer-events: none;
}
/* 18 x 18 icon slot at (31, 6); larger art is centered on it and may overflow (Figma assets carry shadows). */
.hm-sw-home-menu__icon {
position: absolute;
top: 6px;
left: 31px;
display: grid;
place-items: center;
width: 18px;
height: 18px;
color: var(--hm-sw-home-menu-icon-color);
}
.hm-sw-home-menu__icon > * { flex: none; max-width: none; }
.hm-sw-home-menu__icon > :is(svg, img) { display: block; }
.hm-sw-home-menu__icon--hover { visibility: hidden; }
.hm-sw-home-menu__label {
position: absolute;
top: 25px;
left: 50%;
max-width: 76px;
height: 16px;
padding: 0 var(--hm-sw-header-text-outline-room);
overflow: hidden;
transform: translateX(-50%);
font-size: var(--hm-sw-header-font-size);
font-weight: 700;
line-height: 16px;
letter-spacing: 0.04em;
white-space: nowrap;
text-overflow: ellipsis;
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"]) {
--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; }
/* 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); }
/* Frame stroke: 1px #DA6813 left / right / bottom over the list edge (joins the menu's outline accent). */
.hm-sw-recent-files::after {
content: "";
position: absolute;
z-index: 2;
inset: 0;
border: 1px solid var(--hm-sw-recent-files-border-color);
border-top: 0;
border-radius: 0 0 3px 3px;
pointer-events: none;
}
.hm-sw-recent-files__list {
box-sizing: content-box; /* max-height = rows (15 x 50 = Figma 750) */
max-height: var(--hm-sw-recent-files-max-height);
overflow-x: hidden;
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-width: thin;
border: 1px solid var(--hm-sw-recent-files-background);
border-radius: 0 0 4px 4px;
background: var(--hm-sw-recent-files-background);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25), inset 0 4px 8px rgba(0, 0, 0, 0.4);
}
.hm-sw-recent-files__row {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
height: 50px;
padding: 1px 8px;
text-align: left;
}
/* Rows without a badge keep the text column at 45px (Figma px 45). */
.hm-sw-recent-files__row:not(:has(> .hm-sw-recent-files__badge)) { padding-left: 45px; }
.hm-sw-recent-files__badge { display: grid; flex: 0 0 29px; place-items: center; width: 29px; height: 28px; }
.hm-sw-recent-files__badge > :is(svg, img) { display: block; max-width: none; }
.hm-sw-recent-files__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; max-width: 301px; }
.hm-sw-recent-files__name,
.hm-sw-recent-files__path {
display: block;
overflow: hidden;
overflow-clip-margin: var(--hm-sw-header-text-outline-room);
white-space: nowrap;
text-overflow: ellipsis;
letter-spacing: 0.04em;
}
.hm-sw-recent-files__name { color: var(--hm-sw-header-text-color); font-size: var(--hm-sw-header-font-size); font-weight: 700; line-height: 16px; text-shadow: var(--hm-sw-header-text-outline); }
.hm-sw-recent-files__path { color: var(--hm-sw-recent-files-path-color); font-size: var(--hm-sw-header-label-size); line-height: 14px; opacity: 0.6; text-shadow: var(--hm-sw-header-label-outline); }
.hm-sw-recent-files__row:is(:hover, [data-hovered="true"]):not(:disabled) { background: var(--hm-sw-recent-files-row-hover-background); }
.hm-sw-recent-files__row:is(:hover, [data-hovered="true"]):not(:disabled) .hm-sw-recent-files__name { color: var(--hm-sw-recent-files-row-hover-color); }
.hm-sw-recent-files__empty { padding: 16px 45px; color: var(--hm-sw-recent-files-path-color); font-size: var(--hm-sw-header-label-size); opacity: 0.6; }
/* 2-depth preview beside the row (1px gap), top aligned 1px under the row top. */
.hm-sw-recent-files__preview {
position: absolute;
z-index: 3;
left: calc(100% + 1px);
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
width: var(--hm-sw-recent-files-preview-width);
padding: 3px 0 0; /* + 1px border = Figma py 4; 270px total with the 243px body */
border: 1px solid var(--hm-sw-recent-files-preview-background);
border-left: 0;
border-radius: 0 3px 4px 0;
background: var(--hm-sw-recent-files-preview-background);
box-shadow: inset 2px 0 2.5px rgba(0, 0, 0, 0.5);
filter: drop-shadow(0 2px 1px rgba(0, 0, 0, 0.5));
pointer-events: none;
}
.hm-sw-recent-files__preview-title {
width: 294px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
color: var(--hm-sw-recent-files-row-hover-color);
font-size: var(--hm-sw-header-font-size);
line-height: 18px;
letter-spacing: 0.02em;
}
.hm-sw-recent-files__preview-body { position: relative; width: 100%; height: 243px; overflow: hidden; border-radius: 0 0 4px 0; }
.hm-sw-recent-files__preview-body > :is(img, svg, canvas) { display: block; width: 100%; height: 100%; object-fit: cover; }