feat(ui): error & state UX (F4) #29

Merged
developer merged 3 commits from feature/ui-finalize-f4-error-ux into development 2026-05-22 11:53:16 +00:00
Owner

F4 — Error & state UX

From ui/PLAN-finalize.md F4. Consistent, actionable feedback for
failures and for loading / empty / error states, plus the deferred
selected-planet marker and bottom-sheet dismissal.

What changed

  • Central error surface (src/lib/error/): classifyError collapses
    any caught value into a stable ErrorKind from the reliable transport
    signal — HTTP status (AuthError), Connect Code, fetch TypeError,
    navigator.onLine — since result_code is opaque per ARCHITECTURE.
    reportError(err, { onRetry? }) raises a translated toast (sticky with
    a Retry action for retryable kinds; auto-dismiss otherwise);
    errorMessageKey(err) returns the key for inline use. error.*
    messages added (en + ru). Mail compose now shows the translated 403
    inline.
  • Shared ViewState (src/lib/ui/view-state.svelte):
    loading/empty/error placeholder with a spinner, optional action, and
    the right live-region role; the entity tables (races / sciences /
    ship-classes) use it. Remaining views adopt it incrementally.
  • Selected-planet ring (src/map/selection-ring.ts): an accent ring
    around the selected planet, fed into the map's buildExtras.
  • Bottom-sheet dismissal (src/lib/ui/sheet-dismiss.ts): tap-outside
    • drag-handle swipe-down for the planet / ship-group sheets, hand-rolled
      on pointer events (no dependency).

Tests / docs

New unit tests: error, view-state, selection-ring, sheet-dismiss.
pnpm check 0/0; pnpm test 761 passing; the a11y axe + keyboard
specs still pass (12/12, chromium-desktop). Docs:
ui/docs/error-state-ux.md (+ index); F4 marked done.

🤖 Generated with Claude Code

## F4 — Error & state UX From `ui/PLAN-finalize.md` F4. Consistent, actionable feedback for failures and for loading / empty / error states, plus the deferred selected-planet marker and bottom-sheet dismissal. ### What changed - **Central error surface** (`src/lib/error/`): `classifyError` collapses any caught value into a stable `ErrorKind` from the reliable transport signal — HTTP status (`AuthError`), Connect `Code`, fetch `TypeError`, `navigator.onLine` — since `result_code` is opaque per ARCHITECTURE. `reportError(err, { onRetry? })` raises a translated toast (sticky with a **Retry** action for retryable kinds; auto-dismiss otherwise); `errorMessageKey(err)` returns the key for inline use. `error.*` messages added (en + ru). Mail compose now shows the translated 403 inline. - **Shared `ViewState`** (`src/lib/ui/view-state.svelte`): loading/empty/error placeholder with a spinner, optional action, and the right live-region role; the entity tables (races / sciences / ship-classes) use it. Remaining views adopt it incrementally. - **Selected-planet ring** (`src/map/selection-ring.ts`): an accent ring around the selected planet, fed into the map's `buildExtras`. - **Bottom-sheet dismissal** (`src/lib/ui/sheet-dismiss.ts`): tap-outside + drag-handle swipe-down for the planet / ship-group sheets, hand-rolled on pointer events (no dependency). ### Tests / docs New unit tests: `error`, `view-state`, `selection-ring`, `sheet-dismiss`. `pnpm check` 0/0; `pnpm test` **761** passing; the a11y axe + keyboard specs still pass (12/12, chromium-desktop). Docs: `ui/docs/error-state-ux.md` (+ index); F4 marked done. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
developer added 1 commit 2026-05-22 11:29:23 +00:00
feat(ui): error & state UX — error surface, view states, map selection, sheet gestures (F4)
Tests · UI / test (push) Waiting to run
Tests · UI / test (pull_request) Failing after 7m13s
8dcaf1c6c6
- lib/error/: classify any caught error into a stable ErrorKind from the
  transport signal (HTTP status / Connect Code / fetch TypeError /
  navigator.onLine); map to translated error.* messages via reportError
  (sticky Retry toast for retryable kinds) or errorMessageKey (inline).
  Mail compose now surfaces the translated 403/error inline.
- lib/ui/view-state.svelte: shared loading/empty/error placeholder with
  the right live-region role + optional action; entity tables
  (races/sciences/ship-classes) migrated, rest adopt incrementally.
- map/selection-ring.ts: accent ring around the selected planet, fed into
  the map buildExtras alongside the reach circles.
- lib/ui/sheet-dismiss.ts: tap-outside + drag-handle swipe-down dismissal
  for the planet/ship-group bottom-sheets (hand-rolled pointer events).

Tests: error, view-state, selection-ring, sheet-dismiss (761 total).
Docs: ui/docs/error-state-ux.md (+ index); F4 marked done.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
developer added 1 commit 2026-05-22 11:45:41 +00:00
fix(ui): bottom-sheet tap-outside only fires while the sheet is shown
Tests · UI / test (push) Has been cancelled
Tests · UI / test (pull_request) Failing after 2m53s
35e27c5aec
The planet/ship-group sheets stay mounted on desktop but are hidden by a
media query (`display: none`); the document-level tap-outside listener
fired regardless, so the first click after selecting a planet cleared the
selection — breaking every desktop inspector/select flow in CI. Guard the
handler on the sheet's computed display (`offsetParent` is unreliable for
`position: fixed`). The swipe handle is naturally inert when hidden.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
developer added 1 commit 2026-05-22 11:50:45 +00:00
test(ui): cargo-routes counts the selection ring in the primitive total
Tests · UI / test (push) Has been cancelled
Tests · UI / test (pull_request) Successful in 2m4s
b07b8fb1c8
The F4 selection ring is a real map primitive. The cargo-route flow has
the source planet selected, so the total primitive count is 8 (7 + the
ring circle), not 7; the line count (3) is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
developer merged commit 9d3a652b6b into development 2026-05-22 11:53:16 +00:00
developer deleted branch feature/ui-finalize-f4-error-ux 2026-05-22 11:53:17 +00:00
Sign in to join this conversation.