diff --git a/docs/web-ui.md b/docs/web-ui.md index b8cb8f99..37513f7d 100644 --- a/docs/web-ui.md +++ b/docs/web-ui.md @@ -29,11 +29,6 @@ dashboard rather than how it's built, start at - **[CSS theme variables](web-ui/css-vars.md)** — the Catppuccin Mocha custom properties declared once in `base.css` and the rule that per-page stylesheets reference (never redeclare) them. -- **[swarm-ui design guide](web-ui/design-guide.md)** — visual - language, motion, theming, error-UX, and component-first principles - for the swarm-level Preact app specifically (not this doc's - dashboard/agent UIs). `/components` on a running swarm-ui is the - companion living demo of every primitive it references. ## Reading paths diff --git a/docs/web-ui/design-guide.md b/docs/web-ui/design-guide.md deleted file mode 100644 index e8610471..00000000 --- a/docs/web-ui/design-guide.md +++ /dev/null @@ -1,160 +0,0 @@ -# swarm-ui design guide - -Scope: **swarm-ui only** (the swarm-level Preact app — not the per-hive -dashboard, which has its own older visual language). This doc is the -*why*: the principles behind how swarm-ui looks and behaves, and the -concrete rules that follow from them. It deliberately doesn't show what -things look like — that's `ComponentsPage` (`/components`), the living, -always-current demo of every primitive in `src/ui/`. Code can't go stale -the way a doc's screenshots can, so treat `ComponentsPage` as the source -of truth for appearance and this doc as the source of truth for intent. -Colour variables specifically are `docs/web-ui/css-vars.md`'s job, not -repeated here. - -## Visual language - -- **Frosted / tinted glass** where it fits — translucency over flat - panels, not a hard rule for every surface. -- **Playful use of the multiple accent colours**, without tipping into - visual noise — the base16 palette has several accent slots - (`--purple`, `--cyan`, `--pink`, …); use more than one where it adds - distinction, not decoration for its own sake. -- **Whimsy** — small, delightful touches are welcome (the per-hive - dashboard's home-page matrix-rain background, `packages/dashboard/src/ - 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). -- **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 - swarm-ui, but the standard to avoid): the per-hive agent terminal's - model selector living in a three-dot overflow menu instead of next to - the thing that shows the current model. -- Loosely influenced by Material Design's current (Material You) - generation, mainly for shape/elevation ideas. Colour is dynamic too — - auto-derived shades (mixing, lighter/darker) are fair game, same as - Material's own approach — but every derived colour still traces back - to the base16/stylix contract below, never an independent source. - -## Motion - -**General rule, not case-by-case: every non-essential CSS animation -gates on `prefers-reduced-motion` and pauses when its tab/section is -hidden.** The dashboard's matrix-rain background (`packages/dashboard/ -src/home.js`/`.css`) is the existing reference implementation of this -pattern — genuinely does both today, confirmed by reading it — even -though it lives in the dashboard package rather than swarm-ui; every -future swarm-ui animation follows the same pattern, not just whimsy -pieces. - -Prefer CSS-driven animation over JS-driven where possible, and avoid -jarring content swaps (layout shift, hard cuts) where a transition can -smooth them instead. - -## Theming - -The mechanical contract (base16 slots, semantic vars, what a page's CSS -is and isn't allowed to reference) lives in `docs/web-ui/css-vars.md` — -read that for the how. This section is the *policy* layered on top: - -- **User-theming compatible by construction.** The whole point of the - base16/`colors.css` swap contract is that a user's own theme (stylix - today) takes over with zero swarm-ui code changes. Don't build - anything that assumes a specific palette's exact colours (contrast - ratios, "this accent is always purple") beyond what the semantic var - names promise. -- **stylix wins outright when it's active, no in-between state.** When - an operator has stylix supplying swarm-ui's palette, that palette is - authoritative — swarm-ui's own light/dark preference (below) doesn't - override it. This is a deliberate simplification, not a limitation to - fix: a stylix-using operator has already made their choice. -- **Light theme is accessibility, not a cosmetic extra.** Some people - need light for contrast/low-vision reasons, others need dark for - photosensitivity — there's no universally-correct default. The OS - preference (`prefers-color-scheme`) drives the default, with an - explicit user override available, same shape as motion above. - -## Data freshness & refresh - -The governing question for anything that shows time-sensitive data: -**would a user returning to this tab expect current data?** If yes, it -needs a refresh story; a value that's silently gone stale with no way to -tell is worse than one that's visibly stale. - -- **Relative-time labels must actually tick.** A label like "fresh (5s - ago)" is computed from a stored timestamp and re-renders itself on an - interval — never a value frozen at fetch time that quietly goes stale - while still reading as current. Pauses while its tab is hidden. -- **Pages that poll get a refresh-interval control, not silent - staleness.** A small, Grafana-like "refresh every: off / 10s / 30s / - 1m / …" control the operator sets per page, paused while the tab is - backgrounded and resumed on foreground. -- **A refresh must never clobber input the operator is mid-edit on.** - Any polling component's contract needs to make this the caller's - problem to opt out of correctly, not something the next adopter - discovers by shipping a bug. - -## Errors - -**`ApiErrorPanel` + the RFC 9457 `ProblemDetails` shape it renders is -the canonical error surface** for every API failure in swarm-ui, not -just its original callers — nobody should build a softer/quieter error -UI later. Concretely: full untruncated `detail`, a copy button, no -"something went wrong, try reloading." - -This follows from **power-user-first**, one of the standing principles: -swarm-ui instances are mostly self-hosted and operators are techies, so -errors should give them what they need to actually diagnose a problem -rather than a friendly wall. Power-user-first doesn't mean -newcomer-hostile — the UI should still be self-explanatory, warn or ask -for confirmation before a destructive/dangerous action, and offer -helpful hints — it just shouldn't get in the way of someone who already -knows what they're doing. - -## Empty states - -Graceful fallbacks, always — a table with zero rows should show -something that represents "no rows" (a real empty-state message), not -just bare column headers floating over nothing. - -## Layout & viewport - -- **swarm-ui adapts to screen size and fully supports touch** — this is - not a desktop-only app. Concrete floor: every interactive control from - the shared `ui/` kit (buttons, inputs, selects) carries a minimum - touch target (`2.75em` ≈ 44px, WCAG 2.5.5) by default, so this isn't - something each page has to remember. -- **Phone is a second-class citizen, not an unsupported one.** Things - must not *break* at phone width, but don't over-invest in phone - optimization beyond that. swarm-ui is installable as a PWA, so a - phone can check status or do basic interactions. -- **A narrow viewport isn't only a phone** — a tiling-window-manager - user with swarm-ui in a narrow tile hits the same layout constraints a - phone does. Design for the constraint (narrow viewport), not the - device. - -## Component-first design - -Build the `src/ui/` primitive before or alongside the first real page -that needs it, not after it's been styled inline and left for later — -a page reaching for a component that's already there has ready-made -blocks to build with, instead of the next contributor duplicating -ad-hoc styling that someone then has to hunt down and consolidate. -`Panel`/`StatusChip`/`Table`/`TextField`/`SelectField`/`Button` are the -primitives that exist; `/components` always has the current, complete -list — this doc won't try to keep a duplicate inventory in sync. - -**Every new `ui/` component gets a demo section on `/components` the -same day it lands** — no primitive without a place to see it. One -deliberate exception exists today: `FormField`, the internal label+ -control wrapper `TextField`/`SelectField` share, isn't itself a -primitive a page reaches for directly, so it has no demo of its own — -a considered exception, not an oversight this rule missed. - -## Attention - -"Attention-optimized" here means the system should lead the operator's -attention to where it actually matters (an error, a state change worth -noticing) — not attention-optimized in the engagement/growth sense of -maximizing time-on-page.