Skip to content

Dockyard — Frontend Design System & UI Conventions ​

Status: Charter (established at scaffold time; the component inventory in §3 is filled by master-plan Phase 10a).

This document exists from the start of the project on purpose. The sibling project Harbor did not establish a design system up front: pages were built ad hoc, components and patterns were duplicated across the Console, and a costly remediation was needed later to retrofit a shared foundation. Dockyard does not repeat that mistake — the design system is a day-one artifact, and composing it is mandatory repo hygiene (AGENTS.md §20).


1. Why this exists ​

Dockyard ships several frontend surfaces. Without one shared foundation they would drift into duplicated tables, divergent loading states, inconsistent spacing, and parallel data-fetching patterns. One design system keeps every Dockyard surface coherent and keeps the cost of a new page low.

2. Scope — the surfaces this governs ​

SurfaceWhatPhase
Template App UIsThe Svelte UIs of the analytics-widgets, approval-flows, inspector templates24–26
The inspectorDockyard's local test/debug surface22–23
The bridge shell libraryweb/bridge/ — the ui/ postMessage layer (non-visual, but consumes tokens)11
The docs siteThe published GitHub Pages technical docs29
The multi-server consolePost-V1 — must build on this same systemRFC §19

3. The shared component inventory (web/ui/) ​

Shared Svelte components live in web/ui/ and are the only source of these building blocks — pages compose them, never re-implement them. Phase 10a delivered the inventory below (plain Svelte 5, typed props, token-driven, keyboard-accessible with the primary focus ring); docs/design/design-spec.md §3 is its concrete spec.

  • Shell & layout
    • AppShell — the outer frame: header / optional rail / main / footer slots.
    • PageHeader — page title + subtitle, with lead, status, and actions slots.
    • DetailRail — the right-hand rail container; stacked or tabbed RailCards.
    • RailCard — one titled, optionally collapsible card within a rail.
    • ActionBar — a layout row that aligns slotted buttons/controls.
    • ConnectionFooter — the status bar: connection, label, transport, live dot.
  • Data display
    • DataTable — columns, rows, client-side sort, optional pagination; composes Pagination and PageState.
    • Pagination — page controls for a DataTable (or standalone).
    • FilterBar — the search input + filter chips; the one place a search lives.
    • MetricCard — one KPI: label, value, optional delta/trend.
    • Sparkline — a small, token-driven, pure-SVG inline chart (composable inside MetricCard, the inspector, the docs site, and templates). Phase 24, decision D-127.
    • FieldDiff — a labelled, accessible input that pairs an original (current) value with an editable proposed value, with a "differs" badge and a screen-reader-announced cue when the two diverge. Renders five native types — string / number / boolean / enum / text — and falls back to a plain text input for an unknown type (forward-compatibility). The approval-flows template's propose_with_edits App composes one per field; the primitive is reusable in any future review / commit / human-in-the-loop UX. Phase 25.
    • StatusChip — a small semantic state pill (ok / warn / error / info / neutral).
    • Timeline — an ordered sequence of timestamped events.
    • JsonInspector — a collapsible, lightly highlighted, read-only JSON tree.
    • CodeBlock — a read-only monospace block with copy.
  • State — the four-state PageState family
    • PageState — wraps an async region; routes to exactly one of loading / empty / error / ready (see §4).
    • LoadingState, EmptyState, ErrorState, PermissionState — the individual panels; the empty and error panels carry real copy + a working action.

Pattern blocks a single template needs (e.g. an ApprovalPanel) are deliberately not in the V1 web/ui set. They land with their own template phase (24–26), composed from the primitives above — docs/design/design-spec.md §3.4 is the authority.

A genuinely new shared component lands in web/ui/ and in this section in the same PR. A component that is truly page-specific stays page-local but is composed inside web/ui/ primitives — it never reinvents one.

4. The four-state page rule ​

Every page (and every async region) routes its state through the shared PageState, which has exactly four states:

text
loading → ready
        → empty    (no data — real copy + a refresh/retry affordance)
        → error    (a working Retry, not a dead end)

Empty and error states are mandatory, not optional polish. An empty table with no copy, or an error with no retry, is a defect — dockyard validate's quality gate (RFC §9.4) and AGENTS.md §14 enforce this.

5. Design tokens ​

Colour, spacing, typography, radius, and elevation come from a single token set (delivered by Phase 10a). Components and pages reference tokens — never ad-hoc hex values or magic spacing numbers. The tokens also feed the host-themeable CSS variables an MCP App receives via hostContext.styles.variables (RFC §7.3).

6. The spec → mockup → build process ​

UI is designed before it is coded, so look & feel is locked up front:

  1. Spec. The UI-bearing phase plan carries a page spec — the page's purpose, regions, data, and states.
  2. Mockup. A visual mockup is produced and approved before implementation. Mockups live under docs/design/ (e.g. docs/design/mockups/).
  3. Build. Only then is the page implemented, composing web/ui/.

The Dockyard logo and the brand are also Dockyard design artifacts and live here.

7. The rule (binding) ​

  • Compose web/ui/; never duplicate a component or fork a pattern page-locally.
  • A new shared component ⇒ web/ui/ + this document, same PR.
  • Every page: the four-state PageState, empty + error included.
  • Tokens are the single source of visual truth.
  • UI-bearing phases follow spec → mockup → build (§6).

See AGENTS.md §20.

Apache-2.0 licensed — see LICENSE.