mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Chart builder: discoverable entry points — Build Chart door, dataset picker, no-datasets state
This commit is contained in:
@@ -362,6 +362,23 @@ first-use empty state only when one action stays primary. (4) **Domain vocabular
|
||||
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 — the creation surface is builder-forward, Monaco-intact (3D).** The guided
|
||||
path must be visible where the intent to make a chart forms: the library's creation surface
|
||||
is a **primary "Build Chart"** (opens the Chart Builder) beside a **ghost "New JSON
|
||||
snippet"** (the old instant create, unchanged) — two plain buttons with clear hierarchy, no
|
||||
split/menu-button widget (two static choices don't earn an ARIA menu). The expert path
|
||||
stays one visible click away, never hidden (NN/g #6 recognition over recall, #7 flexibility/
|
||||
efficiency; Carbon: one primary per surface, a tertiary for the secondary CTA). The builder
|
||||
itself opens **without a preselected dataset** (it picks the most recently modified; a
|
||||
header **Dataset picker** switches without leaving), and with an empty dataset library it
|
||||
shows a **no-datasets state** per the Carbon no-data pattern: what the space does + one
|
||||
primary next step ("Add a dataset" → the Datasets create form) — never a dead end. The
|
||||
dataset-row "Build Chart" stays as the contextual shortcut; the onboarding canvas gains the
|
||||
data-first door ("Build a chart from your data") beside its primary. _(Consulted via
|
||||
/council → NN/g #6/#7, Carbon empty-states; recorded in
|
||||
docs/chart-builder-enhancement-scope.md §3 · 3D. 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
|
||||
**one** subscriber is the live region (`role="alert"` on the editor, where focus is); the
|
||||
|
||||
@@ -25,6 +25,34 @@
|
||||
Newest first. The at-a-glance build-order tracker is §4; per-item detail is §3. This log is
|
||||
the quick "where are we" — read it first.
|
||||
|
||||
- **2026-06-12 (3D)** — **entry points & discoverability shipped. Up next: 3A (the
|
||||
front door now has somewhere to be found).**
|
||||
- **Library creation surface forked:** primary **Build Chart** (accent, takes the
|
||||
slack) + ghost **New JSON snippet** (the old instant create) — two plain buttons,
|
||||
no menu widget; labels collapse in two stages as the pane narrows (the long ghost
|
||||
label first). New `chart` icon (rising columns, pane-icon rect style).
|
||||
- **The builder opens un-targeted:** `init(null)` picks the most recently modified
|
||||
dataset; a **Dataset picker** heads the config pane (replaces the "Building from"
|
||||
line). Switching with an untouched config re-derives smart defaults; a built-on
|
||||
config is **rebased** via the new core `rebaseBuilderConfig` (mark/title/size/
|
||||
sort/stack/calculates/expression-filters kept; encodings + predicate filters bound
|
||||
to columns the new dataset lacks shed; same-schema switch keeps everything).
|
||||
- **No-datasets state** (Carbon no-data): what the builder does + primary "Add a
|
||||
dataset" → Datasets create form. A defensive "Choose a dataset" chooser covers the
|
||||
datasets-exist-but-none-loaded case. New `#build` hash serializes the
|
||||
no-dataset builder (spec §01E table).
|
||||
- **Onboarding gains the data-first door** ("Build a chart from your data", ghost
|
||||
beside the primary; applies the workspace split up front since the builder can
|
||||
create the first snippet). Dataset-row "Build Chart" unchanged (the contextual
|
||||
shortcut).
|
||||
- **Contract updated:** spec §02 (creation surface, onboarding), §06 (Opening
|
||||
rewritten: doors, dataset picker, no-datasets state), §01E (`#build`); council
|
||||
resolutions recorded in `architecture/10` §5 ("builder-forward, Monaco-intact").
|
||||
- **Verified:** `typecheck` + `test` (873, +10: core rebase, store init(null)/
|
||||
switchDataset, url-hash `#build`, modal empty states) + `eslint` + prettier.
|
||||
**Owed:** a visual pass on the forked creation surface + builder picker/empty
|
||||
states (user-driven, batched with the 2B visual debt).
|
||||
|
||||
- **2026-06-12 (polish batch)** — **the 2B visual-pass findings fixed; the parked council
|
||||
batch resolved and applied; two capability gaps closed.**
|
||||
- **Aggregation for any field type.** `validAggregateOps` replaces the quantitative-only
|
||||
@@ -400,7 +428,7 @@ builder only creates) and the disabled-button affordance (disabled-with-reason v
|
||||
park in `ux-second-pass.md` if non-obvious). _Spec impact: §02 (library row action) + §06
|
||||
(hydration + the strict gate)._
|
||||
|
||||
**3D · Entry points & discoverability** — _decided 2026-06-12, council-reviewed; lands with or just before 3A_
|
||||
**3D · Entry points & discoverability** — _done 2026-06-12 (council-reviewed; see status log); 3A opens onto it next_
|
||||
Today the builder has **one entry, two levels deep**: Datasets modal → per-dataset "Build
|
||||
Chart" (`DatasetsModal.tsx`) — the data model's shape ("charts come from datasets"), not
|
||||
the user's intent ("I want to make a chart"). Meanwhile the library's pinned primary
|
||||
@@ -423,9 +451,11 @@ The decided shape:
|
||||
ghost/tertiary **New JSON snippet** (today's instant create, unchanged). Two plain
|
||||
buttons with clear hierarchy — no split/menu-button widget (two static choices don't
|
||||
earn an ARIA menu).
|
||||
2. **Dataset picker inside the builder** (header select, default = most recently used), so
|
||||
the builder opens without a preselected dataset. Build-time detail: switching datasets
|
||||
mid-build re-derives smart defaults vs. prunes incompatible encodings — decide then.
|
||||
2. **Dataset picker inside the builder** (header select, default = most recently
|
||||
modified), so the builder opens without a preselected dataset. Build-time decision
|
||||
taken: switching with an **untouched** opening config re-derives fresh smart defaults;
|
||||
switching a **built-on** config rebases it (`rebaseBuilderConfig` — chart-level intent
|
||||
kept, bindings to missing columns shed; a same-schema dataset keeps everything).
|
||||
Useful beyond 3D (switch data without leaving the builder).
|
||||
3. **No-datasets empty state** in the builder, per the Carbon no-data pattern: what the
|
||||
builder does + one primary action ("Add a dataset" → Datasets modal). No dead end.
|
||||
@@ -526,8 +556,8 @@ Phase 1 1A actionable hints ✓ done
|
||||
1E expr-validate ✓ done (syntax + unknown-field; completion popup deferred)
|
||||
Phase 2 2A value-or-field channels (Property model) ✓ done
|
||||
2B field shelf + in-place type cycling ✓ done (field-first + on-chart shelves)
|
||||
Phase 3 3D entry points & discoverability ← next, with/just before 3A (its prerequisite)
|
||||
3A intent-first front door (Tier C) ← built on 2B; the defining feature
|
||||
Phase 3 3D entry points & discoverability ✓ done (2026-06-12)
|
||||
3A intent-first front door (Tier C) ← next; built on 2B; the defining feature
|
||||
3B starter examples
|
||||
3C open in builder (strict hydration) ← added 2026-06-11; pairs with 3B
|
||||
Phase 4 (gated) theta/facets/styling-overrides/undo/lookup — decide after Phase 3
|
||||
|
||||
@@ -82,13 +82,16 @@ The app reflects its current location in the URL hash so that reloading restores
|
||||
|
||||
States and their hash forms:
|
||||
|
||||
| State | Hash |
|
||||
| --------------------------- | ------------------------------ |
|
||||
| A selected snippet | `#snippet-<id>` |
|
||||
| Datasets manager (list) | `#datasets` |
|
||||
| A specific dataset | `#datasets/dataset-<id>` |
|
||||
| New-dataset form | `#datasets/new` |
|
||||
| Chart Builder for a dataset | `#datasets/dataset-<id>/build` |
|
||||
| State | Hash |
|
||||
| ------------------------------ | ------------------------------ |
|
||||
| A selected snippet | `#snippet-<id>` |
|
||||
| Datasets manager (list) | `#datasets` |
|
||||
| A specific dataset | `#datasets/dataset-<id>` |
|
||||
| New-dataset form | `#datasets/new` |
|
||||
| Chart Builder for a dataset | `#datasets/dataset-<id>/build` |
|
||||
| Chart Builder, no dataset open | `#build` |
|
||||
|
||||
`#build` is the Chart Builder opened with an empty dataset library (its no-datasets state). When datasets exist, an un-targeted builder open immediately lands on one (see _Chart Builder → Opening_), so the URL shows the dataset form instead.
|
||||
|
||||
Behavior:
|
||||
|
||||
|
||||
@@ -4,10 +4,14 @@ The Snippet Library is the left pane and the primary entry point to the app. A *
|
||||
|
||||
## The List
|
||||
|
||||
The list shows every saved snippet and is always visible. A persistent "Create New Snippet" affordance sits at the top of the list, above all snippets, so the user can always start a new snippet regardless of scroll position.
|
||||
The list shows every saved snippet and is always visible. A persistent **creation surface** sits at the top of the list, above all snippets, so the user can always start a new chart regardless of scroll position. It offers the two ways in with a clear hierarchy:
|
||||
|
||||
- **Build Chart** — the primary action; opens the **Chart Builder** (see _Chart Builder_), the guided no-JSON path. The builder opens on the most recently modified dataset (or its no-datasets state when the library has none) — it is not gated on first selecting a dataset.
|
||||
- **New JSON snippet** — a ghost/tertiary action beside it; creates and selects a new snippet directly in the editor (see _Snippet Operations_ → Create New), the expert path — always visible, one click, never hidden behind the guided one.
|
||||
|
||||
When the library pane is dragged narrow, the buttons shed their labels (the long ghost label first) and keep their icons and accessible names.
|
||||
|
||||
- The list shows all snippets, ordered newest-modified first by default (see _Sort_).
|
||||
- A "Create New Snippet" item is pinned at the top of the list; activating it creates and selects a new snippet (see _Snippet Operations_).
|
||||
- Selecting a snippet makes it the **active snippet**: it loads into the editor and preview, becomes highlighted in the list, and the URL updates to reflect the selected snippet so the state is shareable and survives a page reload (see _Application Shell & Navigation_).
|
||||
- Exactly one snippet is active at a time.
|
||||
- When no snippets match the current search, the list shows an empty-state message ("No snippets match your search", with a hint to try a different term). This is the list's only empty state: a genuinely empty library never shows the list at all (see next).
|
||||
@@ -17,8 +21,9 @@ The list shows every saved snippet and is always visible. A persistent "Create N
|
||||
|
||||
When the library is empty — on first run, or after the user deletes their last snippet — the app does **not** seed placeholder content. Instead the **onboarding canvas takes the full workspace**, replacing the pane chrome (the pane toggle strip, the library list, the editor, and the preview): with no snippets, the library's create/search/sort/storage controls and the pane toggles have nothing to act on, so the welcome gets the whole width. The user starts from a deliberate choice rather than dropped into the middle of an unfamiliar spec.
|
||||
|
||||
- The canvas briefly identifies what Astrolabe is, then offers two ways to begin.
|
||||
- The canvas briefly identifies what Astrolabe is, then offers the ways to begin.
|
||||
- **Create your first snippet** — the primary action; starts a new snippet from the sample bar-chart template and opens it in the editor (identical to _Create New_ under _Snippet Operations_).
|
||||
- **Build a chart from your data** — the data-first door beside the primary; opens the **Chart Builder** over the canvas. With no datasets yet, the builder's no-datasets state explains itself and leads to "Add a dataset" (see _Chart Builder → Opening_) — the path never dead-ends. Opening the builder also lays the workspace out at the default split below, since creating from the builder leaves the canvas directly.
|
||||
- An **example gallery** of a few simple snippets showcasing distinct Vega-Lite capabilities (e.g. a bar chart, a time-series line, a scatter plot, a stacked area, a donut, a binned histogram). Each example shows a **live preview** of the chart and a one-line description.
|
||||
- **Add** on an example creates it as an ordinary snippet and makes it active (opening it in the editor).
|
||||
- **Add all** creates the whole set at once and makes one of them active.
|
||||
|
||||
@@ -6,15 +6,30 @@ The Chart Builder is a visual, no-JSON way to compose a Vega-Lite chart from a s
|
||||
|
||||
## Opening
|
||||
|
||||
- Launched from a selected dataset in the _Datasets_ manager via that dataset's "build chart" action.
|
||||
- Opens as a modal dialog over the application; the URL reflects the dataset's "build" action so the open builder is shareable/restorable (see _Application Shell & Navigation_).
|
||||
- On open, the builder loads the selected dataset, displays its name, and pre-populates sensible defaults (see below). If no dataset is available, it shows a "No dataset loaded" message and offers no controls.
|
||||
The builder has several doors; the guided creation path must be visible where the intent to make a chart forms, not buried behind the data model.
|
||||
|
||||
- **The library's creation surface** — the primary **Build Chart** action (see _Snippet Library → The List_). Opens the builder with no preselected dataset; the builder picks the **most recently modified dataset** itself.
|
||||
- **The onboarding canvas** — the data-first "Build a chart from your data" door (see _Snippet Library → First-Run & Empty Workspace_).
|
||||
- **A dataset's "Build Chart" action** in the _Datasets_ manager — the contextual shortcut; opens the builder on that dataset.
|
||||
- Opens as a modal dialog over the application; the URL reflects the loaded dataset's "build" form (or `#build` while no dataset is loaded) so the open builder is shareable/restorable (see _Application Shell & Navigation_).
|
||||
- On open, the builder loads its dataset and pre-populates sensible defaults (see below).
|
||||
|
||||
### Dataset picker
|
||||
|
||||
Which data the chart builds from is itself a builder choice. A **Dataset** picker sits at the top of the configuration pane, showing the loaded dataset and letting the user switch to any other without leaving the builder.
|
||||
|
||||
- Switching while the configuration is still the untouched opening default **re-derives fresh smart defaults** for the new dataset.
|
||||
- Switching after the user has built on the configuration **rebases** it instead: chart-level intent survives (mark, title/subtitle, explicit size, sort/stack, calculated fields, expression filters), while bindings to columns the new dataset lacks are shed (encodings cleared, predicate filters dropped). A same-schema dataset — the common switch — keeps everything.
|
||||
|
||||
### No datasets
|
||||
|
||||
With an empty dataset library the builder shows a **no-datasets state** instead of controls: it says what the builder does and offers one primary next step — **Add a dataset**, which opens the _Datasets_ manager on its create form. The guided path never dead-ends.
|
||||
|
||||
## Layout
|
||||
|
||||
A two-pane modal:
|
||||
|
||||
- **Left — configuration:** dataset name, a **Data** section (row filters, calculated fields, and a collapsible row preview — see _Data_ below), mark type selector, a **field shelf** (the dataset's columns, field-first), a **Marks** card (the Colour and Size encodings), and a "Create Snippet" action. Chart-level properties (title/subtitle, width/height) sit on the **preview side**, under the chart (see _Chart properties_).
|
||||
- **Left — configuration:** the dataset picker, a **Data** section (row filters, calculated fields, and a collapsible row preview — see _Data_ below), mark type selector, a **field shelf** (the dataset's columns, field-first), a **Marks** card (the Colour and Size encodings), and a "Create Snippet" action. Chart-level properties (title/subtitle, width/height) sit on the **preview side**, under the chart (see _Chart properties_).
|
||||
- **Right — live preview:** the **Columns** (X) and **Rows** (Y) shelves stacked above a rendered chart that updates as the configuration changes, with a placeholder/error area. Position is a property of the chart, so its controls sit on the chart (Tableau's Columns/Rows metaphor).
|
||||
|
||||
## Data (preview, filters, calculated fields)
|
||||
|
||||
Reference in New Issue
Block a user