batchCooking/apps/web/src/components/ui/dialog.scss
Nicolas 85fd9bae7d feat(planning): le picker prévisualise avant de confirmer, formulaire de revue intégré
Trois ajustements successifs sur le dialogue de sélection de recette
(RecipePickerDialog), demandés en continu après le premier correctif
de débordement :

1. Dialogue élargi et à hauteur fixe (95vw plafonné à 85rem, 80vh) au
   lieu de dépendre du contenu, avec la répartition liste/détail
   redéfinie en fractions du dialogue lui-même (3fr/2fr) plutôt qu'en
   vw — cette dernière suivait la largeur du viewport, sans rapport
   avec la largeur désormais fixe du dialogue.

2. Le formulaire de revue d'import (ex-ImportRecipePage) est extrait
   dans un composant partagé, RecipeImportForm — toujours monté en
   page autonome (route directe/rechargement), mais désormais aussi
   intégré comme une étape du dialogue lui-même quand un item de
   source a besoin d'une résolution manuelle, au lieu de naviguer et
   perdre le contexte du picker (recherche, filtres, créneau).

3. Cliquer sur une recette dans le dialogue ne fait plus que la
   sélectionner/prévisualiser (RecipeDetailPanel, comme /recettes) —
   plus de saut automatique vers l'étape suivante. Un nouveau pied de
   dialogue (Dialog.tsx gagne une prop ) porte Confirmer/
   Fermer : Confirmer agit sur la sélection en cours (recette réelle
   → étape portions existante ; item de source pas encore importé →
   import transparent ou formulaire intégré, point 2). Les onglets
   réguliers gagnent leur propre paire maître-détail (RecipeTable +
   RecipeDetailPanel, showActions=false) sur ce même modèle ; les
   onglets source prévisualisent désormais aussi les items déjà
   importés en interne (RecipeSourcesPanel), plus de saut direct.

Cypress (planning.feature/planning.ts) mis à jour en conséquence :
sélectionner puis confirmer sont deux étapes distinctes, le clic sur
la ligne ne déclenche plus rien tout seul.

Bug pré-existant trouvé en testant en direct (sans rapport avec ce qui
précède) : l'import d'une recette source plante avec une contrainte
d'unicité Prisma dès que deux lignes d'ingrédient se résolvent au même
ingrédient catalogue — signalé séparément (tâche en arrière-plan), pas
corrigé ici.

Vérifié en direct (navigateur, comptes de test) : sélection sans saut
d'écran, pied de dialogue activé/désactivé correctement, Confirmer sur
un item de source non résolu bascule vers le formulaire intégré,
Fermer ferme bien le dialogue.

pnpm exec tsc -b --force (web) — propre.
pnpm exec biome check — propre.
pnpm --filter web build — propre.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 00:05:17 +02:00

73 lines
1.8 KiB
SCSS

// Modal panel — see Dialog.tsx. A native <dialog> opened via showModal(),
// so the browser supplies the backdrop/centering/focus-trap; this only
// resets its default UA styling (border, padding, colors) and layers the
// header/body layout on top. Colocated here rather than in global.scss
// since it's one component's styling, same convention as every feature's
// own .scss file (recipes.scss, planning-page.scss, …).
.dialog-panel {
display: flex;
flex-direction: column;
width: 100%;
max-width: 48rem;
max-height: calc(100vh - var(--space-2xl));
margin: auto; // UA default for a shown <dialog>, kept explicit
padding: 0;
border: none;
background: var(--color-surface);
color: var(--color-text);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-md);
overflow: hidden;
&::backdrop {
background: rgba(0, 0, 0, 0.45);
}
}
.dialog-panel__header {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-md);
padding: var(--space-md) var(--space-lg);
border-bottom: 1px solid var(--color-border);
h2 {
font-size: var(--font-size-lg);
}
}
.dialog-panel__close {
flex: none;
width: 2rem;
height: 2rem;
border: none;
border-radius: var(--radius-base);
background: transparent;
color: var(--color-text-muted);
font-size: var(--font-size-md);
cursor: pointer;
&:hover {
background: var(--color-surface-alt);
color: var(--color-text);
}
}
.dialog-panel__body {
flex: 1;
min-height: 0;
overflow-y: auto;
padding: var(--space-lg);
}
.dialog-panel__footer {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: flex-end;
gap: var(--space-sm);
padding: var(--space-md) var(--space-lg);
border-top: 1px solid var(--color-border);
}