Patterns Modals
Guide complet pour la création de modals cohérents avec le design system YaniPay. Structure, composants et exemples d'implémentation.
Overview
Les modals YaniPay suivent un design glassmorphism avec des fonds semi-transparents, un effet de blur, et des bordures subtiles. Ils utilisent des gradients teal/cyan pour les CTAs et du blanc pur pour les actions secondaires.
Modal Structure
Chaque modal est composé de ces éléments principaux :
| Élément | Classes | Description |
|---|---|---|
| Container | rounded-2xl bg-slate-900/90 backdrop-blur-xl | Surface principale glassmorphism |
| Border | border border-white/10 | Bordure subtile |
| Shadow | shadow-2xl shadow-black/50 | Ombre profonde |
| Close Button | absolute top-4 left-4 | Bouton fermer (×) |
| Badge | rounded-full from-teal-500 to-cyan-500 | Badge optionnel (Dev Mode, etc.) |
| Title | text-xl font-bold text-white | Titre avec icône optionnelle |
| Description | text-sm text-white/60 | Texte descriptif |
| Primary CTA | from-teal-500 to-cyan-500 w-full | Bouton gradient full-width |
| Secondary Button | bg-white text-slate-900 w-full | Bouton blanc solide |
| Info Box | bg-white/5 border-white/10 | Zone d'information |
Example: Animation Modal
Voici la reproduction du modal "Animation non visible ?" analysé comme référence de design :
Animation non visible ?
L'animation YaniPay ne s'affiche que lors de la première visite.
Voici comment la tester :
Pourquoi ?
L'animation utilise des cookies pour ne s'afficher qu'une seule fois. Les boutons ci-dessus contournent cette logique.
Example: Form Modal
Modal de formulaire avec header, icon badge et boutons d'action :
Créer une nouvelle carte
Common Patterns
Header avec Icon Badge
Utilisé pour les modals de formulaire et les actions importantes :
<DialogHeader className="border-b border-white/10 pb-4">
<div className="flex items-center gap-3">
{/* Icon Badge */}
<div className="rounded-xl border border-emerald-500/20
bg-gradient-to-br from-emerald-500/20 to-cyan-500/20 p-3">
<CreditCard className="h-5 w-5 text-emerald-400" />
</div>
{/* Title */}
<DialogTitle className="text-xl font-bold text-white">
Titre du modal
</DialogTitle>
</div>
</DialogHeader>Info Box
Zone d'information contextuelle :
<div className="p-4 rounded-xl bg-white/5 border border-white/10">
<div className="flex items-start gap-3">
<Info className="w-4 h-4 text-white/40 mt-0.5 flex-shrink-0" />
<div>
<p className="text-sm font-medium text-white">Titre</p>
<p className="text-xs text-white/60 mt-1">
Description détaillée de l'information.
</p>
</div>
</div>
</div>Action Buttons
Paire de boutons Annuler/Confirmer :
<div className="flex justify-end gap-3 pt-6 border-t border-white/10">
{/* Cancel */}
<Button
variant="outline"
className="border-white/20 bg-white/5 text-white hover:bg-white/10"
>
Annuler
</Button>
{/* Confirm */}
<Button
className="bg-gradient-to-r from-emerald-600 to-cyan-600 text-white
hover:from-emerald-500 hover:to-cyan-500
shadow-lg shadow-emerald-500/20"
>
<Save className="w-4 h-4 mr-2" />
Confirmer
</Button>
</div>Implementation
Implémentation complète d'un modal avec Radix Dialog :
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { CreditCard, Save } from 'lucide-react';
import { Button } from '@/components/ui/button';
export function CreateCardModal({
open,
onOpenChange
}: {
open: boolean;
onOpenChange: (open: boolean) => void;
}) {
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent
className="max-w-lg rounded-2xl border border-white/10
bg-slate-900/95 backdrop-blur-xl
shadow-2xl shadow-black/50"
>
{/* Header */}
<DialogHeader className="border-b border-white/10 pb-4">
<div className="flex items-center gap-3">
<div className="rounded-xl border border-emerald-500/20
bg-gradient-to-br from-emerald-500/20 to-cyan-500/20 p-3">
<CreditCard className="h-5 w-5 text-emerald-400" />
</div>
<DialogTitle className="text-xl font-bold text-white">
Créer une carte
</DialogTitle>
</div>
</DialogHeader>
{/* Body */}
<div className="p-6 space-y-4">
{/* Form fields here */}
</div>
{/* Footer */}
<div className="flex justify-end gap-3 p-6 pt-0">
<Button
variant="outline"
onClick={() => onOpenChange(false)}
className="border-white/20 bg-white/5 text-white hover:bg-white/10"
>
Annuler
</Button>
<Button
className="bg-gradient-to-r from-emerald-600 to-cyan-600
text-white shadow-lg shadow-emerald-500/20"
>
<Save className="w-4 h-4 mr-2" />
Créer
</Button>
</div>
</DialogContent>
</Dialog>
);
}