feat(sw): viewer layer eye-icon rule, header hover, trailing strip and file name width
User-requested SW Viewer changes (2026-10-21); no new Props, public .d.ts unchanged. - Layer popup visibility: AI docs (VIEWER §4.1, catalog, design rules, patterns, AI_GUIDE) require the Eye / EyeOff icon button, never a switch; example H now renders a real layer list with eye buttons; Storybook eye button gets the pointer. - Viewer header hover: text and icon #FFC600, the #266651 hover face removed; size and position unchanged. Status stays display only. - Trailing strip: status, the trailing icon button (info / license) and SWHeader minimize / close are full-height (48px) segments on the window-area face, no gap, top and bottom on the object surface border; no line around the license button. - File name: the measured steps use the file-name basis (header width), not the text width, so a short and a long name give the same Open / file-name widths. - File open icon: the black icon outline of every viewer icon (SWViewerIcon), no frame.
This commit is contained in:
1 parent
32e46c32be
commit
caf4c32592
14 files changed
+109
-26
No files matched your search
@@ -410,7 +410,7 @@ export const SWViewerHeader = forwardRef<HTMLElement, SWViewerHeaderProps>(funct
|
||||
<SWToolButton appearance="document" className="hm-sw-viewer-header__open" data-document-open="" data-icon-only={iconOnly ? "" : undefined}
|
||||
aria-label={iconOnly ? label : undefined} title={iconOnly ? label : undefined}
|
||||
onClick={() => { onDocumentOpen(); command({ id: "open", itemId: "document" }) }}>
|
||||
<span className="hm-sw-viewer-header__open-icon" aria-hidden="true"><FolderIcon /></span>
|
||||
<span className="hm-sw-viewer-header__open-icon" aria-hidden="true"><SWViewerIcon><FolderIcon /></SWViewerIcon></span>
|
||||
{!iconOnly && <span className="hm-sw-viewer-header__open-label">{label}</span>}
|
||||
</SWToolButton>
|
||||
)
|
||||
|
||||
@@ -192,7 +192,8 @@ button.hm-sw-viewer-header__brand { text-align: left; }
|
||||
box-shadow: none;
|
||||
text-shadow: none;
|
||||
}
|
||||
.hm-sw-viewer-header__open-icon > svg { width: var(--hm-sw-viewer-icon-size); height: var(--hm-sw-viewer-icon-size); }
|
||||
/* The folder icon carries the black icon outline of every viewer header icon (SWViewerIcon, 2026-10-21 user request). */
|
||||
.hm-sw-viewer-header__open-icon > :is(svg, .hm-sw-viewer-icon) { width: var(--hm-sw-viewer-icon-size); height: var(--hm-sw-viewer-icon-size); }
|
||||
.hm-sw-viewer-header > .hm-sw-header__document[data-tool] + .hm-sw-viewer-header__document { padding-left: 0; }
|
||||
.hm-sw-viewer-header__document[data-list] > .hm-sw-header__document { flex: 1 1 auto; min-width: 0; }
|
||||
/* No file open button before it: the file name starts 10px after the slanted logo edge (at mid height), as in
|
||||
@@ -213,8 +214,11 @@ button.hm-sw-viewer-header__brand { text-align: left; }
|
||||
/* 2026-10-21 user request: viewer file rows show the name only (no icon, no icon gap); rows, hover and the current
|
||||
file color are unchanged. The SWHeader document list keeps its icons. */
|
||||
.hm-sw-viewer-header__document[data-list] .hm-sw-header__document-icon { display: none; }
|
||||
/* SWHeader minimize / close (SWHeaderWindowControls) at the end of `trailing`: right edge as in SWHeader, no inset. */
|
||||
.hm-sw-viewer-header__object:has(> .hm-sw-viewer-header__actions > .hm-sw-header__window-buttons:last-child) { padding-right: 0; }
|
||||
/* Trailing strip (2026-10-21 user request): status, the trailing icon buttons (e.g. 정보 / license) and SWHeader minimize /
|
||||
close (SWHeaderWindowControls) are separate full-height segments in one continuous strip at the right end, as the
|
||||
SWHeader window area (print · K | window move | minimize · close): its face and 1px border color, a 1px line before
|
||||
a segment (none around the license button), no gap, top and bottom on the object surface border. The strip ends at the object surface edge, as in SWHeader. Status stays display only. */
|
||||
.hm-sw-viewer-header__object:has(> .hm-sw-viewer-header__actions > :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons):last-child) { padding-right: 0; }
|
||||
/* Viewer header dropdown colors (2026-10-21): the menus of the header — menu buttons, More and their submenus — use the
|
||||
colors of the SWHeader `...` menu (sw.css .hm-sw-header__more-menu): its face and shadow (fixed values there), the
|
||||
object border token, the header text, secondary text at 80% (as its values) and the white 8% row hover with the text
|
||||
@@ -234,9 +238,10 @@ button.hm-sw-viewer-header__brand { text-align: left; }
|
||||
.hm-sw-viewer-header .hm-sw-viewer-menu .hm-sw-viewer-menu__separator { background: var(--hm-sw-header-document-menu-divider-color); }
|
||||
|
||||
/* Measured responsive steps (2026-10-21, SWViewerHeader measureRoom): set only inside one layout pass, never painted.
|
||||
Every part at its natural width: the file name at its text width up to its usual flex basis, the object surface
|
||||
neither stretched nor shrunk, the trailing area without its auto margin. */
|
||||
.hm-sw-viewer-header[data-measuring] .hm-sw-viewer-header__document { flex: 0 0 auto; width: max-content; max-width: clamp(140px, 25cqw, 360px); }
|
||||
Every part at its natural width: the file name at its usual flex basis (2026-10-21 user request: the header width
|
||||
decides it, never the length of the name, so a short and a long name give the same steps, Open label and widths),
|
||||
the object surface neither stretched nor shrunk, the trailing area without its auto margin. */
|
||||
.hm-sw-viewer-header[data-measuring] .hm-sw-viewer-header__document { flex: 0 0 clamp(140px, 25cqw, 360px); }
|
||||
.hm-sw-viewer-header[data-measuring] .hm-sw-viewer-header__object { flex: 0 0 auto; }
|
||||
.hm-sw-viewer-header[data-measuring] .hm-sw-viewer-header__actions { margin-left: 0; }
|
||||
/* While the logo menu or the document list is open, the header takes the viewer dropdown layer (SWViewerMenu, 60) so
|
||||
@@ -279,7 +284,8 @@ button.hm-sw-viewer-header__brand { text-align: left; }
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
/* Buttons, menu buttons and toggles: transparent, #266651 hover, #FFC600 pressed / open / on (no selected box). */
|
||||
/* Buttons, menu buttons and toggles: transparent; Hover, pressed / open / on = text and icon #FFC600 (no face, no
|
||||
selected box; 2026-10-21 user request: the former #266651 hover face is removed, size and position never change). */
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -299,7 +305,7 @@ button.hm-sw-viewer-header__brand { text-align: left; }
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__button[data-icon-only] { min-width: var(--hm-sw-viewer-button-height); padding: 0 8px; }
|
||||
/* Always-icon buttons (info, More): the reference 32 x 40 icon button. */
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__button[data-icon-only="always"] { min-width: 32px; width: 32px; height: var(--hm-sw-viewer-control-height); padding: 0 8px; }
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__button:hover:not(:disabled) { background: var(--hm-sw-viewer-hover); }
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__button:hover:not(:disabled) { color: var(--hm-sw-viewer-accent); }
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__button:active:not(:disabled),
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__button:is([data-state="open"], [data-state="on"]) { color: var(--hm-sw-viewer-accent); }
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__button:is([data-state="open"], [data-state="on"]):not(:hover) { background: transparent; }
|
||||
@@ -329,7 +335,7 @@ button.hm-sw-viewer-header__brand { text-align: left; }
|
||||
line-height: 1.4;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__tab:hover:not(:disabled) { background: var(--hm-sw-viewer-hover); }
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__tab:hover:not(:disabled) { color: var(--hm-sw-viewer-accent); }
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__tab[data-state="active"] { color: var(--hm-sw-viewer-accent); }
|
||||
.hm-sw-viewer-header__count { font-size: var(--hm-sw-viewer-label-size); font-weight: 400; font-variant-numeric: tabular-nums; }
|
||||
|
||||
@@ -392,12 +398,37 @@ button.hm-sw-viewer-header__brand { text-align: left; }
|
||||
@keyframes hm-sw-viewer-spin { to { transform: rotate(360deg); } }
|
||||
@media (prefers-reduced-motion: reduce) { .hm-sw-viewer-status__spin { animation: none; } }
|
||||
|
||||
/* Trailing strip segments (see the strip note above the dropdown colors). After the button rules so the strip
|
||||
height wins over the 40px icon button. */
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__actions > :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons) {
|
||||
align-self: stretch;
|
||||
height: auto;
|
||||
border-radius: 0;
|
||||
background: var(--hm-sw-header-document-background);
|
||||
/* Only the 1px line before a segment: top, bottom and right are the object surface border itself, so every segment
|
||||
(and the license button between them) has the same top and bottom edge (2026-10-21; no doubled lines). */
|
||||
box-shadow: inset 1px 0 0 var(--hm-sw-header-document-border-color);
|
||||
}
|
||||
.hm-sw-viewer-header__actions > :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons) + :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons) { margin-left: calc(-1 * var(--hm-sw-viewer-gap)); }
|
||||
.hm-sw-viewer-header__actions > .hm-sw-viewer-status { padding-inline: 12px; }
|
||||
/* Icon buttons in the strip (e.g. 정보 / license, 2026-10-21 final): 32px wide, full strip height, the strip face but no
|
||||
line around the button in any state (no border, no side / top / bottom lines). Keyboard focus keeps its outline. */
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__actions > .hm-sw-viewer-header__button {
|
||||
border-color: transparent;
|
||||
/* No line at all on the button (2026-10-21 final): same 48px box and edges as minimize / close, the strip face only. */
|
||||
box-shadow: none;
|
||||
}
|
||||
/* No line around the license / info button: the window buttons right after it drop their line before it. */
|
||||
.hm-sw-viewer-header .hm-sw-viewer-header__actions > .hm-sw-viewer-header__button + .hm-sw-header__window-buttons { box-shadow: none; }
|
||||
|
||||
/* Narrow header (reference breakpoints, measured on the header itself). */
|
||||
@container hm-sw-viewer (max-width: 1179.98px) {
|
||||
.hm-sw-viewer-header__object { gap: 2px; padding-inline: 2px; }
|
||||
.hm-sw-viewer-header__group { gap: 2px; padding-inline: 2px; }
|
||||
.hm-sw-viewer-header__actions { padding-left: 2px; gap: 2px; }
|
||||
.hm-sw-viewer-status { padding-inline: 2px; }
|
||||
.hm-sw-viewer-header__actions > .hm-sw-viewer-status { padding-inline: 8px; }
|
||||
.hm-sw-viewer-header__actions > :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons) + :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons) { margin-left: -2px; }
|
||||
}
|
||||
@container hm-sw-viewer (max-width: 559.98px) {
|
||||
.hm-sw-viewer-header__document { padding-right: 8px; }
|
||||
|
||||
Reference in new issue
Block a user