696 lines
40 KiB
Markdown
696 lines
40 KiB
Markdown
# Nouvelle architecture UI & plan de refonte — Xpeditis
|
||
|
||
**Date :** 2026-08-12 · **Branche :** `ui_update`
|
||
**Prérequis de lecture :** [`design-system-audit.md`](./design-system-audit.md) (charte verrouillée) · [`ui-audit.md`](./ui-audit.md) (cartographie)
|
||
|
||
> **Contrainte cardinale.** Toute valeur visuelle produite ici provient du §1–§22 de `design-system-audit.md`.
|
||
> Aucune couleur, police, rayon ou token n'est introduit. Ce document ne fait que **réorganiser** et **appliquer** l'existant.
|
||
|
||
---
|
||
|
||
## Sommaire
|
||
|
||
- [1. Principes directeurs](#1-principes-directeurs)
|
||
- [2. Vocabulaire visuel appliqué](#2-vocabulaire-visuel-appliqué)
|
||
- [3. App shell](#3-app-shell)
|
||
- [4. Composants de navigation](#4-composants-de-navigation)
|
||
- [5. Composants de contenu](#5-composants-de-contenu)
|
||
- [6. Composants de saisie](#6-composants-de-saisie)
|
||
- [7. Composants de surface](#7-composants-de-surface)
|
||
- [8. Composants d'état](#8-composants-détat)
|
||
- [9. Architecture de fichiers](#9-architecture-de-fichiers)
|
||
- [10. Responsive](#10-responsive)
|
||
- [11. Micro-interactions](#11-micro-interactions)
|
||
- [12. Accessibilité](#12-accessibilité)
|
||
- [13. Plan de refonte par lots](#13-plan-de-refonte-par-lots)
|
||
- [14. Protocole de validation](#14-protocole-de-validation)
|
||
- [15. Ce que je ne ferai pas](#15-ce-que-je-ne-ferai-pas)
|
||
|
||
---
|
||
|
||
## 1. Principes directeurs
|
||
|
||
Quatre règles arbitrent chaque décision de la refonte. Elles sont volontairement peu nombreuses et opposables.
|
||
|
||
**P1 — Le navy porte la structure, le turquoise porte l'action.**
|
||
`brand-navy #10183A` = chrome, titres, surfaces d'autorité, état actif.
|
||
`brand-turquoise #34CCCD` = action primaire, focus, sélection, accent de données.
|
||
Cette règle remplace, à elle seule, les 816 usages de bleu générique. Elle n'invente rien : c'est la lecture littérale de la charte.
|
||
|
||
**P2 — La densité est une fonctionnalité.**
|
||
Xpeditis est un outil de transitaire : listes longues, colonnes nombreuses, comparaison de taux. La refonte va vers **plus d'information par écran**, pas moins. Concrètement : cartes KPI alignées à gauche et non centrées, tables en densité compacte par défaut, padding `p-4`/`p-5` plutôt que `p-6`, suppression des conteneurs décoratifs intermédiaires.
|
||
|
||
**P3 — Une seule manière de faire chaque chose.**
|
||
Un bouton, un champ, une table, une modale, un état vide. Les trois systèmes de boutons deviennent un. Les 7 paginations deviennent une. Toute variante doit être justifiée par un besoin fonctionnel distinct, pas par une préférence locale.
|
||
|
||
**P4 — Le mouvement sert la compréhension.**
|
||
Une animation n'est acceptée que si elle explique une transition d'état ou une relation spatiale. 120–200 ms, `ease-out`, sur `opacity` / `transform` uniquement. Tout le reste est supprimé.
|
||
|
||
---
|
||
|
||
## 2. Vocabulaire visuel appliqué
|
||
|
||
### 2.1 Rôles de couleur — dérivés stricts de la charte
|
||
|
||
| Rôle | Token | Valeur | Application |
|
||
|------|-------|--------|-------------|
|
||
| Surface application | `bg-white` | `#FFFFFF` | Cartes, panneaux, tables |
|
||
| Surface page | `neutral-50` | `#F8F9FC` | Fond de zone de contenu |
|
||
| Surface d'autorité | `brand-navy` | `#10183A` | Sidebar admin, sections navy, en-têtes sombres |
|
||
| Bordure | `--border` | `#E2E8F0` | Bordures 1px, séparateurs |
|
||
| Texte principal | `brand-navy` | `#10183A` | Titres, valeurs KPI |
|
||
| Texte courant | `neutral-800` | `#1E2859` | Corps |
|
||
| Texte secondaire | `neutral-500` | `#5A6BB8` | Descriptions, métadonnées |
|
||
| Action primaire | `brand-turquoise` | `#34CCCD` | CTA, boutons primaires |
|
||
| Focus | `brand-turquoise` | `#34CCCD` | Anneau de focus (via `--ring`) |
|
||
| État actif (nav) | `brand-navy` + fond `neutral-100` | `#10183A` / `#EDEEF5` | Item de sidebar actif |
|
||
| Succès | `success` / `brand-green` | `#067224` | Accepté, validé, payé |
|
||
| Erreur | `--destructive` | `#EF4444` | Refusé, erreur, suppression |
|
||
| Avertissement | `amber-500` | `#F59E0B` | En attente, expiration proche |
|
||
|
||
> **Trois substitutions systématiques, et rien d'autre :**
|
||
> `blue-*` → `brand-turquoise` (action) ou `brand-navy` (structure) selon le rôle
|
||
> `gray-*` → `neutral-*` (échelle déjà définie dans la charte)
|
||
> `purple-*` / `emerald-*` / `orange-*` / `indigo-*` → rôle sémantique ci-dessus
|
||
|
||
### 2.2 Élévation — 3 niveaux, pas 6
|
||
|
||
L'audit relève 6 niveaux d'ombre utilisés sans règle. La refonte en retient trois :
|
||
|
||
| Niveau | Classe | Usage |
|
||
|--------|--------|-------|
|
||
| 0 | `border` seul | Cartes, panneaux, tables — **défaut** |
|
||
| 1 | `shadow-sm` | Éléments flottants ancrés : dropdowns, popovers, sidebar mobile |
|
||
| 2 | `shadow-lg` | Éléments détachés : modales, drawers, toasts |
|
||
|
||
`shadow-md`, `shadow-xl`, `shadow-2xl` et la classe fantôme `shadow-brand` sont retirés du produit.
|
||
**La carte par défaut passe de `shadow-sm` à `border` seul** — c'est le principal levier pour un rendu net et non « cartonné ».
|
||
|
||
### 2.3 Rayons — 3 valeurs
|
||
|
||
| Classe | Valeur | Usage |
|
||
|--------|--------|-------|
|
||
| `rounded-md` | 6px | Contrôles : boutons, champs, selects, badges carrés |
|
||
| `rounded-lg` | 8px | Conteneurs : cartes, panneaux, modales, dropdowns |
|
||
| `rounded-full` | — | Pilules, avatars, points d'état |
|
||
|
||
`rounded-xl`, `rounded-2xl`, `rounded-3xl` sont retirés du produit. (Conservés uniquement sur la landing, traitée en dernier lot — voir §13, L9.)
|
||
|
||
### 2.4 Typographie appliquée
|
||
|
||
L'échelle `text-h1…h6` / `text-body-*` / `text-label-*` de la charte est **enfin utilisée**, en remplacement de l'échelle Tailwind par défaut :
|
||
|
||
| Élément | Token de charte |
|
||
|---------|-----------------|
|
||
| Titre de page | `text-h3` (24px/600, Manrope) |
|
||
| Description de page | `text-body-sm` + `neutral-500` |
|
||
| Titre de section / carte | `text-h5` (18px/500) |
|
||
| Valeur KPI | `text-h2` (32px/600) + `brand-navy` |
|
||
| Corps | `text-body-sm` (14px) — densité produit |
|
||
| En-tête de table | `text-label` (12px/600, +0.05em, capitales) |
|
||
| Cellule de table | `text-body-sm` |
|
||
| Libellé de champ | `text-label-lg` (14px/600) |
|
||
| Aide / erreur de champ | `text-body-xs` (12px) |
|
||
|
||
> Le titre de page passe de `text-3xl` (30px) à `text-h3` (24px). C'est volontaire : combiné à la suppression du double titre (§3), l'écran gagne en hiérarchie **et** en espace utile.
|
||
|
||
### 2.5 Rythme d'espacement — échelle 4/8
|
||
|
||
Multiples retenus : **4, 8, 12, 16, 24, 32, 48**. (`gap-1` `gap-2` `gap-3` `gap-4` `gap-6` `gap-8` `gap-12`)
|
||
|
||
| Contexte | Valeur |
|
||
|----------|--------|
|
||
| Padding de carte | `p-5` (20px) desktop, `p-4` mobile |
|
||
| Padding de cellule de table | `px-4 py-3` (compact) / `px-4 py-4` (confortable) |
|
||
| Gap de grille | `gap-4` |
|
||
| Espacement entre sections | `space-y-6` |
|
||
| Padding de zone de contenu | `p-4 lg:p-6 2xl:p-8` |
|
||
|
||
---
|
||
|
||
## 3. App shell
|
||
|
||
### 3.1 Structure cible
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────┐
|
||
│ Sidebar (w-60 / w-16 replié) │ Topbar (h-14) │
|
||
│ ───────────────────────────── ├──────────────────────────────│
|
||
│ Logo [«] │ Breadcrumb ⌘K 🔔 🌐 👤 │
|
||
│ ├──────────────────────────────│
|
||
│ ── Pilotage │ │
|
||
│ ▸ Tableau de bord │ PageHeader │
|
||
│ ▸ Réservations │ Titre (h3) + description │
|
||
│ ▸ Documents │ [onglets] [actions] │
|
||
│ ▸ Suivi │ ────────────────────────── │
|
||
│ │ │
|
||
│ ── Ressources │ Contenu │
|
||
│ ▸ Wiki │ │
|
||
│ │ │
|
||
│ ── Organisation │ │
|
||
│ ▸ Paramètres │ │
|
||
│ · Organisation │ │
|
||
│ · Membres │ │
|
||
│ · Clés API │ │
|
||
│ ───────────────────────────── │ │
|
||
│ 👤 Utilisateur [⋮] │ │
|
||
└──────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 3.2 Décisions
|
||
|
||
| Décision | Avant | Après | Motif |
|
||
|----------|-------|-------|-------|
|
||
| **Suppression du double titre** | Topbar affiche le nom de nav + page affiche son `<h1>` | Topbar affiche le **breadcrumb** ; la page seule porte le `<h1>` | Corrige A5 |
|
||
| **Sidebar repliable** | `w-64` fixe | `w-60` / `w-16` replié, persisté en `localStorage` | Rend 240px aux tables larges |
|
||
| **Groupes de navigation** | 8 entrées à plat | 3 groupes (Pilotage / Ressources / Organisation) avec libellés `text-label` | Lisibilité, prépare la croissance |
|
||
| **Paramètres regroupés** | 3 entrées de nav dispersées | 1 entrée + sous-navigation | Corrige la dispersion relevée en B2 |
|
||
| **Un seul avatar** | Sidebar + topbar | Pied de sidebar uniquement, avec menu (Profil / Déconnexion) | Corrige la redondance |
|
||
| **Logout dans le menu** | Bouton rouge pleine largeur permanent | Entrée du menu utilisateur | Poids visuel proportionné |
|
||
| **Command menu ⌘K** | Absent | Recherche globale : navigation, réservations, ports, actions | Standard SaaS attendu |
|
||
| **Bottom-nav mobile** | 5 entrées sur 8 | 4 entrées + « Plus » ouvrant le drawer complet | Aucune section inaccessible |
|
||
| **Shell mutualisé** | 2 layouts dupliqués à 80 % | `AppShell` paramétré (`variant: 'app' | 'admin'`) | Corrige D2 |
|
||
| **Icônes** | SVG inline manuscrits | `Menu`, `X`, `PanelLeftClose` de lucide | Cohérence |
|
||
|
||
**Variante admin :** même `AppShell`, `variant="admin"` → sidebar `bg-brand-navy text-white`, logo blanc, séparateurs `border-white/10`. Le contenu des pages admin adopte le même vocabulaire que le dashboard (correction de la rupture chrome/contenu relevée en B3).
|
||
|
||
### 3.3 États de l'item de navigation
|
||
|
||
| État | Style |
|
||
|------|-------|
|
||
| Défaut | `text-neutral-700 hover:bg-neutral-100 hover:text-brand-navy` |
|
||
| Actif | `bg-neutral-100 text-brand-navy font-semibold` + barre `w-0.5 bg-brand-turquoise` à gauche |
|
||
| Verrouillé (plan) | `text-neutral-400` + icône `Lock` + `Tooltip` expliquant le plan requis, lien `/pricing` |
|
||
| Replié | icône seule centrée + `Tooltip` au survol |
|
||
|
||
> L'état actif abandonne le fond bleu au profit d'un fond neutre + **accent turquoise en filet**. Plus discret, plus précis, strictement dans la charte.
|
||
|
||
---
|
||
|
||
## 4. Composants de navigation
|
||
|
||
| Composant | Rôle | Notes d'implémentation |
|
||
|-----------|------|------------------------|
|
||
| `AppShell` | Enveloppe sidebar + topbar + contenu + bottom-nav | Remplace les 2 layouts |
|
||
| `Sidebar` | Navigation groupée, repliable, drawer sous `lg` | Focus trap en mode drawer |
|
||
| `Topbar` | Breadcrumb + ⌘K + notifications + langue + avatar | `h-14`, `sticky`, `border-b` |
|
||
| `Breadcrumb` | Fil d'Ariane dérivé de la route + libellés i18n | Tronque au milieu sur mobile |
|
||
| `PageHeader` | Titre `h3`, description, onglets, actions | **Extension** de l'existant (déjà sur 9 pages) |
|
||
| `Tabs` | Sous-navigation de page (paramètres, détail réservation) | Sur `@radix-ui/react-tabs` (installé) |
|
||
| `CommandMenu` | Palette ⌘K | Sur `ui/command.tsx` complété |
|
||
| `BottomNav` | Navigation mobile 4 + « Plus » | — |
|
||
|
||
---
|
||
|
||
## 5. Composants de contenu
|
||
|
||
### 5.1 `DataTable` — pièce maîtresse
|
||
|
||
Fondé sur `@tanstack/react-table` v8 (installé, utilisé une seule fois) et `@tanstack/react-virtual` (installé, jamais utilisé).
|
||
|
||
| Capacité | Détail |
|
||
|----------|--------|
|
||
| Colonnes | Définition déclarative, tri, redimensionnement, visibilité |
|
||
| Densité | `compact` (`py-3`) par défaut / `comfortable` (`py-4`) |
|
||
| Sélection | Cases à cocher + barre d'actions groupées flottante |
|
||
| En-tête | `sticky top-0`, `text-label`, fond `neutral-50` |
|
||
| Ligne | `hover:bg-neutral-50`, sélectionnée `bg-neutral-100` |
|
||
| Colonne d'actions | `sticky right-0`, menu sur `@radix-ui/react-dropdown-menu` — **remplace le positionnement manuel `menuPos`** relevé en B2 |
|
||
| **Responsive** | ≥ `lg` : table · `md` : colonnes secondaires masquées · < `md` : **liste de `DataCard`** (titre, 3 champs clés, menu d'actions) |
|
||
| Virtualisation | Activable, pour `/admin/logs` et les résultats de recherche |
|
||
| États | `loading` → `TableSkeleton` · `empty` → `EmptyState` · `error` → `ErrorState` |
|
||
| Pagination | `Pagination` intégré, taille de page persistée |
|
||
|
||
Ce composant absorbe **26 tables brutes, 7 paginations et 21 `overflow-x-auto`**.
|
||
|
||
### 5.2 Autres
|
||
|
||
| Composant | Rôle |
|
||
|-----------|------|
|
||
| `Card` | Rectifié : `border` seul, `p-5`, `CardTitle` en `text-h5` |
|
||
| `StatCard` | KPI : libellé `text-label`, valeur `text-h2`, delta, icône discrète. **Aligné à gauche.** |
|
||
| `DataCard` | Représentation mobile d'une ligne de table |
|
||
| `Badge` | Variants sémantiques : `neutral` `info` `success` `warning` `danger` — tokens de charte uniquement |
|
||
| `StatusBadge` | Conservé (badges d'abonnement Silver/Gold/Platinium) |
|
||
| `Callout` | Encadré éditorial : `info` `warning` `success` `danger` — absorbe les ~30 encadrés du wiki |
|
||
| `Pagination` | Précédent/Suivant + pages + sélecteur de taille + compteur |
|
||
| `DescriptionList` | Paires libellé/valeur des pages de détail |
|
||
| `Timeline` | Suivi d'expédition (`/track-trace`), étapes de réservation |
|
||
|
||
---
|
||
|
||
## 6. Composants de saisie
|
||
|
||
| Composant | Base | Correction apportée |
|
||
|-----------|------|---------------------|
|
||
| `Button` | `cva` + `cn()` + `@radix-ui/react-slot` | `asChild` (corrige le `<a><button>` invalide) · état `loading` · `active:` · **`hover:bg-accent` turquoise plein supprimé** sur `ghost`/`outline` |
|
||
| `Input` | Existant corrigé | Focus turquoise · états `error` · préfixe/suffixe · tailles `sm`/`md` |
|
||
| `Textarea` | Nouveau | Aligné sur `Input` |
|
||
| `Select` | **`@radix-ui/react-select`** | Réécriture — l'actuel n'affiche jamais sa valeur |
|
||
| `Combobox` | `Command` + `Popover` Radix | Remplace les autocomplétions manuelles (ports, compagnies) |
|
||
| `Checkbox` / `Radio` | Nouveaux | Aujourd'hui inputs bruts |
|
||
| `Switch` | Existant | Conservé, aligné sur les tokens |
|
||
| `DatePicker` | `react-day-picker` + `date-fns` (installé) | Dates de départ/arrivée |
|
||
| `FormField` | Nouveau | `Label` + contrôle + aide + erreur + `aria-describedby`/`aria-invalid`. **Absorbe 175 inputs bruts.** |
|
||
| `Form` | `react-hook-form` + `zod` (installés) | Validation unifiée ; remplace les 25 `useState` de `/register` |
|
||
| `FileDropzone` | Nouveau | Glisser-déposer + progression + validation. **Absorbe 4 implémentations.** |
|
||
| `SearchInput` | Nouveau | Champ de recherche debounced avec effacement |
|
||
| `FilterBar` | Nouveau | Filtres + jetons actifs + réinitialisation, état synchronisé à l'URL |
|
||
|
||
### Variants de `Button` (définitifs)
|
||
|
||
| Variant | Style | Usage |
|
||
|---------|-------|-------|
|
||
| `primary` | `bg-brand-turquoise text-white hover:bg-brand-turquoise/90` | Action principale — **une seule par écran** |
|
||
| `secondary` | `bg-brand-navy text-white hover:bg-brand-navy/90` | Action structurante |
|
||
| `outline` | `border border-[--border] text-brand-navy hover:bg-neutral-50` | Action secondaire |
|
||
| `ghost` | `text-neutral-700 hover:bg-neutral-100` | Actions de table, icônes |
|
||
| `destructive` | `bg-[--destructive] text-white hover:bg-[--destructive]/90` | Suppression |
|
||
| `link` | `text-brand-turquoise hover:underline underline-offset-4` | Liens en ligne |
|
||
|
||
Tailles : `sm` (32px) · `md` (36px, défaut) · `lg` (40px) · `icon` (36×36).
|
||
> Les hauteurs passent de 40/36/44 à 36/32/40 : cohérent avec P2 (densité) et avec la topbar `h-14`.
|
||
|
||
---
|
||
|
||
## 7. Composants de surface
|
||
|
||
| Composant | Base | Notes |
|
||
|-----------|------|-------|
|
||
| `Dialog` | **`@radix-ui/react-dialog`** | Portal, focus trap, `Escape`, scroll-lock, `aria-modal`. Tailles `sm`/`md`/`lg`/`full`. Absorbe les modales inline de `/documents` et `/admin/blog` |
|
||
| `ConfirmDialog` | Sur `Dialog` | **Remplace les 14 `confirm()` natifs.** Variante `destructive` avec libellé d'action explicite |
|
||
| `Drawer` | Sur `Dialog` Radix | Panneau latéral : détail de réservation, filtres mobiles, aperçu de document |
|
||
| `Popover` | **`@radix-ui/react-popover`** | Portalisé — corrige le clipping |
|
||
| `DropdownMenu` | **`@radix-ui/react-dropdown-menu`** | Menus d'actions de table, menu utilisateur |
|
||
| `Tooltip` | `@radix-ui/react-tooltip` | Items de sidebar repliée, icônes, valeurs tronquées |
|
||
| `Toast` / `Toaster` | Nouveau, monté dans `Providers` | **Remplace les 44 `alert()`.** Variants `success` `error` `warning` `info`. Bas-droite desktop, haut mobile. Auto-dismiss 4 s, action optionnelle, empilement max 3 |
|
||
| `Sheet` | Sur `Dialog` | Drawer mobile de la sidebar |
|
||
|
||
---
|
||
|
||
## 8. Composants d'état
|
||
|
||
Quatre composants qui absorbent ~126 réimplémentations.
|
||
|
||
| Composant | Remplace | Contenu |
|
||
|-----------|----------|---------|
|
||
| `Skeleton` + `TableSkeleton` / `CardSkeleton` / `FormSkeleton` | ~30 `animate-pulse` inline | `bg-neutral-100 animate-pulse rounded-md`, forme calquée sur le contenu réel |
|
||
| `EmptyState` | 27 blocs vides | Icône (cercle `neutral-100`), titre `text-h5`, description `text-body-sm`, action. Variantes : *aucune donnée* / *aucun résultat de filtrage* / *accès verrouillé* |
|
||
| `ErrorState` | 29 bandeaux inline | Icône, message, bouton « Réessayer », détail repliable |
|
||
| `Spinner` | 40 fichiers `animate-spin` | Tailles `sm`/`md`/`lg`, couleur `brand-turquoise` |
|
||
|
||
**Règle de complétude :** toute vue asynchrone doit traiter les **4 états** — chargement, vide, erreur, contenu. C'est un critère de revue par page.
|
||
|
||
---
|
||
|
||
## 9. Architecture de fichiers
|
||
|
||
```
|
||
apps/frontend/src/
|
||
├── components/
|
||
│ ├── ui/ # Primitives — aucune logique métier
|
||
│ │ ├── button.tsx input.tsx textarea.tsx select.tsx combobox.tsx
|
||
│ │ ├── checkbox.tsx radio.tsx switch.tsx date-picker.tsx
|
||
│ │ ├── card.tsx badge.tsx callout.tsx separator.tsx avatar.tsx
|
||
│ │ ├── dialog.tsx drawer.tsx popover.tsx dropdown-menu.tsx tooltip.tsx
|
||
│ │ ├── toast.tsx toaster.tsx
|
||
│ │ ├── table.tsx pagination.tsx tabs.tsx command.tsx
|
||
│ │ ├── skeleton.tsx spinner.tsx empty-state.tsx error-state.tsx
|
||
│ │ └── index.ts # export unique
|
||
│ ├── shell/ # Chrome applicatif
|
||
│ │ ├── app-shell.tsx sidebar.tsx topbar.tsx
|
||
│ │ ├── breadcrumb.tsx bottom-nav.tsx command-menu.tsx
|
||
│ │ └── user-menu.tsx
|
||
│ ├── data/ # Affichage de données
|
||
│ │ ├── data-table.tsx data-card.tsx stat-card.tsx
|
||
│ │ ├── description-list.tsx timeline.tsx
|
||
│ │ └── filter-bar.tsx search-input.tsx
|
||
│ ├── forms/
|
||
│ │ ├── form.tsx form-field.tsx file-dropzone.tsx
|
||
│ │ └── port-autocomplete.tsx
|
||
│ └── [feature]/ # bookings/ documents/ rate-search/ admin/ …
|
||
├── hooks/
|
||
│ ├── use-toast.ts use-media-query.ts use-sidebar.ts
|
||
│ └── use-url-state.ts # synchronisation filtres ↔ URL
|
||
└── lib/
|
||
└── utils.ts # cn() — déjà présent
|
||
```
|
||
|
||
**Conventions :**
|
||
- `ui/` ne connaît ni l'API, ni l'i18n, ni le routage. Composants purs et testables.
|
||
- Tout composant utilise `cn()` pour fusionner les classes (aujourd'hui : concaténation de strings).
|
||
- Aucun texte en dur : tout passe par `next-intl`. **`messages/fr.json` et `messages/en.json` (4 600 lignes chacun) restent synchronisés clé pour clé.**
|
||
- Les pages orchestrent, les composants affichent. Objectif : aucune page > 300 lignes.
|
||
|
||
---
|
||
|
||
## 10. Responsive
|
||
|
||
### 10.1 Paliers et intentions
|
||
|
||
| Palier | Largeur | Layout |
|
||
|--------|---------|--------|
|
||
| **Mobile** | < 640px | 1 colonne · bottom-nav · sidebar en drawer · tables → `DataCard` · filtres en `Drawer` · actions en `DropdownMenu` |
|
||
| **Tablette** | 640–1023px | 2 colonnes · sidebar en drawer · tables réduites aux colonnes essentielles · filtres en ligne repliables |
|
||
| **Desktop** | 1024–1535px | Sidebar fixe · tables complètes · 3–4 colonnes de KPI · panneaux latéraux |
|
||
| **Grand écran** | ≥ 1536px | Contenu jusqu'à **1600px** · 4–6 colonnes de KPI · densité augmentée · `p-8` |
|
||
|
||
### 10.2 Corrections ciblées
|
||
|
||
- **A8 — grand écran.** `max-w-7xl` (1280px) devient `max-w-[1600px]` sur les vues de données (listes, tables, dashboard). Les vues de lecture (wiki, blog, légal) restent contraintes à `max-w-3xl` pour la longueur de ligne. Introduction effective du palier `2xl:` (aujourd'hui **0 occurrence**).
|
||
- **A9 — tablette.** Le palier `md` reçoit un traitement propre : grilles KPI en 2 colonnes, tables à colonnes réduites, `PageHeader` en pile. Cible : `md:` passe de 120 à un niveau comparable à `sm:`/`lg:`.
|
||
- **A10 — tables.** Bascule `DataTable` → `DataCard` sous `md`, native au composant. Aucun scroll horizontal subi.
|
||
- **Cibles tactiles.** Minimum 44×44px sur mobile pour toute action (bottom-nav, menus, boutons de table).
|
||
|
||
---
|
||
|
||
## 11. Micro-interactions
|
||
|
||
Technologies déjà présentes uniquement : **`tailwindcss-animate`** (installé, quasi inutilisé) pour l'UI, **`framer-motion`** (installé) réservé à la landing.
|
||
|
||
| Interaction | Effet | Durée |
|
||
|-------------|-------|-------|
|
||
| Survol de bouton | `background-color` | 120 ms `ease-out` |
|
||
| Pression de bouton | `scale(0.98)` | 80 ms |
|
||
| Survol de ligne de table | `background-color` | 100 ms |
|
||
| Ouverture de modale | `fade-in` + `zoom-in-95` | 180 ms `ease-out` |
|
||
| Ouverture de dropdown/popover | `fade-in` + `slide-in-from-top-1` | 140 ms |
|
||
| Toast | `slide-in-from-bottom` / `fade-out` | 200 ms |
|
||
| Drawer / sidebar mobile | `translate-x` | 220 ms `ease-out` |
|
||
| Onglets | Indicateur glissant | 160 ms |
|
||
| Sidebar repliée | `width` | 200 ms `ease-out` |
|
||
| Skeleton | `animate-pulse` | — |
|
||
|
||
**Règles :** `opacity` et `transform` uniquement (pas de `height`/`width` animées hors sidebar) · jamais de délai avant une réponse à un clic · pas d'animation d'entrée sur le contenu de page (perçu comme lent) · **`prefers-reduced-motion` respecté globalement** :
|
||
|
||
```css
|
||
@media (prefers-reduced-motion: reduce) {
|
||
*, *::before, *::after {
|
||
animation-duration: 0.01ms !important;
|
||
transition-duration: 0.01ms !important;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 12. Accessibilité
|
||
|
||
Cible : **WCAG 2.1 AA**.
|
||
|
||
| Point | Action |
|
||
|-------|--------|
|
||
| Focus | `focus-visible` partout (aujourd'hui 454 `focus:` contre 13 `focus-visible:`), anneau `ring-2 ring-brand-turquoise ring-offset-2` |
|
||
| `--ring` | Corrigé vers le turquoise de marque — **restauration de charte**, pas modification |
|
||
| Clavier | Navigation complète : tables, menus, modales, combobox, tunnel de recherche |
|
||
| Focus trap | Modales, drawers, sidebar mobile (via Radix) |
|
||
| Libellés | Tout contrôle a un `<label>` associé ou un `aria-label` ; tout bouton-icône a un `aria-label` (29 aujourd'hui pour 299 boutons) |
|
||
| Régions | `<nav>`, `<main>`, `<aside>`, `<header>` + lien d'évitement |
|
||
| Annonces | `aria-live` sur les toasts et les résultats de recherche |
|
||
| Contraste | Vérifier `neutral-400`/`neutral-500` sur blanc ; `brand-turquoise #34CCCD` **ne passe pas AA en texte sur blanc** → réservé aux fonds, bordures et grandes tailles, jamais au texte courant sur blanc |
|
||
| Mouvement | `prefers-reduced-motion` |
|
||
|
||
> Le point contraste est important : il ne change pas la charte, il **encadre l'usage** du turquoise. Texte turquoise sur blanc → remplacé par navy, le turquoise restant sur les surfaces d'action (texte blanc sur turquoise = conforme).
|
||
|
||
---
|
||
|
||
## 13. Plan de refonte par lots
|
||
|
||
11 lots, séquencés par dépendance. Chaque lot est autonome, compilable et validable.
|
||
|
||
| Lot | Contenu | Fichiers | Effort |
|
||
|-----|---------|----------|--------|
|
||
| **L0 — Fondations** | Corriger `--ring` · `cn()` partout · réécrire `Button`/`Input`/`Select`/`Dialog`/`Popover` sur Radix · créer `Toast`, `Skeleton`, `EmptyState`, `ErrorState`, `Spinner`, `Pagination`, `Breadcrumb`, `Callout`, `FormField`, `Tooltip`, `DropdownMenu`, `Checkbox`, `Radio`, `Textarea` · monter `Toaster` dans `Providers` · `prefers-reduced-motion` | ~25 nouveaux, 8 réécrits | 2–3 j |
|
||
| **L1 — App shell** | `AppShell` mutualisé · sidebar repliable groupée · topbar + breadcrumb · suppression du double titre · `CommandMenu` ⌘K · bottom-nav complète · `UserMenu` · **restauration charte sur le chrome** | 2 layouts → ~8 composants | 2 j |
|
||
| **L2 — Données** | `DataTable` + `DataCard` + `FilterBar` + `SearchInput` + `StatCard` + `useUrlState` · virtualisation | ~8 composants | 2–3 j |
|
||
| **L3 — Dashboard & réservations** | `/dashboard` (hiérarchie KPI, charts aux couleurs de charte, suppression du `#8884d8`) · `/bookings` · `/bookings/[id]` · **arbitrage D1** | 4 pages | 3 j |
|
||
| **L4 — Documents & recherche** | `/documents` (démonolithisation 1169 l., `FileDropzone`, modales Radix, 9 `alert()` → toasts) · `/search` · `/search-advanced` (état en URL, `Combobox`) · `/results` · `/track-trace` | 5 pages | 3–4 j |
|
||
| **L5 — Paramètres & profil** | `SettingsLayout` à onglets · `/settings/organization` · `/settings/users` · `/settings/api-keys` · `/profile` · `/notifications` | 6 pages | 2 j |
|
||
| **L6 — Admin** | Alignement chrome/contenu · `DataTable` sur les 5 listes · démonolithisation `/admin/blog` (1341 l.) · 11+9 `alert()` → toasts · virtualisation `/admin/logs` | 8 pages | 3–4 j |
|
||
| **L7 — Wiki & docs** | `Callout` (~30) · `.prose` + `@tailwindcss/typography` · sommaire + ancres · largeur de lecture · breadcrumb · nav précédent/suivant · **93 `blue-*` corrigés** | 13 + 2 pages | 2 j |
|
||
| **L8 — Auth & portails** | `AuthLayout` mutualisé · `/register` sur `react-hook-form`+`zod` (25 `useState`) · fusion accept/reject · états d'expiration de lien · robustesse mot de passe | 11 pages | 2 j |
|
||
| **L9 — Marketing** | Extraction de `/` (1082 l.) en sections · alignement rayons/ombres · suppression des nuances navy inventées (`#1A2550`, `#1A2A5E`) · `LegalPageLayout` | 11 pages | 2 j |
|
||
| **L10 — Nettoyage** | Supprimer `/test-image`, `/demo-carte`, `src/legacy-pages/` · trancher `src/app/rates/csv-search` · `gray-*` → `neutral-*` · retirer `.btn-*`/`.input`/`.card` de `globals.css` · trancher le dark mode · mettre à jour `DESIGN_SYSTEM.md` | — | 1 j |
|
||
|
||
**Total estimé : 24–29 jours de travail.**
|
||
|
||
**Chemin critique :** L0 → L1 → L2 conditionnent tout le reste. L3 à L9 sont ensuite parallélisables.
|
||
|
||
---
|
||
|
||
## 14. Protocole de validation
|
||
|
||
### Après chaque lot
|
||
|
||
```bash
|
||
cd "apps/frontend"
|
||
|
||
# 1. La charte n'a pas bougé
|
||
git diff tailwind.config.ts # doit être VIDE
|
||
git diff app/globals.css # seul --ring modifié (L0), validé
|
||
|
||
# 2. Les dérives reculent
|
||
grep -rE "\b(bg|text|border|ring|from|to)-blue-" app src --include="*.tsx" | wc -l # jamais croissant
|
||
grep -rE "[^.](alert|confirm)\(" app src --include="*.tsx" | wc -l # jamais croissant
|
||
|
||
# 3. Qualité
|
||
npm run type-check
|
||
npm run lint
|
||
npm run build
|
||
npm test
|
||
|
||
# 4. i18n synchronisé
|
||
python3 -c "import json;a=json.load(open('messages/fr.json'));b=json.load(open('messages/en.json'));\
|
||
def k(d,p=''):\
|
||
s=set()\
|
||
for x,v in d.items():\
|
||
s|=k(v,p+x+'.') if isinstance(v,dict) else {p+x}\
|
||
return s
|
||
print('écart:', k(a)^k(b))"
|
||
```
|
||
|
||
### Indicateurs de progression
|
||
|
||
Mesures prises avec `scripts` de comptage homogènes (occurrences via `grep -o`, jamais des lignes).
|
||
|
||
> ⚠️ **Correction de métrique (lot L5).** Deux lignes de ce tableau étaient fausses dans les versions précédentes du document :
|
||
> - **Dialogues natifs** : le motif de comptage excluait `window.confirm(` (précédé d'un point). Le vrai point de départ est **62**, pas 58.
|
||
> - **Fichiers > 600 lignes** : la valeur de départ « 12 » était une estimation non mesurée. Le comptage réel sur `HEAD` donne **17**.
|
||
>
|
||
> Les colonnes ci-dessous sont recalculées avec la métrique corrigée. Les autres lignes étaient exactes.
|
||
|
||
| Indicateur | Départ | L0 | L1 | L2 | L3 | L4 | L5 | L6 | L7 | Cible |
|
||
|------------|--------|----|----|----|----|----|----|----|----|-------|
|
||
| `blue-*` | 816 | 729 | 722 | 722 | 691 | 552 | 438 | 312 | **177** | **0** |
|
||
| `gray-*` | 2 485 | 2 355 | 2 331 | 2 331 | 2 108 | 1 833 | 1 523 | 1 088 | **759** | **0** (→ `neutral-*`) |
|
||
| Dialogues natifs | 62 | — | — | — | — | 48 | 44 | **7** | 7 | **0** |
|
||
| `<button>` bruts | 299 | 291 | 287 | 290 | 278 | 262 | 262 | 262 | 262 | < 30 |
|
||
| `<input>` bruts | 175 | 146 | 147 | 147 | 146 | 143 | 143 | 143 | 143 | < 20 |
|
||
| `<table>` bruts | 26 | 26 | 26 | 27 | 26 | 25 | 25 | 25 | 25 | **0** |
|
||
| Fichiers > 600 lignes | 17 | — | — | — | — | — | 12 | 12 | 12 | **0** |
|
||
| `2xl:` | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | > 40 |
|
||
| `focus-visible:` | 13 | 41 | 62 | 71 | 71 | 82 | 93 | 93 | **97** | > 100 |
|
||
| Paquets Radix importés | 0 | 7 | 7 | 7 | 7 | 7 | **8** | 8 | 8 | ≥ 8 |
|
||
| Tests frontend | 123 | 123 | **135** | **144** | 144 | 144 | 144 | 144 | 144 | croissant |
|
||
|
||
**Après L8 :** `blue-*` **148** · `gray-*` **610** · dialogues natifs **6**.
|
||
|
||
**Après L9 : `blue-*` = 0 · `gray-*` = 0.**
|
||
|
||
## 🎯 Objectif atteint — la charte est restaurée dans toute l'application
|
||
|
||
| Indicateur | Départ | Aujourd'hui |
|
||
|---|---|---|
|
||
| `blue-*` (accent hors charte) | **816** | **0** |
|
||
| `gray-*` (échelle neutre concurrente) | **2 485** | **0** |
|
||
| Nuances de marque inventées (`#1a2550`, `#0e9999`…) | 9 | **0** |
|
||
| Dialogues natifs | 62 | **6** (dont 4 en code mort ou faux positifs) |
|
||
|
||
Vérification reproductible :
|
||
```bash
|
||
cd apps/frontend
|
||
grep -rhoE '\b[a-z:-]*-(blue|gray)-[0-9]+' app src --include='*.tsx' | wc -l # 0
|
||
git diff --quiet tailwind.config.ts && echo "charte intacte" # charte intacte
|
||
```
|
||
|
||
---
|
||
|
||
## 19. État à l'issue du lot L10
|
||
|
||
| Indicateur | Départ | Fin | Cible |
|
||
|---|---|---|---|
|
||
| `blue-*` | 816 | **0** ✅ | 0 |
|
||
| `gray-*` | 2 485 | **0** ✅ | 0 |
|
||
| Nuances de marque inventées | 9 | **0** ✅ | 0 |
|
||
| Dialogues natifs | 62 | **2** | 0 |
|
||
| Paquets Radix importés | 0 | **8** ✅ | ≥ 8 |
|
||
| Tests frontend | 123 | **144** ✅ | croissant |
|
||
| `focus-visible:` | 13 | 97 | > 100 |
|
||
| `<button>` bruts | 299 | 255 | < 30 |
|
||
| `<input>` bruts | 175 | 143 | < 20 |
|
||
| `<table>` bruts | 26 | 24 | 0 |
|
||
| `2xl:` | 0 | 1 | > 40 |
|
||
| Fichiers > 600 lignes | 17 | 12 | 0 |
|
||
|
||
Les 2 dialogues natifs restants sont des **faux positifs** : une fonction locale nommée `confirm()` dans `dashboard/booking/[id]/payment-success/page.tsx`, sans rapport avec le dialogue du navigateur.
|
||
|
||
### Code mort supprimé
|
||
|
||
| Cible | Motif |
|
||
|---|---|
|
||
| `src/legacy-pages/` (3 fichiers) | Aucune référence dans le projet |
|
||
| `src/app/` (`rates/csv-search`) | **Jamais construit** : `app/` existe à la racine, donc Next.js ignore `src/app/`. Absent du manifeste de build. |
|
||
| `dashboard/search` + `dashboard/bookings/new` | Îlot orphelin fermé (L10a) |
|
||
| `test-image`, `demo-carte` | Pages de test |
|
||
|
||
### Corrections d'accessibilité appliquées à `globals.css`
|
||
|
||
- `.btn-primary` : texte blanc → **navy** sur turquoise (2,05:1 → 8,49:1)
|
||
- `.badge-info` : libellé turquoise → **navy** sur fond turquoise clair
|
||
- `.link` et `Button variant="link"` : **soulignement permanent** (un lien identifié par la seule couleur échoue au critère WCAG 1.4.1) et passage au navy
|
||
|
||
Les classes `@layer components` **ne sont pas supprimées** : `.btn-primary` sert dans 8 fichiers, `.label` et `.link` dans `/register` et `/admin/login`. Leur retrait est conditionné au passage de ces pages aux primitives.
|
||
|
||
---
|
||
|
||
## 20. Travaux restants
|
||
|
||
Ce qui n'a pas été fait, explicitement.
|
||
|
||
### Démonolithisation
|
||
| Fichier | Lignes |
|
||
|---|---|
|
||
| `src/components/docs/DocsPageContent.tsx` | 1 506 |
|
||
| `app/[locale]/admin/blog/page.tsx` | 1 341 |
|
||
| `app/[locale]/page.tsx` | 1 082 |
|
||
| `app/[locale]/dashboard/search-advanced/page.tsx` | 1 067 |
|
||
| `app/[locale]/dashboard/settings/users/page.tsx` | 884 |
|
||
| `app/[locale]/register/page.tsx` · `admin/organizations` | 832 |
|
||
| + 5 autres | 621–736 |
|
||
|
||
### Adoption des primitives
|
||
255 `<button>`, 143 `<input>` et 24 `<table>` restent écrits à la main. Leur mise en forme est conforme à la charte, mais ils ne bénéficient ni des états, ni de l'accessibilité, ni de la cohérence des primitives.
|
||
|
||
### Responsive grand écran
|
||
`2xl:` n'apparaît qu'une fois (dans `AppShell`). Les pages n'exploitent pas la largeur au-delà de 1 280 px.
|
||
|
||
### Autres
|
||
- `Callout` non substitué aux ~30 encadrés du wiki
|
||
- Sommaire, ancres et navigation précédent/suivant du wiki
|
||
- Chaînes françaises codées en dur dans `admin/blog` et `RichTextEditor` (hors i18n)
|
||
- Usage du turquoise en texte à auditer : 176 occurrences de `text-brand-turquoise`, dont une partie sur fond clair
|
||
- **Défaut `/booking` du middleware** (§18) — en attente d'arbitrage
|
||
|
||
---
|
||
|
||
## 18. Défaut fonctionnel relevé — liens magiques de réservation
|
||
|
||
Découvert en vérifiant le rendu des portails token au lot L8. **Sans rapport avec la refonte** : `middleware.ts` n'a été modifié à aucun moment.
|
||
|
||
`apps/frontend/middleware.ts` liste `/carrier` dans `prefixPublicPaths`, mais **pas `/booking`**. Or `/booking/confirm/[token]` et `/booking/reject/[token]` sont des pages atteintes par lien magique, envoyées par e-mail à des clients qui ne sont pas connectés.
|
||
|
||
**Conséquence :** ces deux liens redirigent vers `/login?redirect=…`. Le destinataire ne peut ni confirmer ni refuser sa réservation.
|
||
|
||
**Vérification :**
|
||
```bash
|
||
curl -s -o /dev/null -w "%{http_code}" http://localhost:3001/fr/carrier/accept/xxx # 200
|
||
curl -s -o /dev/null -w "%{http_code}" http://localhost:3001/fr/booking/confirm/xxx # 307
|
||
```
|
||
|
||
**Correction :** ajouter `'/booking'` à `prefixPublicPaths`. Une ligne.
|
||
|
||
**Non appliquée** : modifier une frontière d'authentification dépasse le périmètre d'une refonte UI et relève d'une décision produit. À arbitrer.
|
||
|
||
**Les 7 dialogues natifs restants** (contre 62 au départ) :
|
||
|
||
| Emplacement | Nombre | Traitement |
|
||
|---|---|---|
|
||
| `src/legacy-pages/CarrierManagement.tsx` | 3 | Code mort — supprimé en L10 |
|
||
| `src/app/rates/csv-search/page.tsx` | 1 | Route orpheline — arbitrage L10 |
|
||
| `carrier/documents/[token]/page.tsx` | 1 | L8 |
|
||
| `dashboard/booking/[id]/payment-success/page.tsx` | 2 | **Faux positifs** — une fonction locale nommée `confirm()`, sans rapport avec le dialogue natif |
|
||
|
||
Soit **2 appels natifs réels** hors code mort et route orpheline.
|
||
|
||
**Fichiers restant au-dessus de 600 lignes après L5** (12) — cible des lots suivants :
|
||
|
||
| Fichier | Lignes | Lot |
|
||
|---|---|---|
|
||
| `src/components/docs/DocsPageContent.tsx` | 1 506 | L7 |
|
||
| `app/[locale]/admin/blog/page.tsx` | 1 341 | L6 |
|
||
| `app/[locale]/page.tsx` | 1 082 | L9 |
|
||
| `app/[locale]/dashboard/search-advanced/page.tsx` | 1 067 | reporté |
|
||
| `app/[locale]/dashboard/settings/users/page.tsx` | 884 | reporté |
|
||
| `app/[locale]/register/page.tsx` | 832 | L8 |
|
||
| `app/[locale]/admin/organizations/page.tsx` | 832 | L6 |
|
||
| `app/[locale]/dashboard/booking/new/page.tsx` | 736 | reporté |
|
||
| `app/[locale]/admin/bookings/page.tsx` | 735 | L6 |
|
||
| `app/[locale]/admin/documents/page.tsx` | 684 | L6 |
|
||
| `app/[locale]/contact/page.tsx` | 681 | L9 |
|
||
| `app/[locale]/dashboard/booking/[id]/pay/page.tsx` | 621 | reporté |
|
||
|
||
**Réduction de volume :**
|
||
|
||
| Fichier | Avant | Après | Lot |
|
||
|---|---|---|---|
|
||
| `dashboard/documents/page.tsx` | 1 169 l. | **549 l.** | L4 |
|
||
| `dashboard/bookings/page.tsx` | 908 l. | **501 l.** | L3 |
|
||
| `dashboard/page.tsx` | 454 l. | **372 l.** | L3 |
|
||
| `dashboard/bookings/[id]/page.tsx` | 284 l. | **239 l.** | L3 |
|
||
|
||
---
|
||
|
||
## 17. Correction de contraste — texte sur turquoise
|
||
|
||
Constat fait en cours de lot L4, vérifié par calcul de luminance relative WCAG :
|
||
|
||
| Couple | Contraste | Verdict |
|
||
|---|---|---|
|
||
| Blanc sur `brand-turquoise #34CCCD` | **2,05:1** | ❌ Échoue AA (4,5:1 requis) |
|
||
| `brand-navy #10183A` sur `brand-turquoise` | **8,49:1** | ✅ Passe AAA |
|
||
|
||
Le token `accent.foreground` de `tailwind.config.ts` vaut `#FFFFFF`. **Il n'est pas modifié** — la charte reste verrouillée. Ce qui change est le couple appliqué dans les composants : les aplats turquoise portent désormais du texte **navy**.
|
||
|
||
Ce n'est pas une invention : la sidebar d'administration d'origine employait déjà `bg-brand-turquoise text-brand-navy`. La refonte généralise une pratique déjà présente dans le projet, et la rend conforme.
|
||
|
||
> Les légères hausses de `<button>` (+3) et `<table>` (+1) après L2 sont attendues : ce sont les **composants mutualisés eux-mêmes** (`DataTable`, `FilterBar`, `SearchInput`) qui contiennent désormais ces éléments — une fois pour toutes, à la place des 26 tables et des 290 boutons dispersés qu'ils vont absorber à partir de L3.
|
||
|
||
> Le recul entre « Départ » et « Après L0 » provient de la suppression du code mort validé (L10a). L0 construit les fondations sans toucher aux pages.
|
||
> Après L1, **le chrome applicatif ne contient plus aucun bleu générique** : les 722 occurrences restantes sont toutes dans le corps des pages, traitées par les lots L3 à L9.
|
||
|
||
### Revue visuelle par lot
|
||
Captures avant/après aux 4 paliers (375 / 768 / 1440 / 1920 px), sur `chromium`, `firefox`, `webkit` via la configuration Playwright existante.
|
||
|
||
---
|
||
|
||
## 15. Ce que je ne ferai pas
|
||
|
||
Engagements explicites, opposables en revue :
|
||
|
||
1. ❌ Modifier `brand-navy`, `brand-turquoise`, `brand-green`, `brand-gray`.
|
||
2. ❌ Modifier `primary.*`, `accent.*`, `success.*`, l'échelle `neutral-*`.
|
||
3. ❌ Changer Manrope / Montserrat ou leurs affectations.
|
||
4. ❌ Modifier l'échelle `fontSize` de `tailwind.config.ts`.
|
||
5. ❌ Modifier `--radius: 0.5rem`.
|
||
6. ❌ Remplacer `lucide-react` ou toucher aux logos et assets de marque.
|
||
7. ❌ Introduire une couleur d'accent nouvelle, un dégradé décoratif, une teinte inventée.
|
||
8. ❌ Glassmorphism, ombres portées lourdes, rayons > 8px dans le produit, cartes empilées gratuitement.
|
||
9. ❌ Animer pour animer.
|
||
10. ❌ Ajouter une dépendance non justifiée. Nouvelles dépendances envisagées, **toutes déjà partiellement présentes ou triviales** : `@radix-ui/react-popover`, `@radix-ui/react-tooltip`, `@radix-ui/react-checkbox`, `react-day-picker`. Chacune sera soumise à validation avant installation.
|
||
11. ❌ Modifier le backend, les contrats d'API ou la logique métier. **La refonte est strictement frontend.**
|
||
12. ❌ Supprimer une route ou du code mort sans arbitrage explicite (voir §F de `ui-audit.md`).
|
||
|
||
---
|
||
|
||
## 16. Arbitrages requis avant démarrage
|
||
|
||
| # | Question | Bloque |
|
||
|---|----------|--------|
|
||
| 1 | **Validez-vous le remplacement `blue-*` → navy/turquoise sur les 64 fichiers ?** C'est le changement le plus visible de la refonte. Sans lui, l'application conserve deux identités. | L1 et tous les suivants |
|
||
| 2 | Lequel des deux tunnels de réservation est actif : `/dashboard/bookings/new` ou `/dashboard/booking/new` ? | L3 |
|
||
| 3 | `src/app/rates/csv-search` (hors i18n, hors middleware) : migrer ou supprimer ? | L10 |
|
||
| 4 | `src/legacy-pages/` : code mort confirmé ? | L10 |
|
||
| 5 | Dark mode : l'implémenter réellement, ou retirer le scaffolding mort ? | L0 |
|
||
| 6 | Wiki : le contenu reste-t-il en JSX, ou passe-t-il en MDX ? | L7 |
|
||
| 7 | Les 4 dépendances du §15.10 sont-elles autorisées ? | L0 |
|