26 KiB
26 KiB
| id | title | sidebar_label |
|---|---|---|
| design-system | 🎨 Design System Veza Platform | 🎨 Design System Veza Platform |
NOTE: Cette page décrit la CIBLE (but visé).
🎨 Design System Veza Platform
Système de design unifié pour toutes les interfaces Veza (Web, Desktop, Mobile)
🎯 Vision & Identité
Identité de Veza
Veza Platform est une plateforme musicale collaborative moderne qui combine :
- Créativité - Outils de création musicale avancés
- Collaboration - Jam sessions temps réel et projets partagés
- Innovation - IA, streaming adaptatif, marketplace
- Accessibilité - Interface intuitive pour tous les niveaux
Ton Visuel
- Moderne - Design épuré et contemporain
- Professionnel - Interface sérieuse pour créateurs
- Créatif - Couleurs vibrantes et animations fluides
- Inclusif - Accessible et adaptatif
Inspiration
- Spotify - Interface audio moderne et intuitive
- Discord - Collaboration temps réel et communauté
- SoundCloud - Découverte et partage musical
- Figma - Outils créatifs professionnels
🎨 Palette de Couleurs
Mode Sombre (Principal)
Couleurs Principales
/* Primary - Bleu/Violet créatif */
--veza-primary-50: #f0f9ff;
--veza-primary-100: #e0f2fe;
--veza-primary-200: #bae6fd;
--veza-primary-300: #7dd3fc;
--veza-primary-400: #38bdf8;
--veza-primary-500: #0ea5e9; /* Couleur principale */
--veza-primary-600: #0284c7;
--veza-primary-700: #0369a1;
--veza-primary-800: #075985;
--veza-primary-900: #0c4a6e;
/* Secondary - Violet/Purple créatif */
--veza-secondary-50: #fdf4ff;
--veza-secondary-100: #fae8ff;
--veza-secondary-200: #f5d0fe;
--veza-secondary-300: #f0abfc;
--veza-secondary-400: #e879f9;
--veza-secondary-500: #d946ef; /* Couleur secondaire */
--veza-secondary-600: #c026d3;
--veza-secondary-700: #a21caf;
--veza-secondary-800: #86198f;
--veza-secondary-900: #701a75;
/* Accent - Orange/Ambre énergique */
--veza-accent-50: #fff7ed;
--veza-accent-100: #ffedd5;
--veza-accent-200: #fed7aa;
--veza-accent-300: #fdba74;
--veza-accent-400: #fb923c;
--veza-accent-500: #f97316; /* Couleur d'accent */
--veza-accent-600: #ea580c;
--veza-accent-700: #c2410c;
--veza-accent-800: #9a3412;
--veza-accent-900: #7c2d12;
Couleurs de Fond
/* Background - Gradients sombres */
--veza-bg-primary: #0f0f23; /* Fond principal */
--veza-bg-secondary: #1a1a2e; /* Fond secondaire */
--veza-bg-tertiary: #16213e; /* Fond tertiaire */
--veza-bg-surface: #1f2937; /* Surfaces (cards) */
--veza-bg-elevated: #374151; /* Surfaces élevées */
--veza-bg-overlay: rgba(0, 0, 0, 0.5); /* Overlays */
/* Gradients de fond */
--veza-gradient-primary: linear-gradient(135deg, #0f0f23 0%, #1a1a2e 50%, #16213e 100%);
--veza-gradient-header: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--veza-gradient-card: linear-gradient(135deg, #1f2937 0%, #374151 100%);
Couleurs de Texte
/* Text - Hiérarchie claire */
--veza-text-primary: #ffffff; /* Texte principal */
--veza-text-secondary: #e5e7eb; /* Texte secondaire */
--veza-text-tertiary: #9ca3af; /* Texte tertiaire */
--veza-text-muted: #6b7280; /* Texte atténué */
--veza-text-inverse: #111827; /* Texte inversé */
/* Text avec opacité */
--veza-text-primary-87: rgba(255, 255, 255, 0.87);
--veza-text-secondary-70: rgba(229, 231, 235, 0.7);
Couleurs d'État
/* Success - Vert */
--veza-success-50: #f0fdf4;
--veza-success-500: #10b981;
--veza-success-600: #059669;
--veza-success-700: #047857;
/* Warning - Jaune */
--veza-warning-50: #fffbeb;
--veza-warning-500: #f59e0b;
--veza-warning-600: #d97706;
--veza-warning-700: #b45309;
/* Error - Rouge */
--veza-error-50: #fef2f2;
--veza-error-500: #ef4444;
--veza-error-600: #dc2626;
--veza-error-700: #b91c1c;
/* Info - Bleu */
--veza-info-50: #eff6ff;
--veza-info-500: #3b82f6;
--veza-info-600: #2563eb;
--veza-info-700: #1d4ed8;
Mode Clair (Alternative)
Couleurs Principales (Clair)
/* Background - Clair */
--veza-light-bg-primary: #ffffff;
--veza-light-bg-secondary: #f9fafb;
--veza-light-bg-tertiary: #f3f4f6;
--veza-light-bg-surface: #ffffff;
--veza-light-bg-elevated: #f9fafb;
/* Text - Clair */
--veza-light-text-primary: #111827;
--veza-light-text-secondary: #374151;
--veza-light-text-tertiary: #6b7280;
--veza-light-text-muted: #9ca3af;
🖋 Typographie
Police Principale
/* Inter - Police moderne et lisible */
--veza-font-family: 'Inter', system-ui, -apple-system, sans-serif;
--veza-font-mono: 'JetBrains Mono', 'Fira Code', monospace;
Hiérarchie Typographique
Titres
/* H1 - Titre principal */
--veza-h1-font-size: 3rem; /* 48px */
--veza-h1-font-weight: 700;
--veza-h1-line-height: 1.2;
--veza-h1-letter-spacing: -0.025em;
/* H2 - Titre de section */
--veza-h2-font-size: 2.25rem; /* 36px */
--veza-h2-font-weight: 600;
--veza-h2-line-height: 1.3;
--veza-h2-letter-spacing: -0.025em;
/* H3 - Titre de sous-section */
--veza-h3-font-size: 1.875rem; /* 30px */
--veza-h3-font-weight: 600;
--veza-h3-line-height: 1.4;
/* H4 - Titre de carte */
--veza-h4-font-size: 1.5rem; /* 24px */
--veza-h4-font-weight: 600;
--veza-h4-line-height: 1.4;
/* H5 - Titre de composant */
--veza-h5-font-size: 1.25rem; /* 20px */
--veza-h5-font-weight: 600;
--veza-h5-line-height: 1.5;
/* H6 - Titre de détail */
--veza-h6-font-size: 1.125rem; /* 18px */
--veza-h6-font-weight: 600;
--veza-h6-line-height: 1.5;
Corps de Texte
/* Body - Texte principal */
--veza-body-font-size: 1rem; /* 16px */
--veza-body-font-weight: 400;
--veza-body-line-height: 1.6;
/* Body Large - Texte important */
--veza-body-large-font-size: 1.125rem; /* 18px */
--veza-body-large-font-weight: 400;
--veza-body-large-line-height: 1.6;
/* Body Small - Texte secondaire */
--veza-body-small-font-size: 0.875rem; /* 14px */
--veza-body-small-font-weight: 400;
--veza-body-small-line-height: 1.5;
/* Caption - Légendes */
--veza-caption-font-size: 0.75rem; /* 12px */
--veza-caption-font-weight: 400;
--veza-caption-line-height: 1.4;
Interface
/* Button - Boutons */
--veza-button-font-size: 0.875rem; /* 14px */
--veza-button-font-weight: 500;
--veza-button-line-height: 1.4;
/* Input - Champs de saisie */
--veza-input-font-size: 0.875rem; /* 14px */
--veza-input-font-weight: 400;
--veza-input-line-height: 1.4;
/* Label - Étiquettes */
--veza-label-font-size: 0.875rem; /* 14px */
--veza-label-font-weight: 500;
--veza-label-line-height: 1.4;
🔲 Composants UI de Base
Boutons
Variantes de Boutons
// Primary Button
<button className="bg-veza-primary-500 hover:bg-veza-primary-600 text-white px-4 py-2 rounded-lg font-medium transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-veza-primary-500 focus:ring-offset-2">
Action Principale
</button>
// Secondary Button
<button className="bg-veza-secondary-500 hover:bg-veza-secondary-600 text-white px-4 py-2 rounded-lg font-medium transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-veza-secondary-500 focus:ring-offset-2">
Action Secondaire
</button>
// Ghost Button
<button className="text-veza-primary-500 hover:text-veza-primary-400 hover:bg-veza-primary-50 px-4 py-2 rounded-lg font-medium transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-veza-primary-500 focus:ring-offset-2">
Action Ghost
</button>
// Danger Button
<button className="bg-veza-error-500 hover:bg-veza-error-600 text-white px-4 py-2 rounded-lg font-medium transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-veza-error-500 focus:ring-offset-2">
Action Dangereuse
</button>
Tailles de Boutons
// Small
<button className="px-3 py-1.5 text-sm">Petit</button>
// Medium (default)
<button className="px-4 py-2 text-sm">Moyen</button>
// Large
<button className="px-6 py-3 text-base">Grand</button>
// Extra Large
<button className="px-8 py-4 text-lg">Très Grand</button>
Inputs
Champs de Texte
// Text Input
<input
type="text"
className="w-full px-3 py-2 bg-veza-bg-surface border border-veza-bg-elevated rounded-lg text-veza-text-primary placeholder-veza-text-muted focus:outline-none focus:ring-2 focus:ring-veza-primary-500 focus:border-veza-primary-500 transition-colors duration-200"
placeholder="Entrez votre texte..."
/>
// Password Input
<input
type="password"
className="w-full px-3 py-2 bg-veza-bg-surface border border-veza-bg-elevated rounded-lg text-veza-text-primary placeholder-veza-text-muted focus:outline-none focus:ring-2 focus:ring-veza-primary-500 focus:border-veza-primary-500 transition-colors duration-200"
placeholder="Mot de passe..."
/>
// Search Input
<div className="relative">
<input
type="search"
className="w-full pl-10 pr-3 py-2 bg-veza-bg-surface border border-veza-bg-elevated rounded-lg text-veza-text-primary placeholder-veza-text-muted focus:outline-none focus:ring-2 focus:ring-veza-primary-500 focus:border-veza-primary-500 transition-colors duration-200"
placeholder="Rechercher..."
/>
<svg className="absolute left-3 top-2.5 h-5 w-5 text-veza-text-muted" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
États des Inputs
// Error State
<input
className="w-full px-3 py-2 bg-veza-bg-surface border border-veza-error-500 rounded-lg text-veza-text-primary focus:outline-none focus:ring-2 focus:ring-veza-error-500 transition-colors duration-200"
/>
// Success State
<input
className="w-full px-3 py-2 bg-veza-bg-surface border border-veza-success-500 rounded-lg text-veza-text-primary focus:outline-none focus:ring-2 focus:ring-veza-success-500 transition-colors duration-200"
/>
// Disabled State
<input
disabled
className="w-full px-3 py-2 bg-veza-bg-tertiary border border-veza-bg-elevated rounded-lg text-veza-text-muted cursor-not-allowed"
/>
Cards
Card de Base
// Basic Card
<div className="bg-veza-bg-surface border border-veza-bg-elevated rounded-xl p-6 shadow-lg hover:shadow-xl transition-shadow duration-200">
<h3 className="text-veza-h4-font-size font-veza-h4-font-weight text-veza-text-primary mb-2">
Titre de la Carte
</h3>
<p className="text-veza-body-font-size text-veza-text-secondary">
Contenu de la carte avec description détaillée.
</p>
</div>
// Interactive Card
<div className="bg-veza-bg-surface border border-veza-bg-elevated rounded-xl p-6 shadow-lg hover:shadow-xl hover:scale-105 transition-all duration-200 cursor-pointer">
<div className="flex items-center justify-between mb-4">
<h3 className="text-veza-h4-font-size font-veza-h4-font-weight text-veza-text-primary">
Carte Interactive
</h3>
<span className="text-veza-accent-500">→</span>
</div>
<p className="text-veza-body-font-size text-veza-text-secondary">
Cliquez pour plus d'informations.
</p>
</div>
Card avec Gradient
// Gradient Card
<div className="bg-gradient-to-br from-veza-primary-500 to-veza-secondary-500 rounded-xl p-6 text-white shadow-lg">
<h3 className="text-veza-h4-font-size font-veza-h4-font-weight mb-2">
Carte avec Gradient
</h3>
<p className="text-white/90">
Carte avec dégradé de couleurs Veza.
</p>
</div>
Navigation
Sidebar
// Sidebar Container
<aside className="w-64 bg-veza-bg-secondary border-r border-veza-bg-elevated h-screen">
<div className="p-6">
<h2 className="text-veza-h5-font-size font-veza-h5-font-weight text-veza-text-primary mb-6">
Navigation
</h2>
{/* Navigation Items */}
<nav className="space-y-2">
<a href="/dashboard" className="flex items-center space-x-3 px-4 py-3 rounded-lg text-veza-text-secondary hover:text-veza-text-primary hover:bg-veza-bg-surface transition-colors duration-200">
<span className="text-xl">📊</span>
<span className="font-medium">Dashboard</span>
</a>
<a href="/media" className="flex items-center space-x-3 px-4 py-3 rounded-lg text-veza-text-secondary hover:text-veza-text-primary hover:bg-veza-bg-surface transition-colors duration-200">
<span className="text-xl">🎵</span>
<span className="font-medium">Media</span>
</a>
</nav>
</div>
</aside>
Top Navigation
// Top Navigation
<header className="bg-veza-bg-surface border-b border-veza-bg-elevated px-6 py-4">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="text-2xl">🎵</div>
<h1 className="text-veza-h5-font-size font-veza-h5-font-weight text-veza-text-primary">
Veza Platform
</h1>
</div>
<nav className="flex items-center space-x-6">
<a href="/notifications" className="text-veza-text-secondary hover:text-veza-text-primary transition-colors duration-200">
🔔
</a>
<a href="/profile" className="text-veza-text-secondary hover:text-veza-text-primary transition-colors duration-200">
👤
</a>
</nav>
</div>
</header>
États Interactifs
Hover States
/* Hover sur les boutons */
.button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
/* Hover sur les cards */
.card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
}
/* Hover sur les liens */
.link:hover {
color: var(--veza-primary-400);
text-decoration: underline;
}
Focus States
/* Focus sur les inputs */
.input:focus {
outline: none;
ring: 2px;
ring-color: var(--veza-primary-500);
ring-offset: 2px;
}
/* Focus sur les boutons */
.button:focus {
outline: none;
ring: 2px;
ring-color: var(--veza-primary-500);
ring-offset: 2px;
}
Loading States
// Loading Button
<button className="bg-veza-primary-500 text-white px-4 py-2 rounded-lg font-medium opacity-75 cursor-not-allowed">
<svg className="animate-spin -ml-1 mr-2 h-4 w-4 inline" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
</svg>
Chargement...
</button>
// Loading Spinner
<div className="flex items-center justify-center">
<svg className="animate-spin h-8 w-8 text-veza-primary-500" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
</svg>
</div>
🌗 Modes Clair et Sombre
Variables CSS pour les Thèmes
/* Mode Sombre (Par défaut) */
[data-theme="dark"] {
--veza-bg-primary: #0f0f23;
--veza-bg-secondary: #1a1a2e;
--veza-bg-surface: #1f2937;
--veza-text-primary: #ffffff;
--veza-text-secondary: #e5e7eb;
--veza-border-color: #374151;
}
/* Mode Clair */
[data-theme="light"] {
--veza-bg-primary: #ffffff;
--veza-bg-secondary: #f9fafb;
--veza-bg-surface: #ffffff;
--veza-text-primary: #111827;
--veza-text-secondary: #374151;
--veza-border-color: #e5e7eb;
}
Composant de Toggle de Thème
// Theme Toggle Component
const ThemeToggle: React.FC = () => {
const [theme, setTheme] = useState<'light' | 'dark'>('dark');
const toggleTheme = () => {
const newTheme = theme === 'dark' ? 'light' : 'dark';
setTheme(newTheme);
document.documentElement.setAttribute('data-theme', newTheme);
};
return (
<button
onClick={toggleTheme}
className="p-2 rounded-lg bg-veza-bg-surface border border-veza-border-color text-veza-text-primary hover:bg-veza-bg-elevated transition-colors duration-200"
>
{theme === 'dark' ? '☀️' : '🌙'}
</button>
);
};
🎛 Micro-interactions et Animations
Animations CSS
/* Fade In */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.fade-in {
animation: fadeIn 0.5s ease-out;
}
/* Pulse */
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
.pulse {
animation: pulse 2s infinite;
}
/* Wave */
@keyframes wave {
0%, 100% {
transform: rotate(0deg);
}
25% {
transform: rotate(20deg);
}
75% {
transform: rotate(-20deg);
}
}
.wave {
animation: wave 1.5s ease-in-out infinite;
}
/* Slide In */
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.slide-in {
animation: slideIn 0.3s ease-out;
}
Transitions
/* Transitions fluides */
* {
transition: all 0.2s ease-in-out;
}
/* Transitions spécifiques */
.button {
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.input {
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
Feedback Visuel
// Success Feedback
const SuccessFeedback: React.FC = () => (
<div className="fixed top-4 right-4 bg-veza-success-500 text-white px-6 py-3 rounded-lg shadow-lg slide-in">
<div className="flex items-center space-x-2">
<span>✅</span>
<span>Action réussie !</span>
</div>
</div>
);
// Error Feedback
const ErrorFeedback: React.FC = () => (
<div className="fixed top-4 right-4 bg-veza-error-500 text-white px-6 py-3 rounded-lg shadow-lg slide-in">
<div className="flex items-center space-x-2">
<span>❌</span>
<span>Une erreur s'est produite</span>
</div>
</div>
);
// Loading Feedback
const LoadingFeedback: React.FC = () => (
<div className="fixed inset-0 bg-veza-bg-overlay flex items-center justify-center">
<div className="bg-veza-bg-surface rounded-lg p-6 shadow-xl">
<div className="flex items-center space-x-3">
<svg className="animate-spin h-6 w-6 text-veza-primary-500" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
</svg>
<span className="text-veza-text-primary">Chargement...</span>
</div>
</div>
</div>
);
📦 Kit de Composants React/Tailwind
Composant Button
// Button.tsx
interface ButtonProps {
children: React.ReactNode;
variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
size?: 'sm' | 'md' | 'lg' | 'xl';
disabled?: boolean;
loading?: boolean;
onClick?: () => void;
type?: 'button' | 'submit' | 'reset';
className?: string;
}
const Button: React.FC<ButtonProps> = ({
children,
variant = 'primary',
size = 'md',
disabled = false,
loading = false,
onClick,
type = 'button',
className = '',
}) => {
const baseClasses = 'inline-flex items-center justify-center font-medium rounded-lg transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2';
const variantClasses = {
primary: 'bg-veza-primary-500 hover:bg-veza-primary-600 text-white focus:ring-veza-primary-500 hover:scale-105',
secondary: 'bg-veza-secondary-500 hover:bg-veza-secondary-600 text-white focus:ring-veza-secondary-500 hover:scale-105',
ghost: 'text-veza-primary-500 hover:text-veza-primary-400 hover:bg-veza-primary-50 focus:ring-veza-primary-500',
danger: 'bg-veza-error-500 hover:bg-veza-error-600 text-white focus:ring-veza-error-500 hover:scale-105',
};
const sizeClasses = {
sm: 'px-3 py-1.5 text-sm',
md: 'px-4 py-2 text-sm',
lg: 'px-6 py-3 text-base',
xl: 'px-8 py-4 text-lg',
};
const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed hover:scale-100' : '';
const loadingClasses = loading ? 'cursor-wait' : '';
const classes = `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${disabledClasses} ${loadingClasses} ${className}`;
return (
<button
type={type}
className={classes}
disabled={disabled || loading}
onClick={onClick}
>
{loading && (
<svg className="animate-spin -ml-1 mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
</svg>
)}
{children}
</button>
);
};
export default Button;
Composant Input
// Input.tsx
interface InputProps {
type?: 'text' | 'password' | 'email' | 'search' | 'number';
placeholder?: string;
value?: string;
onChange?: (value: string) => void;
error?: string;
success?: boolean;
disabled?: boolean;
className?: string;
icon?: React.ReactNode;
}
const Input: React.FC<InputProps> = ({
type = 'text',
placeholder,
value,
onChange,
error,
success,
disabled = false,
className = '',
icon,
}) => {
const baseClasses = 'w-full px-3 py-2 bg-veza-bg-surface border rounded-lg text-veza-text-primary placeholder-veza-text-muted focus:outline-none focus:ring-2 focus:ring-offset-2 transition-colors duration-200';
const stateClasses = error
? 'border-veza-error-500 focus:ring-veza-error-500'
: success
? 'border-veza-success-500 focus:ring-veza-success-500'
: 'border-veza-bg-elevated focus:ring-veza-primary-500 focus:border-veza-primary-500';
const disabledClasses = disabled ? 'bg-veza-bg-tertiary cursor-not-allowed' : '';
const classes = `${baseClasses} ${stateClasses} ${disabledClasses} ${className}`;
return (
<div className="relative">
{icon && (
<div className="absolute left-3 top-2.5 text-veza-text-muted">
{icon}
</div>
)}
<input
type={type}
placeholder={placeholder}
value={value}
onChange={(e) => onChange?.(e.target.value)}
disabled={disabled}
className={classes}
style={icon ? { paddingLeft: '2.5rem' } : {}}
/>
{error && (
<p className="mt-1 text-sm text-veza-error-500">{error}</p>
)}
</div>
);
};
export default Input;
Composant Card
// Card.tsx
interface CardProps {
children: React.ReactNode;
title?: string;
subtitle?: string;
interactive?: boolean;
gradient?: boolean;
className?: string;
onClick?: () => void;
}
const Card: React.FC<CardProps> = ({
children,
title,
subtitle,
interactive = false,
gradient = false,
className = '',
onClick,
}) => {
const baseClasses = 'rounded-xl p-6 shadow-lg transition-all duration-200';
const styleClasses = gradient
? 'bg-gradient-to-br from-veza-primary-500 to-veza-secondary-500 text-white'
: 'bg-veza-bg-surface border border-veza-bg-elevated';
const interactiveClasses = interactive
? 'hover:shadow-xl hover:scale-105 cursor-pointer'
: '';
const classes = `${baseClasses} ${styleClasses} ${interactiveClasses} ${className}`;
return (
<div className={classes} onClick={onClick}>
{(title || subtitle) && (
<div className="mb-4">
{title && (
<h3 className="text-veza-h4-font-size font-veza-h4-font-weight text-veza-text-primary mb-1">
{title}
</h3>
)}
{subtitle && (
<p className="text-veza-body-small-font-size text-veza-text-secondary">
{subtitle}
</p>
)}
</div>
)}
{children}
</div>
);
};
export default Card;
Composant Modal
// Modal.tsx
interface ModalProps {
isOpen: boolean;
onClose: () => void;
title?: string;
children: React.ReactNode;
size?: 'sm' | 'md' | 'lg' | 'xl';
}
const Modal: React.FC<ModalProps> = ({
isOpen,
onClose,
title,
children,
size = 'md',
}) => {
if (!isOpen) return null;
const sizeClasses = {
sm: 'max-w-md',
md: 'max-w-lg',
lg: 'max-w-2xl',
xl: 'max-w-4xl',
};
return (
<div className="fixed inset-0 bg-veza-bg-overlay flex items-center justify-center z-50">
<div className={`bg-veza-bg-surface rounded-xl shadow-2xl ${sizeClasses[size]} w-full mx-4`}>
{title && (
<div className="flex items-center justify-between p-6 border-b border-veza-bg-elevated">
<h2 className="text-veza-h4-font-size font-veza-h4-font-weight text-veza-text-primary">
{title}
</h2>
<button
onClick={onClose}
className="text-veza-text-muted hover:text-veza-text-primary transition-colors duration-200"
>
✕
</button>
</div>
)}
<div className="p-6">
{children}
</div>
</div>
</div>
);
};
export default Modal;
🎯 Guide d'Utilisation
Principes de Design
- Cohérence - Utilisez toujours les mêmes couleurs, typographies et espacements
- Accessibilité - Respectez les contrastes et les états de focus
- Performance - Optimisez les animations et transitions
- Responsive - Adaptez l'interface à tous les écrans
- Feedback - Donnez toujours un retour visuel aux actions utilisateur
Checklist d'Implémentation
- Variables CSS définies dans le thème
- Composants React créés et documentés
- Animations CSS optimisées
- Tests d'accessibilité passés
- Tests de performance validés
- Documentation des composants mise à jour
Prochaines Étapes
- Implémenter les composants dans les applications existantes
- Créer un Storybook pour documenter tous les composants
- Tester l'accessibilité et la performance
- Former l'équipe sur l'utilisation du design system
- Maintenir et évoluer le design system
Dernière mise à jour : $(date) Version : 1.0.0 Statut : ✅ Design System Complet