diff --git a/docs/superpowers/specs/2026-07-31-file-card-polish-design.md b/docs/superpowers/specs/2026-07-31-file-card-polish-design.md new file mode 100644 index 0000000..02a9daa --- /dev/null +++ b/docs/superpowers/specs/2026-07-31-file-card-polish-design.md @@ -0,0 +1,87 @@ +# File card / language switcher polish + +Date: 2026-07-31 + +## Goal + +Polish pass on top of the existing frontend redesign ([[2026-07-31-ombrora-frontend-redesign-design]]): flag icons for the language switcher, a friendlier destination-format/quality picker, a consistent visual skeleton across the three file-lifecycle states (choosing format, converting, downloading), and human-readable file size shown alongside the filename in both the choosing and downloading states. + +## Problem + +- `LanguageSwitcher.jsx` renders a plain text link ("English"/"Français") instead of a flag. +- `FileConfigCard` (choosing step) shows a generic `FileIcon` + filename; `FileCard` (download step) shows only the filename with no icon — different markup between the two, which reads as the icon "disappearing" when a file moves from one list to the other. +- Neither step shows file size. +- The target-format ``**, not a custom chip grid. Chosen for lower implementation cost and to keep native accessibility/keyboard behavior, restyled with border/focus/theme-token styling plus a small badge next to it showing the currently selected extension. +- **File size is computed and carried client-side, no backend change.** `File.size` is already available at selection time in `HomePage.handleFilesSelected`. For the download step, `uploadFiles(items)` returns jobs in the same order as the request array (confirmed in `src/app.js`'s `POST /api/jobs` handler, which builds jobs by iterating `req.files` index-for-index) — so `handleConvert` can zip the returned jobs with the original `validItems` by index to attach `size` onto each job object before it's stored in `submittedJobs`, with no API contract change. +- **"Converting" state gets a spinning icon**, not a progress bar (no real progress percentage exists to drive one) — `CircleNotch` from the already-installed `@phosphor-icons/react`, animated via a CSS `@keyframes spin`, respecting `prefers-reduced-motion` (existing design-system rule from the foundation spec). +- **Download link becomes a filled button** matching `.convert-button`'s visual language (same accent color, radius, min-height), not just a restyled inline link. + +## Architecture + +### New dependency + +Add `flag-icons` to `dependencies` in both `package.json` (root) and `frontend/package.json`, then `npm install` in both locations to keep both lockfiles in sync (per existing o2switch mirroring rule). + +### New util + +`frontend/src/utils/formatBytes.js` — pure function `formatBytes(bytes)` returning a human-readable string (`"2.4 MB"`, `"512 KB"`, `"0 B"` for falsy/zero/undefined input). Used by both `FileConfigCard` and `FileCard`. + +### Shared header markup/CSS + +Both components render the same header shape: + +``` +
+ + {name} + {formatBytes(size)} +
+``` + +CSS classes `.file-tile-header`, `.file-tile-name`, `.file-tile-size` added to `frontend/src/styles/home.css` (renaming/superseding today's `.file-config-name`, which only exists in that file today and is used by both components already — checked: `FileCard.jsx` currently reuses `.file-config-name` for its filename span, so this is a rename/extension of an existing shared class, not a net-new pattern). `FileCard` gains the icon it's currently missing. + +### `FileConfigCard.jsx` changes + +- Add size display next to filename (via `item.file.size`). +- Restyle the target-format `` with a custom chip/grid picker (considered, declined — see scope decisions). +- Any backend/API changes — file size is entirely a client-side, already-available value. +- A progress-percentage-driven progress bar for the "converting" state (no real progress data exists). +- Automated frontend tests (no test harness exists yet, per the foundation spec's own out-of-scope note). + +## Testing + +Manual only, consistent with the foundation spec's approach (no frontend test harness exists): +- `npm run dev` in `frontend/`, both `/fr/` and `/en/`. +- Upload one or more files, verify: file icon + name + size shown in the choosing step; format select is restyled with the extension badge visible; quality/PNG/ICO/PDF controls still function exactly as before. +- Convert, verify: converting state shows the spinning icon; on completion the download step shows the same icon + name + size layout as the choosing step, plus a filled download button; clicking it downloads the converted file. +- Verify the language switcher shows the correct flag for the *other* language (FR page shows GB flag and vice versa) and that keyboard/screen-reader users still get a meaningful accessible name. +- Verify at 375/768/1024/1440px widths that the new header layout doesn't break wrapping (existing `flex-wrap` behavior in `.file-config-card`/`.file-card` should still apply). +- Verify dark mode: flag icons, badges, and the new button render with sufficient contrast in both themes.