Three things the unified Settings window was still missing next to v4's own, all found by looking at it next to v4 rather than in isolation: - The sidebar is a 52px icon rail now, expanding to a full list on hover/focus and overlaying the content instead of a splitPane's permanently-docked two-pane shape -- v4's own sidebar, not an approximation of it. Fixing this surfaced two real CSS bugs along the way: filterList's own min-width:220px silently defeated the collapse (clipping the search box to "Sear" instead of showing an icon), and .cx-filter-list's unset overflow-x (computed to auto once overflow-y was set) put a horizontal scrollbar under it. Centering the icon in the collapsed row needed the label's flex-basis AND the row's own gap to both go to zero -- an invisible label still claims its share of both otherwise, and the icon renders off-centre. - The modal now has a real height (v4's own 660px) rather than sizing to whichever section is showing, so switching between a short section (About) and a long one (Node packs) doesn't visibly resize the whole window. That exposed a THIRD latent bug: .cx-modal-body never had flex:1 1 auto, invisible until a modal had a real height to fill -- every prior modal shrink-wrapped its content, so head+body+foot always summed to exactly the card's height by accident. Fixed at the shared rule, not just for Settings. - About now shows what v4's does: commit and dirty state, a codename when the checkout has one, and the machine's real hardware/software facts (chip, memory, GPU or MPS, disk, OS, ComfyUI/Python/Torch/ attention-backend versions, hostname) -- a new core/sysinfo.py (ported from v4's own, individually guarded so a missing probe never takes the panel down) behind a new GET /funpack/api/system, injected into settings_window.js the same way every other network call here is. Also: a nav row's tone (the coloured icon chip) is now validated against its closed set the same way button.js already validates its own tone -- an unknown one used to render silently wrong instead of failing loudly.
152 lines
8.3 KiB
CSS
152 lines
8.3 KiB
CSS
.cx-input, .cx-textarea, .cx-select {
|
|
width: 100%;
|
|
border: var(--bw) solid var(--line); border-radius: var(--ctl-r);
|
|
background: var(--elev-2); color: var(--text);
|
|
font-family: var(--font-ui);
|
|
transition: border-color var(--dur-1) var(--ease-standard);
|
|
}
|
|
.cx-input-md { height: var(--ctl-h-lg); padding: 0 var(--ctl-pad-x-md); font-size: var(--fs-4); }
|
|
.cx-input-sm { height: var(--ctl-h-md); padding: 0 var(--ctl-pad-x-sm); font-size: var(--fs-5); }
|
|
.cx-input:hover:not(:disabled), .cx-textarea:hover:not(:disabled) { border-color: var(--line-hover); }
|
|
.cx-input:disabled, .cx-textarea:disabled, .cx-select:disabled { opacity: var(--disabled-opacity); }
|
|
.cx-input::placeholder, .cx-textarea::placeholder { color: var(--faint); }
|
|
|
|
.cx-number { font-variant-numeric: tabular-nums; }
|
|
.cx-number-wrap { display: inline-flex; align-items: center; gap: var(--sp-2); width: 100%; }
|
|
.cx-unit { font-size: var(--fs-6); color: var(--muted); }
|
|
|
|
.cx-stepper { display: inline-flex; align-items: stretch; gap: var(--sp-1); }
|
|
.cx-stepper .cx-number { text-align: center; }
|
|
.cx-step-btn {
|
|
width: var(--ctl-h-lg); height: var(--ctl-h-lg); flex: none;
|
|
border: var(--bw) solid var(--line); border-radius: var(--ctl-r);
|
|
background: var(--elev-2); color: var(--muted);
|
|
font-size: var(--fs-4); line-height: 1; cursor: pointer;
|
|
}
|
|
.cx-step-btn:hover { border-color: var(--line-hover); color: var(--text); }
|
|
|
|
.cx-textarea {
|
|
padding: var(--sp-3) var(--ctl-pad-x-md);
|
|
font-size: var(--fs-4); line-height: var(--lh-snug);
|
|
resize: vertical; min-height: var(--ctl-h-xl);
|
|
}
|
|
.cx-autogrow { resize: none; overflow: hidden; }
|
|
|
|
.cx-search { appearance: none; }
|
|
.cx-search::-webkit-search-cancel-button { filter: grayscale(1) opacity(.6); }
|
|
|
|
.cx-filter { display: flex; flex-direction: column; gap: var(--sp-3); min-width: 220px; }
|
|
.cx-filter-list {
|
|
display: flex; flex-direction: column; gap: 1px;
|
|
max-height: 240px; overflow-y: auto; overflow-x: hidden;
|
|
border: var(--bw) solid var(--line); border-radius: var(--r-3);
|
|
background: var(--elev-1); padding: var(--sp-1);
|
|
}
|
|
.cx-filter-row {
|
|
display: flex; align-items: center; gap: var(--sp-3);
|
|
padding: var(--sp-3) var(--sp-4); border: 0; border-radius: var(--r-2);
|
|
background: transparent; color: var(--text);
|
|
font-size: var(--fs-5); text-align: left; cursor: pointer; width: 100%;
|
|
}
|
|
.cx-filter-row:hover { background: var(--hover); }
|
|
.cx-filter-row.cx-on { background: var(--accent-soft); color: var(--accent-hi); }
|
|
.cx-filter-row.cx-on .cx-filter-label { font-weight: var(--fw-semibold); }
|
|
/* A column so a wrapping hint sits directly under its own label, both flush
|
|
to the same left edge, instead of floating as a baseline-aligned sibling
|
|
of the icon and the label. Centred on the icon: with the hint gone (a
|
|
nav row now, not a compact picker's two-line entry) top-aligning the two
|
|
just looks like a mistake. */
|
|
.cx-filter-text { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; justify-content: center; }
|
|
.cx-filter-label { display: block; }
|
|
.cx-filter-hint { display: block; font-size: var(--fs-7); color: var(--muted); line-height: var(--lh-snug); }
|
|
.cx-filter-empty { padding: var(--sp-5); font-size: var(--fs-6); color: var(--faint); text-align: center; }
|
|
|
|
/* A chip, not a bare glyph floating in the row -- the thing a nav list reads
|
|
as unfinished without. `tone` is a closed set of pre-approved looks
|
|
(accent/danger/warn/good/neutral), the same rule as everywhere else in the
|
|
kit; there is no path from item data to a raw colour. */
|
|
.cx-filter-icon {
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
width: 22px; height: 22px; flex: 0 0 auto; border-radius: var(--r-2);
|
|
background: var(--elev-3); color: var(--text); font-size: var(--fs-6); line-height: 1;
|
|
/* Optical, against the label's cap-height, not the row's own top edge. */
|
|
margin-block-start: 1px;
|
|
}
|
|
.cx-filter-icon-accent { background: var(--grad-accent); color: var(--on-accent); }
|
|
.cx-filter-icon-danger { background: linear-gradient(180deg, var(--danger), color-mix(in srgb, var(--danger) 65%, black)); color: #fff; }
|
|
.cx-filter-icon-warn { background: linear-gradient(180deg, var(--warn), color-mix(in srgb, var(--warn) 65%, black)); color: #fff; }
|
|
.cx-filter-icon-good { background: linear-gradient(180deg, var(--good), color-mix(in srgb, var(--good) 65%, black)); color: #fff; }
|
|
.cx-filter-icon-neutral { background: linear-gradient(180deg, var(--muted), color-mix(in srgb, var(--muted) 65%, black)); color: #fff; }
|
|
.cx-filter-row.cx-on .cx-filter-icon { box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent-hi) 50%, transparent); }
|
|
|
|
/* The Settings sidebar: a 52px icon rail by default, expanding to a full list
|
|
on hover or keyboard focus and OVERLAYING the content rather than pushing
|
|
it -- v4's own sidebar, and the reason nothing here uses splitPane's
|
|
resizable two-pane shape: this one is not meant to stay open. */
|
|
.cx-settings-body { position: relative; min-block-size: 0; block-size: 100%; }
|
|
.cx-settings-rail {
|
|
position: absolute; inset-block: 0; inset-inline-start: 0; z-index: 2;
|
|
/* .cx-filter's own min-width:220px is a floor for its NORMAL (small,
|
|
always-220px-ish) role; here it would keep this element from ever
|
|
actually reaching 52px regardless of inline-size below, since min-width
|
|
always wins over a smaller width -- the search box then rendered at its
|
|
un-shrunk content width and this clipped it to "Sear", not an icon. */
|
|
min-inline-size: 52px; inline-size: 52px; overflow: hidden;
|
|
background: var(--elev-2); border-inline-end: var(--bw) solid var(--line);
|
|
transition: inline-size var(--dur-2) var(--ease-standard),
|
|
box-shadow var(--dur-2) var(--ease-standard);
|
|
}
|
|
.cx-settings-rail:hover, .cx-settings-rail:focus-within {
|
|
inline-size: 218px;
|
|
box-shadow: 18px 0 40px -18px color-mix(in srgb, var(--shadow-ink) 80%, transparent);
|
|
}
|
|
/* The label, and the search box's placeholder -- the icon chip stays put so
|
|
the collapsed rail still says something, the way a dock of icons does.
|
|
The label's WIDTH collapses too, not just its opacity: an invisible label
|
|
still claiming its flex share left the icon sitting off-centre with dead
|
|
space after it, rather than centred in the icon-only rail. */
|
|
.cx-settings-rail .cx-filter-text {
|
|
flex: 0 1 0; inline-size: 0; overflow: hidden;
|
|
transition: flex-basis var(--dur-2) var(--ease-standard);
|
|
}
|
|
.cx-settings-rail .cx-filter-row {
|
|
justify-content: center;
|
|
/* The row's own gap still opens a space before a zero-width label -- two
|
|
flex items with nothing between them still get one gap's worth of
|
|
nothing, which shifted the centred GROUP (icon + gap) off the icon. */
|
|
gap: 0;
|
|
}
|
|
.cx-settings-rail .cx-filter-label {
|
|
opacity: 0; transition: opacity var(--dur-1) var(--ease-standard); white-space: nowrap;
|
|
}
|
|
.cx-settings-rail .cx-search::placeholder {
|
|
opacity: 0; transition: opacity var(--dur-1) var(--ease-standard);
|
|
}
|
|
.cx-settings-rail:hover .cx-search::placeholder,
|
|
.cx-settings-rail:focus-within .cx-search::placeholder { opacity: 1; }
|
|
.cx-settings-rail:hover .cx-filter-label, .cx-settings-rail:focus-within .cx-filter-label { opacity: 1; }
|
|
.cx-settings-rail:hover .cx-filter-text, .cx-settings-rail:focus-within .cx-filter-text {
|
|
flex: 1 1 auto; inline-size: auto;
|
|
}
|
|
.cx-settings-rail:hover .cx-filter-row, .cx-settings-rail:focus-within .cx-filter-row {
|
|
justify-content: flex-start; gap: var(--sp-3);
|
|
}
|
|
.cx-settings-content {
|
|
/* The rail's own right edge, plus real breathing room from the scale --
|
|
flush against it read as a layout bug, not a deliberate two regions
|
|
meeting. sp-8, not the gutter (sp-5): the gutter is for regions that
|
|
border each other structurally: this is content clearing an overlay. */
|
|
margin-inline-start: calc(52px + var(--sp-8)); block-size: 100%; overflow-y: auto; min-inline-size: 0;
|
|
}
|
|
|
|
/* Used as a whole pane (the Settings sidebar) rather than a compact dropdown
|
|
list -- the 240px cap and boxed border/background are right for the small
|
|
version and wrong for this one, so a host opts in with this class instead
|
|
of the base rules changing under every other consumer. */
|
|
.cx-filter-full { min-block-size: 0; block-size: 100%; }
|
|
.cx-filter-full .cx-filter-list {
|
|
max-height: none; flex: 1 1 auto; min-block-size: 0;
|
|
border: 0; background: transparent; padding: 0;
|
|
}
|
|
.cx-filter-full .cx-filter-row { padding: var(--sp-3) var(--sp-3); }
|