Replace the first-run placeholder seed with an onboarding canvas

This commit is contained in:
2026-06-09 14:03:47 +03:00
parent 7d247e8d2c
commit 81f563a3e7
16 changed files with 852 additions and 93 deletions
@@ -265,15 +265,38 @@ default Modified/desc); search is **not** persisted (it's a transient view narro
_(Consulted via /council → WAI-ARIA APG disclosure + menu-button, NN/g #6. This bullet is the
contract; cite it, not the source.)_
**Resolved — the two library empty states (Carbon's two types).** The snippet list owes
**two distinct empty states** (Carbon empty-state types), chosen by cause and never conflated:
(a) a **genuinely empty library** (first run) is **positive and concise and guides to the
Create action** — title "No snippets yet" + a one-line nudge to create one; (b) **no search
matches** says "No snippets match your search" + a hint to try a different term. Both are
plain-language and minimal (NN/g aesthetic-and-minimalist; §3 empty ≠ error). The library
derives **which** to show from whether a query is active, not from the raw count alone.
_(Consulted via /council → Carbon empty-state, NN/g. This bullet is the contract; cite it,
not the source.)_
**Resolved — the empty-library onboarding canvas (and the list's single empty state).** The
snippet list owes **one empty state**: **no search matches** — "No snippets match your search"
- a hint to try a different term. There is **no separate "empty library" list state**, because
a genuinely empty library never shows the list at all: rather than seeding a placeholder
snippet (the old behavior), the workspace replaces the **entire pane chrome — toggle strip,
library list, editor, and preview — with a full-width onboarding canvas** (spec §02 →
First-Run & Empty Workspace): with no snippets, the library controls and pane toggles have
nothing to act on. (So the list's own empty copy is reached only mid-search, never on a cold
start.) The canvas is a welcome, a primary "Create your first
snippet", and a gallery of example snippets; leaving it (creating the first snippet) lays the
panes out at a default **25·25·50** split via `PanesStore.applyOnboardingSplit` so the first
chart opens with a generous preview. Each card
**renders live through the shared `chart-renderer`** (no parallel embed path; each card owns
its `RenderHandle` and finalizes on unmount — the per-card nodes are independent, so they
don't touch `LivePreview`'s single-host serialization), and adds as an ordinary snippet.
Empty stays calm and positive, never an error (NN/g aesthetic-and-minimalist; §3 empty ≠
error). Council resolutions for the canvas: (1) **each card preview is decorative**
`aria-hidden`, skipped by screen readers (Carbon empty-states a11y / WCAG decorative
images); the card **name + one-line description + a uniquely-labelled `Add` button** ("Add
Bar chart", APG button) carry the meaning, so AT users reach no dead end. (2) The canvas is
the **single empty surface** — because it replaces the library list outright, there is no
competing "No snippets yet" status elsewhere to keep in sync. Its heading **owns the app
identity** ("Welcome to Astrolabe") and it carries the only Create nudge, so the empty-state
message lives in exactly one place (Carbon "keep words to a minimum"; no duplication).
(3) The **primary action dominates** (accent "Create your first snippet" first; the example
gallery is framed as a secondary "Or start from an example") — Carbon sanctions starter
content as an in-depth first-use empty state only when one action stays primary. (4)
**Domain vocabulary stands**: "Vega-Lite", "JSON", "snippet" are kept despite Carbon's
avoid-jargon rule, because SOUL #2 (Vega-Lite Native) makes them the user's real language —
a deliberate divergence. _(Consulted via /council → Carbon empty-state + content, GOV.UK
headings, WAI-ARIA APG button, NN/g. This bullet is the contract; cite it, not the source.)_
**Resolved — one live region per shared message.** When the same error feeds two surfaces
(the §1 "one producer, two subscribers" case — render errors via `PreviewStore`), exactly