batchCooking/apps/web/src/components/ui/Checkbox.tsx
Nicolas 66f2a36b8c chore(web): session de polish global — version, checkbox, danger zone, icônes
- Affiche le numéro de version (package.json, injecté via Vite) en bas de
  la sidebar, masqué en mode collapse et en mobile.
- Factorise les checkbox/radio dupliqués (AllergySelect, DietTagSelect,
  IngredientPicker, UserPreferencesPage) en composants partagés
  CheckboxOption/RadioOption (components/ui/), et inverse le layout pour
  que la case soit à gauche du label.
- Teinte la "zone de danger" de suppression de compte en rouge (fond +
  bordure), pas seulement le bouton.
- Migre les icônes de navigation générale vers lucide-react (nav-icons.tsx
  devient un fichier de ré-export) ; les pictogrammes d'ingrédients métier
  restent en SVG custom (pas d'équivalents fins côté lucide).

Vérifié : pnpm build, pnpm lint, pnpm --filter web e2e (43/43), et
vérification visuelle manuelle (sidebar desktop/collapsed/mobile, light/dark).
2026-08-18 14:39:06 +02:00

41 lines
1.5 KiB
TypeScript

import type { ReactNode } from "react";
/**
* The app-wide "selectable card" checkbox — see `global.scss`'s
* `label:has(> input[type="checkbox"])` rule for the actual look (hidden
* native input, a `.check-mark` that scales in, `is-selected` driving the
* tinted/bordered state). Factors out the JSX triplet (`label` → hidden
* `input` → `span.check-mark` → label text) that used to be duplicated
* across `AllergySelect`, `DietTagSelect`, `IngredientPicker`'s display
* menu, and `UserPreferencesPage`'s theme picker (see {@link RadioOption}
* for its `type="radio"` sibling) — one place to get the markup/a11y right
* instead of four.
*
* `is-selected` is applied in JS from the same `checked` boolean the caller
* already has, not derived via a CSS `:has(:checked)` chain — that turned
* out unreliable across browsers (see the callers this replaces for the
* original note).
*
* `className` is for the *container* layout only (grid item, flex-wrap
* chip, stacked list…) — the control's own look never varies, so there's
* no `variant` prop here.
*/
export function CheckboxOption({
checked,
onChange,
children,
className,
}: {
checked: boolean;
onChange: (checked: boolean) => void;
children: ReactNode;
className?: string;
}) {
return (
<label className={[className, checked && "is-selected"].filter(Boolean).join(" ")}>
<input type="checkbox" checked={checked} onChange={(e) => onChange(e.target.checked)} />
<span className="check-mark" aria-hidden="true" />
{children}
</label>
);
}