Files
manage/openspec/changes/mobile-responsive-parity/tasks.md
T
Developer 18ee77a4e4 Plan mobile responsive parity (OpenSpec change)
Add proposal/spec/design/tasks for full mobile parity across all 9 routes.
Decisions: hybrid tables (cards below md for big four), Sheet-based forms,
always-visible edit affordance, 44px touch targets, single-column dashboard
with anchors, responsive web only (no PWA), phone portrait at md:768px cut.
Polling unchanged (risk flagged). Delivery: 10 chained PRs, primitives first.
2026-06-26 11:49:47 +00:00

7.2 KiB
Raw Blame History

Tasks — Mobile responsive parity

Change: mobile-responsive-parity Phase: tasks Date: 2026-06-26

Review workload forecast

Field Value
Estimated changed lines ~22002800
Chained PRs recommended Yes (10 slices)
Chain strategy stacked-to-main
Slice order 1 (primitives) → 2 (Dashboard) → 35 (tables) → 68 (forms) → 9 (touch audit) → 10 (docs + verify)

Each slice is committed separately (user pref). Every slice must leave cd frontend && npm run lint && npm run build && npm run test green. Every touched page gains a Vitest case asserting behavior at <768px and ≥768px.


Slice 1 — Shared primitives

Goal: Land the four building blocks every later slice depends on. No page-level behavior changes yet.

  • 1.1 useIsMobile() hook

    • Files: frontend/src/hooks/useIsMobile.ts (new)
    • Lines: ~20
    • Details: SSR-safe matchMedia("(max-width: 768px)") listener per design.
  • 1.2 MobileCardRow component

    • Files: frontend/src/components/ui/mobile-card.tsx (new), plus a Vitest spec frontend/src/components/ui/__tests__/mobile-card.test.tsx.
    • Lines: ~80 + ~60 test
    • Details: generic <T,>, fields list, primary field, optional onRowClick and actions slot per design. 44px min card height.
  • 1.3 SheetForm component

    • Files: frontend/src/components/ui/sheet-form.tsx (new), plus spec.
    • Lines: ~70 + ~50 test
    • Details: wraps shadcn Sheet; sticky header + sticky footer; h-[100dvh]; props per design. Dirty-state confirm on outside click.
  • 1.4 EditActionButton — extend HoverEditButton

    • Files: frontend/src/components/HoverEditButton.tsx
    • Lines: ~15
    • Details: add mobile="always" | "hover" (default always). Tailwind: always visible below md, hover-revealed at md: and up.
  • 1.5 mobile-touch-target utility

    • Files: frontend/src/index.css (add utility)
    • Lines: ~10
    • Details: media-gated 44×44 min hit area per design.
  • 1.6 Replace inline matchMedia in App.tsx

    • Files: frontend/src/App.tsx
    • Lines: ~10 removed, ~3 added
    • Details: use useIsMobile(); preserve current shell behavior exactly.

Slice 2 — Dashboard (R7)

Goal: Dashboard collapses to single column + section anchor bar on mobile.

  • 2.1 Single-column grid below md

    • Files: frontend/src/pages/Dashboard.tsx
    • Lines: ~20
    • Details: widget list uses grid grid-cols-1 md:grid-cols-* (match existing desktop column count). Respect configured sort order.
  • 2.2 Section anchor bar

    • Files: frontend/src/pages/Dashboard.tsx
    • Lines: ~40
    • Details: group widgets (Observability / Media / Backups / Custom). Anchor bar md:hidden, horizontal scroll of pills, jumps to section by id.
  • 2.3 Tests

    • Files: frontend/src/pages/__tests__/Dashboard.test.tsx
    • Lines: ~40
    • Details: assert single column at 375px, grid at 1280px, anchor bar visible only at <768px.

Slice 3 — Media table (R3.1, R3.5)

  • 3.1 Mobile fields + card render

    • Files: frontend/src/pages/Media.tsx
    • Lines: ~60
    • Details: card primary = title; fields = size, HDR flag, library, year. Hide column-visibility toggle below md. Preserve pagination controls.
  • 3.2 Tests

    • Files: frontend/src/pages/__tests__/Media.test.tsx
    • Lines: ~40

Slice 4 — FileBrowser table (R3.1)

  • 4.1 Mobile fields + card render

    • Files: frontend/src/pages/FileBrowser.impl.tsx
    • Lines: ~60
    • Details: card primary = name; fields = size, mtime, type. Preserve directory-navigation tap target (whole card). Preserve ffprobe/job affordances.
  • 4.2 Tests

    • Files: frontend/src/pages/__tests__/FileBrowser.test.tsx
    • Lines: ~30

Slice 5 — Users + Backups tables (R3.1)

  • 5.1 UsersPage card

    • Files: frontend/src/pages/UsersPage.impl.tsx
    • Lines: ~70
    • Details: card primary = display name; fields = username, activity badge, email (if present). Preserve selection checkboxes (44px) and drawer open.
  • 5.2 Backups cards (3 tables)

    • Files: frontend/src/components/BackupAlertsTable.tsx, frontend/src/components/BackupJobsTable.tsx, frontend/src/components/BackupRunsTable.tsx
    • Lines: ~120 (3 × ~40)
    • Details: per-table primary + 3 fields; preserve acknowledge/run actions on the card.
  • 5.3 Tests

    • Files: existing component test files
    • Lines: ~90

Slice 6 — ServicePage form (R4)

  • 6.1 Sheet form below md

    • Files: frontend/src/pages/ServicePage.tsx
    • Lines: ~60
    • Details: branch on useIsMobile(); reuse form body inside SheetForm. Single-column fields. Preserve save semantics.
  • 6.2 Tests

    • Files: frontend/src/pages/__tests__/ServicePage.test.tsx (new or extend)
    • Lines: ~50

Slice 7 — Settings form (R4)

  • 7.1 Machines + SSH-key editors in Sheet

    • Files: frontend/src/pages/Settings.tsx
    • Lines: ~100
    • Details: both machine editor and SSH-key editor open in SheetForm below md. Validate-on-save preserved.
  • 7.2 Tests

    • Files: frontend/src/pages/__tests__/Settings.test.tsx
    • Lines: ~40

Slice 8 — Message compose + WidgetConfigDialog (R4)

  • 8.1 Message compose Sheet

    • Files: frontend/src/pages/UsersPage.impl.tsx
    • Lines: ~60
    • Details: compose dialog → SheetForm below md. HTML body textarea + iOS Safari attachment upload verified manually.
  • 8.2 WidgetConfigDialog Sheet

    • Files: frontend/src/components/WidgetConfigDialog.tsx
    • Lines: ~60
    • Details: reorder list and per-widget config render inside SheetForm below md. Sticky save bar.
  • 8.3 Tests

    • Files: extend existing
    • Lines: ~60

Slice 9 — Touch-target audit (R6)

  • 9.1 Apply mobile-touch-target across routes

    • Files: all 9 pages + shared components (SessionActivityPanel, ObservabilityPage, etc.)
    • Lines: ~150 (sprinkled)
    • Details: icon buttons, checkboxes, switches, badges-as-buttons, row taps. Manual device-mode pass at 375px logging violations; fix each.
  • 9.2 Audit log

    • Files: this PR description
    • Details: list every element touched with before/after hit-area size.

Slice 10 — Docs + verify

  • 10.1 Update docs/REQUIREMENTS.md

    • Files: docs/REQUIREMENTS.md
    • Lines: ~20
    • Details: add a Mobile section documenting the breakpoint, card/Sheet behavior, 44px policy, and the polling follow-up risk.
  • 10.2 Cross-route manual pass

    • Details: walk all 9 routes at 375px (iPhone 12 Pro preset) and at 1280px. Confirm no regressions; file follow-ups for any iOS Safari quirks found.
  • 10.3 Verify report

    • Files: openspec/changes/mobile-responsive-parity/verify-report.md
    • Lines: ~80
    • Details: per-AC evidence (AC1AC8), tool versions, manual test notes.

Notes

  • Each slice's diff should stay well under 400 changed lines. If a slice (e.g. Settings at ~100 + 40 test) approaches the budget, split along the natural sub-section boundary.
  • Slices 35 (tables) and 68 (forms) can be reordered or parallelized across branches if helpful, but each must merge green.
  • No slice touches the backend.