docs: rework design guide per mara's review
Addresses all 7 line comments from her REQUEST_CHANGES review: - drop the issue-#3444 history pointer and any issue-number tracking refs throughout (a design guide states expectations, it isn't a change log or a status report) - stop naming specific rejected technical solutions (SSE/WS) for a design constraint — state the chosen shape only - flip the component-first heuristic: build the primitive first/ alongside its first real caller, not after — the point is giving the next thing built ready-made blocks, not lagging behind usage - drop the 'Open questions' section entirely — that's what the issue thread is for, not a doc - stop leading Visual language with 'basis: Material Design' and then immediately carving out big exceptions — lead with what we actually want, mention Material as a minor closing influence instead - drop 'future work'/timeline framing everywhere (motion override, PWA-as-future-slice, 'not shipped yet' theming caveats) — state the target design as the expectation, not its current build status - reworded the stylix-wins theming bullet to drop 'build time', which reads wrong from a frontend dev's perspective (stylix supplies the palette separately, it isn't decided by the frontend's own build)
This commit is contained in:
parent
a5864c0fde
commit
61b7bb4b4d
1 changed files with 41 additions and 78 deletions
|
|
@ -11,16 +11,8 @@ 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
|
Colour variables specifically are `docs/web-ui/css-vars.md`'s job, not
|
||||||
repeated here.
|
repeated here.
|
||||||
|
|
||||||
Distilled from the design-language discussion in issue #3444 — read that
|
|
||||||
thread for the full reasoning behind any rule below that needs more
|
|
||||||
context than fits here.
|
|
||||||
|
|
||||||
## Visual language
|
## Visual language
|
||||||
|
|
||||||
- **Basis: Material Design, the Material You generation** (Android's
|
|
||||||
current design language) — but swarm-ui strays fairly far from its
|
|
||||||
theming approach; base16/stylix (below) is the actual colour contract,
|
|
||||||
not Material's dynamic-colour system.
|
|
||||||
- **Frosted / tinted glass** where it fits — translucency over flat
|
- **Frosted / tinted glass** where it fits — translucency over flat
|
||||||
panels, not a hard rule for every surface.
|
panels, not a hard rule for every surface.
|
||||||
- **Playful use of the multiple accent colours**, without tipping into
|
- **Playful use of the multiple accent colours**, without tipping into
|
||||||
|
|
@ -39,6 +31,10 @@ context than fits here.
|
||||||
swarm-ui, but the standard to avoid): the per-hive agent terminal's
|
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
|
model selector living in a three-dot overflow menu instead of next to
|
||||||
the thing that shows the current model.
|
the thing that shows the current model.
|
||||||
|
- Loosely influenced by Material Design's current (Material You)
|
||||||
|
generation, mainly for shape/elevation ideas — colour theming is
|
||||||
|
governed entirely by the base16/stylix contract below, not Material's
|
||||||
|
dynamic-colour system.
|
||||||
|
|
||||||
## Motion
|
## Motion
|
||||||
|
|
||||||
|
|
@ -51,11 +47,6 @@ though it lives in the dashboard package rather than swarm-ui; every
|
||||||
future swarm-ui animation follows the same pattern, not just whimsy
|
future swarm-ui animation follows the same pattern, not just whimsy
|
||||||
pieces.
|
pieces.
|
||||||
|
|
||||||
An in-app override (independent of the OS-level media query, for
|
|
||||||
someone who wants motion on despite a system-wide reduced-motion
|
|
||||||
setting, or vice versa) is tracked separately — see #3456, which needs
|
|
||||||
the client-settings surface from #3453 first.
|
|
||||||
|
|
||||||
Prefer CSS-driven animation over JS-driven where possible, and avoid
|
Prefer CSS-driven animation over JS-driven where possible, and avoid
|
||||||
jarring content swaps (layout shift, hard cuts) where a transition can
|
jarring content swaps (layout shift, hard cuts) where a transition can
|
||||||
smooth them instead.
|
smooth them instead.
|
||||||
|
|
@ -68,24 +59,20 @@ read that for the how. This section is the *policy* layered on top:
|
||||||
|
|
||||||
- **User-theming compatible by construction.** The whole point of the
|
- **User-theming compatible by construction.** The whole point of the
|
||||||
base16/`colors.css` swap contract is that a user's own theme (stylix
|
base16/`colors.css` swap contract is that a user's own theme (stylix
|
||||||
today) takes over with zero swarm-ui code changes — a generator
|
today) takes over with zero swarm-ui code changes. Don't build
|
||||||
replaces exactly one file. Don't build anything that assumes a
|
anything that assumes a specific palette's exact colours (contrast
|
||||||
specific palette's exact colours (contrast ratios, "this accent is
|
ratios, "this accent is always purple") beyond what the semantic var
|
||||||
always purple") beyond what the semantic var names promise.
|
names promise.
|
||||||
- **stylix wins outright when it's active, no in-between state.**
|
- **stylix wins outright when it's active, no in-between state.** When
|
||||||
`nix/host-modules/hive-c0re/theme.nix` decides at *build time* whether
|
an operator has stylix supplying swarm-ui's palette, that palette is
|
||||||
a hive is stylix-themed; when it is, that palette is authoritative —
|
authoritative — swarm-ui's own light/dark preference (below) doesn't
|
||||||
swarm-ui's own light/dark logic (below) doesn't run at all rather than
|
override it. This is a deliberate simplification, not a limitation to
|
||||||
trying to negotiate with it. This is a deliberate simplification, not
|
fix: a stylix-using operator has already made their choice.
|
||||||
a limitation to fix: a stylix-using operator has already made their
|
- **Light theme is accessibility, not a cosmetic extra.** Some people
|
||||||
choice.
|
need light for contrast/low-vision reasons, others need dark for
|
||||||
- **Light theme is accessibility, not a cosmetic extra** — confirmed
|
photosensitivity — there's no universally-correct default. The OS
|
||||||
position on #3444/#3452: some people need light for contrast/low-vision
|
preference (`prefers-color-scheme`) drives the default, with an
|
||||||
reasons, others need dark for photosensitivity, so "OS preference by
|
explicit user override available, same shape as motion above.
|
||||||
default + explicit override" is the right shape, same as motion above.
|
|
||||||
**Not shipped yet** — tracked as #3452 (light palette itself), #3453
|
|
||||||
(the client-settings surface an override setting needs), #3454 (the
|
|
||||||
override setting). Until #3452 lands, swarm-ui is dark-only.
|
|
||||||
|
|
||||||
## Data freshness & refresh
|
## Data freshness & refresh
|
||||||
|
|
||||||
|
|
@ -94,22 +81,18 @@ The governing question for anything that shows time-sensitive data:
|
||||||
needs a refresh story; a value that's silently gone stale with no way to
|
needs a refresh story; a value that's silently gone stale with no way to
|
||||||
tell is worse than one that's visibly stale.
|
tell is worse than one that's visibly stale.
|
||||||
|
|
||||||
- **Relative-time labels must actually tick.** A `StatusChip`-style
|
- **Relative-time labels must actually tick.** A label like "fresh (5s
|
||||||
"fresh (5s ago)" computed once at fetch and never updated again reads
|
ago)" is computed from a stored timestamp and re-renders itself on an
|
||||||
as current when it isn't. Tracked as #3445 (`RelativeTime` component:
|
interval — never a value frozen at fetch time that quietly goes stale
|
||||||
takes a UTC datetime, not a precomputed age, and re-renders itself on
|
while still reading as current. Pauses while its tab is hidden.
|
||||||
an internal interval; pauses while its tab is hidden).
|
|
||||||
- **Pages that poll get a refresh-interval control, not silent
|
- **Pages that poll get a refresh-interval control, not silent
|
||||||
staleness and not push.** SSE/WebSocket push was considered and
|
staleness.** A small, Grafana-like "refresh every: off / 10s / 30s /
|
||||||
rejected for now — "overkill, leads to the same mess we have in
|
1m / …" control the operator sets per page, paused while the tab is
|
||||||
core." Instead: a small, Grafana-like "refresh every: off / 10s / 30s
|
backgrounded and resumed on foreground.
|
||||||
/ 1m / …" control the operator sets per page, paused while the tab is
|
|
||||||
backgrounded and resumed on foreground. Tracked as #3446
|
|
||||||
(`OverviewPage`'s hive-status roster is the first real caller).
|
|
||||||
- **A refresh must never clobber input the operator is mid-edit on.**
|
- **A refresh must never clobber input the operator is mid-edit on.**
|
||||||
Any future polling component's contract needs to make this the
|
Any polling component's contract needs to make this the caller's
|
||||||
caller's problem to opt out of correctly, not something the next
|
problem to opt out of correctly, not something the next adopter
|
||||||
adopter discovers by shipping a bug.
|
discovers by shipping a bug.
|
||||||
|
|
||||||
## Errors
|
## Errors
|
||||||
|
|
||||||
|
|
@ -140,13 +123,11 @@ just bare column headers floating over nothing.
|
||||||
not a desktop-only app. Concrete floor: every interactive control from
|
not a desktop-only app. Concrete floor: every interactive control from
|
||||||
the shared `ui/` kit (buttons, inputs, selects) carries a minimum
|
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
|
touch target (`2.75em` ≈ 44px, WCAG 2.5.5) by default, so this isn't
|
||||||
something each page has to remember. Tracked follow-through:
|
something each page has to remember.
|
||||||
#3447 (page-level layout — nav wrap, no fixed-width assumptions).
|
- **Phone is a second-class citizen, not an unsupported one.** Things
|
||||||
- **Phone is a second-class citizen for now, not an unsupported one.**
|
must not *break* at phone width, but don't over-invest in phone
|
||||||
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
|
||||||
optimization beyond that yet. A PWA manifest (installable, basic
|
phone can check status or do basic interactions.
|
||||||
status-check/interaction use case) is wanted eventually but is its own
|
|
||||||
future slice, not implied by "supports touch" today.
|
|
||||||
- **A narrow viewport isn't only a phone** — a tiling-window-manager
|
- **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
|
user with swarm-ui in a narrow tile hits the same layout constraints a
|
||||||
phone does. Design for the constraint (narrow viewport), not the
|
phone does. Design for the constraint (narrow viewport), not the
|
||||||
|
|
@ -154,27 +135,21 @@ just bare column headers floating over nothing.
|
||||||
|
|
||||||
## Component-first design
|
## Component-first design
|
||||||
|
|
||||||
When something needs a table, a form field, a button — build (or adopt)
|
Build the `src/ui/` primitive before or alongside the first real page
|
||||||
a `src/ui/` primitive that enforces consistent theming and behaviour,
|
that needs it, not after it's been styled inline and left for later —
|
||||||
rather than styling it inline on the page that happens to need it first.
|
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
|
`Panel`/`StatusChip`/`Table`/`TextField`/`SelectField`/`Button` are the
|
||||||
primitives that exist as of this writing, each with its own
|
primitives that exist; `/components` always has the current, complete
|
||||||
`/components` demo; `/components` always has the current, complete list
|
list — this doc won't try to keep a duplicate inventory in sync.
|
||||||
— this doc won't try to keep a duplicate inventory in sync.
|
|
||||||
|
|
||||||
Default heuristic for *when* to promote page-scoped styling into a
|
|
||||||
shared primitive: the day a second real page needs the same thing, not
|
|
||||||
speculatively ahead of one. (Exception: when a peer explicitly asks for
|
|
||||||
a primitive ahead of a second caller, as happened with the form kit —
|
|
||||||
that's a judgement call each time, not a rule change.)
|
|
||||||
|
|
||||||
**Every new `ui/` component gets a demo section on `/components` the
|
**Every new `ui/` component gets a demo section on `/components` the
|
||||||
same day it lands** — no primitive without a place to see it. One
|
same day it lands** — no primitive without a place to see it. One
|
||||||
deliberate exception exists today: `FormField`, the internal label+
|
deliberate exception exists today: `FormField`, the internal label+
|
||||||
control wrapper `TextField`/`SelectField` share, isn't itself a
|
control wrapper `TextField`/`SelectField` share, isn't itself a
|
||||||
primitive a page reaches for directly, so it has no demo of its own —
|
primitive a page reaches for directly, so it has no demo of its own —
|
||||||
that's a real, considered exception (see its own doc comment), not an
|
a considered exception, not an oversight this rule missed.
|
||||||
oversight this rule missed.
|
|
||||||
|
|
||||||
## Attention
|
## Attention
|
||||||
|
|
||||||
|
|
@ -182,15 +157,3 @@ oversight this rule missed.
|
||||||
attention to where it actually matters (an error, a state change worth
|
attention to where it actually matters (an error, a state change worth
|
||||||
noticing) — not attention-optimized in the engagement/growth sense of
|
noticing) — not attention-optimized in the engagement/growth sense of
|
||||||
maximizing time-on-page.
|
maximizing time-on-page.
|
||||||
|
|
||||||
## Open questions
|
|
||||||
|
|
||||||
Tracked separately rather than asserted here as settled:
|
|
||||||
|
|
||||||
| Question | Tracked in |
|
|
||||||
| --- | --- |
|
|
||||||
| Light theme (palette + `prefers-color-scheme` default) | #3452 |
|
|
||||||
| Client-local settings surface (page + storage) | #3453 |
|
|
||||||
| Theme override setting | #3454 |
|
|
||||||
| Reduced-motion override setting | #3456 |
|
|
||||||
| PWA manifest / installable phone experience | not yet filed — mentioned in #3444, no concrete scope agreed |
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue