feat(sw): refine headers, status label, popups and AI guide rules
Deploy Storybook / deploy (push) Successful in 1m10s
Deploy Storybook / deploy (push) Successful in 1m10s
- SW Header: the five field previews hide and return together in one measured step; from 760 to 1920px the groups from 레이어 to 치수스타일 share the room left before 속성보기, above 1920px they keep the 1920 widths (controls bars and < 760px unchanged) - SW Viewer Header Model / Layout: long names ellipsize in equal buttons (minmax(0, 1fr), name counted at --hm-sw-viewer-tab-name-basis) so they never change the box or the measured steps; green outer outline and its tokens removed; 378px / 42px, text-shadow and state unchanged - SWViewerStatus: the label keeps the width of its widest real state text (idle keeps its icon slot), so a state change never moves the header; with too little room it ellipsizes after the file name gives way - Popups: body inset shadow removed, title SVG drop shadow removed, viewer panel title icons use --hm-sw-viewer-panel-icon-color (#c7bda9) - Storybook: SW/Viewer › Model / Layout story removed - AI guide (docs/ai + package copies): design-only changes for every component, content limits for Submodule consumers (Header excluded), Submodule usage rules; VIEWER / DESIGN_RULES synced - viewer.browser.mjs: explicit 1920 / 1440 labels and approved 1280 icon-only expectations
This commit is contained in:
1 parent
325ec25e37
commit
db03e155dd
19 files changed
+190
-119
No files matched your search
@@ -1,5 +1,5 @@
|
||||
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="308" height="38" viewBox="0 0 308 38" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Union" filter="url(#filter0_d_0_140)">
|
||||
<g id="Union">
|
||||
<mask id="path-1-inside-1_0_140" fill="white">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M252 6H0V33C0 34.6569 1.34314 36 3 36H252H260H270.947C276.28 36 280.369 29.2601 284.685 22.1464C289.05 14.9502 293.648 7.37149 300 6H260H252Z"/>
|
||||
</mask>
|
||||
@@ -7,16 +7,6 @@
|
||||
<path d="M0 6V5H-1V6H0ZM284.685 22.1464L285.54 22.665V22.665L284.685 22.1464ZM300 6L300.211 6.97748L300 5V6ZM0 6V7H252V6V5H0V6ZM0 33H1V6H0H-1V33H0ZM3 36V35C1.89543 35 1 34.1046 1 33H0H-1C-1 35.2091 0.790855 37 3 37V36ZM252 36V35H3V36V37H252V36ZM252 36V37H260V36V35H252V36ZM260 36V37H270.947V36V35H260V36ZM270.947 36V37C274.062 37 276.672 35.0311 278.953 32.3953C281.248 29.7442 283.395 26.2 285.54 22.665L284.685 22.1464L283.83 21.6277C281.658 25.2064 279.603 28.5891 277.441 31.0864C275.266 33.5989 273.165 35 270.947 35V36ZM284.685 22.1464L285.54 22.665C287.732 19.051 289.933 15.4276 292.363 12.5318C294.799 9.62962 297.357 7.59367 300.211 6.97748L300 6L299.789 5.02252C296.291 5.77782 293.374 8.21697 290.831 11.246C288.284 14.2816 286.003 18.0456 283.83 21.6277L284.685 22.1464ZM300 6V5H260V6V7H300V6ZM260 6V5H252V6V7H260V6Z" fill="url(#paint0_linear_0_140)" mask="url(#path-1-inside-1_0_140)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_d_0_140" x="0" y="0" width="308" height="38" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dx="4" dy="-2"/>
|
||||
<feGaussianBlur stdDeviation="2"/>
|
||||
<feComposite in2="hardAlpha" operator="out"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.4 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_0_140"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_0_140" result="shape"/>
|
||||
</filter>
|
||||
<linearGradient id="paint0_linear_0_140" x1="150" y1="6" x2="150" y2="36" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#493927"/>
|
||||
<stop offset="0.17" stop-color="#6F5739"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.9 KiB |
@@ -1,5 +1,5 @@
|
||||
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="308" height="38" viewBox="0 0 308 38" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Union" filter="url(#filter0_d_0_167)">
|
||||
<g id="Union">
|
||||
<mask id="path-1-inside-1_0_167" fill="white">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M252 6H0V33C0 34.6569 1.34314 36 3 36H252H260H270.947C276.28 36 280.369 29.2601 284.685 22.1464C289.05 14.9502 293.648 7.37149 300 6H260H252Z"/>
|
||||
</mask>
|
||||
@@ -8,16 +8,6 @@
|
||||
<path d="M0 6V5H-1V6H0ZM284.685 22.1464L285.54 22.665V22.665L284.685 22.1464ZM300 6L300.211 6.97748L300 5V6ZM0 6V7H252V6V5H0V6ZM0 33H1V6H0H-1V33H0ZM3 36V35C1.89543 35 1 34.1046 1 33H0H-1C-1 35.2091 0.790855 37 3 37V36ZM252 36V35H3V36V37H252V36ZM252 36V37H260V36V35H252V36ZM260 36V37H270.947V36V35H260V36ZM270.947 36V37C274.062 37 276.672 35.0311 278.953 32.3953C281.248 29.7442 283.395 26.2 285.54 22.665L284.685 22.1464L283.83 21.6277C281.658 25.2064 279.603 28.5891 277.441 31.0864C275.266 33.5989 273.165 35 270.947 35V36ZM284.685 22.1464L285.54 22.665C287.732 19.051 289.933 15.4276 292.363 12.5318C294.799 9.62962 297.357 7.59367 300.211 6.97748L300 6L299.789 5.02252C296.291 5.77782 293.374 8.21697 290.831 11.246C288.284 14.2816 286.003 18.0456 283.83 21.6277L284.685 22.1464ZM300 6V5H260V6V7H300V6ZM260 6V5H252V6V7H260V6Z" fill="url(#paint1_linear_0_167)" mask="url(#path-1-inside-1_0_167)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_d_0_167" x="0" y="0" width="308" height="38" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dx="4" dy="-2"/>
|
||||
<feGaussianBlur stdDeviation="2"/>
|
||||
<feComposite in2="hardAlpha" operator="out"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.4 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_0_167"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_0_167" result="shape"/>
|
||||
</filter>
|
||||
<linearGradient id="paint0_linear_0_167" x1="161.151" y1="6" x2="161.151" y2="38.5" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#0F3025"/>
|
||||
<stop offset="0.34535" stop-color="#194335"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -46,8 +46,8 @@ const MORE_BELOW = 760
|
||||
/** File name width from 760px up: Figma 310px, smallest 96px (sw.css .hm-sw-header__document). */
|
||||
const DOCUMENT_MAX = 310
|
||||
const DOCUMENT_MIN = 96
|
||||
/** Field pictures that hide one at a time while the header lacks room (sw.css [data-compact]). */
|
||||
const COMPACT_LEVELS = 5
|
||||
/** Field pictures hide together, in one step, while the header lacks room (sw.css [data-compact], 2026-10-23). */
|
||||
const COMPACT_LEVELS = 1
|
||||
/** From this header width the Figma field boxes apply (sw.css "Responsive"). */
|
||||
const FIGMA_LAYOUT_FROM = 1800
|
||||
|
||||
@@ -304,9 +304,9 @@ export const SWHeader = forwardRef<HTMLElement, SWHeaderProps>(function SWHeader
|
||||
})
|
||||
|
||||
// 2026-10-22 (user request): from 760px to 1800px the space left decides, not fixed widths. While the object area lacks
|
||||
// room, the field pictures hide one at a time (data-compact 1-5: 치수 아이콘, 선 그림, 글꼴명, 색상 칩, 레이어 상태
|
||||
// 아이콘, sw.css), then the file name gives way (310 -> 96px), then the values ellipsize. With room to spare the
|
||||
// pictures stay and the file name keeps 310px.
|
||||
// room, the field pictures hide all at once (data-compact 1: 레이어 상태 아이콘, 색상 칩, 선 그림, 글꼴명, 치수 아이콘,
|
||||
// sw.css; 2026-10-23 user request, formerly one at a time), then the file name gives way (310 -> 96px), then the
|
||||
// values ellipsize. With room for all of them the pictures stay and the file name keeps 310px.
|
||||
// Measured on every render and again once web fonts finish loading (text widths change, the header size does not).
|
||||
const fitFieldsRef = useRef(() => {})
|
||||
fitFieldsRef.current = () => {
|
||||
|
||||
@@ -45,12 +45,24 @@ const StatusIcon = ({ state }: { state: SWViewerStatusState }) => state === "idl
|
||||
</svg>
|
||||
)
|
||||
|
||||
/** Load state of the viewer header (reference status: muted 11px text, icon; text hides below 560px). */
|
||||
/**
|
||||
* Load state of the viewer header (reference status: muted 11px text, icon; text hides below 560px). The label area is
|
||||
* as wide as the widest text it can show (2026-10-23): every state label (and a custom `label`) sits in the same grid
|
||||
* cell, the others hidden, so a state change never resizes it or moves the menus; with too little room it ellipsizes.
|
||||
* The icon slot is kept (empty) for `idle` for the same reason.
|
||||
*/
|
||||
export function SWViewerStatus({ state, label, detail, className, ...rest }: SWViewerStatusProps) {
|
||||
const text = label ?? statusLabel[state]
|
||||
const sizers = Array.from(new Set([text, ...Object.values(statusLabel)])).filter(candidate => candidate !== text)
|
||||
return (
|
||||
<div role="status" className={cx("hm-sw-viewer-status", className)} data-state={state} title={detail} {...rest}>
|
||||
{state !== "idle" && <span className="hm-sw-viewer-status__icon"><SWViewerIcon><StatusIcon state={state} /></SWViewerIcon></span>}
|
||||
<span className="hm-sw-viewer-status__label">{label ?? statusLabel[state]}</span>
|
||||
<span className="hm-sw-viewer-status__icon" data-empty={state === "idle" ? "" : undefined} aria-hidden={state === "idle" ? true : undefined}>
|
||||
{state !== "idle" && <SWViewerIcon><StatusIcon state={state} /></SWViewerIcon>}
|
||||
</span>
|
||||
<span className="hm-sw-viewer-status__label">
|
||||
<span className="hm-sw-viewer-status__text">{text}</span>
|
||||
{sizers.map(candidate => <span key={candidate} className="hm-sw-viewer-status__sizer" aria-hidden="true">{candidate}</span>)}
|
||||
</span>
|
||||
{detail && <span className="hm-sw-viewer-sr-only">: {detail}</span>}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -212,7 +212,8 @@ function Tabs({ item, onCommand }: { item: Extract<SWViewerHeaderItem, { type: "
|
||||
<button key={option.value} type="button" role="radio" aria-checked={selected} tabIndex={option.value === current ? 0 : -1}
|
||||
className="hm-sw-viewer-header__tab" data-state={selected ? "active" : undefined} title={option.title} disabled={item.disabled || option.disabled}
|
||||
onClick={() => { if (!selected) select(option.value) }}>
|
||||
{option.label}
|
||||
{/* The name shrinks first (ellipsis, sw-viewer.css); the full name stays the accessible name. */}
|
||||
<span className="hm-sw-viewer-header__tab-name">{option.label}</span>
|
||||
{option.count !== undefined && option.count > 0 && <span className="hm-sw-viewer-header__count">{option.count.toLocaleString()}</span>}
|
||||
</button>
|
||||
)
|
||||
|
||||
@@ -34,10 +34,7 @@
|
||||
--hm-sw-viewer-tabs-height: calc(var(--hm-sw-viewer-control-height) + 2px);
|
||||
--hm-sw-viewer-tabs-radius: 6px;
|
||||
--hm-sw-viewer-tabs-background: rgba(0, 0, 0, 0.8);
|
||||
/* Outline: a 1px line just outside the frame, blurred (Figma Rectangle 9333: stroke outside + layer blur 2). */
|
||||
--hm-sw-viewer-tabs-outline-color: #349f7f;
|
||||
--hm-sw-viewer-tabs-outline-blur: 1px;
|
||||
/* Extra glow around the frame: none in Figma (the blurred outline is the glow); set a color to add one. */
|
||||
/* Extra glow around the frame: none by default (the green outline was removed on 2026-10-23); set a color to add one. */
|
||||
--hm-sw-viewer-tabs-glow-color: transparent;
|
||||
--hm-sw-viewer-tabs-glow: 0 0 4px var(--hm-sw-viewer-tabs-glow-color);
|
||||
--hm-sw-viewer-tabs-shadow: inset 0 2.857px 2.857px rgba(0, 0, 0, 0.25);
|
||||
@@ -45,6 +42,9 @@
|
||||
--hm-sw-viewer-tab-radius: 5px;
|
||||
--hm-sw-viewer-tab-border-width: 1.428px;
|
||||
--hm-sw-viewer-tab-gap: 14px;
|
||||
/* Width a tab name counts for in the space calculation (2026-10-23): a longer name measures as this (about the
|
||||
default "Model"), so it never claims more room, takes free room when there is some and ellipsizes otherwise. */
|
||||
--hm-sw-viewer-tab-name-basis: 3em;
|
||||
--hm-sw-viewer-tab-background: #0e3d2f;
|
||||
--hm-sw-viewer-tab-gradient: linear-gradient(180deg, #081813 0%, #09271e 8.6884%, #0b3227 25.428%, #0e3d2f 51.252%, #0b3227 80.027%, #0a2b21 89.759%, #081813 100%);
|
||||
/* Selected (Model in Figma) / not selected (Layout in Figma). Borders are images (Figma gradient strokes, top to
|
||||
@@ -105,6 +105,9 @@
|
||||
--hm-sw-viewer-panel-badge-background: var(--hm-sw-property-table);
|
||||
--hm-sw-viewer-panel-overlay: rgba(0, 0, 0, 0.1);
|
||||
--hm-sw-viewer-panel-spacing: 12px;
|
||||
/* Title-bar icon buttons of viewer panels (collapse, `ghost` header actions; 2026-10-23). Popup-only: the header
|
||||
status text and switch captions keep --hm-sw-viewer-muted. SWPopup's own title icons are images. */
|
||||
--hm-sw-viewer-panel-icon-color: #c7bda9;
|
||||
}
|
||||
|
||||
.hm-sw-viewer-sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
|
||||
@@ -160,7 +163,9 @@ button.hm-sw-viewer-header__brand { text-align: left; }
|
||||
.hm-sw-viewer-header__document {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 1 clamp(140px, 25cqw, 360px);
|
||||
/* Very large shrink weight (2026-10-23): the file name gives way first, as before; the object (shrink 1) only once
|
||||
the file name is at its minimum (see .hm-sw-viewer-header__object). */
|
||||
flex: 0 1000000 clamp(140px, 25cqw, 360px);
|
||||
width: clamp(220px, 25cqw, 360px);
|
||||
min-width: 56px;
|
||||
height: calc(var(--hm-sw-viewer-height) - 2px);
|
||||
@@ -318,7 +323,10 @@ button.hm-sw-viewer-header__brand { text-align: left; }
|
||||
.hm-sw-viewer-header__object {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1 0 auto;
|
||||
/* Shrinkable (2026-10-23): the file name still gives way first (its huge shrink weight, down to its minimum); only
|
||||
when nothing is left after the measured steps does the object give way, so the status label ellipsizes instead of
|
||||
the header overflowing. The measurement (data-measuring) keeps flex: 0 0 auto. */
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
height: calc(var(--hm-sw-viewer-height) - 2px);
|
||||
gap: var(--hm-sw-viewer-gap);
|
||||
@@ -399,34 +407,25 @@ button.hm-sw-viewer-header__brand { text-align: left; }
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-auto-columns: 1fr;
|
||||
/* minmax(0, 1fr) (2026-10-23): equal columns that may shrink below their content, so a long name never pushes the
|
||||
box past its group (max 378px) or makes the buttons unequal; the name ellipsizes instead (below). */
|
||||
grid-auto-columns: minmax(0, 1fr);
|
||||
min-width: 0;
|
||||
align-items: stretch;
|
||||
gap: 1px;
|
||||
box-sizing: border-box;
|
||||
height: var(--hm-sw-viewer-tabs-height);
|
||||
/* The transparent 1px edge is the room of the blurred outline (it stays inside the box height); the padding is the
|
||||
black margin around the buttons, which fill the rest. 1.5px at the bottom (2026-10-23 user value): the outline
|
||||
blur covers part of a 1px bottom margin, while the inner shadow darkens the top, so 1px read as no room below. */
|
||||
/* The transparent 1px edge was the room of the outline (removed 2026-10-23, user request); it stays so the box and
|
||||
button sizes do not change. The padding is the black margin around the buttons, which fill the rest; 1.5px at the
|
||||
bottom (2026-10-23 user value). */
|
||||
padding: 1px 1px 1.5px 1px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: calc(var(--hm-sw-viewer-tabs-radius) + 1px);
|
||||
background: var(--hm-sw-viewer-tabs-background) padding-box;
|
||||
box-shadow: var(--hm-sw-viewer-tabs-glow);
|
||||
}
|
||||
/* The outline (blurred, on the frame edge) and the inner shadow lie over the buttons, as the last Figma layers do. */
|
||||
.hm-sw-viewer-header__tabs::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
/* The outer edge of the box (its border box, over the transparent 1px edge row): same size as the tabs box. */
|
||||
inset: -1px;
|
||||
border: 1px solid var(--hm-sw-viewer-tabs-outline-color);
|
||||
border-radius: inherit;
|
||||
filter: blur(var(--hm-sw-viewer-tabs-outline-blur));
|
||||
/* The blur may soften 1px past that edge, no further (2026-10-23 user decision). */
|
||||
clip-path: inset(-1px round calc(var(--hm-sw-viewer-tabs-radius) + 1px));
|
||||
pointer-events: none;
|
||||
}
|
||||
/* The inner shadow lies over the buttons, as the last Figma layer does. (The blurred green outline, ::before, was
|
||||
removed on 2026-10-23 at the user's request, with its outline color / blur tokens.) */
|
||||
.hm-sw-viewer-header__tabs::after { content: ""; position: absolute; z-index: 1; inset: 0; border-radius: var(--hm-sw-viewer-tabs-radius); box-shadow: var(--hm-sw-viewer-tabs-shadow); pointer-events: none; }
|
||||
/* A group holding only the tabs: the container is its face (no field face around it, as in Figma: the tabs sit on
|
||||
the header object surface). */
|
||||
@@ -474,7 +473,23 @@ button.hm-sw-viewer-header__brand { text-align: left; }
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__tab[data-state="active"] { --hm-sw-viewer-tab-border-face: var(--hm-sw-viewer-tab-active-border); color: var(--hm-sw-viewer-tab-active-text); }
|
||||
.hm-sw-viewer-header__count { font-size: var(--hm-sw-viewer-label-size); font-weight: 400; font-variant-numeric: tabular-nums; }
|
||||
/* In a tab the count has the name's size (Figma: 14px Regular) and color. */
|
||||
.hm-sw-viewer-header__tab .hm-sw-viewer-header__count { font-size: inherit; }
|
||||
.hm-sw-viewer-header__tab .hm-sw-viewer-header__count { flex: 0 0 auto; font-size: inherit; }
|
||||
/* Long names (2026-10-23 user decision): the name gives way first with an ellipsis, the count keeps its width; the
|
||||
outline may paint 2px outside the clipped name (as the file name). The name counts at most
|
||||
--hm-sw-viewer-tab-name-basis in the tabs' natural width (width + max-width: max-content: shorter names keep their own
|
||||
width), so a long name changes neither the tabs' width nor the measured steps of the other items; it grows (flex-grow,
|
||||
up to its text) only into room the box has anyway. */
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__tab { min-width: 0; }
|
||||
.hm-sw-viewer-header__tab-name {
|
||||
flex: 1 1 auto;
|
||||
width: var(--hm-sw-viewer-tab-name-basis);
|
||||
max-width: max-content;
|
||||
min-width: 0;
|
||||
overflow: clip;
|
||||
overflow-clip-margin: var(--hm-sw-header-text-outline-room);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Switch fields (2.5D, 어두운 배경): 11px muted caption above the switch. */
|
||||
.hm-sw-viewer-header__switch-field {
|
||||
@@ -533,7 +548,22 @@ button.hm-sw-viewer-header__brand { text-align: left; }
|
||||
font-weight: 400;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.hm-sw-viewer-status__icon { display: inline-flex; width: var(--hm-sw-viewer-icon-size); height: var(--hm-sw-viewer-icon-size); }
|
||||
.hm-sw-viewer-status__icon { display: inline-flex; flex: 0 0 auto; width: var(--hm-sw-viewer-icon-size); height: var(--hm-sw-viewer-icon-size); }
|
||||
/* Stable status width (2026-10-23): the empty idle icon slot keeps its place; the label is one grid cell holding the
|
||||
shown text and, hidden, every other text it can show (SWViewerStatus), so its width is the widest real candidate in
|
||||
the real font. With too little room (after the measured steps) it shrinks and the text ellipsizes; with room again
|
||||
the full text returns. */
|
||||
.hm-sw-viewer-status__icon[data-empty] { visibility: hidden; }
|
||||
.hm-sw-viewer-status__label { display: inline-grid; grid-template-columns: minmax(0, auto); flex: 0 1 auto; min-width: 0; }
|
||||
.hm-sw-viewer-status__label > * {
|
||||
grid-area: 1 / 1;
|
||||
min-width: 0;
|
||||
overflow: clip;
|
||||
overflow-clip-margin: var(--hm-sw-header-text-outline-room);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.hm-sw-viewer-status__sizer { visibility: hidden; }
|
||||
.hm-sw-viewer-status[data-state="error"] { color: var(--hm-sw-viewer-accent); }
|
||||
.hm-sw-viewer-status__spin { animation: hm-sw-viewer-spin 1s linear infinite; }
|
||||
@keyframes hm-sw-viewer-spin { to { transform: rotate(360deg); } }
|
||||
@@ -753,7 +783,7 @@ button.hm-sw-viewer-header__brand { text-align: left; }
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
color: var(--hm-sw-viewer-muted);
|
||||
color: var(--hm-sw-viewer-panel-icon-color);
|
||||
}
|
||||
.hm-sw-viewer-panel :is(.hm-sw-viewer-panel__icon-button, .hm-sw-viewer-button[data-variant="ghost"]):hover:not(:disabled) { background: transparent; color: var(--hm-sw-header-selected-color); }
|
||||
.hm-sw-viewer-panel :is(.hm-sw-viewer-panel__icon-button, .hm-sw-viewer-button[data-variant="ghost"]):focus-visible { outline: 2px solid var(--hm-sw-header-selected-color); outline-offset: -2px; }
|
||||
|
||||
@@ -1637,7 +1637,7 @@ div.hm-sw-header__menu-row { justify-content: space-between; gap: 8px; padding-l
|
||||
.hm-sw-property__close-hover { visibility: hidden; }
|
||||
.hm-sw-property__close:hover > .hm-sw-property__close-default { visibility: hidden; }
|
||||
.hm-sw-property__close:hover > .hm-sw-property__close-hover { visibility: visible; }
|
||||
.hm-sw-property__body { display: flex; flex-direction: column; gap: 8px; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 7px 7px 7px; box-shadow: inset 0 2px 2px rgba(255,255,255,.6); }
|
||||
.hm-sw-property__body { display: flex; flex-direction: column; gap: 8px; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 7px 7px 7px; }
|
||||
/* Popup scrollbar: the body and any scrolling area inside it (zero-specificity so content can still override). */
|
||||
.hm-sw-property__body, .hm-sw-property__body :where(*) { scrollbar-width: thin; scrollbar-color: var(--hm-sw-popup-scrollbar-thumb) var(--hm-sw-popup-scrollbar-track); }
|
||||
/* Popup toggle switch (Figma toggle_btn_new 633:75188 / 633:75902): one face for every switch inside an SW popup —
|
||||
@@ -1948,7 +1948,7 @@ div.hm-sw-header__menu-row { justify-content: space-between; gap: 8px; padding-l
|
||||
< 1800 the 그리기모드 text hides; fields take their content width and shrink with an ellipsis, each by its own width.
|
||||
< 1080 window move area 88 -> 24 (window 240 -> 176), field insets 6px.
|
||||
Measured (2026-10-22 user request, SWHeader data-compact): from 760px to 1800px, while the object area lacks
|
||||
room the field pictures hide one at a time — 치수 아이콘, 선 그림, 글꼴명, 색상 칩, 레이어 상태 아이콘 — then the file
|
||||
room the field pictures hide together — 레이어 상태 아이콘, 색상 칩, 선 그림, 글꼴명, 치수 아이콘 — then the file
|
||||
name gives way (310 -> 96px), then the values ellipsize. With room to spare nothing hides.
|
||||
<= 900 the 선스타일 field shows 선스타일 only (가중치 / 스케일 hide).
|
||||
Below 760px (phones, e.g. 390) the former tiers are unchanged: parts move into More (선/문자/치수 스타일, 그리기모드,
|
||||
@@ -1994,6 +1994,16 @@ div.hm-sw-header__menu-row { justify-content: space-between; gap: 8px; padding-l
|
||||
/* 1610 - 1301 + the tighter object area with titles, without 그리기모드 (891, measured) = 1200. */
|
||||
.hm-sw-header__document { flex-basis: clamp(96px, calc(100cqw - 1200px - var(--hm-sw-header-leading-width, 0px)), 310px); }
|
||||
}
|
||||
/* Free room (2026-10-23 user request): from 760px (속성보기 shown) up to a 1920px header the groups from 레이어 to
|
||||
치수스타일 share the room left before 속성보기 (each grows by the same amount from its own width, its field box with
|
||||
it), so no gap stays there. Wider headers keep the 1920 widths (234 / 192 / 284 / 164 / 164) and the extra room stays
|
||||
before 속성보기 (its auto margin). The standard bar only: a `controls` bar ([data-configured]) keeps its own layout.
|
||||
The measured steps read the natural widths (data-measuring sets flex-grow 0), so hiding is unchanged. */
|
||||
@container hm-sw-header (min-width: 760px) and (max-width: 1920px) {
|
||||
.hm-sw-header__fields:not([data-configured]) { flex-grow: 1; }
|
||||
.hm-sw-header__fields:not([data-configured]) > :is(.hm-sw-header__layer, .hm-sw-header__menu, .hm-sw-header__field),
|
||||
.hm-sw-header__fields:not([data-configured]) :is(.hm-sw-header__layer, .hm-sw-header__menu) > .hm-sw-header__field { flex-grow: 1; }
|
||||
}
|
||||
@container hm-sw-header (min-width: 760px) and (max-width: 1079.98px) {
|
||||
/* Values need the room (1024px, 2026-10-21 user request): insets 6px, every value part may shrink (ellipsis); the
|
||||
pictures hide by measurement (data-compact). */
|
||||
@@ -2151,13 +2161,11 @@ 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 pictures (SWHeader data-compact, 2026-10-22 user request): from 760px to 1800px the field pictures hide one at a
|
||||
time while the object area lacks room — 1 치수 아이콘, 2 선 그림, 3 글꼴명, 4 색상 칩, 5 레이어 상태 아이콘. */
|
||||
.hm-sw-header__fields:is([data-compact="1"], [data-compact="2"], [data-compact="3"], [data-compact="4"], [data-compact="5"]) .hm-sw-header__dimension-icon,
|
||||
.hm-sw-header__fields:is([data-compact="2"], [data-compact="3"], [data-compact="4"], [data-compact="5"]) .hm-sw-header__linetype,
|
||||
.hm-sw-header__fields:is([data-compact="3"], [data-compact="4"], [data-compact="5"]) .hm-sw-header__font-name,
|
||||
.hm-sw-header__fields:is([data-compact="4"], [data-compact="5"]) .hm-sw-header__chip,
|
||||
.hm-sw-header__fields[data-compact="5"] .hm-sw-header__field--layer .hm-sw-header__layer-icons { display: none; }
|
||||
/* Measured pictures (SWHeader data-compact): from 760px to 1800px, while the object area lacks room, the field pictures
|
||||
hide together in one step (2026-10-23 user request; formerly one at a time): 레이어 상태 아이콘, 색상 칩, 선 그림,
|
||||
글꼴명, 치수 아이콘. They come back together once all of them fit. */
|
||||
.hm-sw-header__fields[data-compact="1"] :is(.hm-sw-header__dimension-icon, .hm-sw-header__linetype, .hm-sw-header__font-name, .hm-sw-header__chip),
|
||||
.hm-sw-header__fields[data-compact="1"] .hm-sw-header__field--layer .hm-sw-header__layer-icons { display: none; }
|
||||
|
||||
/* 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
|
||||
|
||||
Reference in new issue
Block a user