Foundation (phase 01, verified): - FastAPI app: /api/health, /api/suggestions, /api/chat (placeholder), static frontend served locally (no CDN) - Postgres 17 + pgvector via db/Containerfile + compose.yaml (podman compose up -d db), Alembic initial migration (documents, chunks with vector(768), query_log) - LLM client targeting https://aipi.reeseapps.com/v1 (turbo/embed); scripts/llm_probe.py verified models + 768-dim embeddings live - Conditional debugpy: imported only when DEBUGPY=1 (attach on demand, :5678); logging config for clean single-line logs - Frontend shell: mobile-first chat + Sources pages, tokens, a11y baselines - Tests: 24 unit+integration (99% coverage on app/), ruff + pyright clean, Playwright smoke E2E (3 tests) against a deterministic mock LLM - Planning: .agent/PLAN.md (architecture + LOCKED decisions), AGENTS.md, 6 user stories, 7 phase files (one story / one phase / one Playwright suite each)
66 lines
3.5 KiB
Markdown
66 lines
3.5 KiB
Markdown
# Story: Responsive, Polished, Accessible UI
|
|
|
|
**Phase:** `07_story_responsive_polish.md` · **E2E:** `tests/e2e/test_responsive_polish.py`
|
|
|
|
## Narrative
|
|
|
|
As **a user on any device** — phone at the coffee shop, laptop at the
|
|
desk — I want the chat to be comfortable to read and drive: no pinched
|
|
layout, no tiny tap targets, no contrast failures, no wasted whitespace —
|
|
so asking Brain feels effortless everywhere.
|
|
|
|
- **Given** any viewport from 360px to 1600px+
|
|
- **When** I use the chat and the Sources page
|
|
- **Then** the layout follows the PLAN §7 standards (containers, chat
|
|
column, full-width table), all interactive elements are reachable by
|
|
keyboard, and every color pair meets WCAG 2.1 AA.
|
|
|
|
## Acceptance criteria
|
|
1. **Layout:** container 72rem centered with side padding; chat column
|
|
capped at 46rem centered; Sources table uses full container width with
|
|
horizontal scroll below 640px (never a squeezed single hairline column).
|
|
2. **Mobile (375px):** header condenses, composer reachable above the home
|
|
indicator (`safe-area-inset-bottom`), chips scroll horizontally, bubbles
|
|
≤92% width, no horizontal page overflow (document `scrollWidth ==
|
|
clientWidth`).
|
|
3. **A11y sweep:** landmarks present on both pages (`header/nav/main/
|
|
footer`); skip link works (focus `#main`); all inputs have labels
|
|
(visible or programmatically associated); all icon-only buttons have
|
|
`aria-label`; `:focus-visible` outline on every control (Tab through).
|
|
4. **Contrast:** automated check of the key pairs (ink/surface,
|
|
ink-soft/surface, white/brand, chip-ink/chip-bg, deflection pairs) ≥4.5:1
|
|
(test computes from computed styles; PLAN §7.2 table is the baseline).
|
|
5. **No-CDN re-verification** on both pages (no `http(s)://` src/href
|
|
except same-origin `/…`).
|
|
6. **Reduced motion:** with `prefers-reduced-motion`, typing dots and
|
|
spinner do not animate (computed `animation: none` or duration ≥2s).
|
|
7. Long words/paths (e.g. a 60-char file path) wrap or ellipsize without
|
|
breaking the bubble (overflow-wrap anywhere).
|
|
|
|
## UI Visualization & Structure
|
|
- This phase is the **visual audit + fix pass**: it does not add features,
|
|
it enforces PLAN §7 end-to-end on chat + sources.
|
|
- Desktop 1440px screenshot pass: header 64px, chat centered with balanced
|
|
margins, sources table edge-to-edge within the container.
|
|
- Tablet 768px: chat column uses most of the width (≤46rem cap), no
|
|
mid-column dead zones; stat cards 3-across.
|
|
- Phone 375px: one-column flow, 44px+ targets, thumb-zone composer.
|
|
- Any deviation found → fix in `frontend/assets/styles.css` (tokens first),
|
|
re-verify with the E2E below.
|
|
|
|
## Playwright Mapping Rule
|
|
**Test Scenario → `tests/e2e/test_responsive_polish.py`**:
|
|
1. `test_no_horizontal_overflow_at_viewports` — for 360/375/768/1280/1600:
|
|
`document.documentElement.scrollWidth <= clientWidth` on both pages.
|
|
2. `test_chat_column_capped_and_centered` — at 1600px, `.chat-shell`
|
|
width ≤ 46rem (736px) + 2% and horizontally centered (±2%).
|
|
3. `test_sources_table_full_width` — at 1280px, `.table-wrap` width ≥ 80%
|
|
of `.container` width.
|
|
4. `test_a11y_landmarks_and_labels` — both pages: landmarks present,
|
|
skip link target `#main` focusable, `#message-input` has an associated
|
|
label, no `<img>`/icon buttons without accessible name.
|
|
5. `test_contrast_pairs_pass_aa` — computed-color contrast assertions for
|
|
the PLAN §7.2 pairs (helper computes WCAG relative luminance).
|
|
6. `test_reduced_motion_respected` — emulate `reducedMotion: 'reduce'`;
|
|
typing dots have no running animation (or ≥2s duration).
|