swarm-ui: create-agent layout fills the page width, centered

mara: the two cards were neither centered nor filling the space in
two-column mode. Dropped the page's own max-width entirely — Panel
already has no width opinion, and once both cards are equal-width
flex children there's no reason for an extra cap between them and
.shell-body's own 60em/centered column. Removed the now-pointless
wrapper div along with it.

Checked centered + filling behaviour at both a normal (1200px) and an
ultra-wide (1600px) viewport, and narrow-viewport stacking still
works.
This commit is contained in:
iris 2026-08-19 14:55:44 +02:00 committed by mara
commit 1207a0e282
2 changed files with 85 additions and 90 deletions

View file

@ -6,28 +6,25 @@
looked misaligned mara: "make it a col". Reuses the same base16 looked misaligned mara: "make it a col". Reuses the same base16
slots (../theme.css) every other component draws from. slots (../theme.css) every other component draws from.
`.create-agent-page` caps the whole layout's width: `Panel` has no This layout dropped an explicit page `max-width` after a few rounds:
width opinion of its own, so left unconstrained a single form panel first added so bare `Panel` (no width opinion of its own) wouldn't
filled `.shell-body`'s full 60em column a lot of bare panel to the fill `.shell-body`'s full 60em column behind a narrow form (the
right of a narrow form, the "weird empty space" mara flagged original "weird empty space" complaint), then widened for two panels
alongside the original field misalignment. The follow-up ask was to side by side but once both were equal-width flex children that cap
fill that space with something that explains the page rather than itself became "doesn't fill the space" (mara: "the cards are neither
just narrowing it further `.create-agent-layout` puts the form centered nor fill the space tho"). Removing it lets the row fill
beside a second, explanatory panel instead, `.create-agent-form-col` `.shell-body`'s own width like most pages nothing sits off-center
and `.create-agent-info-col` sized equally (`flex: 1 1 0` an equal once nothing is narrower than the row.
*basis* of zero so the 1.5em `gap` splits the remaining row width
evenly between them, rather than each keeping its own natural `.create-agent-form-col`/`.create-agent-info-col` are equal-sized
content width) per mara's follow-up ("both cards should be equal (`flex: 1 1 0` zero basis so the 1.5em `gap` splits the row evenly,
sized"). `min-width` on both is the wrap threshold: below it a card not each column keeping its natural content width) per mara's "both
would get uncomfortably narrow, so the row wraps to a single column cards should be equal sized". `min-width` is the wrap threshold below
instead (`.create-agent-info-col` moving under the form) no which the row goes single-column instead (info card moving under the
separate media query needed. The form's own inputs now fill that form) no separate media query needed. Inputs fill their whole
whole column width too (mara: "inputs should fill full card width") column now too ("inputs should fill full card width") the kit's
the kit's `.ui-form-control`/`.ui-form-field` dropped their old `.ui-form-control`/`.ui-form-field` dropped their old 16em cap for
16em cap for exactly this (../ui/form-field/FormField.css). */ exactly this (../ui/form-field/FormField.css). */
.create-agent-page {
max-width: 44em;
}
.create-agent-layout { .create-agent-layout {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;

View file

@ -125,75 +125,73 @@ export function CreateAgentPage() {
} }
return ( return (
<div class="create-agent-page"> <div class="create-agent-layout">
<div class="create-agent-layout"> <div class="create-agent-form-col">
<div class="create-agent-form-col"> <Panel title="create agent">
<Panel title="create agent"> <p class="create-agent-intro">
<p class="create-agent-intro"> Create a new agent's swarm-level identity. This only queues the job — check{' '}
Create a new agent's swarm-level identity. This only queues the job — check{' '} <Link href="/jobs">jobs</Link> to watch it settle.
<Link href="/jobs">jobs</Link> to watch it settle. </p>
{hivesError && (
<ApiErrorPanel context="failed to load the hive list" problem={hivesError} />
)}
<form class="create-agent-form" onSubmit={submit}>
<TextField
id="agent-name"
label="agent name"
value={name}
pattern={NAME_PATTERN}
title="1-63 chars: lowercase letters, digits, hyphens"
required
onInput={setName}
/>
<SelectField
id="agent-hive"
label="hive"
value={hive}
onChange={setHive}
options={hiveOptions}
required
disabled={!hivesReady}
placeholder={
!hives ? 'loading…' : hives.length === 0 ? 'no hives configured' : 'select a hive'
}
/>
<Button
variant="primary"
type="submit"
disabled={result.status === 'submitting' || !hivesReady}
>
{result.status === 'submitting' ? 'creating…' : 'create'}
</Button>
</form>
{result.status === 'done' && (
<p class="create-agent-result create-agent-result-ok">
queued as job node #{result.nodeId} <Link href="/jobs">watch it in jobs</Link>
</p> </p>
{hivesError && ( )}
<ApiErrorPanel context="failed to load the hive list" problem={hivesError} /> {result.status === 'error' && (
)} <ApiErrorPanel context="failed to queue" problem={result.problem} />
<form class="create-agent-form" onSubmit={submit}> )}
<TextField </Panel>
id="agent-name" </div>
label="agent name" <div class="create-agent-info-col">
value={name} {/* Describes the intended end state (a running agent), not today's
pattern={NAME_PATTERN} literal behaviour (deploying the container onto the hive isn't
title="1-63 chars: lowercase letters, digits, hyphens" wired up server-side yet see this file's top comment)
required mara's explicit call on this copy: read as finished, not as a
onInput={setName} running commentary on partial implementation. */}
/> <Panel title="what this creates">
<SelectField <p class="create-agent-info-glyph" aria-hidden="true">
id="agent-hive" 🪪
label="hive" </p>
value={hive} <p>
onChange={setHive} Submitting this queues everything a new agent needs: a swarm-level identity, a config
options={hiveOptions} repo on the forge with the operator added as a collaborator, and a container running
required the agent on the hive you pick above. Watch it all settle on{' '}
disabled={!hivesReady} <Link href="/jobs">jobs</Link>.
placeholder={ </p>
!hives ? 'loading…' : hives.length === 0 ? 'no hives configured' : 'select a hive' </Panel>
}
/>
<Button
variant="primary"
type="submit"
disabled={result.status === 'submitting' || !hivesReady}
>
{result.status === 'submitting' ? 'creating…' : 'create'}
</Button>
</form>
{result.status === 'done' && (
<p class="create-agent-result create-agent-result-ok">
queued as job node #{result.nodeId} <Link href="/jobs">watch it in jobs</Link>
</p>
)}
{result.status === 'error' && (
<ApiErrorPanel context="failed to queue" problem={result.problem} />
)}
</Panel>
</div>
<div class="create-agent-info-col">
{/* Describes the intended end state (a running agent), not today's
literal behaviour (deploying the container onto the hive isn't
wired up server-side yet see this file's top comment)
mara's explicit call on this copy: read as finished, not as a
running commentary on partial implementation. */}
<Panel title="what this creates">
<p class="create-agent-info-glyph" aria-hidden="true">
🪪
</p>
<p>
Submitting this queues everything a new agent needs: a swarm-level identity, a
config repo on the forge with the operator added as a collaborator, and a container
running the agent on the hive you pick above. Watch it all settle on{' '}
<Link href="/jobs">jobs</Link>.
</p>
</Panel>
</div>
</div> </div>
</div> </div>
); );