Revert "feat: update TODO and enhance design token integration"
This reverts commit aa348a0f82.
This commit is contained in:
5
TODO.md
5
TODO.md
@@ -16,9 +16,8 @@
|
|||||||
- [x] **Supprimer la double application** du thème (layout.tsx + ThemeContext + UserPreferencesContext) <!-- ThemeContext est maintenant la source unique -->
|
- [x] **Supprimer la double application** du thème (layout.tsx + ThemeContext + UserPreferencesContext) <!-- ThemeContext est maintenant la source unique -->
|
||||||
- [x] **Refactorer les CSS variables** : `:root` pour défaut, `.dark/.light` pour override <!-- Architecture CSS propre avec :root neutre -->
|
- [x] **Refactorer les CSS variables** : `:root` pour défaut, `.dark/.light` pour override <!-- Architecture CSS propre avec :root neutre -->
|
||||||
- [x] **Nettoyer les composants** : supprimer classes `dark:` hardcodées, utiliser uniquement CSS variables <!-- TERMINÉ : toutes les occurrences supprimées -->
|
- [x] **Nettoyer les composants** : supprimer classes `dark:` hardcodées, utiliser uniquement CSS variables <!-- TERMINÉ : toutes les occurrences supprimées -->
|
||||||
- [x] **Corriger les problèmes d'hydration** mismatch et flashs de thème <!-- Script inline + ThemeContext optimisé -->
|
- [ ] **Corriger les problèmes d'hydration** mismatch et flashs de thème
|
||||||
- [x] **Créer un système de design cohérent** avec tokens de couleur <!-- Design tokens + composants utilitaires + documentation -->
|
- [ ] **Créer un système de design cohérent** avec tokens de couleur
|
||||||
- [ ] **MIGRATION MASSIVE : Refactorer tous les composants** pour utiliser les design tokens <!-- Gros travail de migration composant par composant -->
|
|
||||||
|
|
||||||
### **Phase 2: Système Couleurs Personnalisées**
|
### **Phase 2: Système Couleurs Personnalisées**
|
||||||
- [ ] **Étendre le modèle UserPreferences** pour supporter des couleurs personnalisées
|
- [ ] **Étendre le modèle UserPreferences** pour supporter des couleurs personnalisées
|
||||||
|
|||||||
@@ -1,14 +1,5 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
|
||||||
/*
|
|
||||||
* CSS Variables - Design Tokens
|
|
||||||
*
|
|
||||||
* Ces variables sont synchronisées avec src/lib/design-tokens.ts
|
|
||||||
* Pour modifier les couleurs, utilisez les design tokens plutôt que ce fichier directement.
|
|
||||||
*
|
|
||||||
* Documentation: src/lib/DESIGN_SYSTEM.md
|
|
||||||
*/
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
/* Valeurs par défaut (Light theme) */
|
/* Valeurs par défaut (Light theme) */
|
||||||
--background: #f1f5f9; /* slate-100 */
|
--background: #f1f5f9; /* slate-100 */
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { Card, CardContent } from '@/components/ui/Card';
|
import { Card, CardContent } from '@/components/ui/Card';
|
||||||
import { StatusMessage } from '@/components/ui/StatusMessage';
|
|
||||||
import { useDesignTokens } from '@/hooks/useDesignTokens';
|
|
||||||
|
|
||||||
interface Message {
|
interface Message {
|
||||||
type: 'success' | 'error';
|
type: 'success' | 'error';
|
||||||
@@ -29,7 +27,6 @@ export function QuickActions({
|
|||||||
jiraEnabled,
|
jiraEnabled,
|
||||||
messages
|
messages
|
||||||
}: QuickActionsProps) {
|
}: QuickActionsProps) {
|
||||||
const { styles } = useDesignTokens();
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
<h2 className="text-xl font-semibold text-[var(--foreground)] mb-4">
|
<h2 className="text-xl font-semibold text-[var(--foreground)] mb-4">
|
||||||
@@ -46,18 +43,17 @@ export function QuickActions({
|
|||||||
Créer une sauvegarde des données
|
Créer une sauvegarde des données
|
||||||
</p>
|
</p>
|
||||||
{messages.backup && (
|
{messages.backup && (
|
||||||
<div className="mt-2">
|
<p className="text-xs mt-1" style={{
|
||||||
<StatusMessage type={messages.backup.type}>
|
color: messages.backup.type === 'success' ? 'var(--success)' : 'var(--destructive)'
|
||||||
{messages.backup.text}
|
}}>
|
||||||
</StatusMessage>
|
{messages.backup.text}
|
||||||
</div>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={onCreateBackup}
|
onClick={onCreateBackup}
|
||||||
disabled={isBackupLoading}
|
disabled={isBackupLoading}
|
||||||
className="px-3 py-1.5 rounded text-sm disabled:opacity-50 disabled:cursor-not-allowed"
|
className="px-3 py-1.5 bg-[var(--primary)] text-[var(--primary-foreground)] rounded text-sm disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
style={styles.primaryButton}
|
|
||||||
>
|
>
|
||||||
{isBackupLoading ? 'En cours...' : 'Sauvegarder'}
|
{isBackupLoading ? 'En cours...' : 'Sauvegarder'}
|
||||||
</button>
|
</button>
|
||||||
@@ -74,18 +70,17 @@ export function QuickActions({
|
|||||||
Tester la connexion Jira
|
Tester la connexion Jira
|
||||||
</p>
|
</p>
|
||||||
{messages.jira && (
|
{messages.jira && (
|
||||||
<div className="mt-2">
|
<p className="text-xs mt-1" style={{
|
||||||
<StatusMessage type={messages.jira.type}>
|
color: messages.jira.type === 'success' ? 'var(--success)' : 'var(--destructive)'
|
||||||
{messages.jira.text}
|
}}>
|
||||||
</StatusMessage>
|
{messages.jira.text}
|
||||||
</div>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={onTestJira}
|
onClick={onTestJira}
|
||||||
disabled={!jiraEnabled || isJiraTestLoading}
|
disabled={!jiraEnabled || isJiraTestLoading}
|
||||||
className="px-3 py-1.5 rounded text-sm disabled:opacity-50 disabled:cursor-not-allowed"
|
className="px-3 py-1.5 bg-[var(--card)] text-[var(--foreground)] border border-[var(--border)] rounded text-sm disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
style={styles.input}
|
|
||||||
>
|
>
|
||||||
{isJiraTestLoading ? 'Test...' : 'Tester'}
|
{isJiraTestLoading ? 'Test...' : 'Tester'}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
/**
|
|
||||||
* Composant de carte colorée utilisant les design tokens
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ReactNode } from 'react';
|
|
||||||
import { useDesignTokens } from '@/hooks/useDesignTokens';
|
|
||||||
|
|
||||||
interface ColoredCardProps {
|
|
||||||
color: 'primary' | 'purple' | 'yellow' | 'green' | 'blue' | 'gray';
|
|
||||||
children: ReactNode;
|
|
||||||
className?: string;
|
|
||||||
hover?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ColoredCard({ color, children, className = '', hover = true }: ColoredCardProps) {
|
|
||||||
const { styles } = useDesignTokens();
|
|
||||||
|
|
||||||
const getStyle = () => {
|
|
||||||
switch (color) {
|
|
||||||
case 'primary':
|
|
||||||
return styles.primaryCard;
|
|
||||||
case 'purple':
|
|
||||||
return styles.purpleCard;
|
|
||||||
case 'yellow':
|
|
||||||
return styles.yellowCard;
|
|
||||||
case 'green':
|
|
||||||
return {
|
|
||||||
color: 'var(--green)',
|
|
||||||
backgroundColor: 'color-mix(in srgb, var(--green) 10%, transparent)',
|
|
||||||
borderColor: 'color-mix(in srgb, var(--green) 20%, var(--border))',
|
|
||||||
};
|
|
||||||
case 'blue':
|
|
||||||
return {
|
|
||||||
color: 'var(--blue)',
|
|
||||||
backgroundColor: 'color-mix(in srgb, var(--blue) 10%, transparent)',
|
|
||||||
borderColor: 'color-mix(in srgb, var(--blue) 20%, var(--border))',
|
|
||||||
};
|
|
||||||
case 'gray':
|
|
||||||
return {
|
|
||||||
color: 'var(--muted-foreground)',
|
|
||||||
backgroundColor: 'color-mix(in srgb, var(--muted) 10%, transparent)',
|
|
||||||
borderColor: 'color-mix(in srgb, var(--muted) 20%, var(--border))',
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
return styles.primaryCard;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={`p-4 rounded-lg border transition-all ${hover ? 'hover:shadow-sm hover:scale-[1.01]' : ''} ${className}`}
|
|
||||||
style={getStyle()}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
/**
|
|
||||||
* Composant pour afficher des messages d'état avec les design tokens
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ReactNode } from 'react';
|
|
||||||
import { useDesignTokens } from '@/hooks/useDesignTokens';
|
|
||||||
|
|
||||||
interface StatusMessageProps {
|
|
||||||
type: 'success' | 'error' | 'warning' | 'info';
|
|
||||||
children: ReactNode;
|
|
||||||
className?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function StatusMessage({ type, children, className = '' }: StatusMessageProps) {
|
|
||||||
const { styles } = useDesignTokens();
|
|
||||||
|
|
||||||
const getStyle = () => {
|
|
||||||
switch (type) {
|
|
||||||
case 'success':
|
|
||||||
return styles.successMessage;
|
|
||||||
case 'error':
|
|
||||||
return styles.errorMessage;
|
|
||||||
case 'warning':
|
|
||||||
return styles.warningMessage;
|
|
||||||
case 'info':
|
|
||||||
return styles.primaryCard;
|
|
||||||
default:
|
|
||||||
return styles.primaryCard;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getIcon = () => {
|
|
||||||
switch (type) {
|
|
||||||
case 'success':
|
|
||||||
return '✅';
|
|
||||||
case 'error':
|
|
||||||
return '❌';
|
|
||||||
case 'warning':
|
|
||||||
return '⚠️';
|
|
||||||
case 'info':
|
|
||||||
return 'ℹ️';
|
|
||||||
default:
|
|
||||||
return 'ℹ️';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={`p-3 rounded border ${className}`}
|
|
||||||
style={getStyle()}
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<span>{getIcon()}</span>
|
|
||||||
<span>{children}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
/**
|
|
||||||
* Hook pour utiliser les design tokens dans les composants
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { useTheme } from '@/contexts/ThemeContext';
|
|
||||||
import { DesignTokenUtils, COLOR_PATTERNS, OPACITY } from '@/lib/design-tokens';
|
|
||||||
|
|
||||||
export function useDesignTokens() {
|
|
||||||
const { theme } = useTheme();
|
|
||||||
|
|
||||||
return {
|
|
||||||
theme,
|
|
||||||
|
|
||||||
// Utilitaires de couleur
|
|
||||||
withOpacity: DesignTokenUtils.withOpacity,
|
|
||||||
borderWithOpacity: DesignTokenUtils.borderWithOpacity,
|
|
||||||
backgroundWithOpacity: DesignTokenUtils.backgroundWithOpacity,
|
|
||||||
|
|
||||||
// Patterns prédéfinis
|
|
||||||
patterns: COLOR_PATTERNS,
|
|
||||||
|
|
||||||
// Opacités courantes
|
|
||||||
opacity: OPACITY,
|
|
||||||
|
|
||||||
// Couleurs CSS Variables (pour usage direct)
|
|
||||||
colors: {
|
|
||||||
background: 'var(--background)',
|
|
||||||
foreground: 'var(--foreground)',
|
|
||||||
card: 'var(--card)',
|
|
||||||
cardHover: 'var(--card-hover)',
|
|
||||||
cardColumn: 'var(--card-column)',
|
|
||||||
border: 'var(--border)',
|
|
||||||
input: 'var(--input)',
|
|
||||||
primary: 'var(--primary)',
|
|
||||||
primaryForeground: 'var(--primary-foreground)',
|
|
||||||
muted: 'var(--muted)',
|
|
||||||
mutedForeground: 'var(--muted-foreground)',
|
|
||||||
destructive: 'var(--destructive)',
|
|
||||||
success: 'var(--success)',
|
|
||||||
accent: 'var(--accent)',
|
|
||||||
purple: 'var(--purple)',
|
|
||||||
yellow: 'var(--yellow)',
|
|
||||||
green: 'var(--green)',
|
|
||||||
blue: 'var(--blue)',
|
|
||||||
gray: 'var(--gray)',
|
|
||||||
grayLight: 'var(--gray-light)',
|
|
||||||
},
|
|
||||||
|
|
||||||
// Styles prédéfinis pour les composants courants
|
|
||||||
styles: {
|
|
||||||
// Messages d'état
|
|
||||||
successMessage: {
|
|
||||||
color: COLOR_PATTERNS.success.text,
|
|
||||||
backgroundColor: COLOR_PATTERNS.success.background,
|
|
||||||
borderColor: COLOR_PATTERNS.success.border,
|
|
||||||
},
|
|
||||||
errorMessage: {
|
|
||||||
color: COLOR_PATTERNS.error.text,
|
|
||||||
backgroundColor: COLOR_PATTERNS.error.background,
|
|
||||||
borderColor: COLOR_PATTERNS.error.border,
|
|
||||||
},
|
|
||||||
warningMessage: {
|
|
||||||
color: COLOR_PATTERNS.warning.text,
|
|
||||||
backgroundColor: COLOR_PATTERNS.warning.background,
|
|
||||||
borderColor: COLOR_PATTERNS.warning.border,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Cards colorées
|
|
||||||
primaryCard: {
|
|
||||||
color: COLOR_PATTERNS.primary.text,
|
|
||||||
backgroundColor: COLOR_PATTERNS.primary.background,
|
|
||||||
borderColor: COLOR_PATTERNS.primary.border,
|
|
||||||
},
|
|
||||||
purpleCard: {
|
|
||||||
color: COLOR_PATTERNS.purple.text,
|
|
||||||
backgroundColor: COLOR_PATTERNS.purple.background,
|
|
||||||
borderColor: COLOR_PATTERNS.purple.border,
|
|
||||||
},
|
|
||||||
yellowCard: {
|
|
||||||
color: COLOR_PATTERNS.yellow.text,
|
|
||||||
backgroundColor: COLOR_PATTERNS.yellow.background,
|
|
||||||
borderColor: COLOR_PATTERNS.yellow.border,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Boutons
|
|
||||||
primaryButton: {
|
|
||||||
backgroundColor: 'var(--primary)',
|
|
||||||
color: 'var(--primary-foreground)',
|
|
||||||
borderColor: 'var(--primary)',
|
|
||||||
},
|
|
||||||
destructiveButton: {
|
|
||||||
backgroundColor: 'var(--destructive)',
|
|
||||||
color: 'white',
|
|
||||||
borderColor: 'var(--destructive)',
|
|
||||||
},
|
|
||||||
|
|
||||||
// Inputs
|
|
||||||
input: {
|
|
||||||
backgroundColor: 'var(--input)',
|
|
||||||
borderColor: 'var(--border)',
|
|
||||||
color: 'var(--foreground)',
|
|
||||||
},
|
|
||||||
|
|
||||||
// Scrollbars
|
|
||||||
scrollbar: {
|
|
||||||
track: 'var(--card)',
|
|
||||||
thumb: 'var(--muted)',
|
|
||||||
thumbHover: 'var(--primary)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,199 +0,0 @@
|
|||||||
# Design System - TowerControl
|
|
||||||
|
|
||||||
## Vue d'ensemble
|
|
||||||
|
|
||||||
Le design system de TowerControl utilise des **Design Tokens** pour assurer la cohérence visuelle et faciliter la maintenance des couleurs et styles.
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
### 1. Design Tokens (`src/lib/design-tokens.ts`)
|
|
||||||
|
|
||||||
Source unique de vérité pour toutes les couleurs et styles :
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { DesignTokenUtils, COLOR_PATTERNS } from '@/lib/design-tokens';
|
|
||||||
|
|
||||||
// Utilisation des utilitaires
|
|
||||||
const backgroundColor = DesignTokenUtils.withOpacity('var(--primary)', 0.1);
|
|
||||||
const borderColor = DesignTokenUtils.borderWithOpacity('var(--success)', 0.2, 'var(--border)');
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Hook useDesignTokens (`src/hooks/useDesignTokens.ts`)
|
|
||||||
|
|
||||||
Hook React pour utiliser facilement les tokens dans les composants :
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import { useDesignTokens } from '@/hooks/useDesignTokens';
|
|
||||||
|
|
||||||
function MyComponent() {
|
|
||||||
const { colors, styles, patterns } = useDesignTokens();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ color: colors.primary }}>
|
|
||||||
<div style={styles.successMessage}>Succès !</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Composants utilitaires
|
|
||||||
|
|
||||||
#### StatusMessage
|
|
||||||
```tsx
|
|
||||||
import { StatusMessage } from '@/components/ui/StatusMessage';
|
|
||||||
|
|
||||||
<StatusMessage type="success">Opération réussie</StatusMessage>
|
|
||||||
<StatusMessage type="error">Une erreur est survenue</StatusMessage>
|
|
||||||
<StatusMessage type="warning">Attention requise</StatusMessage>
|
|
||||||
<StatusMessage type="info">Information</StatusMessage>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ColoredCard
|
|
||||||
```tsx
|
|
||||||
import { ColoredCard } from '@/components/ui/ColoredCard';
|
|
||||||
|
|
||||||
<ColoredCard color="primary">Contenu principal</ColoredCard>
|
|
||||||
<ColoredCard color="purple">Contenu violet</ColoredCard>
|
|
||||||
<ColoredCard color="yellow">Contenu jaune</ColoredCard>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Couleurs disponibles
|
|
||||||
|
|
||||||
### Couleurs principales
|
|
||||||
- `--background` : Arrière-plan principal
|
|
||||||
- `--foreground` : Texte principal
|
|
||||||
- `--card` : Arrière-plan des cartes
|
|
||||||
- `--card-hover` : État hover des cartes
|
|
||||||
- `--border` : Couleur des bordures
|
|
||||||
- `--input` : Arrière-plan des inputs
|
|
||||||
|
|
||||||
### Couleurs sémantiques
|
|
||||||
- `--primary` : Couleur principale (cyan)
|
|
||||||
- `--success` : Succès (vert)
|
|
||||||
- `--destructive` : Erreur/danger (rouge)
|
|
||||||
- `--accent` : Accent (orange/amber)
|
|
||||||
- `--muted` : Texte atténué
|
|
||||||
- `--muted-foreground` : Texte secondaire
|
|
||||||
|
|
||||||
### Couleurs étendues
|
|
||||||
- `--purple` : Violet
|
|
||||||
- `--yellow` : Jaune
|
|
||||||
- `--green` : Vert
|
|
||||||
- `--blue` : Bleu
|
|
||||||
- `--gray` : Gris
|
|
||||||
- `--gray-light` : Gris clair
|
|
||||||
|
|
||||||
## Patterns de couleurs
|
|
||||||
|
|
||||||
### Messages d'état
|
|
||||||
```typescript
|
|
||||||
const { patterns } = useDesignTokens();
|
|
||||||
|
|
||||||
// Utilisation directe
|
|
||||||
<div style={patterns.success}>Message de succès</div>
|
|
||||||
<div style={patterns.error}>Message d'erreur</div>
|
|
||||||
<div style={patterns.warning}>Message d'avertissement</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Opacités courantes
|
|
||||||
```typescript
|
|
||||||
const { opacity } = useDesignTokens();
|
|
||||||
|
|
||||||
// Opacités prédéfinies
|
|
||||||
opacity.subtle // 5% - très subtil
|
|
||||||
opacity.light // 10% - léger
|
|
||||||
opacity.medium // 20% - moyen
|
|
||||||
opacity.strong // 30% - fort
|
|
||||||
opacity.solid // 80% - presque opaque
|
|
||||||
```
|
|
||||||
|
|
||||||
## Bonnes pratiques
|
|
||||||
|
|
||||||
### ✅ Recommandé
|
|
||||||
```tsx
|
|
||||||
// Utiliser les design tokens
|
|
||||||
const { colors, styles } = useDesignTokens();
|
|
||||||
|
|
||||||
<div style={{ color: colors.primary }}>
|
|
||||||
<div style={styles.successMessage}>
|
|
||||||
|
|
||||||
// Utiliser les composants utilitaires
|
|
||||||
<StatusMessage type="success">Succès</StatusMessage>
|
|
||||||
<ColoredCard color="primary">Contenu</ColoredCard>
|
|
||||||
```
|
|
||||||
|
|
||||||
### ❌ À éviter
|
|
||||||
```tsx
|
|
||||||
// Couleurs hardcodées
|
|
||||||
<div style={{ color: '#0891b2' }}>
|
|
||||||
<div className="text-blue-600">
|
|
||||||
|
|
||||||
// Classes Tailwind dark:
|
|
||||||
<div className="bg-white dark:bg-gray-800">
|
|
||||||
```
|
|
||||||
|
|
||||||
## Migration des composants existants
|
|
||||||
|
|
||||||
### Avant (avec classes Tailwind)
|
|
||||||
```tsx
|
|
||||||
<div className="bg-green-50 border border-green-200 text-green-800 dark:bg-green-900/20 dark:border-green-800 dark:text-green-200">
|
|
||||||
✅ Succès
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Après (avec design tokens)
|
|
||||||
```tsx
|
|
||||||
<StatusMessage type="success">
|
|
||||||
Succès
|
|
||||||
</StatusMessage>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Extensibilité
|
|
||||||
|
|
||||||
Le système est conçu pour supporter facilement :
|
|
||||||
- **Nouveaux thèmes** : Ajouter dans `themeTokens`
|
|
||||||
- **Nouveaux patterns** : Étendre `COLOR_PATTERNS`
|
|
||||||
- **Nouvelles opacités** : Ajouter dans `OPACITY`
|
|
||||||
- **Composants personnalisés** : Utiliser `useDesignTokens`
|
|
||||||
|
|
||||||
## Exemples d'usage
|
|
||||||
|
|
||||||
### Composant personnalisé
|
|
||||||
```tsx
|
|
||||||
import { useDesignTokens } from '@/hooks/useDesignTokens';
|
|
||||||
|
|
||||||
function CustomComponent() {
|
|
||||||
const { colors, withOpacity } = useDesignTokens();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
backgroundColor: withOpacity(colors.primary, 0.1),
|
|
||||||
borderColor: colors.primary,
|
|
||||||
color: colors.primary
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Contenu personnalisé
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Style conditionnel
|
|
||||||
```tsx
|
|
||||||
function ConditionalComponent({ isActive }: { isActive: boolean }) {
|
|
||||||
const { colors } = useDesignTokens();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
color: isActive ? colors.success : colors.mutedForeground
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isActive ? 'Actif' : 'Inactif'}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Ce système garantit la cohérence visuelle et facilite la maintenance des styles dans toute l'application.
|
|
||||||
@@ -1,241 +0,0 @@
|
|||||||
/**
|
|
||||||
* Design Tokens - Système de couleurs cohérent pour TowerControl
|
|
||||||
*
|
|
||||||
* Ce fichier définit tous les tokens de design utilisés dans l'application.
|
|
||||||
* Il sert de source unique de vérité pour les couleurs et facilite la maintenance.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export type ColorToken = string;
|
|
||||||
|
|
||||||
export interface ColorPalette {
|
|
||||||
// Couleurs principales
|
|
||||||
background: ColorToken;
|
|
||||||
foreground: ColorToken;
|
|
||||||
|
|
||||||
// Surfaces
|
|
||||||
card: ColorToken;
|
|
||||||
cardHover: ColorToken;
|
|
||||||
cardColumn: ColorToken;
|
|
||||||
|
|
||||||
// Bordures et inputs
|
|
||||||
border: ColorToken;
|
|
||||||
input: ColorToken;
|
|
||||||
|
|
||||||
// Couleurs sémantiques
|
|
||||||
primary: ColorToken;
|
|
||||||
primaryForeground: ColorToken;
|
|
||||||
muted: ColorToken;
|
|
||||||
mutedForeground: ColorToken;
|
|
||||||
|
|
||||||
// Couleurs d'état
|
|
||||||
destructive: ColorToken;
|
|
||||||
success: ColorToken;
|
|
||||||
accent: ColorToken;
|
|
||||||
|
|
||||||
// Couleurs étendues
|
|
||||||
purple: ColorToken;
|
|
||||||
yellow: ColorToken;
|
|
||||||
green: ColorToken;
|
|
||||||
blue: ColorToken;
|
|
||||||
gray: ColorToken;
|
|
||||||
grayLight: ColorToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ThemeTokens {
|
|
||||||
light: ColorPalette;
|
|
||||||
dark: ColorPalette;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tokens de couleurs pour le thème clair
|
|
||||||
*/
|
|
||||||
export const lightTheme: ColorPalette = {
|
|
||||||
// Couleurs principales
|
|
||||||
background: '#f1f5f9', // slate-100
|
|
||||||
foreground: '#0f172a', // slate-900
|
|
||||||
|
|
||||||
// Surfaces
|
|
||||||
card: '#ffffff', // white
|
|
||||||
cardHover: '#f8fafc', // slate-50
|
|
||||||
cardColumn: '#f8fafc', // slate-50
|
|
||||||
|
|
||||||
// Bordures et inputs
|
|
||||||
border: '#cbd5e1', // slate-300
|
|
||||||
input: '#ffffff', // white
|
|
||||||
|
|
||||||
// Couleurs sémantiques
|
|
||||||
primary: '#0891b2', // cyan-600
|
|
||||||
primaryForeground: '#ffffff', // white
|
|
||||||
muted: '#94a3b8', // slate-400
|
|
||||||
mutedForeground: '#64748b', // slate-500
|
|
||||||
|
|
||||||
// Couleurs d'état
|
|
||||||
destructive: '#dc2626', // red-600
|
|
||||||
success: '#059669', // emerald-600
|
|
||||||
accent: '#d97706', // amber-600
|
|
||||||
|
|
||||||
// Couleurs étendues
|
|
||||||
purple: '#8b5cf6', // purple-500
|
|
||||||
yellow: '#eab308', // yellow-500
|
|
||||||
green: '#059669', // emerald-600
|
|
||||||
blue: '#2563eb', // blue-600
|
|
||||||
gray: '#6b7280', // gray-500
|
|
||||||
grayLight: '#e5e7eb', // gray-200
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tokens de couleurs pour le thème sombre
|
|
||||||
*/
|
|
||||||
export const darkTheme: ColorPalette = {
|
|
||||||
// Couleurs principales
|
|
||||||
background: '#1e293b', // slate-800
|
|
||||||
foreground: '#f1f5f9', // slate-100
|
|
||||||
|
|
||||||
// Surfaces
|
|
||||||
card: '#334155', // slate-700
|
|
||||||
cardHover: '#475569', // slate-600
|
|
||||||
cardColumn: '#0f172a', // slate-900
|
|
||||||
|
|
||||||
// Bordures et inputs
|
|
||||||
border: '#64748b', // slate-500
|
|
||||||
input: '#334155', // slate-700
|
|
||||||
|
|
||||||
// Couleurs sémantiques
|
|
||||||
primary: '#06b6d4', // cyan-500
|
|
||||||
primaryForeground: '#f1f5f9', // slate-100
|
|
||||||
muted: '#64748b', // slate-500
|
|
||||||
mutedForeground: '#94a3b8', // slate-400
|
|
||||||
|
|
||||||
// Couleurs d'état
|
|
||||||
destructive: '#ef4444', // red-500
|
|
||||||
success: '#10b981', // emerald-500
|
|
||||||
accent: '#f59e0b', // amber-500
|
|
||||||
|
|
||||||
// Couleurs étendues
|
|
||||||
purple: '#8b5cf6', // purple-500
|
|
||||||
yellow: '#eab308', // yellow-500
|
|
||||||
green: '#10b981', // emerald-500
|
|
||||||
blue: '#3b82f6', // blue-500
|
|
||||||
gray: '#9ca3af', // gray-400
|
|
||||||
grayLight: '#374151', // gray-700
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Collection complète des tokens de thème
|
|
||||||
*/
|
|
||||||
export const themeTokens: ThemeTokens = {
|
|
||||||
light: lightTheme,
|
|
||||||
dark: darkTheme,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utilitaires pour les tokens de couleur
|
|
||||||
*/
|
|
||||||
export class DesignTokenUtils {
|
|
||||||
/**
|
|
||||||
* Génère une couleur avec transparence
|
|
||||||
*/
|
|
||||||
static withOpacity(color: ColorToken, opacity: number): string {
|
|
||||||
return `color-mix(in srgb, ${color} ${opacity * 100}%, transparent)`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Génère une couleur de bordure avec transparence
|
|
||||||
*/
|
|
||||||
static borderWithOpacity(color: ColorToken, opacity: number, baseBorder: ColorToken): string {
|
|
||||||
return `color-mix(in srgb, ${color} ${opacity * 100}%, ${baseBorder})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Génère un background avec transparence
|
|
||||||
*/
|
|
||||||
static backgroundWithOpacity(color: ColorToken, opacity: number): string {
|
|
||||||
return `color-mix(in srgb, ${color} ${opacity * 100}%, transparent)`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtient les tokens pour un thème donné
|
|
||||||
*/
|
|
||||||
static getTokens(theme: 'light' | 'dark'): ColorPalette {
|
|
||||||
return themeTokens[theme];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Génère les CSS Variables pour un thème
|
|
||||||
*/
|
|
||||||
static generateCSSVariables(theme: 'light' | 'dark'): Record<string, string> {
|
|
||||||
const tokens = this.getTokens(theme);
|
|
||||||
return {
|
|
||||||
'--background': tokens.background,
|
|
||||||
'--foreground': tokens.foreground,
|
|
||||||
'--card': tokens.card,
|
|
||||||
'--card-hover': tokens.cardHover,
|
|
||||||
'--card-column': tokens.cardColumn,
|
|
||||||
'--border': tokens.border,
|
|
||||||
'--input': tokens.input,
|
|
||||||
'--primary': tokens.primary,
|
|
||||||
'--primary-foreground': tokens.primaryForeground,
|
|
||||||
'--muted': tokens.muted,
|
|
||||||
'--muted-foreground': tokens.mutedForeground,
|
|
||||||
'--destructive': tokens.destructive,
|
|
||||||
'--success': tokens.success,
|
|
||||||
'--accent': tokens.accent,
|
|
||||||
'--purple': tokens.purple,
|
|
||||||
'--yellow': tokens.yellow,
|
|
||||||
'--green': tokens.green,
|
|
||||||
'--blue': tokens.blue,
|
|
||||||
'--gray': tokens.gray,
|
|
||||||
'--gray-light': tokens.grayLight,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constantes pour les opacités courantes
|
|
||||||
*/
|
|
||||||
export const OPACITY = {
|
|
||||||
subtle: 0.05, // 5% - très subtil
|
|
||||||
light: 0.1, // 10% - léger
|
|
||||||
medium: 0.2, // 20% - moyen
|
|
||||||
strong: 0.3, // 30% - fort
|
|
||||||
solid: 0.8, // 80% - presque opaque
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Patterns de couleurs prédéfinis pour les composants
|
|
||||||
*/
|
|
||||||
export const COLOR_PATTERNS = {
|
|
||||||
// Messages d'état
|
|
||||||
success: {
|
|
||||||
text: 'var(--success)',
|
|
||||||
background: DesignTokenUtils.withOpacity('var(--success)', OPACITY.light),
|
|
||||||
border: DesignTokenUtils.borderWithOpacity('var(--success)', OPACITY.medium, 'var(--border)'),
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
text: 'var(--destructive)',
|
|
||||||
background: DesignTokenUtils.withOpacity('var(--destructive)', OPACITY.light),
|
|
||||||
border: DesignTokenUtils.borderWithOpacity('var(--destructive)', OPACITY.medium, 'var(--border)'),
|
|
||||||
},
|
|
||||||
warning: {
|
|
||||||
text: 'var(--accent)',
|
|
||||||
background: DesignTokenUtils.withOpacity('var(--accent)', OPACITY.light),
|
|
||||||
border: DesignTokenUtils.borderWithOpacity('var(--accent)', OPACITY.medium, 'var(--border)'),
|
|
||||||
},
|
|
||||||
|
|
||||||
// Cards colorées
|
|
||||||
primary: {
|
|
||||||
text: 'var(--primary)',
|
|
||||||
background: DesignTokenUtils.withOpacity('var(--primary)', OPACITY.light),
|
|
||||||
border: DesignTokenUtils.borderWithOpacity('var(--primary)', OPACITY.medium, 'var(--border)'),
|
|
||||||
},
|
|
||||||
purple: {
|
|
||||||
text: 'var(--purple)',
|
|
||||||
background: DesignTokenUtils.withOpacity('var(--purple)', OPACITY.light),
|
|
||||||
border: DesignTokenUtils.borderWithOpacity('var(--purple)', OPACITY.medium, 'var(--border)'),
|
|
||||||
},
|
|
||||||
yellow: {
|
|
||||||
text: 'var(--yellow)',
|
|
||||||
background: DesignTokenUtils.withOpacity('var(--yellow)', OPACITY.light),
|
|
||||||
border: DesignTokenUtils.borderWithOpacity('var(--yellow)', OPACITY.medium, 'var(--border)'),
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
Reference in New Issue
Block a user