Files
olivv-cs-ComfyUI-FunPack/app/composer/elements/layout.css
T
digital-garbage f37f526268 app: Generate wired to a real run -- queued, progress, cancel, result
ComfyUI's own queue and its own socket, not a second one alongside them. A
FunPack queue would be a second thing tracking what is running, and the one the
user believes is whichever spoke last -- so this speaks to /prompt, /interrupt
and /ws as any ComfyUI client does and holds only a view of the server's state.
The graph is asked for, never assembled here, for the same reason.

The client id is remembered: ComfyUI addresses progress to the client that
queued the run, so a reload with a fresh id hears nothing about the generation
already in flight -- the run continues, the GPU time is spent, and the app says
Ready.

Faults found on the way, each in code that already had passing tests:

* `[hidden]` was inert across the whole kit. The UA rule is element-level, so
  `.cx-btn { display: inline-flex }` beats it -- Cancel was marked hidden, sat
  there, and nothing reported anything. jsdom cannot see it: the attribute was
  always correct. One reset rule, and a browser test over four element kinds.
* A panel passed no height to its body and a split pane passed none to its
  panes, so the viewer asked for 100% of `auto` and collapsed to a single line
  inside a panel that was the right size around it.
* subscribe() delivered the first state outside the guard every later delivery
  gets, so one bad listener took down whoever was wiring the UI up -- at
  startup, before anything existed to report it.
* A whole tests directory was never run: the test script globbed
  composer/tests only. `node --test` discovers them itself now, so there is no
  list to forget.
* `empty` was not in the content rule's key list, so three elements were never
  asked to prove their empty-state text comes back as text rather than markup.

The dev server now mounts the REAL routes -- register() already took a route
table -- instead of reimplementing them over http.server. It answered POST
/api/pipeline with 501, so the edit-and-queue path could not be looked at, which
is the one thing the dev server exists for.
2026-08-30 03:36:40 +03:00

204 lines
9.6 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.
.cx-field { display: flex; flex-direction: column; gap: var(--sp-2); }
.cx-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5); }
.cx-field-error { font-size: var(--fs-6); color: var(--danger); }
.cx-settings-row {
display: flex; align-items: center; justify-content: space-between; gap: var(--sp-7);
padding: var(--sp-4) 0; border-bottom: var(--bw) solid var(--line-2);
}
.cx-settings-row:last-child { border-bottom: 0; }
.cx-settings-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cx-settings-label { font-size: var(--fs-4); line-height: var(--lh-4); color: var(--text); }
.cx-settings-control { flex: none; min-width: 140px; display: flex; justify-content: flex-end; }
.cx-settings-row.cx-danger .cx-settings-label { color: var(--danger); }
.cx-group { display: flex; flex-direction: column; gap: var(--sp-3); }
.cx-group-rows {
border: var(--bw) solid var(--line); border-radius: var(--r-4);
background: var(--elev-1); padding: 0 var(--sp-6);
}
.cx-panel {
border: var(--bw) solid var(--line); border-radius: var(--r-4);
background: var(--elev-1); overflow: hidden;
/* A column, so a panel given a height passes it to its body. Without this a
viewer asking for 100% of its parent got 100% of `auto` and collapsed to
one line, inside a panel that was the right size around it. */
display: flex; flex-direction: column; min-block-size: 0;
}
.cx-panel-head {
display: flex; align-items: center; justify-content: space-between; gap: var(--sp-5);
padding: var(--sp-4) var(--sp-6); border-bottom: var(--bw) solid var(--line);
background: var(--elev-2); min-height: var(--menubar-h);
}
.cx-panel-title { font-family: var(--font-display); font-size: var(--fs-3); font-weight: var(--fw-semibold); }
.cx-panel-actions { display: flex; gap: var(--sp-2); }
.cx-panel-body { padding: var(--sp-6); flex: 1 1 auto; min-block-size: 0; overflow: auto; }
.cx-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.cx-action-bar {
display: flex; align-items: center; justify-content: space-between; gap: var(--sp-6);
padding: var(--sp-5) var(--sp-6);
border-top: var(--bw) solid var(--line); background: var(--elev-2);
position: sticky; bottom: 0;
}
.cx-action-bar-buttons { display: flex; gap: var(--sp-3); margin-left: auto; }
.cx-list-wrap { display: flex; flex-direction: column; gap: var(--sp-3); align-items: flex-start; }
.cx-list {
width: 100%; border: var(--bw) solid var(--line); border-radius: var(--r-3);
background: var(--elev-1); overflow: hidden;
}
.cx-list-row {
display: flex; align-items: center; gap: var(--sp-4);
padding: var(--sp-3) var(--sp-5); border-bottom: var(--bw) solid var(--line-2);
}
.cx-list-row:last-child { border-bottom: 0; }
.cx-list-label { font-size: var(--fs-4); flex: 1; min-width: 0; }
.cx-list-hint { font-size: var(--fs-7); color: var(--muted); }
.cx-list-control { flex: none; width: 92px; }
/* Separated from the row's own control by a rule, so the arrows read as
* "reorder this row" rather than "adjust that number". */
.cx-list-actions {
display: flex; gap: var(--sp-1); flex: none;
padding-left: var(--sp-4); margin-left: var(--sp-2);
border-left: var(--bw) solid var(--line-2);
}
.cx-list-move { color: var(--faint); }
.cx-list-move:hover:not(:disabled) { color: var(--accent); }
.cx-list-empty { padding: var(--sp-6); font-size: var(--fs-6); color: var(--faint); text-align: center; }
.cx-tabs { display: flex; gap: var(--sp-1); }
.cx-tab {
border: 0; background: transparent; color: var(--muted);
cursor: pointer; font-family: var(--font-ui); font-size: var(--fs-5);
transition: color var(--dur-1) var(--ease-standard);
}
.cx-tabs-underline { border-bottom: var(--bw) solid var(--line); gap: var(--sp-5); }
.cx-tabs-underline .cx-tab {
padding: var(--sp-3) 0; border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.cx-tabs-underline .cx-tab.cx-on { color: var(--text); border-bottom-color: var(--accent); }
.cx-tabs-dock .cx-tab {
height: var(--ctl-h-md); padding: 0 var(--ctl-pad-x-md);
border: var(--bw) solid var(--line); border-radius: var(--r-3);
font-size: var(--fs-6);
}
.cx-tabs-dock .cx-tab.cx-on { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
.cx-tab:hover { color: var(--text); }
.cx-split { display: flex; width: 100%; min-height: 120px; }
.cx-split-v { flex-direction: column; }
/* A column, so what is inside a pane inherits the pane's height instead of
sizing to its own content. A panel in a pane was the right size with a body
one line tall inside it, which looks like the panel is fine and the content
is empty. */
.cx-split-pane {
flex: 1 1 0; min-inline-size: 0; min-block-size: 0; overflow: auto;
display: flex; flex-direction: column;
}
.cx-split-pane > * { flex: 1 1 auto; min-block-size: 0; }
.cx-split > .cx-split-pane:first-child { flex: 0 0 auto; }
/* A horizontal split stacks rather than overflowing when there is not room for
two columns. The first pane carries an inline size, so on a narrow screen it
could not shrink and the whole page scrolled sideways -- 407px of content in
a 360px viewport. Wrapping rather than a media query because the kit sizes
itself from its container, not from the window. */
.cx-split-h { flex-wrap: wrap; }
.cx-split-h > .cx-split-pane { min-inline-size: min(100%, 260px); }
.cx-split-h > .cx-split-pane:first-child { max-inline-size: 100%; }
.cx-split-bar { flex: none; background: transparent; position: relative; }
.cx-split-h > .cx-split-bar { width: 7px; cursor: col-resize; }
.cx-split-v > .cx-split-bar { height: 7px; cursor: row-resize; }
.cx-split-bar::after {
content: ""; position: absolute; inset: 0; margin: auto;
background: var(--line); transition: background var(--dur-1) var(--ease-standard);
}
.cx-split-h > .cx-split-bar::after { width: 1px; }
.cx-split-v > .cx-split-bar::after { height: 1px; }
.cx-split-bar:hover::after, .cx-split-bar:focus-visible::after { background: var(--accent); }
.cx-split-bar:focus-visible { outline: none; }
.cx-collapsible { border: var(--bw) solid var(--line); border-radius: var(--r-3); background: var(--elev-1); }
.cx-collapsible-head {
display: flex; align-items: baseline; gap: var(--sp-3);
padding: var(--sp-3) var(--sp-5); cursor: pointer; list-style: none;
font-size: var(--fs-5);
}
.cx-collapsible-head::-webkit-details-marker { display: none; }
.cx-collapsible-head::before {
content: "›"; color: var(--faint); display: inline-block;
transition: transform var(--dur-1) var(--ease-standard);
}
.cx-collapsible[open] > .cx-collapsible-head::before { transform: rotate(90deg); }
.cx-collapsible-body { padding: 0 var(--sp-5) var(--sp-5); }
.cx-rail { display: flex; flex-direction: column; gap: var(--sp-1); padding: var(--sp-2); }
.cx-rail-item {
display: flex; align-items: center; gap: var(--sp-4);
height: var(--ctl-h-xl); padding: 0 var(--sp-4);
border: 0; border-radius: var(--r-3); background: transparent;
color: var(--muted); font-size: var(--fs-5); cursor: pointer; text-align: left;
}
.cx-rail-item:hover { background: var(--hover); color: var(--text); }
.cx-rail-item.cx-on { background: var(--accent-soft); color: var(--accent-hi); }
.cx-rail-icon { width: 18px; text-align: center; }
/* Workspace: a centre that shrinks, panels docked either side.
The rails hold the toggles and never collapse, so the control for a panel is
never inside the panel it controls. */
.cx-workspace { display: flex; align-items: stretch; min-block-size: 0; block-size: 100%; inline-size: 100%; }
/* Flex containers, not blocks with overflow. A region whose height comes from
its content gives a vertical split inside it a basis of `auto`, so the split's
second pane resolves to zero and simply is not there -- the prompt under the
preview vanished exactly that way, with no error and nothing to see. */
.cx-workspace-main {
flex: 1 1 auto; min-inline-size: 0; min-block-size: 0;
display: flex; flex-direction: column;
}
.cx-workspace-main > *, .cx-workspace-side > * { flex: 1 1 auto; min-block-size: 0; }
.cx-workspace-side {
/* Allowed to shrink, and sized from the viewport rather than fixed: two
fixed 240px panels plus their rails are wider than a 480px window, and the
page then scrolls sideways -- the one thing a docked layout must never do,
because the transport bar goes with it. Narrow is cramped and legible; the
user can collapse either side. */
flex: 0 1 auto;
inline-size: clamp(0px, 22vw, 340px);
min-inline-size: 0;
min-block-size: 0;
overflow: auto;
display: flex; flex-direction: column;
padding: var(--sp-3);
border-inline: 1px solid var(--line);
}
/* Width nil rather than display:none -- the panel stays in the flow, stays
measurable, and can come back without being rebuilt.
Deliberately not animated. A remembered-closed panel would animate shut on
every page load, which reads as the app doing something rather than as a
remembered preference, and an in-flight width is a state anything measuring
the layout has to wait out. */
.cx-workspace-side.cx-collapsed {
inline-size: 0;
padding-inline: 0;
border-inline-width: 0;
overflow: hidden;
}
.cx-workspace-rail {
flex: 0 0 auto;
display: flex;
align-items: flex-start;
justify-content: center;
padding: var(--sp-2) var(--sp-1);
}
/* The page frame. The one place a definite height is established, so everything
below can fill instead of each pane guessing at a percentage of nothing. */
.cx-frame { display: flex; flex-direction: column; block-size: 100%; min-block-size: 0; }
.cx-frame-main { flex: 1 1 auto; min-block-size: 0; display: flex; }
.cx-frame-main > * { flex: 1 1 auto; min-inline-size: 0; }
.cx-frame-foot { flex: 0 0 auto; }