Files
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

138 lines
5.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Spec — Mobile responsive parity
**Change:** `mobile-responsive-parity`
**Phase:** spec
**Date:** 2026-06-26
## Scope
All 9 application routes must be fully operable in phone portrait viewports
(≥360px) at a single `md:` (768px) breakpoint. Tablets and wider viewports keep
the existing desktop layout unchanged. No product behavior changes; this is a
presentation-layer parity change only.
## Requirements
### R1 — Viewport & breakpoint policy
- R1.1 The viewport meta stays `width=device-width, initial-scale=1.0` (no zoom
lock). User zoom remains enabled.
- R1.2 There is exactly one responsive cut: `md:` (768px). Below is "mobile";
at-or-above is "desktop" (existing behavior).
- R1.3 No `sm:` intermediate cut is introduced.
### R2 — App shell (already compliant; locked in)
- R2.1 Desktop `Sidebar` renders `null` when `isMobile` (`matchMedia("(max-width:
768px)")`).
- R2.2 Mobile nav uses the existing `MobileDrawer` (hamburger, `md:hidden`,
`Sheet` side=left) with no behavioral change.
- R2.3 `TopBar` keeps its existing responsive behavior (version badges hidden
on small screens, hamburger visible below `md`).
### R3 — Data tables (hybrid)
- R3.1 The four wide tables — **Media** (`pages/Media.tsx`), **FileBrowser**
(`pages/FileBrowser.impl.tsx`), **Users** (`pages/UsersPage.impl.tsx`), and the
three **Backups** tables (`BackupAlertsTable.tsx`, `BackupJobsTable.tsx`,
`BackupRunsTable.tsx`) — render a stacked **card per row** below `md`.
- R3.2 Each card shows a primary title plus the 35 most important fields for
that table (chosen per-table; documented in tasks). All remaining fields are
omitted from the mobile card.
- R3.3 Row click / selection semantics are preserved on the card (tap target =
the whole card where applicable).
- R3.4 **SessionActivityPanel** (narrow, 3-column) keeps the `<table>` shape
inside a horizontal-scroll container below `md`.
- R3.5 The TanStack **column-visibility toggle is hidden below `md`** on every
table that uses it (Media). The mobile card picks the fields; the user does
not re-show hidden columns on touch.
- R3.6 At `md:` and above, all tables render exactly as today.
### R4 — Edit forms (Sheet)
- R4.1 Below `md`, these edit flows open in a full-height `Sheet` (side=bottom
or side=right, full screen) instead of a centered `Dialog`:
- **ServicePage** connection config + secrets
- **Settings** machines and SSH-key editors
- **Message compose** dialog (`UsersPage.impl.tsx`)
- **WidgetConfigDialog**
- R4.2 The Sheet form has a sticky header (title + close affordance) and a
sticky footer/save bar (Cancel + Save).
- R4.3 Form fields stack to a single column inside the Sheet.
- R4.4 At `md:` and above, the existing `Dialog`-based forms are unchanged.
- R4.5 The Sheet closes on successful save and on explicit cancel; it does not
close on outside-click while the form is dirty (confirm prompt).
### R5 — Touch edit affordance
- R5.1 `HoverEditButton` gains a `md:` variant: hover-revealed on desktop
(unchanged), **always visible** below `md`.
- R5.2 Row/card edit and delete actions surface as persistent icon buttons on
the right edge below `md`.
- R5.3 Desktop hover-reveal aesthetic is not regressed at `md:` and above.
### R6 — Touch targets
- R6.1 All interactive elements below `md` have a minimum 44×44px hit area.
This includes: buttons, icon buttons, checkboxes, switches, row/card tap
targets, and badges that act as buttons.
- R6.2 Visual size may remain smaller than 44px (padding-only hit areas are
acceptable) as long as the tappable region meets the minimum.
- R6.3 At `md:` and above, sizes are unchanged.
### R7 — Dashboard layout
- R7.1 The widget grid collapses to a **single column** below `md`.
- R7.2 A **section anchor bar** appears at the top of the dashboard below `md`,
grouping widgets (e.g. Observability / Media / Backups / Custom) and allowing
quick jump-to-section.
- R7.3 Widget order respects the user's configured sort order.
- R7.4 At `md:` and above, the grid renders exactly as today.
### R8 — Polling (unchanged)
- R8.1 Widget refresh intervals and the message-queue poll interval are
identical on mobile and desktop.
- R8.2 (Follow-up risk, not in scope: pause refetch on `document.visibilityState
=== "hidden"`. Tracked in proposal §Risks.)
### R9 — No PWA
- R9.1 No web manifest, service worker, or standalone display mode is added.
- R9.2 OIDC continues to work in-browser; no standalone-mode redirect handling
is introduced.
### R10 — Non-regression
- R10.1 No desktop layout (≥768px) is visually or functionally regressed.
- R10.2 No backend API contract change.
- R10.3 No existing test is deleted; mobile-specific tests are additive.
## Acceptance criteria
- AC1 Every route listed in `App.tsx` `navItems` (Dashboard, Observability,
Media, Files, Backups, Users, Actions, Services, Settings) is fully operable
at 375px width in Chrome DevTools device mode (iPhone 12 Pro preset or
equivalent).
- AC2 Each of the four wide tables shows a card layout at 375px and the table
layout at 1280px.
- AC3 Each of the four edit forms opens in a Sheet at 375px and a Dialog at
1280px.
- AC4 `HoverEditButton` is always visible at 375px and hover-revealed at 1280px.
- AC5 A 44px-minimum touch-target audit passes for all interactive elements at
375px.
- AC6 The Dashboard renders a single column with an anchor bar at 375px and the
existing grid at 1280px.
- AC7 `cd frontend && npm run lint && npm run build && npm run test` is green.
- AC8 At least one Vitest test per touched page asserts behavior at <768px and
≥768px breakpoints.
## Non-goals
- Tablet/landscape/sm: intermediate layout.
- PWA, manifest, service worker, offline mode.
- Polling-interval changes.
- Backend changes.
- New data-table library.
- New product features.