Files
astrolabe/docs/ux-second-pass.md

3.7 KiB

UX second pass — batched council review

A running parking lot of small UX / interaction decisions deferred for a batched /council review, rather than gating each one the moment it surfaces. Append quirks here as they come up; resolve them together in one pass, record the resolution into the contract (docs/architecture/09+10 and the relevant docs/spec/), then delete the row.

Open

  • Extract-to-Dataset has no keyboard accelerator — its sibling editor actions (wrap / config, in spec-transform-actions / spec-config-actions) register an F1-palette command and a lightbulb; Extract is toolbar-only (runExtract in services/extract-action.ts), because it opens a modal rather than making an in-place undoable edit, so the palette/lightbulb fit awkwardly. Decide whether to add a palette command anyway for parity (a keyboard path to open the modal at the cursor), or leave toolbar-only.

  • Storage-full copy implies a per-tier budget, but quota is whole-origin — the messages say "snippet storage is full" / "dataset storage is full" and tell the user to delete that entity's items, yet IndexedDB quota is shared across the whole origin. Per-tier framing is more actionable (deleting the tier you're saving into does free space) but misstates the scope. Decide: keep the actionable per-tier framing, or switch to a whole-origin "Storage is full — free space (the Storage monitor shows what's using it)". Affects both storageErrorNotification and entityStorageErrorNotification in services/storage-errors.ts and the import-quota copy in services/transfer.ts.

  • "Row" vs "column" naming differs between the wireframe's pull-out and pair drags — the frame-margin pull-out chip/announcement (pullLabel, commitDrop) name the new full-span band by its spatial shape (a vconcat slot is "a new row above"; an hconcat slot "a new column left"), while the pair-into-split chip/announcement use the container convention (hconcat = "row", vconcat = "column"). Both describe the same axis — pulling a view above a row and pairing two views vertically are both a vconcat — yet one calls it a row and the other a column. Each reading is locally sensible (a pulled-out band reads as a row; a 2-cell vertical split reads as a column) but the divergence can confuse. Decide: unify on one vocabulary, or keep the gesture-specific framing. In components/CompositionWireframe.tsx (pullLabel, the 'row'/'column' ternaries in resolveDrop/commitDrop).

  • Post-first-snippet feature discoverability — onboarding ends the instant one snippet exists; draft/publish, extract-to-dataset, and theming are then discovered only by accident (the CodeLens scaffolds are the exception — discoverable inline). Tours are against the app's grain; decide what light-touch surface (if any) carries discovery: a richer About/shortcuts panel, first-visit hints, or nothing. Context in docs/exploration/landing-onboarding-scope.md (§ Parked).

Deferred (not design debts, revisit on demand)

  • Drag-and-drop field assignment — chips are click/keyboard-first by design; drag would be a progressive enhancement on top of the chooser model, not a replacement. Revisit if real usage asks for it (likely alongside Phase 4 faceting, where drag-to-shelf reads most naturally).

  • Theme Builder config editor stays a plain textarea (decided 2026-06-13) — a second Monaco mount is heavy inside a modal for an occasional surface; the parse error is the feedback channel that matters. Revisit only if real usage asks for config completions. The gallery's per-card captions stand as the canvas charts' text alternative.