mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Docs: move point-in-time records to exploration/, trim build-narration, lift open items to plan
This commit is contained in:
@@ -64,6 +64,7 @@ docs/
|
||||
├── spec/ # Authoritative behavioral specification (00–10) — the WHAT
|
||||
├── architecture/ # Architecture playbook (00–10) — the HOW (self-contained)
|
||||
│ └── visual-specimen.html # Standalone token sandbox + reusable-primitive catalog
|
||||
├── exploration/ # Point-in-time records (research, reviews, scope memos) — not maintained
|
||||
├── IMPLEMENTATION-PLAN.md # Milestone sequence (M0–M6)
|
||||
└── WHY-A-SEPARATE-REBUILD.md
|
||||
```
|
||||
|
||||
@@ -65,7 +65,7 @@ Vite + React + Zustand + TypeScript + Vitest (happy-dom) + vite-plugin-pwa.
|
||||
`src/core` ↔ `src/app` split, `useAppStore`, design tokens, three-pane placeholder
|
||||
shell, first core module (`format-detection`) with tests.
|
||||
|
||||
**Verified:** `npm run typecheck`, `npm test` (14 passing), `npm run build` (PWA SW generated).
|
||||
**Verified:** `npm run typecheck`, `npm test`, `npm run build` (PWA SW generated).
|
||||
|
||||
---
|
||||
|
||||
@@ -167,7 +167,7 @@ and the companion `visual-specimen.html`.
|
||||
- Keyboard focus ring visible; text/UI contrast passes AA in light and dark.
|
||||
- No placeholder styling remains on the M1 surfaces.
|
||||
|
||||
**Verified:** `typecheck` + `test` (61 passing, incl. `vega-themes.test.ts`) +
|
||||
**Verified:** `typecheck` + `test` (incl. `vega-themes.test.ts`) +
|
||||
`build` (Plex woff2, all script subsets, bundled & precached via the PWA
|
||||
`globPatterns`). Both themes screenshotted via the real
|
||||
app (chrome + Monaco + chart all repaint on theme flip); focus ring visible.
|
||||
@@ -216,7 +216,7 @@ assistance, and the fit-mode rendering contract.
|
||||
- Invalid spec shows inline error; autocomplete suggests Vega-Lite properties.
|
||||
- Each fit mode resizes the chart as specified; choice survives reload.
|
||||
|
||||
**Verified:** `typecheck` + `test` (83 passing — `rendering` fit-mode incl.
|
||||
**Verified:** `typecheck` + `test` (`rendering` fit-mode incl.
|
||||
nested layer/concat/facet specs, `SnippetStore` draft/publish/revert/editorView,
|
||||
`settings-store` `previewFitMode` round-trip) + `build` (PWA, 41 precache
|
||||
entries) + `eslint` clean. Implementation notes: editing now writes the
|
||||
@@ -290,9 +290,9 @@ the reference.
|
||||
**Goal:** no-JSON chart composition from a dataset → a new snippet.
|
||||
|
||||
> **Enhancement push (post-M4).** The forward plan now lives in
|
||||
> [`docs/chart-builder-enhancement-scope.md`](chart-builder-enhancement-scope.md) — it merges
|
||||
> the Tier-B backlog ([`chart-builder-research.md`](chart-builder-research.md) §8) with the
|
||||
> Lyra interaction review ([`lyra-review.md`](lyra-review.md)) and sets a **Tier-C** target.
|
||||
> [`docs/exploration/chart-builder-enhancement-scope.md`](exploration/chart-builder-enhancement-scope.md) — it merges
|
||||
> the Tier-B backlog ([`chart-builder-research.md`](exploration/chart-builder-research.md) §8) with the
|
||||
> Lyra interaction review ([`lyra-review.md`](exploration/lyra-review.md)) and sets a **Tier-C** target.
|
||||
> Shipped beyond the Tier-B floor so far: per-channel aggregate/bin/`timeUnit`, sort/stack;
|
||||
> **actionable hints** (one-click warning fixes); and a builder UX/perf batch (near-fullscreen
|
||||
> modal, canvas preview + canvas max-dimension guard, data-aware default pre-population). See
|
||||
@@ -326,7 +326,7 @@ canon): this is where Astrolabe stops being a pass-through JSON editor and start
|
||||
chart-shaped suggestions/defaults, so "_which chart, and why_" becomes a decision the app
|
||||
owns — the one thing Carbon's data-viz styling doesn't cover. Rather than a styling-only
|
||||
seating, we ran a full **research-first** pass (FT + Datawrapper + the formal engines
|
||||
**Draco** and **Voyager**), recorded in [`docs/chart-builder-research.md`](chart-builder-research.md),
|
||||
**Draco** and **Voyager**), recorded in [`docs/exploration/chart-builder-research.md`](exploration/chart-builder-research.md),
|
||||
and chose the **Tier B "smart + guarded"** design: smart default mark for the data shape,
|
||||
valid-type-locked field-type menus, Size-channel discipline, and non-blocking guidance.
|
||||
The convergent rules and citations live in that doc; the spec (§06) was amended to match.
|
||||
@@ -372,7 +372,7 @@ debounces only keystroke (`shownText`-only) changes.
|
||||
**Deferred at the time to M5/M6 (per §02):** Search, Sort controls + persistence, two
|
||||
distinct empty-state messages, Storage Monitor — all now delivered in M6.
|
||||
|
||||
**Verified:** `typecheck` + `test` (287 passing — `snippet` duplicate factory,
|
||||
**Verified:** `typecheck` + `test` (`snippet` duplicate factory,
|
||||
`SnippetStore` rename/comment/duplicate, a `SnippetLibrary` render test guarding the
|
||||
auto-save effect against a render loop) + `eslint` clean + `build` (PWA, 41 precache
|
||||
entries).
|
||||
@@ -507,6 +507,28 @@ not a silent drift:
|
||||
|
||||
---
|
||||
|
||||
## Open items (carried from the exploration memos)
|
||||
|
||||
Deferred features whose reasoning lives in `docs/exploration/`; pulled here so the backlog
|
||||
is in the maintained plan, not the archive.
|
||||
|
||||
**Chart theming** (`exploration/chart-theming-scope.md`):
|
||||
|
||||
- **User font upload** — FontFace-from-IndexedDB tier; theme `fonts: { family, source: 'file' }`.
|
||||
- **Google Fonts opt-in CDN tier** — keyless catalog, opt-in only.
|
||||
- **SVG export font embedding** — embed face data so exported SVGs render off-app.
|
||||
- **Theme↔font pairing metadata** — a suggestion nicety.
|
||||
- **Built-in expressive theme preset gallery** — e.g. "Editorial", "Terminal", "Sketch".
|
||||
|
||||
**Chart Builder** (`exploration/chart-builder-enhancement-scope.md`):
|
||||
|
||||
- **Transform-aware data inspector** — show resolved post-transform rows
|
||||
(`exploration/data-inspector-exploration.md`).
|
||||
- **Field-chip drag-and-drop** — click/keyboard-first shipped; drag deferred.
|
||||
- **Calculated-field autocomplete popup** — Monaco-style completion for expressions.
|
||||
|
||||
---
|
||||
|
||||
## Architecture reference
|
||||
|
||||
The **how** behind each milestone is documented self-containedly in
|
||||
|
||||
@@ -22,11 +22,8 @@ about user-facing widgets. At that overlap, one rule keeps them from drifting:
|
||||
and never contradict it.** A playbook bullet may _name_ the behavior in one clause and cite
|
||||
the spec, then spend its words on the _how_ (the role, the keys, the focus move) and the
|
||||
_why_ (the council/canon citation). When a playbook bullet and the spec disagree, the
|
||||
**spec wins** and the bullet is the bug.
|
||||
|
||||
_(This bit us once: arch §10 described "keep the library list, title-only" while spec §02
|
||||
said "replace the entire list with the onboarding canvas" — the two halves were authored from
|
||||
opposite mental models. The restatement, not the separation, was the leak.)_
|
||||
**spec wins** and the bullet is the bug. Restatement is the leak: two docs describing the
|
||||
same behavior in their own words drift into contradiction; one cites the other instead.
|
||||
|
||||
## How to use this playbook
|
||||
|
||||
|
||||
@@ -30,12 +30,9 @@ A store is a module that calls `create<State>()` once and exports the resulting
|
||||
hook. The state object holds both **data fields** and **action functions**.
|
||||
|
||||
```ts
|
||||
// src/app/stores/AppStore.ts
|
||||
import { create } from 'zustand';
|
||||
import type { UiTheme } from '@core/theme'; // defined in core; charts key off it too
|
||||
|
||||
export type ModalName = 'datasets' | 'about' | 'donate' | 'chartBuilder' | 'extract';
|
||||
|
||||
// ModalName is the union of the app's modal identifiers; UiTheme is defined in core.
|
||||
export interface AppState {
|
||||
uiTheme: UiTheme;
|
||||
activeModal: ModalName | null;
|
||||
@@ -297,36 +294,17 @@ export const useSnippetStore = create<SnippetState>((set, get) => ({
|
||||
}));
|
||||
```
|
||||
|
||||
The component is thin — it selects state and calls actions:
|
||||
The component is thin — it selects state narrowly and wires events to actions, with no
|
||||
mutation logic of its own:
|
||||
|
||||
```tsx
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useSnippetStore } from '../stores/SnippetStore';
|
||||
|
||||
export function SnippetList() {
|
||||
const { snippets, activeSnippetId } = useSnippetStore(
|
||||
useShallow((s) => ({ snippets: s.snippets, activeSnippetId: s.activeSnippetId })),
|
||||
);
|
||||
const select = useSnippetStore((s) => s.select);
|
||||
const select = useSnippetStore((s) => s.select); // stable identity — select actions individually
|
||||
const remove = useSnippetStore((s) => s.remove);
|
||||
|
||||
return (
|
||||
<ul>
|
||||
{snippets.map((s) => (
|
||||
<li key={s.id} aria-current={s.id === activeSnippetId} onClick={() => select(s.id)}>
|
||||
{s.name}
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
remove(s.id);
|
||||
}}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
// render: one row per snippet, each calling select(id) / remove(id) on the events.
|
||||
}
|
||||
```
|
||||
|
||||
@@ -508,11 +486,8 @@ couples every intermediate component to data it doesn't use.
|
||||
Each store exposes a `reset()` action that returns its fields to initial values
|
||||
(used on "new workspace", sign-out, or test teardown). Because every fact is a
|
||||
single source field with no hand-maintained duplicates, reset is a flat `set(...)`
|
||||
of the initial values; selector-derived values recompute on their own.
|
||||
|
||||
```ts
|
||||
reset: () => set({ snippets: [], activeSnippetId: null, draftSpec: '' });
|
||||
```
|
||||
of the initial values (as in `SnippetStore` above); selector-derived values
|
||||
recompute on their own.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -422,7 +422,7 @@ export async function readOriginUsage(): Promise<number | undefined> {
|
||||
}
|
||||
```
|
||||
|
||||
**The bar is decorative; the legend is the data.** There is no `role="meter"` — a meter needs a meaningful maximum, which a composition with no fixed ceiling lacks (APG → meter). The legend's text labels + sizes are the accessible source of truth, so meaning never rests on hue (WCAG 1.4.1). Dropping the old 0.8/0.95 "almost full" thresholds is deliberate: they keyed off the untrustworthy quota; the genuine out-of-room event surfaces at save time (below), where it is accurate. (Resolves the former spec §02 ↔ code "whole-origin vs. snippet budget" divergence; council resolution recorded in `docs/architecture/10`.)
|
||||
**The bar is decorative; the legend is the data.** There is no `role="meter"` — a meter needs a meaningful maximum, which a composition with no fixed ceiling lacks (APG → meter). The legend's text labels + sizes are the accessible source of truth, so meaning never rests on hue (WCAG 1.4.1). There are no "almost full" percentage thresholds — a fraction would key off the untrustworthy quota; the genuine out-of-room event surfaces at save time (below), where it is accurate.
|
||||
|
||||
### Fail loudly, never silently lose data
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ above it is data; everything below it is a Vega `View` we own and must tear down
|
||||
> the main Live Preview) reads runtime rows via `view.data(name)`. It rides this same
|
||||
> boundary: a `RenderHandle.data()` accessor wraps the view (like `toImageURL`), so no
|
||||
> component touches the raw view. Parked, not built — see
|
||||
> [`docs/data-inspector-exploration.md`](../data-inspector-exploration.md).
|
||||
> [`docs/exploration/data-inspector-exploration.md`](../exploration/data-inspector-exploration.md).
|
||||
|
||||
---
|
||||
|
||||
@@ -126,8 +126,7 @@ async function rerender(node: HTMLElement, spec: TopLevelSpec, config: Config) {
|
||||
crisp/inspectable/copyable and stays the default for the editor's LivePreview. But an
|
||||
SVG chart renders one DOM node per mark, so a many-mark chart (e.g. the Chart Builder's
|
||||
default one-bar-per-row on a 10k-row dataset) costs **seconds** of main-thread
|
||||
layout/paint per render (measured ~6.5s on 9994 rows; the chart paints _after_ it first
|
||||
appears, freezing the tab). The **Chart Builder preview** therefore passes
|
||||
layout/paint per render (the chart paints _after_ it first appears, freezing the tab). The **Chart Builder preview** therefore passes
|
||||
`renderSpec(…, { renderer: 'canvas' })` — canvas is a single node and paints in
|
||||
milliseconds. The raster trade-off is invisible for an ephemeral preview, and image
|
||||
export (`view.toImageURL`) is renderer-agnostic.
|
||||
@@ -165,7 +164,7 @@ background, the categorical color range. Astrolabe ships one config per UI theme
|
||||
so charts visually belong to the app rather than looking like stock Vega-Lite.
|
||||
`src/core/vega-themes.ts` is the single source of truth; each house config is
|
||||
**two merged layers** (the full audit and forward plan live in
|
||||
[`docs/chart-theming-scope.md`](../chart-theming-scope.md)):
|
||||
[`docs/exploration/chart-theming-scope.md`](../exploration/chart-theming-scope.md)):
|
||||
|
||||
- **Base** (`lightBaseConfig`/`darkBaseConfig`) — the legibility minimum:
|
||||
`background: 'transparent'` (the pane shows through) plus guide colors on the
|
||||
|
||||
@@ -254,12 +254,9 @@ the Draft/Published view) is a **radio group**, never a row of `aria-pressed` to
|
||||
|
||||
- `role="radio"`/`aria-checked`, a **roving tabindex** (only the selected option is a tab
|
||||
stop), and Arrow/Home/End to move-and-select (APG → Radio Group). One widget so the keyboard
|
||||
model is defined once. _(Tabs were a candidate for Draft/Published; we chose radio group for
|
||||
consistency with the other segmented controls and to avoid tabpanel wiring to Monaco. A
|
||||
**toggle switch** was also weighed and rejected: APG defines `role="switch"` as on/off of a
|
||||
**single** setting, but Draft/Published selects between two **named peer views** with no
|
||||
natural "on" side — a radio group is the right semantics. Reserve the switch for genuine
|
||||
on/off settings. Consulted via /council → APG switch / radio-group / tabs.)_ A per-option
|
||||
model is defined once. _(Not a toggle switch: APG defines `role="switch"` as on/off of a **single** setting, but
|
||||
Draft/Published selects between two **named peer views** with no natural "on" side — a radio
|
||||
group is the right semantics. Reserve the switch for genuine on/off settings.)_ A per-option
|
||||
`title` (tooltip for a terse label) doubles as the option's accessible name, so it must
|
||||
**lead with the visible label** ("Original — the natural size from the spec"), or
|
||||
speech-input users can't address the control they see (WCAG 2.5.3 label-in-name).
|
||||
@@ -302,9 +299,9 @@ show real measured sizes instead.
|
||||
- **Unavailable degrades, not disappears.** Snippets + datasets are measured from our own data, so
|
||||
they always show; only the **App** segment (which needs the origin estimate) drops out when the
|
||||
Storage Manager API is absent.
|
||||
- **No proactive "almost full" warning.** Dropping the old 0.8/0.95 thresholds is intentional —
|
||||
they keyed off the untrustworthy quota, and a fake fuel gauge fails NN/g #1 (_visibility of system
|
||||
status_) more than it serves it. The genuine out-of-room event surfaces at **save time** as an
|
||||
- **No proactive "almost full" warning.** A percentage gauge would key off the untrustworthy
|
||||
quota, and a fake fuel gauge fails NN/g #1 (_visibility of system status_) more than it
|
||||
serves it. The genuine out-of-room event surfaces at **save time** as an
|
||||
actionable error (`services/storage-errors.ts` → recover by deleting), satisfying NN/g #9.
|
||||
|
||||
_(Consulted via /council → WAI-ARIA APG `meter`, FT Visual Vocabulary + Datawrapper (part-to-whole),
|
||||
@@ -356,7 +353,7 @@ generous preview. Each card **renders live through the shared `chart-renderer`**
|
||||
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** —
|
||||
§3 empty ≠ error). Three rules govern 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
|
||||
@@ -386,7 +383,7 @@ primary next step ("Add a dataset" → the Datasets create form) — never a dea
|
||||
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
|
||||
docs/exploration/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
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# docs/exploration
|
||||
|
||||
Point-in-time records: research, tool reviews, and scope/planning memos written to think a
|
||||
decision through. Unlike `docs/spec/` (the contract — the _what_) and `docs/architecture/`
|
||||
(the maintained _how_), nothing here is kept current — each file reflects what was known
|
||||
when it was written. Decisions that survived are folded into the spec and architecture;
|
||||
these remain as the reasoning behind them.
|
||||
|
||||
Active follow-up work is tracked in [`../IMPLEMENTATION-PLAN.md`](../IMPLEMENTATION-PLAN.md),
|
||||
not here. Exact figures in these files (timings, line counts, test counts) are frozen
|
||||
snapshots, not live numbers.
|
||||
|
||||
- `chart-builder-research.md` — cross-source chart-choice research (Draco, Voyager, FT Visual Vocabulary, Datawrapper).
|
||||
- `lyra-review.md` — review of vega/lyra for Chart Builder interaction ideas.
|
||||
- `chart-builder-enhancement-scope.md` — consolidated Tier-B → Tier-C forward plan for the Chart Builder.
|
||||
- `chart-theming-scope.md` — chart theming plan and slice breakdown.
|
||||
- `monetization-and-sync-exploration.md` — monetization + BYO-cloud-sync direction memo.
|
||||
- `data-inspector-exploration.md` — transform-aware data-inspector direction.
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
> for chart-builder enhancement work — it merges the research backlog from
|
||||
> [`chart-builder-research.md`](./chart-builder-research.md) §8 (the M4 decision and its
|
||||
> deferred items) with the interaction ideas from [`lyra-review.md`](./lyra-review.md) §5,
|
||||
> read against the current spec ([`spec/06-chart-builder.md`](./spec/06-chart-builder.md))
|
||||
> read against the current spec ([`spec/06-chart-builder.md`](../spec/06-chart-builder.md))
|
||||
> and the shipped code (`src/core/chart-builder.ts`).
|
||||
>
|
||||
> **Goal (the brief):** a **rapid, intuitive GUI for building Vega-Lite specs**, with
|
||||
@@ -58,7 +58,7 @@ mapping those to friendly labels and choosing which to expose is the main design
|
||||
|
||||
- Seed: builder **1D** data preview — see
|
||||
[`chart-builder-enhancement-scope.md`](./chart-builder-enhancement-scope.md) (§3 1D).
|
||||
- Renderer/preview home: [`architecture/05`](./architecture/05-rendering-theming-preview.md)
|
||||
- Renderer/preview home: [`architecture/05`](../architecture/05-rendering-theming-preview.md)
|
||||
(the `RenderHandle` boundary the `view.data` accessor extends).
|
||||
- Behaviour, once built, is specified in `docs/spec/04` (Live Preview) and `docs/spec/06`
|
||||
(the builder preview), per "spec follows code".
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
|
||||
## 1. The tension this collides with
|
||||
|
||||
A login + encrypted-DB system isn't a neutral feature add. [`SOUL.md`](../SOUL.md) makes
|
||||
A login + encrypted-DB system isn't a neutral feature add. [`SOUL.md`](../../SOUL.md) makes
|
||||
"no account" a **named value**, and lists the opposite under _What We're Not_:
|
||||
|
||||
- Value #5, _Own Your Data_: "Your library is a file you control, **not a row in someone's
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
The Chart Builder is a visual, no-JSON way to compose a Vega-Lite chart from a selected dataset. The user picks a mark type and maps the dataset's columns to encoding channels; the builder produces a complete Vega-Lite spec and saves it as a new snippet that references the dataset. It is intended for users who want to start a chart quickly without hand-writing JSON in the _Spec Editor & Draft/Published Workflow_.
|
||||
|
||||
> **Design level — "smart + guarded" (Tier B).** The builder is field-first — the user works from a shelf of the dataset's columns and drops them onto encoding channels — and stays within the inputs below, but it is not a dumb composer: it picks a sensible default mark for the data shape, offers only field types valid for each column, keeps unsuitable channel mappings out of reach, and surfaces non-blocking guidance for encodings that render poorly. These behaviors are derived from cross-source chart-choice research recorded in [`docs/chart-builder-research.md`](../chart-builder-research.md) (the convergence of Draco, Voyager, the FT Visual Vocabulary, and Datawrapper). On top of this "smart + guarded" base sits the **intent-first front door** (Tier C — _what do you want to show?_, see _Intent_ below): an on-ramp that recommends a whole chart from the user's stated intent, without replacing the mark-first builder beneath it.
|
||||
> **Design level — "smart + guarded" (Tier B).** The builder is field-first — the user works from a shelf of the dataset's columns and drops them onto encoding channels — and stays within the inputs below, but it is not a dumb composer: it picks a sensible default mark for the data shape, offers only field types valid for each column, keeps unsuitable channel mappings out of reach, and surfaces non-blocking guidance for encodings that render poorly. These behaviors are derived from cross-source chart-choice research recorded in [`docs/exploration/chart-builder-research.md`](../exploration/chart-builder-research.md) (the convergence of Draco, Voyager, the FT Visual Vocabulary, and Datawrapper). On top of this "smart + guarded" base sits the **intent-first front door** (Tier C — _what do you want to show?_, see _Intent_ below): an on-ramp that recommends a whole chart from the user's stated intent, without replacing the mark-first builder beneath it.
|
||||
|
||||
## Opening
|
||||
|
||||
@@ -52,7 +52,7 @@ The section is ordered **input → shaping** so the distinction reads at a glanc
|
||||
### Data preview
|
||||
|
||||
- The first item in the section: a collapsible, **read-only** sample of the dataset's first rows (capped), with a per-column **type chip** in each header. It lets the user sanity-check inferred types against the actual values _before_ building — exactly when type inference is most likely to surprise. Editing the data is out of scope. A non-tabular payload (a single JSON object, TopoJSON, an unfetched URL) has no rows to show.
|
||||
- The preview shows the dataset's **raw source rows** — _before_ the filters and calculated fields below are applied; it does not show derived columns. Its position above those controls makes that explicit: it is the input, not the result. (The transformed result is what the right-hand chart renders. A transform-aware "data inspector" that shows the resolved rows is a planned future direction — see [`docs/data-inspector-exploration.md`](../data-inspector-exploration.md).)
|
||||
- The preview shows the dataset's **raw source rows** — _before_ the filters and calculated fields below are applied; it does not show derived columns. Its position above those controls makes that explicit: it is the input, not the result. (The transformed result is what the right-hand chart renders. A transform-aware "data inspector" that shows the resolved rows is a planned future direction — see [`docs/exploration/data-inspector-exploration.md`](../exploration/data-inspector-exploration.md).)
|
||||
|
||||
### Filters
|
||||
|
||||
@@ -122,7 +122,7 @@ These controls appear only when they apply:
|
||||
|
||||
### Guidance (non-blocking)
|
||||
|
||||
The builder surfaces short, plain-language hints for configurations that render but read poorly — advisory only, never blocking the **Create Snippet** action (validation below is the sole gate). A hint states the _problem_; where there is an obvious remedy, it also offers one or more **one-click fix** buttons that apply the change to the configuration (e.g. _Aggregate as Sum_, _Swap X/Y_, _Switch to Point_, _Stack_, _Remove colour_). A fix is an offer, never a forced change — applying it updates the config and the hint re-derives away. Interaction/accessibility of these actions follows [`architecture/10`](../architecture/10-interaction-and-feedback.md) §5 (polite announcement, focus moved off the removed button). These follow the chart-choice research ([`docs/chart-builder-research.md`](../chart-builder-research.md)) and include, for example:
|
||||
The builder surfaces short, plain-language hints for configurations that render but read poorly — advisory only, never blocking the **Create Snippet** action (validation below is the sole gate). A hint states the _problem_; where there is an obvious remedy, it also offers one or more **one-click fix** buttons that apply the change to the configuration (e.g. _Aggregate as Sum_, _Swap X/Y_, _Switch to Point_, _Stack_, _Remove colour_). A fix is an offer, never a forced change — applying it updates the config and the hint re-derives away. Interaction/accessibility of these actions follows [`architecture/10`](../architecture/10-interaction-and-feedback.md) §5 (polite announcement, focus moved off the removed button). These follow the chart-choice research ([`docs/exploration/chart-builder-research.md`](../exploration/chart-builder-research.md)) and include, for example:
|
||||
|
||||
- A **Line**, **Area**, or **Heatmap** mark with only one axis mapped (both axes are needed to draw it).
|
||||
- A **Bar/Line/Area** whose X and Y are both categories (nothing to measure).
|
||||
|
||||
@@ -126,4 +126,4 @@ A **CustomTheme** is a user-named Vega-Lite config saved in the library and offe
|
||||
| `created` | ISO-timestamp string | When the theme was first created. |
|
||||
| `modified` | ISO-timestamp string | When the theme was last changed. |
|
||||
|
||||
Selection is keyed by `id` (not name) so renaming a theme never invalidates the persisted `ui.chartTheme`. A persisted `custom:<id>` whose record no longer exists is not an error: charts render with the house style until the record appears (themes hydrate asynchronously), and deleting the actively-selected theme resets the selection to `astrolabe` explicitly. Custom themes are not yet included in the _Import & Export_ envelope (planned; see `docs/chart-theming-scope.md`).
|
||||
Selection is keyed by `id` (not name) so renaming a theme never invalidates the persisted `ui.chartTheme`. A persisted `custom:<id>` whose record no longer exists is not an error: charts render with the house style until the record appears (themes hydrate asynchronously), and deleting the actively-selected theme resets the selection to `astrolabe` explicitly. Custom themes travel in the _Import & Export_ envelope alongside snippets and datasets (spec §08).
|
||||
|
||||
Reference in New Issue
Block a user