dashboard.css + docs: migrate topology indent + icon/pending prose (#712 batch 12)
dashboard.css carried many CSS WHY-blocks duplicating prose already in docs/web-ui.md (after PRs #722/#724/#728/#776). Substantive new migration: topology indent geometry. Remaining cookies collapse to docs pointers. Moved to docs/web-ui.md::Topology tree: - Indent + lane geometry paragraph (~18 lines new prose): per-depth 1.8em ladder rationale + hardcoded six levels + CSS Values 5 attr() partial-support caveat (Chromium-only as of 2026) + lane center continuation bars + bottom: -0.4em prefix extension to merge sibling vertical lines + horizontal stub at icon midline. Collapsed in dashboard.css: - Topology indent block (#363/#361) → 3-line pointer - Tree prefix lanes block (#388) → 3-line pointer - Tree prefix depth-step ladder (~6 lines) → 4-line tighter paraphrase (lane-meets-icon rationale stays inline as it's immediate context for the values below) - Live cards icon-left split (#177/#344) → 6-line tighter paraphrase + docs pointer - Icon selection-toggle hover/focus (#443) → docs pointer - Icon img absolute positioning (#177) → docs pointer - Icon favicon fallback (#195/#202) → docs pointer - Pending state queued vs running (#769) → docs pointer - Icon-only nav strip (#262/#333) → 7-line tighter + docs pointer - Approval requested-at chip (#272) → 2-line pointer - In-flight step indicator (#437) → 4-line pointer - M0V3 affordance (#486) → 3-line pointer - Cancel-X queued (#575) → 5-line pointer dashboard.css: 51 → 36 cookies (counting hex-color false positives; ~15 actual issue refs scrubbed). Net ~50 lines of CSS WHY-prose collapsed to brief docs pointers; ~18 lines of new substantive prose migrated to docs/web-ui.md::Topology tree.
This commit is contained in:
parent
dfbaa2654b
commit
9c72fd369a
2 changed files with 72 additions and 70 deletions
|
|
@ -538,6 +538,26 @@ needed). The joint at the row's own depth column is `├` (more
|
|||
siblings below) or `└` (last sibling at this depth — vertical
|
||||
stops at the row's icon midline).
|
||||
|
||||
**Indent + lane geometry.** Each depth level shifts the row right
|
||||
by `1.8em` (the lane width). The per-depth ladders are hardcoded
|
||||
for six levels — enough for any plausible hive topology, and the
|
||||
typed `attr()` function from CSS Values 5 that would collapse
|
||||
this to one rule is still partial-support (Chromium-only as of
|
||||
2026). The `.tree-prefix` span sits absolutely positioned with
|
||||
`left: -<depth>*1.8em` so its right edge meets the row content
|
||||
(the icon) and its leftmost lane lines up with top-level rows'
|
||||
icons at `x = 0`. Each `.tree-lane` is `flex: 0 0 1.8em` so all
|
||||
lanes have equal width. Continuation bars are drawn at lane
|
||||
center (`left: 0.6em`, `border-left: 1px solid currentColor`,
|
||||
`top: 0; bottom: 0`) and extend through `.containers { gap: 0.4em }`
|
||||
into the next sibling's prefix (`bottom: -0.4em` on the prefix
|
||||
span itself) so adjacent ancestor lines visually merge into one
|
||||
unbroken vertical line. The horizontal stub at a row's own joint
|
||||
lands at the icon midline so the L/T meets the icon edge cleanly.
|
||||
When every container has `parent = null` (pre-topology state) the
|
||||
`[data-depth]` attribute is absent on every row and these rules
|
||||
are no-ops — the layout reads exactly like the legacy flat list.
|
||||
|
||||
### Selection bar
|
||||
|
||||
Per-card action buttons (`R3ST4RT` / `ST0P` / `ST4RT` / `R3BU1LD` /
|
||||
|
|
|
|||
|
|
@ -189,16 +189,9 @@ a:hover {
|
|||
background: rgba(24, 24, 37, 0.55);
|
||||
transition: opacity 200ms ease, border-color 200ms ease;
|
||||
}
|
||||
/* Topology indent (#363). Each depth level shifts the row right by one
|
||||
step; the .tree-prefix span (drawn by tabs.js::treePrefix) carries
|
||||
the ├─ / └─ glyph and any continuation lines that thread through
|
||||
ancestor columns. When every container has parent=null (pre-#361
|
||||
state) `[data-depth]` is absent on every row and these rules are
|
||||
no-ops — the layout reads exactly like the legacy flat list.
|
||||
Per-depth indent: hardcoded steps for 6 levels (sufficient for any
|
||||
plausible hive topology) — the typed `attr()` function from CSS
|
||||
Values 5 would collapse this to one rule, but browser support is
|
||||
still partial (Chromium-only as of 2026). */
|
||||
/* Topology indent ladder. See docs/web-ui.md::Topology tree (Indent
|
||||
+ lane geometry paragraph) for the 1.8em-per-depth-level
|
||||
rationale + CSS-attr()-not-yet-portable caveat. */
|
||||
.container-row[data-depth] { position: relative; }
|
||||
.container-row[data-depth="1"] { margin-left: 1.8em; }
|
||||
.container-row[data-depth="2"] { margin-left: 3.6em; }
|
||||
|
|
@ -206,16 +199,9 @@ a:hover {
|
|||
.container-row[data-depth="4"] { margin-left: 7.2em; }
|
||||
.container-row[data-depth="5"] { margin-left: 9em; }
|
||||
.container-row[data-depth="6"] { margin-left: 10.8em; }
|
||||
/* Tree prefix sits in the left margin and paints the connecting
|
||||
├ / └ / │ lanes as CSS rules rather than text glyphs (#388). Each
|
||||
ancestor depth gets its own `.tree-lane` so we can paint a
|
||||
full-row-height vertical bar that extends through the
|
||||
.containers row gap into the next sibling — text box-drawing
|
||||
glyphs only fill one text line, which left visible breaks
|
||||
between rows once cards grew taller than one line of text (5em
|
||||
square icons + multi-line body). The horizontal stub at the row's
|
||||
own joint lands at the icon midline so the L/T meets the icon
|
||||
edge cleanly. */
|
||||
/* Tree prefix lanes — DOM-painted, not text-glyph-painted. See
|
||||
docs/web-ui.md::Topology tree for the full-row-height vertical
|
||||
bar rationale + icon-midline joint alignment. */
|
||||
.container-row .tree-prefix {
|
||||
position: absolute;
|
||||
/* Extend into the `.containers { gap: 0.4em }` below so vertical
|
||||
|
|
@ -228,12 +214,10 @@ a:hover {
|
|||
user-select: none;
|
||||
color: var(--purple-dim);
|
||||
}
|
||||
/* Each depth step is one 1.8em lane wide — same step as the row's
|
||||
own margin-left ladder above, so the rightmost lane (the joint)
|
||||
sits flush against the row content (the icon). The prefix's left
|
||||
edge is depth*1.8em LEFT of the row's left edge, so its right
|
||||
edge meets the icon, and the leftmost lane lines up with the
|
||||
top-level rows' icons at x=0. */
|
||||
/* Prefix-left-edge ladder. Each depth step is 1.8em (matches the
|
||||
row indent ladder above) so the prefix's right edge meets the
|
||||
icon and its leftmost lane lines up with top-level rows' icons
|
||||
at x = 0. */
|
||||
.container-row[data-depth="1"] .tree-prefix { left: -1.8em; }
|
||||
.container-row[data-depth="2"] .tree-prefix { left: -3.6em; }
|
||||
.container-row[data-depth="3"] .tree-prefix { left: -5.4em; }
|
||||
|
|
@ -277,14 +261,12 @@ a:hover {
|
|||
width: 2em;
|
||||
border-top: 1px solid currentColor;
|
||||
}
|
||||
/* Live cards get the icon-left / body-right split; tombstone rows keep
|
||||
the plain stacked block layout. The icon is a background-image div
|
||||
with no intrinsic size, so its load state can never reflow the row
|
||||
(issue #177). It used to `align-self: stretch` to fill the body
|
||||
height, but with state badges / rate-limit pills / etc. wrapping the
|
||||
head row, the body grew taller and the square icon grew with it —
|
||||
so two cards with different content showed different-sized icons
|
||||
(issue #344). Fixed at 5em now; height follows from aspect-ratio. */
|
||||
/* Live cards get the icon-left / body-right split; tombstone rows
|
||||
keep the plain stacked block layout. The icon's fixed 5em width
|
||||
+ aspect-ratio-derived height avoid the align-self: stretch
|
||||
feedback loop that used to make different-content cards show
|
||||
different-sized icons. See docs/web-ui.md::Container row (Icon
|
||||
layout + load strategy) for the load-state reflow rationale. */
|
||||
.container-row:not(.tombstone) {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
|
@ -298,9 +280,10 @@ a:hover {
|
|||
aspect-ratio: 1;
|
||||
border-radius: 6px;
|
||||
background-color: rgba(17, 17, 27, 0.6);
|
||||
/* #443 — icon is the selection toggle. Cursor + hover ring make
|
||||
that affordable without a chrome change. The :focus-visible ring
|
||||
covers keyboard activation (Enter / Space). */
|
||||
/* Icon doubles as the selection toggle — cursor + hover ring
|
||||
make that affordable without a chrome change. The
|
||||
:focus-visible ring covers keyboard activation (Enter / Space).
|
||||
See docs/web-ui.md::Selection bar for the toggle semantics. */
|
||||
cursor: pointer;
|
||||
transition: box-shadow 120ms ease, transform 120ms ease;
|
||||
}
|
||||
|
|
@ -321,9 +304,9 @@ a:hover {
|
|||
.container-row.selected > .container-icon {
|
||||
box-shadow: 0 0 0 2px var(--purple), 0 0 12px -4px var(--purple);
|
||||
}
|
||||
/* The icon image fills the square wrapper and is taken out of flow
|
||||
(absolute) so its load state — pending, loaded, broken — can never
|
||||
contribute intrinsic size or reflow the row. (issue #177) */
|
||||
/* Icon image — absolutely positioned, fills the square wrapper.
|
||||
See docs/web-ui.md::Container row (Icon layout + load strategy)
|
||||
for the load-state-can't-reflow-row rationale. */
|
||||
.container-row:not(.tombstone) > .container-icon > .container-icon-img {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
|
|
@ -331,8 +314,9 @@ a:hover {
|
|||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
/* When the <img> fails to load it falls back to the dimmed hyperhive
|
||||
mark, standing in for the unreachable agent icon (issues #195, #202). */
|
||||
/* When the <img> fails to load it falls back to the dimmed
|
||||
hyperhive mark — see docs/web-ui.md::Container row for the
|
||||
fire-and-forget load + favicon fallback chain. */
|
||||
.container-row:not(.tombstone) > .container-icon.icon-unreachable {
|
||||
filter: grayscale(1);
|
||||
opacity: 0.4;
|
||||
|
|
@ -341,11 +325,11 @@ a:hover {
|
|||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
/* Pending state splits queued vs running (#769): queued ops show
|
||||
only the pending-state badge — the row sits unhighlighted so a
|
||||
long queue doesn't paint half the SW4RM tab amber. Running ops
|
||||
keep the amber row tint AND get a rotating amber ring on the
|
||||
agent icon so it's obvious which container is actually moving. */
|
||||
/* Pending state splits queued vs running — queued ops show only
|
||||
the pending-state badge (no row tint), running ops keep the
|
||||
amber row tint AND get a rotating amber ring on the icon. See
|
||||
docs/web-ui.md::Container row (Pending-state derivation) for
|
||||
the priority order. */
|
||||
.container-row.pending .actions { opacity: 0.4; pointer-events: none; }
|
||||
.container-row.pending-running {
|
||||
border-color: var(--amber);
|
||||
|
|
@ -385,11 +369,13 @@ a:hover {
|
|||
font-weight: bold;
|
||||
}
|
||||
.container-row .head .meta { margin-left: auto; }
|
||||
/* Icon-only nav strip in the head row — the per-container backend-
|
||||
supplied link list (issue #262). Inline-flex + gap so a longer list
|
||||
(e.g. with `dashboardLinks` extras) doesn't cram (issue #333). Each
|
||||
link gets a comfortable hit target with a subtle hover so the
|
||||
icons read as interactive rather than decorative. */
|
||||
/* Icon-only nav strip in the head row — backend-supplied per-
|
||||
container link list. Inline-flex + gap so a longer list (e.g.
|
||||
with `dashboardLinks` extras) doesn't cram. Each link gets a
|
||||
comfortable hit target with a subtle hover so the icons read
|
||||
as interactive rather than decorative. See
|
||||
docs/web-ui.md::Container row Line 1 for the link-list source
|
||||
of truth. */
|
||||
.container-row .head .nav-strip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
|
@ -605,9 +591,8 @@ code {
|
|||
flex-wrap: wrap;
|
||||
gap: 0.3em;
|
||||
}
|
||||
/* When the approval was requested — right-aligned in the head row;
|
||||
goes amber once it has been pending ≥ 1h so a stale request stands
|
||||
out at a glance (issue #272). */
|
||||
/* Approval requested-at chip — right-aligned, goes amber after
|
||||
1h. See docs/web-ui.md::Approval card. */
|
||||
.approval-ts {
|
||||
margin-left: auto;
|
||||
color: var(--muted);
|
||||
|
|
@ -836,11 +821,10 @@ code {
|
|||
.rqe-source-approval { color: var(--green); border-color: var(--green); }
|
||||
.rqe-when { color: var(--muted); font-size: 0.85em; }
|
||||
.rqe-reason { color: var(--muted); font-size: 0.85em; flex: 1 1 auto; }
|
||||
/* #437: in-flight step indicator on running queue entries — sub-line
|
||||
below the main row, indented under the state glyph + kind. Cyan
|
||||
keeps it visually grouped with the running spinner instead of
|
||||
blending into the muted reason/timing chips. flex-basis: 100% so
|
||||
it always wraps to its own line. */
|
||||
/* In-flight step indicator on running queue entries — cyan sub-
|
||||
line below the main row, wraps to its own line via flex-basis:
|
||||
100%. See docs/web-ui.md::R3BU1LD QU3U3 for the step-annotation
|
||||
semantics. */
|
||||
.rqe-step {
|
||||
flex-basis: 100%;
|
||||
margin: 0.1em 0 0 1.8em;
|
||||
|
|
@ -858,12 +842,11 @@ code {
|
|||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/* #575: cancel-X for queued rebuild_queue entries. Quiet by default
|
||||
(sits at the far right via margin-left: auto), lights red on hover.
|
||||
Renders only when `state === 'queued'` per renderQueueEntry's
|
||||
guard — Running / terminal rows don't get the affordance. Mirrors
|
||||
the side-panel-close glyph shape (✗) without the full B6N-style
|
||||
`btn-deny` width so it stays unobtrusive in a list row. */
|
||||
/* Cancel-X for queued rebuild_queue entries — sits at far right
|
||||
via margin-left: auto, lights red on hover. Mirrors the side-
|
||||
panel-close glyph shape (✗) so it stays unobtrusive in a list
|
||||
row. See docs/web-ui.md::R3BU1LD QU3U3 for the queued-only
|
||||
gating. */
|
||||
.rqe-cancel {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
|
@ -942,10 +925,9 @@ ul form.inline { display: inline-block; }
|
|||
.btn-restart { color: var(--cyan); border-color: var(--cyan); font-size: 0.75em; padding: 0.15em 0.5em; margin-left: 0.6em; }
|
||||
.btn-stop { color: var(--pink); border-color: var(--pink); font-size: 0.75em; padding: 0.15em 0.5em; margin-left: 0.6em; }
|
||||
.btn-start { color: var(--green); border-color: var(--green); font-size: 0.75em; padding: 0.15em 0.5em; margin-left: 0.6em; }
|
||||
/* #486 — M0V3 affordance (selection bar). Mauve picks up the same
|
||||
accent the question-override / mid-status surfaces use; reads as
|
||||
"structural change" rather than the destructive red / amber chrome
|
||||
of destroy / rebuild. */
|
||||
/* M0V3 affordance (selection bar) — mauve reads as "structural
|
||||
change" rather than the destructive red / amber chrome of
|
||||
destroy / rebuild. See docs/web-ui.md::Selection bar. */
|
||||
.btn-move { color: var(--mauve); border-color: var(--mauve); font-size: 0.75em; padding: 0.15em 0.5em; margin-left: 0.6em; }
|
||||
.btn-talk { color: var(--cyan); border-color: var(--cyan); }
|
||||
.btn-spawn { color: var(--amber); border-color: var(--amber); }
|
||||
|
|
|
|||
Loading…
Reference in a new issue