# UI checks: does it look right on phones and desktops? Tools live in `src/e2e/`. They need the dev stack (`src/dev/devenv.sh start`, app on :8020). | Tool | What it is for | |---|---| | `viewports.mjs` | Shared presets (`iphone-se` 375x667, `android-small` 360x740, `iphone-14` 390x844, `pixel-7` 412x915, `ipad` 768x1024, `laptop` 1280x800, `desktop` 1440x900, `fhd` 1920x1080), groups and `findHorizontalOverflow(page)` | | `shoot.mjs` | Screenshots in any viewport, reports console errors, failed requests and **horizontal overflow** (exit code 1) | | `tests/responsive.ui.spec.ts` | Regression test: no page overflows its viewport (home, create, three stats pages, order, order admin) | ## The process after any layout change 1. **Typecheck:** `cd src/frontend && npx tsc --noEmit`. 2. **Automatic overflow check, all sizes**, for the pages you touched (needs a user with data, `--as=admin` has the most): ```bash cd src/e2e node shoot.mjs /stats/orderee /stats/manager /stats/admin --as=admin --sizes=all # light node shoot.mjs /stats/orderee /stats/manager /stats/admin --as=admin --sizes=all --dark # dark ``` Any `WARN OVERFLOW : ... offenders` line is a bug: the page scrolls sideways on that device. The offenders are the elements that stick out. Fix: wrap tables in `scroll={{ x: true }}`, give flex children `minWidth: 0`, use `minmax(min(Npx, 100%), 1fr)` in grids. 3. **Look at it.** Overflow is only one kind of bug. Shoot the extremes and read the PNGs: ```bash node shoot.mjs /stats/orderee --as=admin --sizes=iphone-se,android-small,fhd --full ``` - Smallest phone (360 / 375): truncated or overlapping labels, tall single-column stacks, controls wrapping ("Stat us"), things that need sideways scrolling without a hint. - Tablet (768): where the layout switches; the awkward in-between. - Widest desktop (1920): content stays centred and readable, nothing stretched. - Dark mode on at least one phone and one desktop size. 4. **Zoom on a single widget** instead of reading a 14000px full-page shot: ```bash node shoot.mjs /stats/manager --as=admin --sizes=android-small,desktop --select='.ant-card:has-text("Participants per order")' ``` 5. **Run the regression spec** (`check` = iphone-se, pixel-7, ipad, desktop; `RESPONSIVE_SIZES=all` for all eight): ```bash npx playwright test --project=ui responsive RESPONSIVE_SIZES=all npx playwright test --project=ui responsive ``` Many parallel page loads can be slow on the Vite dev server; if you see timeouts add `--workers=2`. ## Getting data worth looking at A fresh user has no data and shows only the empty state. Options: - `--as=admin` in the dev stack usually has history. `--seed` or `{order}` / `{admin}` in the path create an order with two submissions. - The API can only create things "now". For charts over time, backdate rows directly in `src/backend/data/burger_orders.db` (`submissions.created_at`, `accepted`, `paid`). Remember the original values and **restore them afterwards**. ## Gotchas - `--sizes` takes preset names, groups (`phones`, `tablets`, `desktops`, `check`, `all`) or `WxH`. A name is never both a group and a preset. - `--mobile` still means the Pixel 7 preset; `--sizes` supersedes it. - `findHorizontalOverflow` ignores elements inside an intentional scroller (`overflow-x: auto|scroll|hidden|clip`) and fixed overlays, so heatmaps that scroll on purpose are not reported. That also means a clipped-but-unhinted scroller is **not** caught: look at the screenshots. - A pre-existing React warning (`useForm` not connected to a Form) appears once per page load in every shoot; it is not caused by the stats pages. - In this repo's shell, `grep` is a wrapper that honours `.gitignore`-style ignore files and silently skips some source files (for example `lib/stats.ts`). Use `command grep` when a search result looks suspiciously empty. ## Conventions the stats pages follow (so they pass) - Cards come from `ChartCard`; grids from `CardGrid` (`minmax(min(Npx, 100%), 1fr)`). - Wide content scrolls inside its own container (tables: `scroll={{ x: true }}`; the year calendar opens scrolled to the latest week) or shrinks to fit (the weekday x hour heatmap). - Column-chart labels are truncated per group of slots (`labelEvery`); the full text is in the tooltip. - Phones (<= 640px) get a tab strip (`Segmented`) instead of the side menu in `StatisticsView.tsx`.