Skip to content

hub-client: UI/UX modernization Phase 3 — functional states and motion safety - #611

Merged
shikokuchuo merged 5 commits into
hub-client-uiux-phase2from
hub-client-uiux-phase3
Aug 26, 2026
Merged

hub-client: UI/UX modernization Phase 3 — functional states and motion safety#611
shikokuchuo merged 5 commits into
hub-client-uiux-phase2from
hub-client-uiux-phase3

Conversation

@shikokuchuo

Copy link
Copy Markdown
Member

Stacked on #609 (phase 2). Phase 3 of the UI/UX modernization plan.

What this change does

Phase 3 gives every async surface a working loading, error, and empty state. It also makes motion safe for users who request reduced motion.

Motion safety. A global rule in ui.css collapses all transitions and animations to 0.01 ms under prefers-reduced-motion: reduce. Motion added later is covered automatically. The visual specs now emulate reduced motion, so screenshots stay deterministic through this rule.

Loading. A new LoadingIndicator component (spinner plus label, announced to screen readers) replaces every bare "Loading…" text.

Errors with retry. A failed project-list load now shows an error with "Try again". Before, it showed the wrong empty state. A failed project open offers "Try again" and runs the attempt again. A failed renderer boot offers "Reload".

Found by the new tests. The empty file tree declared role="tree" with zero items. The tree now drops the widget role when it is empty.

Tests

  • New specs: e2e/reduced-motion.visual.spec.ts (5) and e2e/async-states.visual.spec.ts (14), over six new dev-harness routes.
  • Green locally: typecheck, lint:css, test:ci (1251 tests), test:visual (115 specs), build:all.
  • CI note: the new routes have no linux baselines yet. The retry step will add and commit them, as it did on phases 1 and 2.

@posit-snyk-bot

posit-snyk-bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

shikokuchuo and others added 5 commits August 26, 2026 18:12
…stic visual specs

A global rule in ui.css now collapses every transition/animation to an
effectively-instant 0.01ms under prefers-reduced-motion: reduce (0.01ms
rather than none so transitionend/animationend listeners still fire).
Global by design: any motion Phase 5 adds is covered automatically, so
per-component reduced-motion blocks are banned — ReplayDrawer's local
block is removed as subsumed, and theme.css's motion comment points at
the rule.

The visual specs now get deterministic screenshots through the app's own
rule: bootHarness emulates reducedMotion: 'reduce' (also in
setup-screens), subsuming Phase 0's addStyleTag transition-killer. The
config-level reducedMotion option is silently ignored by Playwright
1.60's default context (verified: browser.newContext honors it, project
use does not), so emulation lives in the helper; a comment in
playwright.visual.config.ts records the trap.

e2e/reduced-motion.visual.spec.ts pins the contract with computed-style
checks (transitions on sidebar/header chrome, the toast entrance
animation, iteration counts) plus no-preference counter-checks proving
the assertions aren't vacuous.

Phase 3 of the UI/UX modernization plan (bd-6oxpa77k).
Every async surface now has functional loading, error-with-retry, and
empty states:

- components/Loading.tsx is the one loading indicator: token-styled
  spinner + label with role='status' (the spin is covered by the global
  reduced-motion rule). Replaces the bare 'Loading…' text in App's auth
  and identity gates, ProjectsHome's loading render, and the classic
  ProjectSelector (whose local .loading class is removed; its
  three-dots '...' becomes … along the way). .qh-loading/.qh-connecting
  move from ProjectsHome.css to ui.css as shared classes.
- ProjectsHome's legacy project-list load no longer swallows failures
  into the wrong empty copy ('No projects yet' on a failed load): a
  load failure now renders an error surface with a working Try again.
- A failed project open surfaces through the connection error banner
  with a Try again action (new onRetry prop); App keeps the last
  open attempt and re-invokes it. The .qh-error-action pattern now
  inherits banner colors (currentColor) so it works on editor-theme
  error surfaces too.
- StatusTab's WASM boot error gains a Reload recovery action (onRetry
  prop, defaulting to a page reload — the renderer initializes at
  Editor mount, so a reload is the honest retry).

New dev-harness routes pin each state (projects-home-loading/-error/
-empty, sidebar-empty, status-tab-loading/-error) with offscreen action
recorders so specs can assert retries fire; e2e/async-states covers
copy, retry click-through, and both themes. The routes join the axe
characterization baseline (they render pre-existing chrome with
baselined contrast debt) — regenerating the baseline surfaced a real
violation: the empty file tree rendered role='tree' with zero items
(aria-required-children). The tree/listbox now drops its widget role
when empty.

Scope notes: the classic ProjectSelector's error banner keeps its
current form (dual-selector consolidation is out of scope; the
collections UI is the default), and in-editor sync loss was already
covered (header Online/Offline + auto-reconnect). Skeleton screens and
designed empty states remain Phase 5.

Phase 3 of the UI/UX modernization plan (bd-6oxpa77k).
The authoritative plan lived in .posit/assistant/plans/ (tool-local,
untracked); claude-notes/plans/2026-08-26-hub-client-uiux-modernization.md
was a pointer to it. The plan now lives at
claude-notes/plans/2026-08-25-hub-client-uiux-modernization.md per the
repo convention, the pointer is removed, and the plan header records the
braid epic (bd-2q55e6rc) and current phase status. Braid references to
the old path updated (bd-2q55e6rc, bd-7byucvr6).
@shikokuchuo
shikokuchuo force-pushed the hub-client-uiux-phase3 branch from 54ce1ac to 4da551b Compare August 26, 2026 17:13
@shikokuchuo
shikokuchuo merged commit 83c818f into main Aug 26, 2026
13 of 18 checks passed
@shikokuchuo
shikokuchuo deleted the hub-client-uiux-phase3 branch August 26, 2026 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants