swarm-ui: extract Card/MultiselectFilter/SplitView per component-first design
Mara: "result looks like the shape i am looking for, but the code does not. you did not follow component first principle" - the card's clickable/selectable mechanics, the card-view filter trigger+popover, and the list+detail split layout were all one-off page-local JSX in AgentsPage.tsx instead of docs/web-ui/design-guide.md's "Component-first design" primitives. Three new ui/ components, each with a same-day /components demo section per that doc's own rule: - ui/card/Card.tsx - the role=button/keyboard-activation/selected mechanics AgentCard now wraps agent-specific content around, instead of owning them itself. - ui/multiselect-filter/MultiselectFilter.tsx - the checkbox-list trigger+popover control. This was also a straight duplicate of Table's own inline popover content once AgentsPage's filter toolbar needed the identical thing; Table now renders the same MultiselectFilterOptions piece too (keeping its own th-anchored trigger and fixed+portal positioning, which are genuinely table-specific), not a second copy. - ui/split-view/SplitView.tsx - the list+detail flex-wrap layout, no opinion on what's inside either pane. AgentsPage.tsx's own CSS shrinks to just the agent-specific content inside these primitives (card line/message layout, detail-panel field grid, the name-search input) - the container/positioning rules moved to each component's own colocated CSS. No behavior change for any other Table caller (HivesPage, IssueReportPage, the components demo's own Table samples) - the popover's visual output is identical, just sourced from the shared component instead of inline JSX. Verified: typecheck/build clean, real screenshots of both AgentsPage (pixel-identical to before) and the three new /components sections, plus a live click confirming MultiselectFilter's popover opens correctly on the demo page too.
This commit is contained in:
parent
60d7e8ce84
commit
7003560569
11 changed files with 646 additions and 400 deletions
|
|
@ -2,7 +2,9 @@
|
|||
old table body (mara: "more like card per agent"). Full-width rows,
|
||||
not a grid: the second line (the agent's free-form status message)
|
||||
reads better wrapping the card's own width than squeezed into a fixed
|
||||
grid cell. */
|
||||
grid cell. Each card's own clickable/selected/border styling is
|
||||
`Card`'s (`ui/card/`) — this file only lays out agent-specific
|
||||
content inside one. */
|
||||
.ui-agent-card-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -45,29 +47,6 @@
|
|||
.ui-agents-view-toggle button:not(.active):hover {
|
||||
color: var(--fg);
|
||||
}
|
||||
.ui-agent-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35em;
|
||||
padding: 0.75em 1em;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 0.5em;
|
||||
background: var(--bg-elev);
|
||||
cursor: pointer;
|
||||
}
|
||||
.ui-agent-card:hover,
|
||||
.ui-agent-card:focus-visible {
|
||||
border-color: var(--purple);
|
||||
outline: none;
|
||||
}
|
||||
/* The row currently shown in the detail panel — a solid border (not
|
||||
just the hover tint above, which needs to keep meaning "hovering",
|
||||
not double as "selected") plus a faint fill so it still reads once
|
||||
the pointer moves away. */
|
||||
.ui-agent-card-selected {
|
||||
border-color: var(--purple);
|
||||
background: color-mix(in srgb, var(--purple) 10%, var(--bg-elev));
|
||||
}
|
||||
.ui-agent-card-line1 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -110,27 +89,11 @@
|
|||
gap: 0.75em;
|
||||
}
|
||||
|
||||
/* List panel + detail panel side by side — `flex-wrap`, not a
|
||||
`@media` breakpoint, so a narrow viewport stacks them the same
|
||||
content-driven way the shell's own nav already wraps (`Shell.css`),
|
||||
rather than picking a second, independent magic-number breakpoint. */
|
||||
.ui-agents-layout {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1em;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.ui-agents-list-panel {
|
||||
flex: 2 1 480px;
|
||||
min-width: 0;
|
||||
}
|
||||
.ui-agents-detail-panel {
|
||||
flex: 1 1 320px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* Card view's filter toolbar — `Table`'s per-column popovers, minus the
|
||||
table to hang them off of. */
|
||||
table to hang them off of. Each `MultiselectFilter` (`ui/
|
||||
multiselect-filter/`) owns its own trigger/popover styling; this file
|
||||
only lays out the row they sit in plus the name-search input, which
|
||||
has no shared-component equivalent (a plain text input). */
|
||||
.ui-agents-filter-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
|
@ -147,17 +110,3 @@
|
|||
font: inherit;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.ui-agents-filter {
|
||||
position: relative;
|
||||
}
|
||||
/* `.ui-table-filter-popover` (Table.css) supplies the panel chrome
|
||||
(background/border/shadow) — this just positions it under the
|
||||
trigger, `position: absolute` rather than the fixed/portal recipe
|
||||
`Table`'s own version needs: nothing here clips this popover, so the
|
||||
simpler positioning is enough (see this component's own comment). */
|
||||
.ui-agents-filter-popover {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue