diff --git a/docs/web-ui/design-guide.md b/docs/web-ui/design-guide.md index e8610471..dc24facf 100644 --- a/docs/web-ui/design-guide.md +++ b/docs/web-ui/design-guide.md @@ -24,7 +24,13 @@ repeated here. home.js`, is the reference example — currently in the dashboard package, not swarm-ui itself, but the pattern it sets applies here too). Whimsy still has to clear the accessibility bar below (motion, - in particular). + in particular). swarm-ui's own reference example: `Panel`'s optional + `icon` prop (`src/ui/panel/Panel.tsx`), a small emoji glyph in a + panel's header, chosen per panel with no default — grew out of a + one-off emoji dropped into a single page's copy, which wasn't whimsy + in this sense (a *consistent*, reusable touch) until it became a real + prop every panel can opt into. `aria-hidden`, since it's decorative — + the title text is still the actual label. - **Efficient navigation** — minimize clicks/hops for a common task. - **Avoid junk drawers.** A control belongs next to the thing it affects, not tucked into a catch-all menu. Concrete anti-example (not diff --git a/frontend/packages/swarm-ui/src/App.tsx b/frontend/packages/swarm-ui/src/App.tsx index 37464e7b..ec28e0c0 100644 --- a/frontend/packages/swarm-ui/src/App.tsx +++ b/frontend/packages/swarm-ui/src/App.tsx @@ -10,7 +10,7 @@ import { Panel } from './ui/panel/Panel.js'; function NotFound() { return ( - +

no route here.

); diff --git a/frontend/packages/swarm-ui/src/pages/ComponentsPage.tsx b/frontend/packages/swarm-ui/src/pages/ComponentsPage.tsx index 0bdca539..f719f361 100644 --- a/frontend/packages/swarm-ui/src/pages/ComponentsPage.tsx +++ b/frontend/packages/swarm-ui/src/pages/ComponentsPage.tsx @@ -88,7 +88,7 @@ function RefreshIntervalPickerSample() { export function ComponentsPage() { return ( - +

Every primitive in src/ui/, shown in each mode it supports. Sample data only — nothing here calls the API. @@ -101,6 +101,11 @@ export function ComponentsPage() { panel body content, no title + + + panel body content + +

- +

Create a new agent's swarm-level identity. This only queues the job — check{' '} jobs to watch it settle. @@ -180,11 +180,11 @@ export function CreateAgentPage() { 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. */} - -

+ running commentary on partial implementation. The 🪪 glyph that + used to sit here as body copy now lives on `Panel`'s own `icon` + prop instead — it's what prompted that prop to exist at all + (see Panel.tsx's doc comment) */} +

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 diff --git a/frontend/packages/swarm-ui/src/pages/HivesPage.tsx b/frontend/packages/swarm-ui/src/pages/HivesPage.tsx index 7149e62f..369b1df4 100644 --- a/frontend/packages/swarm-ui/src/pages/HivesPage.tsx +++ b/frontend/packages/swarm-ui/src/pages/HivesPage.tsx @@ -115,6 +115,7 @@ export function HivesPage() { return ( } > {error ? : null} diff --git a/frontend/packages/swarm-ui/src/pages/JobsPage.tsx b/frontend/packages/swarm-ui/src/pages/JobsPage.tsx index 3e95b00b..932b425c 100644 --- a/frontend/packages/swarm-ui/src/pages/JobsPage.tsx +++ b/frontend/packages/swarm-ui/src/pages/JobsPage.tsx @@ -18,7 +18,7 @@ import './JobsPage.css'; export function JobsPage() { return ( - + diff --git a/frontend/packages/swarm-ui/src/ui/panel/Panel.css b/frontend/packages/swarm-ui/src/ui/panel/Panel.css index 0132d514..6b4b9f10 100644 --- a/frontend/packages/swarm-ui/src/ui/panel/Panel.css +++ b/frontend/packages/swarm-ui/src/ui/panel/Panel.css @@ -15,6 +15,10 @@ font-size: 1em; font-weight: 600; } +.ui-panel-icon { + font-size: 1.2em; + line-height: 1; +} /* `margin-left: auto` (not `justify-content: space-between` on the header) so actions still land at the right edge even on the rare panel that has actions but no title. */ diff --git a/frontend/packages/swarm-ui/src/ui/panel/Panel.tsx b/frontend/packages/swarm-ui/src/ui/panel/Panel.tsx index eea69b56..01265adf 100644 --- a/frontend/packages/swarm-ui/src/ui/panel/Panel.tsx +++ b/frontend/packages/swarm-ui/src/ui/panel/Panel.tsx @@ -11,22 +11,44 @@ // dedicated row stealing vertical space from the panel's actual // content either). `HivesPage`'s refresh-interval picker is the // motivating caller. +// +// `icon` is a small header glyph, left of the title — the swarm-ui +// design guide's own whimsy reference (before this, the guide only +// pointed at the dashboard's matrix-rain background). Grew out of +// CreateAgentPage's one-off 🪪 dropped straight into a panel's body +// copy: mara's call on review was that a single ad-hoc emoji isn't +// whimsy in the guide's sense (small, delightful, *consistent*), it +// should be a real theme every panel can opt into the same way. Plain +// `string` (an emoji literal), not an icon-library asset — same +// lightweight-glyph precedent `RefreshIntervalPicker`'s 🕐 set before +// this. Chosen per panel, no default: not every panel needs one, and +// there's no single semantic mapping (e.g. "jobs" pages) worth +// hardcoding. `aria-hidden` — decorative only, the title text still +// carries the actual label, so this never becomes a second source of +// truth an assistive-tech user has to parse. import type { ComponentChildren } from 'preact'; import './Panel.css'; export function Panel({ title, + icon, actions, children, }: { title?: string; + icon?: string; actions?: ComponentChildren; children: ComponentChildren; }) { return (

- {title || actions ? ( + {title || icon || actions ? (
+ {icon ? ( + + ) : null} {title ?

{title}

: null} {actions ?
{actions}
: null}