# 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.