← Back to devlog

2026-07-05 — v29 front-door polish: empty-state delight, loading feedback, narrow-mobile operability

Three small, cohesive improvements surfaced by the v28 UX-gallery assessment — bundled in one PR to avoid parallel UI merge conflicts. Each change has genuine exact-value behavior tests and clears the mandatory UX-gallery gate.

1. Empty-state dropzone delight

The old empty state said "Load a Sanger trace" — a generic imperative that gives no spatial cue about where to drop a file or how the data is handled. The updated copy makes three things immediately clear:

A data-testid="empty-state-dropzone" attribute was added to the #empty-state div so test selectors can target the empty-state dropzone unambiguously without coupling to the CSS class name.

The .dragging class — added by the existing dragover handler and removed on dragleave / drop — is verified by a test that dispatches both events and asserts the exact class toggle.

2. Loading feedback with file name

Previously the loading banner read "Loading sample.ab1…" for the sample and "Loading filename…" for user files — both technically functional but tonally flat. The updated phrasing is "Loading your trace… filename":

Tests assert the exact string "Loading your trace… sample.ab1" is present in #loading-text while the sample loads (routed with a 800 ms artificial delay), and that #loading-banner is hidden once the trace is ready and #status contains "Loaded sample.ab1".

3. Narrow-mobile keyboard / touch operability

The v28 assessment flagged a coverage gap: the narrow-mobile project ran only the UX gallery capture spec. Core controls were exercised visually but not behaviourally.

This pass documents and tests the intended design:

The narrow-mobile Playwright project now includes front-door-polish.e2e.test.ts in its testMatch so these assertions run against the 360×640 viewport in CI. Mobile-incompatible tests (those that rely on keyboard Tab model or setInputFiles) carry a test.skip(isMobile, …) guard with an explicit explanation of the intended touch-first behaviour.

UX assessment

Is this great UX? Yes, with one caveat. The three changes close real first-impression gaps: the drop-target is now spatially self-explanatory, the loading banner acknowledges the user's file by name, and the touch targets meet the platform standard. The privacy wedge is now front-and-centre rather than in a dismissible ribbon that many users never read. The keyboard/touch operability story is now tested and documented rather than assumed.

What to improve next: The empty-state icon (🧬) is emoji — rendering varies across platforms and is invisible to screen readers in contexts where aria-hidden strips it. An SVG illustration would give pixel-perfect cross-platform appearance and could carry a meaningful aria-label. Additionally, the "Choose file" label still looks like a link rather than a button on first glance — a proper outlined button style (matching the "Try the sample" secondary button) would make the affordance explicit. These are tracked for the next design-system pass.

Tests

tests/e2e/front-door-polish.e2e.test.ts contains 11 genuine behavior assertions across three describe blocks:

Zero capability regressions

All changes are additive or text substitutions. No selectors used by existing tests were removed — #empty-state, #loading-banner, #loading-text, #sample-load-btn, and .dropzone are all preserved. The UX gallery capture spec is unaffected: it asserts on element visibility, not text content.