gitignore propre
This commit is contained in:
@@ -0,0 +1,349 @@
|
||||
# Guide du Design System UnionFlow
|
||||
|
||||
## 📋 Table des matières
|
||||
1. [Introduction](#introduction)
|
||||
2. [Tokens](#tokens)
|
||||
3. [Composants](#composants)
|
||||
4. [Bonnes pratiques](#bonnes-pratiques)
|
||||
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Le Design System UnionFlow garantit la cohérence visuelle et l'expérience utilisateur dans toute l'application.
|
||||
|
||||
**Palette de couleurs** : Bleu Roi (#4169E1) + Bleu Pétrole (#2C5F6F)
|
||||
**Basé sur** : Material Design 3 et tendances UI/UX 2024-2025
|
||||
|
||||
### Import
|
||||
|
||||
```dart
|
||||
import 'package:unionflow_mobile_apps/core/design_system/unionflow_design_system.dart';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tokens
|
||||
|
||||
### 🎨 Couleurs (ColorTokens)
|
||||
|
||||
```dart
|
||||
// Primaire
|
||||
ColorTokens.primary // Bleu Roi #4169E1
|
||||
ColorTokens.onPrimary // Blanc #FFFFFF
|
||||
ColorTokens.primaryContainer // Container bleu roi
|
||||
|
||||
// Sémantiques
|
||||
ColorTokens.success // Vert #10B981
|
||||
ColorTokens.error // Rouge #DC2626
|
||||
ColorTokens.warning // Orange #F59E0B
|
||||
ColorTokens.info // Bleu #0EA5E9
|
||||
|
||||
// Surfaces
|
||||
ColorTokens.surface // Blanc #FFFFFF
|
||||
ColorTokens.background // Gris clair #F8F9FA
|
||||
ColorTokens.onSurface // Texte principal #1F2937
|
||||
ColorTokens.onSurfaceVariant // Texte secondaire #6B7280
|
||||
|
||||
// Gradients
|
||||
ColorTokens.primaryGradient // [Bleu Roi, Bleu Roi clair]
|
||||
```
|
||||
|
||||
### 📏 Espacements (SpacingTokens)
|
||||
|
||||
```dart
|
||||
SpacingTokens.xs // 2px
|
||||
SpacingTokens.sm // 4px
|
||||
SpacingTokens.md // 8px
|
||||
SpacingTokens.lg // 12px
|
||||
SpacingTokens.xl // 16px
|
||||
SpacingTokens.xxl // 20px
|
||||
SpacingTokens.xxxl // 24px
|
||||
SpacingTokens.huge // 32px
|
||||
SpacingTokens.giant // 48px
|
||||
```
|
||||
|
||||
### 🔘 Rayons (SpacingTokens)
|
||||
|
||||
```dart
|
||||
SpacingTokens.radiusXs // 2px
|
||||
SpacingTokens.radiusSm // 4px
|
||||
SpacingTokens.radiusMd // 8px
|
||||
SpacingTokens.radiusLg // 12px - Standard pour cards
|
||||
SpacingTokens.radiusXl // 16px
|
||||
SpacingTokens.radiusXxl // 20px
|
||||
SpacingTokens.radiusCircular // 999px - Boutons ronds
|
||||
```
|
||||
|
||||
### 🌑 Ombres (ShadowTokens)
|
||||
|
||||
```dart
|
||||
ShadowTokens.xs // Ombre minimale
|
||||
ShadowTokens.sm // Ombre petite (cards, boutons)
|
||||
ShadowTokens.md // Ombre moyenne (cards importantes)
|
||||
ShadowTokens.lg // Ombre large (modals, dialogs)
|
||||
ShadowTokens.xl // Ombre très large (éléments flottants)
|
||||
|
||||
// Ombres colorées
|
||||
ShadowTokens.primary // Ombre avec couleur primaire
|
||||
ShadowTokens.success // Ombre verte
|
||||
ShadowTokens.error // Ombre rouge
|
||||
```
|
||||
|
||||
### ✍️ Typographie (TypographyTokens)
|
||||
|
||||
```dart
|
||||
TypographyTokens.displayLarge // 57px - Titres héroïques
|
||||
TypographyTokens.headlineLarge // 32px - Titres de page
|
||||
TypographyTokens.headlineMedium // 28px - Sous-titres
|
||||
TypographyTokens.titleLarge // 22px - Titres de section
|
||||
TypographyTokens.titleMedium // 16px - Titres de card
|
||||
TypographyTokens.bodyLarge // 16px - Corps de texte
|
||||
TypographyTokens.bodyMedium // 14px - Corps standard
|
||||
TypographyTokens.labelLarge // 14px - Labels
|
||||
TypographyTokens.labelSmall // 11px - Petits labels
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Composants
|
||||
|
||||
### 📦 UFCard - Card standardisé
|
||||
|
||||
```dart
|
||||
// Card avec ombre (par défaut)
|
||||
UFCard(
|
||||
child: Text('Contenu'),
|
||||
)
|
||||
|
||||
// Card avec bordure
|
||||
UFCard.outlined(
|
||||
borderColor: ColorTokens.primary,
|
||||
child: Text('Contenu'),
|
||||
)
|
||||
|
||||
// Card avec fond coloré
|
||||
UFCard.filled(
|
||||
color: ColorTokens.primaryContainer,
|
||||
child: Text('Contenu'),
|
||||
)
|
||||
|
||||
// Card cliquable
|
||||
UFCard(
|
||||
onTap: () => print('Cliqué'),
|
||||
child: Text('Contenu'),
|
||||
)
|
||||
```
|
||||
|
||||
### 📦 UFContainer - Container standardisé
|
||||
|
||||
```dart
|
||||
// Container standard
|
||||
UFContainer(
|
||||
child: Text('Contenu'),
|
||||
)
|
||||
|
||||
// Container arrondi
|
||||
UFContainer.rounded(
|
||||
color: ColorTokens.primary,
|
||||
padding: EdgeInsets.all(SpacingTokens.lg),
|
||||
child: Text('Contenu'),
|
||||
)
|
||||
|
||||
// Container avec ombre
|
||||
UFContainer.elevated(
|
||||
child: Text('Contenu'),
|
||||
)
|
||||
|
||||
// Container circulaire
|
||||
UFContainer.circular(
|
||||
width: 48,
|
||||
height: 48,
|
||||
color: ColorTokens.primary,
|
||||
child: Icon(Icons.person),
|
||||
)
|
||||
```
|
||||
|
||||
### 📊 UFStatCard - Card de statistiques
|
||||
|
||||
```dart
|
||||
UFStatCard(
|
||||
title: 'Membres',
|
||||
value: '142',
|
||||
icon: Icons.people,
|
||||
iconColor: ColorTokens.primary,
|
||||
subtitle: '+5 ce mois',
|
||||
onTap: () => navigateToMembers(),
|
||||
)
|
||||
```
|
||||
|
||||
### ℹ️ UFInfoCard - Card d'information
|
||||
|
||||
```dart
|
||||
UFInfoCard(
|
||||
title: 'État du système',
|
||||
icon: Icons.health_and_safety,
|
||||
iconColor: ColorTokens.success,
|
||||
trailing: Badge(label: Text('OK')),
|
||||
child: Column(
|
||||
children: [
|
||||
Text('Tous les systèmes fonctionnent normalement'),
|
||||
],
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
### 🎯 UFHeader - Header de page
|
||||
|
||||
```dart
|
||||
UFHeader(
|
||||
title: 'Tableau de bord',
|
||||
subtitle: 'Vue d\'ensemble de votre activité',
|
||||
icon: Icons.dashboard,
|
||||
onNotificationTap: () => showNotifications(),
|
||||
onSettingsTap: () => showSettings(),
|
||||
)
|
||||
```
|
||||
|
||||
### 📱 UFAppBar - AppBar standardisé
|
||||
|
||||
```dart
|
||||
UFAppBar(
|
||||
title: 'Détails du membre',
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.edit),
|
||||
onPressed: () => edit(),
|
||||
),
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
### 🔘 Boutons
|
||||
|
||||
```dart
|
||||
// Bouton primaire
|
||||
UFPrimaryButton(
|
||||
text: 'Enregistrer',
|
||||
onPressed: () => save(),
|
||||
icon: Icons.save,
|
||||
)
|
||||
|
||||
// Bouton secondaire
|
||||
UFSecondaryButton(
|
||||
text: 'Annuler',
|
||||
onPressed: () => cancel(),
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Bonnes pratiques
|
||||
|
||||
### ✅ À FAIRE
|
||||
|
||||
```dart
|
||||
// ✅ Utiliser les tokens
|
||||
Container(
|
||||
padding: EdgeInsets.all(SpacingTokens.xl),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorTokens.surface,
|
||||
borderRadius: BorderRadius.circular(SpacingTokens.radiusLg),
|
||||
boxShadow: ShadowTokens.sm,
|
||||
),
|
||||
)
|
||||
|
||||
// ✅ Utiliser les composants
|
||||
UFCard(
|
||||
child: Text('Contenu'),
|
||||
)
|
||||
```
|
||||
|
||||
### ❌ À ÉVITER
|
||||
|
||||
```dart
|
||||
// ❌ Valeurs hardcodées
|
||||
Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFFFFFFFF),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
// ❌ Card Flutter standard
|
||||
Card(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text('Contenu'),
|
||||
)
|
||||
```
|
||||
|
||||
### 📐 Hiérarchie des espacements
|
||||
|
||||
- **xs/sm** : Éléments très proches (icône + texte)
|
||||
- **md/lg** : Espacement interne standard
|
||||
- **xl/xxl** : Espacement entre sections
|
||||
- **xxxl+** : Grandes séparations
|
||||
|
||||
### 🎨 Hiérarchie des couleurs
|
||||
|
||||
1. **primary** : Actions principales, navigation active
|
||||
2. **secondary** : Actions secondaires
|
||||
3. **success/error/warning** : États et feedbacks
|
||||
4. **surface/background** : Fonds et containers
|
||||
|
||||
### 🌑 Hiérarchie des ombres
|
||||
|
||||
- **xs/sm** : Cards et boutons standards
|
||||
- **md** : Cards importantes
|
||||
- **lg/xl** : Modals, dialogs, éléments flottants
|
||||
- **Colorées** : Éléments avec accent visuel
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Migration
|
||||
|
||||
Pour migrer du code existant :
|
||||
|
||||
1. Remplacer `Card` par `UFCard`
|
||||
2. Remplacer `Container` personnalisés par `UFContainer`
|
||||
3. Remplacer couleurs hardcodées par `ColorTokens`
|
||||
4. Remplacer espacements hardcodés par `SpacingTokens`
|
||||
5. Remplacer ombres personnalisées par `ShadowTokens`
|
||||
|
||||
**Exemple** :
|
||||
|
||||
```dart
|
||||
// Avant
|
||||
Card(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Text('Contenu'),
|
||||
),
|
||||
)
|
||||
|
||||
// Après
|
||||
UFCard(
|
||||
child: Text('Contenu'),
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Version** : 1.0.0
|
||||
**Dernière mise à jour** : 2025-10-05
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/// UnionFlow Primary Button - Bouton principal
|
||||
///
|
||||
/// Bouton primaire avec la couleur Bleu Roi (#4169E1)
|
||||
/// Utilisé pour les actions principales (connexion, enregistrer, valider, etc.)
|
||||
library uf_primary_button;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../tokens/color_tokens.dart';
|
||||
import '../../tokens/spacing_tokens.dart';
|
||||
import '../../tokens/typography_tokens.dart';
|
||||
|
||||
/// Bouton primaire UnionFlow
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// UFPrimaryButton(
|
||||
/// label: 'Connexion',
|
||||
/// onPressed: () => login(),
|
||||
/// icon: Icons.login,
|
||||
/// isLoading: false,
|
||||
/// )
|
||||
/// ```
|
||||
class UFPrimaryButton extends StatelessWidget {
|
||||
/// Texte du bouton
|
||||
final String label;
|
||||
|
||||
/// Callback appelé lors du clic
|
||||
final VoidCallback? onPressed;
|
||||
|
||||
/// Indique si le bouton est en chargement
|
||||
final bool isLoading;
|
||||
|
||||
/// Icône optionnelle à gauche du texte
|
||||
final IconData? icon;
|
||||
|
||||
/// Bouton pleine largeur
|
||||
final bool isFullWidth;
|
||||
|
||||
/// Hauteur personnalisée (optionnel)
|
||||
final double? height;
|
||||
|
||||
const UFPrimaryButton({
|
||||
super.key,
|
||||
required this.label,
|
||||
this.onPressed,
|
||||
this.isLoading = false,
|
||||
this.icon,
|
||||
this.isFullWidth = false,
|
||||
this.height,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: isFullWidth ? double.infinity : null,
|
||||
height: height ?? SpacingTokens.buttonHeightLarge,
|
||||
child: ElevatedButton(
|
||||
onPressed: isLoading ? null : onPressed,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: ColorTokens.primary, // Bleu roi
|
||||
foregroundColor: ColorTokens.onPrimary, // Blanc
|
||||
disabledBackgroundColor: ColorTokens.primary.withOpacity(0.5),
|
||||
disabledForegroundColor: ColorTokens.onPrimary.withOpacity(0.7),
|
||||
elevation: SpacingTokens.elevationSm,
|
||||
shadowColor: ColorTokens.shadow,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: SpacingTokens.buttonPaddingHorizontal,
|
||||
vertical: SpacingTokens.buttonPaddingVertical,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(SpacingTokens.radiusLg),
|
||||
),
|
||||
),
|
||||
child: isLoading
|
||||
? SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
ColorTokens.onPrimary,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (icon != null) ...[
|
||||
Icon(icon, size: 20),
|
||||
SizedBox(width: SpacingTokens.md),
|
||||
],
|
||||
Text(
|
||||
label,
|
||||
style: TypographyTokens.buttonLarge,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/// UnionFlow Secondary Button - Bouton secondaire
|
||||
///
|
||||
/// Bouton secondaire avec la couleur Indigo (#6366F1)
|
||||
/// Utilisé pour les actions secondaires (annuler, retour, etc.)
|
||||
library uf_secondary_button;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../tokens/color_tokens.dart';
|
||||
import '../../tokens/spacing_tokens.dart';
|
||||
import '../../tokens/typography_tokens.dart';
|
||||
|
||||
/// Bouton secondaire UnionFlow
|
||||
class UFSecondaryButton extends StatelessWidget {
|
||||
final String label;
|
||||
final VoidCallback? onPressed;
|
||||
final bool isLoading;
|
||||
final IconData? icon;
|
||||
final bool isFullWidth;
|
||||
final double? height;
|
||||
|
||||
const UFSecondaryButton({
|
||||
super.key,
|
||||
required this.label,
|
||||
this.onPressed,
|
||||
this.isLoading = false,
|
||||
this.icon,
|
||||
this.isFullWidth = false,
|
||||
this.height,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: isFullWidth ? double.infinity : null,
|
||||
height: height ?? SpacingTokens.buttonHeightLarge,
|
||||
child: ElevatedButton(
|
||||
onPressed: isLoading ? null : onPressed,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: ColorTokens.secondary, // Indigo
|
||||
foregroundColor: ColorTokens.onSecondary, // Blanc
|
||||
disabledBackgroundColor: ColorTokens.secondary.withOpacity(0.5),
|
||||
disabledForegroundColor: ColorTokens.onSecondary.withOpacity(0.7),
|
||||
elevation: SpacingTokens.elevationSm,
|
||||
shadowColor: ColorTokens.shadow,
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: SpacingTokens.buttonPaddingHorizontal,
|
||||
vertical: SpacingTokens.buttonPaddingVertical,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(SpacingTokens.radiusLg),
|
||||
),
|
||||
),
|
||||
child: isLoading
|
||||
? SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
ColorTokens.onSecondary,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (icon != null) ...[
|
||||
Icon(icon, size: 20),
|
||||
SizedBox(width: SpacingTokens.md),
|
||||
],
|
||||
Text(
|
||||
label,
|
||||
style: TypographyTokens.buttonLarge,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../unionflow_design_system.dart';
|
||||
|
||||
/// Card standardisé UnionFlow
|
||||
///
|
||||
/// Composant Card unifié avec 3 styles prédéfinis :
|
||||
/// - elevated : Card avec ombre (par défaut)
|
||||
/// - outlined : Card avec bordure
|
||||
/// - filled : Card avec fond coloré
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// UFCard(
|
||||
/// child: Text('Contenu'),
|
||||
/// )
|
||||
///
|
||||
/// UFCard.outlined(
|
||||
/// child: Text('Contenu'),
|
||||
/// )
|
||||
///
|
||||
/// UFCard.filled(
|
||||
/// color: ColorTokens.primary,
|
||||
/// child: Text('Contenu'),
|
||||
/// )
|
||||
/// ```
|
||||
class UFCard extends StatelessWidget {
|
||||
final Widget child;
|
||||
final EdgeInsets? padding;
|
||||
final EdgeInsets? margin;
|
||||
final VoidCallback? onTap;
|
||||
final VoidCallback? onLongPress;
|
||||
final UFCardStyle style;
|
||||
final Color? color;
|
||||
final Color? borderColor;
|
||||
final double? borderWidth;
|
||||
final double? elevation;
|
||||
final double? borderRadius;
|
||||
|
||||
/// Card avec ombre (style par défaut)
|
||||
const UFCard({
|
||||
super.key,
|
||||
required this.child,
|
||||
this.padding,
|
||||
this.margin,
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
this.color,
|
||||
this.elevation,
|
||||
this.borderRadius,
|
||||
}) : style = UFCardStyle.elevated,
|
||||
borderColor = null,
|
||||
borderWidth = null;
|
||||
|
||||
/// Card avec bordure
|
||||
const UFCard.outlined({
|
||||
super.key,
|
||||
required this.child,
|
||||
this.padding,
|
||||
this.margin,
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
this.color,
|
||||
this.borderColor,
|
||||
this.borderWidth,
|
||||
this.borderRadius,
|
||||
}) : style = UFCardStyle.outlined,
|
||||
elevation = null;
|
||||
|
||||
/// Card avec fond coloré
|
||||
const UFCard.filled({
|
||||
super.key,
|
||||
required this.child,
|
||||
this.padding,
|
||||
this.margin,
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
required this.color,
|
||||
this.borderRadius,
|
||||
}) : style = UFCardStyle.filled,
|
||||
borderColor = null,
|
||||
borderWidth = null,
|
||||
elevation = null;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final effectivePadding = padding ?? EdgeInsets.all(SpacingTokens.cardPadding);
|
||||
final effectiveMargin = margin ?? EdgeInsets.zero;
|
||||
final effectiveBorderRadius = borderRadius ?? SpacingTokens.radiusLg;
|
||||
|
||||
Widget content = Container(
|
||||
padding: effectivePadding,
|
||||
decoration: _getDecoration(effectiveBorderRadius),
|
||||
child: child,
|
||||
);
|
||||
|
||||
if (onTap != null || onLongPress != null) {
|
||||
content = InkWell(
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
borderRadius: BorderRadius.circular(effectiveBorderRadius),
|
||||
child: content,
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: effectiveMargin,
|
||||
child: content,
|
||||
);
|
||||
}
|
||||
|
||||
BoxDecoration _getDecoration(double radius) {
|
||||
switch (style) {
|
||||
case UFCardStyle.elevated:
|
||||
return BoxDecoration(
|
||||
color: color ?? ColorTokens.surface,
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: ColorTokens.shadow,
|
||||
blurRadius: elevation ?? SpacingTokens.elevationSm * 5, // 10
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
case UFCardStyle.outlined:
|
||||
return BoxDecoration(
|
||||
color: color ?? ColorTokens.surface,
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
border: Border.all(
|
||||
color: borderColor ?? ColorTokens.outline,
|
||||
width: borderWidth ?? 1.0,
|
||||
),
|
||||
);
|
||||
|
||||
case UFCardStyle.filled:
|
||||
return BoxDecoration(
|
||||
color: color ?? ColorTokens.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Styles de Card disponibles
|
||||
enum UFCardStyle {
|
||||
/// Card avec ombre
|
||||
elevated,
|
||||
|
||||
/// Card avec bordure
|
||||
outlined,
|
||||
|
||||
/// Card avec fond coloré
|
||||
filled,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/// UnionFlow Info Card - Card d'information générique
|
||||
///
|
||||
/// Card blanche avec titre, icône et contenu personnalisable
|
||||
library uf_info_card;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../tokens/color_tokens.dart';
|
||||
import '../../tokens/spacing_tokens.dart';
|
||||
import '../../tokens/typography_tokens.dart';
|
||||
|
||||
/// Card d'information générique
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// UFInfoCard(
|
||||
/// title: 'État du système',
|
||||
/// icon: Icons.health_and_safety,
|
||||
/// iconColor: ColorTokens.primary,
|
||||
/// trailing: Container(...), // Badge ou autre widget
|
||||
/// child: Column(...), // Contenu de la card
|
||||
/// )
|
||||
/// ```
|
||||
class UFInfoCard extends StatelessWidget {
|
||||
/// Titre de la card
|
||||
final String title;
|
||||
|
||||
/// Icône du titre
|
||||
final IconData icon;
|
||||
|
||||
/// Couleur de l'icône (par défaut: primary)
|
||||
final Color? iconColor;
|
||||
|
||||
/// Widget à droite du titre (badge, bouton, etc.)
|
||||
final Widget? trailing;
|
||||
|
||||
/// Contenu de la card
|
||||
final Widget child;
|
||||
|
||||
/// Padding de la card (par défaut: xl)
|
||||
final EdgeInsets? padding;
|
||||
|
||||
const UFInfoCard({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.icon,
|
||||
this.iconColor,
|
||||
this.trailing,
|
||||
required this.child,
|
||||
this.padding,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final effectiveIconColor = iconColor ?? ColorTokens.primary;
|
||||
final effectivePadding = padding ?? EdgeInsets.all(SpacingTokens.xl);
|
||||
|
||||
return Container(
|
||||
padding: effectivePadding,
|
||||
decoration: BoxDecoration(
|
||||
color: ColorTokens.surface,
|
||||
borderRadius: BorderRadius.circular(SpacingTokens.radiusXl),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Header avec titre et trailing
|
||||
Row(
|
||||
children: [
|
||||
Icon(icon, color: effectiveIconColor, size: 20),
|
||||
SizedBox(width: SpacingTokens.md),
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: TypographyTokens.titleMedium.copyWith(
|
||||
color: ColorTokens.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (trailing != null) trailing!,
|
||||
],
|
||||
),
|
||||
SizedBox(height: SpacingTokens.xl),
|
||||
// Contenu
|
||||
child,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/// UnionFlow Metric Card - Card de métrique système
|
||||
///
|
||||
/// Card compacte pour afficher une métrique système (CPU, RAM, etc.)
|
||||
library uf_metric_card;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../tokens/color_tokens.dart';
|
||||
import '../../tokens/spacing_tokens.dart';
|
||||
import '../../tokens/typography_tokens.dart';
|
||||
|
||||
/// Card de métrique système
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// UFMetricCard(
|
||||
/// label: 'CPU',
|
||||
/// value: '23.5%',
|
||||
/// icon: Icons.memory,
|
||||
/// color: ColorTokens.success,
|
||||
/// )
|
||||
/// ```
|
||||
class UFMetricCard extends StatelessWidget {
|
||||
/// Label de la métrique (ex: "CPU")
|
||||
final String label;
|
||||
|
||||
/// Valeur de la métrique (ex: "23.5%")
|
||||
final String value;
|
||||
|
||||
/// Icône représentant la métrique
|
||||
final IconData icon;
|
||||
|
||||
/// Couleur de la métrique (optionnel)
|
||||
final Color? color;
|
||||
|
||||
const UFMetricCard({
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.value,
|
||||
required this.icon,
|
||||
this.color,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(SpacingTokens.md),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.15),
|
||||
borderRadius: BorderRadius.circular(SpacingTokens.radiusLg),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(icon, color: Colors.white, size: 16),
|
||||
SizedBox(height: SpacingTokens.sm),
|
||||
Text(
|
||||
value,
|
||||
style: TypographyTokens.labelSmall.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Text(
|
||||
label,
|
||||
style: TypographyTokens.labelSmall.copyWith(
|
||||
fontSize: 9,
|
||||
color: Colors.white.withOpacity(0.8),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/// UnionFlow Stat Card - Card de statistiques
|
||||
///
|
||||
/// Card affichant une statistique avec icône, titre, valeur et sous-titre optionnel
|
||||
/// Utilisé dans le dashboard pour afficher les métriques clés
|
||||
library uf_stat_card;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../tokens/color_tokens.dart';
|
||||
import '../../tokens/spacing_tokens.dart';
|
||||
import '../../tokens/typography_tokens.dart';
|
||||
|
||||
/// Card de statistiques UnionFlow
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// UFStatCard(
|
||||
/// title: 'Membres',
|
||||
/// value: '142',
|
||||
/// icon: Icons.people,
|
||||
/// iconColor: ColorTokens.primary,
|
||||
/// subtitle: '+5 ce mois',
|
||||
/// onTap: () => navigateToMembers(),
|
||||
/// )
|
||||
/// ```
|
||||
class UFStatCard extends StatelessWidget {
|
||||
/// Titre de la statistique (ex: "Membres")
|
||||
final String title;
|
||||
|
||||
/// Valeur de la statistique (ex: "142")
|
||||
final String value;
|
||||
|
||||
/// Icône représentant la statistique
|
||||
final IconData icon;
|
||||
|
||||
/// Couleur de l'icône (par défaut: primary)
|
||||
final Color? iconColor;
|
||||
|
||||
/// Sous-titre optionnel (ex: "+5 ce mois")
|
||||
final String? subtitle;
|
||||
|
||||
/// Callback appelé lors du clic sur la card
|
||||
final VoidCallback? onTap;
|
||||
|
||||
/// Couleur de fond de l'icône (par défaut: iconColor avec opacité)
|
||||
final Color? iconBackgroundColor;
|
||||
|
||||
const UFStatCard({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.value,
|
||||
required this.icon,
|
||||
this.iconColor,
|
||||
this.subtitle,
|
||||
this.onTap,
|
||||
this.iconBackgroundColor,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final effectiveIconColor = iconColor ?? ColorTokens.primary;
|
||||
final effectiveIconBgColor = iconBackgroundColor ??
|
||||
effectiveIconColor.withOpacity(0.1);
|
||||
|
||||
return Card(
|
||||
elevation: SpacingTokens.elevationSm,
|
||||
shadowColor: ColorTokens.shadow,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(SpacingTokens.radiusLg),
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(SpacingTokens.radiusLg),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(SpacingTokens.cardPadding),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Header avec icône et flèche
|
||||
Row(
|
||||
children: [
|
||||
// Icône avec background coloré
|
||||
Container(
|
||||
padding: EdgeInsets.all(SpacingTokens.md),
|
||||
decoration: BoxDecoration(
|
||||
color: effectiveIconBgColor,
|
||||
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: effectiveIconColor,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
// Flèche si cliquable
|
||||
if (onTap != null)
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 16,
|
||||
color: ColorTokens.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
SizedBox(height: SpacingTokens.lg),
|
||||
|
||||
// Titre
|
||||
Text(
|
||||
title,
|
||||
style: TypographyTokens.labelLarge.copyWith(
|
||||
color: ColorTokens.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: SpacingTokens.sm),
|
||||
|
||||
// Valeur
|
||||
Text(
|
||||
value,
|
||||
style: TypographyTokens.cardValue.copyWith(
|
||||
color: ColorTokens.onSurface,
|
||||
),
|
||||
),
|
||||
|
||||
// Sous-titre optionnel
|
||||
if (subtitle != null) ...[
|
||||
SizedBox(height: SpacingTokens.sm),
|
||||
Text(
|
||||
subtitle!,
|
||||
style: TypographyTokens.bodySmall.copyWith(
|
||||
color: ColorTokens.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/// UnionFlow Components - Export centralisé
|
||||
///
|
||||
/// Ce fichier exporte tous les composants réutilisables du Design System
|
||||
library components;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// BOUTONS
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
export 'buttons/uf_primary_button.dart';
|
||||
export 'buttons/uf_secondary_button.dart';
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// CARDS
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
export 'cards/uf_stat_card.dart';
|
||||
|
||||
// TODO: Ajouter d'autres composants au fur et à mesure
|
||||
// export 'buttons/uf_outline_button.dart';
|
||||
// export 'buttons/uf_text_button.dart';
|
||||
// export 'cards/uf_event_card.dart';
|
||||
// export 'cards/uf_info_card.dart';
|
||||
// export 'inputs/uf_text_field.dart';
|
||||
// export 'navigation/uf_app_bar.dart';
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/// UnionFlow Dropdown Tile - Ligne de paramètre avec dropdown
|
||||
///
|
||||
/// Tile avec titre et dropdown pour les paramètres
|
||||
library uf_dropdown_tile;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../tokens/color_tokens.dart';
|
||||
import '../../tokens/spacing_tokens.dart';
|
||||
import '../../tokens/typography_tokens.dart';
|
||||
|
||||
/// Tile de paramètre avec dropdown
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// UFDropdownTile<String>(
|
||||
/// title: 'Niveau de log',
|
||||
/// value: 'INFO',
|
||||
/// items: ['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'],
|
||||
/// onChanged: (value) => setState(() => _logLevel = value),
|
||||
/// )
|
||||
/// ```
|
||||
class UFDropdownTile<T> extends StatelessWidget {
|
||||
/// Titre du paramètre
|
||||
final String title;
|
||||
|
||||
/// Valeur actuelle
|
||||
final T value;
|
||||
|
||||
/// Liste des options
|
||||
final List<T> items;
|
||||
|
||||
/// Callback appelé lors du changement
|
||||
final ValueChanged<T?>? onChanged;
|
||||
|
||||
/// Couleur de fond (par défaut: surfaceVariant)
|
||||
final Color? backgroundColor;
|
||||
|
||||
/// Fonction pour afficher le texte d'un item (par défaut: toString())
|
||||
final String Function(T)? itemBuilder;
|
||||
|
||||
const UFDropdownTile({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.value,
|
||||
required this.items,
|
||||
this.onChanged,
|
||||
this.backgroundColor,
|
||||
this.itemBuilder,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final effectiveBgColor = backgroundColor ?? ColorTokens.surfaceVariant;
|
||||
final effectiveItemBuilder = itemBuilder ?? (item) => item.toString();
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.only(bottom: SpacingTokens.lg),
|
||||
padding: EdgeInsets.all(SpacingTokens.lg),
|
||||
decoration: BoxDecoration(
|
||||
color: effectiveBgColor,
|
||||
borderRadius: BorderRadius.circular(SpacingTokens.radiusLg),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: TypographyTokens.bodyMedium.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: ColorTokens.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: SpacingTokens.lg),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorTokens.surface,
|
||||
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
||||
border: Border.all(color: ColorTokens.outline),
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<T>(
|
||||
value: value,
|
||||
onChanged: onChanged,
|
||||
items: items.map((item) {
|
||||
return DropdownMenuItem<T>(
|
||||
value: item,
|
||||
child: Text(effectiveItemBuilder(item)),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/// UnionFlow Switch Tile - Ligne de paramètre avec switch
|
||||
///
|
||||
/// Tile avec titre, description et switch pour les paramètres
|
||||
library uf_switch_tile;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../tokens/color_tokens.dart';
|
||||
import '../../tokens/spacing_tokens.dart';
|
||||
import '../../tokens/typography_tokens.dart';
|
||||
|
||||
/// Tile de paramètre avec switch
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// UFSwitchTile(
|
||||
/// title: 'Notifications',
|
||||
/// subtitle: 'Activer les notifications push',
|
||||
/// value: true,
|
||||
/// onChanged: (value) => setState(() => _notifications = value),
|
||||
/// )
|
||||
/// ```
|
||||
class UFSwitchTile extends StatelessWidget {
|
||||
/// Titre du paramètre
|
||||
final String title;
|
||||
|
||||
/// Description du paramètre
|
||||
final String subtitle;
|
||||
|
||||
/// Valeur actuelle du switch
|
||||
final bool value;
|
||||
|
||||
/// Callback appelé lors du changement
|
||||
final ValueChanged<bool>? onChanged;
|
||||
|
||||
/// Couleur de fond (par défaut: surfaceVariant)
|
||||
final Color? backgroundColor;
|
||||
|
||||
const UFSwitchTile({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
required this.value,
|
||||
this.onChanged,
|
||||
this.backgroundColor,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final effectiveBgColor = backgroundColor ?? ColorTokens.surfaceVariant;
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.only(bottom: SpacingTokens.lg),
|
||||
padding: EdgeInsets.all(SpacingTokens.lg),
|
||||
decoration: BoxDecoration(
|
||||
color: effectiveBgColor,
|
||||
borderRadius: BorderRadius.circular(SpacingTokens.radiusLg),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TypographyTokens.bodyMedium.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: ColorTokens.onSurface,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
subtitle,
|
||||
style: TypographyTokens.bodySmall.copyWith(
|
||||
color: ColorTokens.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Switch(
|
||||
value: value,
|
||||
onChanged: onChanged,
|
||||
activeColor: ColorTokens.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../unionflow_design_system.dart';
|
||||
|
||||
/// AppBar standardisé UnionFlow
|
||||
///
|
||||
/// Composant AppBar unifié pour toutes les pages de détail/formulaire.
|
||||
/// Garantit la cohérence visuelle et l'expérience utilisateur.
|
||||
class UFAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
final String title;
|
||||
final List<Widget>? actions;
|
||||
final Widget? leading;
|
||||
final bool automaticallyImplyLeading;
|
||||
final PreferredSizeWidget? bottom;
|
||||
final Color? backgroundColor;
|
||||
final Color? foregroundColor;
|
||||
final double elevation;
|
||||
|
||||
const UFAppBar({
|
||||
super.key,
|
||||
required this.title,
|
||||
this.actions,
|
||||
this.leading,
|
||||
this.automaticallyImplyLeading = true,
|
||||
this.bottom,
|
||||
this.backgroundColor,
|
||||
this.foregroundColor,
|
||||
this.elevation = 0,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBar(
|
||||
title: Text(title),
|
||||
backgroundColor: backgroundColor ?? ColorTokens.primary,
|
||||
foregroundColor: foregroundColor ?? ColorTokens.onPrimary,
|
||||
elevation: elevation,
|
||||
leading: leading,
|
||||
automaticallyImplyLeading: automaticallyImplyLeading,
|
||||
actions: actions,
|
||||
bottom: bottom,
|
||||
systemOverlayStyle: SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: Brightness.light, // Icônes claires sur fond bleu
|
||||
statusBarBrightness: Brightness.dark, // Pour iOS
|
||||
),
|
||||
centerTitle: false,
|
||||
titleTextStyle: TypographyTokens.titleLarge.copyWith(
|
||||
color: foregroundColor ?? ColorTokens.onPrimary,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Size get preferredSize => Size.fromHeight(
|
||||
kToolbarHeight + (bottom?.preferredSize.height ?? 0.0),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../unionflow_design_system.dart';
|
||||
|
||||
/// Container standardisé UnionFlow
|
||||
///
|
||||
/// Composant Container unifié avec styles prédéfinis.
|
||||
/// Garantit la cohérence des espacements, rayons et ombres.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// UFContainer(
|
||||
/// child: Text('Contenu'),
|
||||
/// )
|
||||
///
|
||||
/// UFContainer.rounded(
|
||||
/// color: ColorTokens.primary,
|
||||
/// child: Text('Contenu'),
|
||||
/// )
|
||||
///
|
||||
/// UFContainer.elevated(
|
||||
/// child: Text('Contenu'),
|
||||
/// )
|
||||
/// ```
|
||||
class UFContainer extends StatelessWidget {
|
||||
final Widget child;
|
||||
final Color? color;
|
||||
final EdgeInsets? padding;
|
||||
final EdgeInsets? margin;
|
||||
final double? width;
|
||||
final double? height;
|
||||
final AlignmentGeometry? alignment;
|
||||
final BoxConstraints? constraints;
|
||||
final Gradient? gradient;
|
||||
final double borderRadius;
|
||||
final Border? border;
|
||||
final List<BoxShadow>? boxShadow;
|
||||
|
||||
/// Container standard
|
||||
const UFContainer({
|
||||
super.key,
|
||||
required this.child,
|
||||
this.color,
|
||||
this.padding,
|
||||
this.margin,
|
||||
this.width,
|
||||
this.height,
|
||||
this.alignment,
|
||||
this.constraints,
|
||||
this.gradient,
|
||||
this.border,
|
||||
this.boxShadow,
|
||||
}) : borderRadius = SpacingTokens.radiusMd;
|
||||
|
||||
/// Container avec coins arrondis
|
||||
const UFContainer.rounded({
|
||||
super.key,
|
||||
required this.child,
|
||||
this.color,
|
||||
this.padding,
|
||||
this.margin,
|
||||
this.width,
|
||||
this.height,
|
||||
this.alignment,
|
||||
this.constraints,
|
||||
this.gradient,
|
||||
this.border,
|
||||
this.boxShadow,
|
||||
}) : borderRadius = SpacingTokens.radiusLg;
|
||||
|
||||
/// Container très arrondi
|
||||
const UFContainer.extraRounded({
|
||||
super.key,
|
||||
required this.child,
|
||||
this.color,
|
||||
this.padding,
|
||||
this.margin,
|
||||
this.width,
|
||||
this.height,
|
||||
this.alignment,
|
||||
this.constraints,
|
||||
this.gradient,
|
||||
this.border,
|
||||
this.boxShadow,
|
||||
}) : borderRadius = SpacingTokens.radiusXl;
|
||||
|
||||
/// Container avec ombre
|
||||
UFContainer.elevated({
|
||||
super.key,
|
||||
required this.child,
|
||||
this.color,
|
||||
this.padding,
|
||||
this.margin,
|
||||
this.width,
|
||||
this.height,
|
||||
this.alignment,
|
||||
this.constraints,
|
||||
this.gradient,
|
||||
this.border,
|
||||
}) : borderRadius = SpacingTokens.radiusLg,
|
||||
boxShadow = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.shadow,
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
];
|
||||
|
||||
/// Container circulaire
|
||||
const UFContainer.circular({
|
||||
super.key,
|
||||
required this.child,
|
||||
this.color,
|
||||
this.padding,
|
||||
this.margin,
|
||||
this.width,
|
||||
this.height,
|
||||
this.alignment,
|
||||
this.constraints,
|
||||
this.gradient,
|
||||
this.border,
|
||||
this.boxShadow,
|
||||
}) : borderRadius = SpacingTokens.radiusCircular;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: width,
|
||||
height: height,
|
||||
padding: padding,
|
||||
margin: margin,
|
||||
alignment: alignment,
|
||||
constraints: constraints,
|
||||
decoration: BoxDecoration(
|
||||
color: gradient == null ? (color ?? ColorTokens.surface) : null,
|
||||
gradient: gradient,
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
border: border,
|
||||
boxShadow: boxShadow,
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../unionflow_design_system.dart';
|
||||
|
||||
/// Header de page compact et moderne
|
||||
///
|
||||
/// Composant header minimaliste pour les pages principales du BottomNavigationBar.
|
||||
/// Design épuré sans gradient lourd, optimisé pour l'espace.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// UFPageHeader(
|
||||
/// title: 'Membres',
|
||||
/// icon: Icons.people,
|
||||
/// actions: [
|
||||
/// IconButton(icon: Icon(Icons.add), onPressed: () {}),
|
||||
/// ],
|
||||
/// )
|
||||
/// ```
|
||||
class UFPageHeader extends StatelessWidget {
|
||||
final String title;
|
||||
final IconData icon;
|
||||
final List<Widget>? actions;
|
||||
final Color? iconColor;
|
||||
final bool showDivider;
|
||||
|
||||
const UFPageHeader({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.icon,
|
||||
this.actions,
|
||||
this.iconColor,
|
||||
this.showDivider = true,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final effectiveIconColor = iconColor ?? ColorTokens.primary;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: SpacingTokens.lg,
|
||||
vertical: SpacingTokens.md,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// Icône
|
||||
Container(
|
||||
padding: EdgeInsets.all(SpacingTokens.sm),
|
||||
decoration: BoxDecoration(
|
||||
color: effectiveIconColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: effectiveIconColor,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
SizedBox(width: SpacingTokens.md),
|
||||
|
||||
// Titre
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: TypographyTokens.titleLarge.copyWith(
|
||||
color: ColorTokens.onSurface,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Actions
|
||||
if (actions != null) ...actions!,
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Divider optionnel
|
||||
if (showDivider)
|
||||
Divider(
|
||||
height: 1,
|
||||
thickness: 1,
|
||||
color: ColorTokens.outline.withOpacity(0.1),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Header de page avec statistiques
|
||||
///
|
||||
/// Header compact avec des métriques KPI intégrées.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// UFPageHeaderWithStats(
|
||||
/// title: 'Membres',
|
||||
/// icon: Icons.people,
|
||||
/// stats: [
|
||||
/// UFHeaderStat(label: 'Total', value: '142'),
|
||||
/// UFHeaderStat(label: 'Actifs', value: '128'),
|
||||
/// ],
|
||||
/// )
|
||||
/// ```
|
||||
class UFPageHeaderWithStats extends StatelessWidget {
|
||||
final String title;
|
||||
final IconData icon;
|
||||
final List<UFHeaderStat> stats;
|
||||
final List<Widget>? actions;
|
||||
final Color? iconColor;
|
||||
|
||||
const UFPageHeaderWithStats({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.icon,
|
||||
required this.stats,
|
||||
this.actions,
|
||||
this.iconColor,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final effectiveIconColor = iconColor ?? ColorTokens.primary;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
// Titre et actions
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
SpacingTokens.lg,
|
||||
SpacingTokens.md,
|
||||
SpacingTokens.lg,
|
||||
SpacingTokens.sm,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// Icône
|
||||
Container(
|
||||
padding: EdgeInsets.all(SpacingTokens.sm),
|
||||
decoration: BoxDecoration(
|
||||
color: effectiveIconColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: effectiveIconColor,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
SizedBox(width: SpacingTokens.md),
|
||||
|
||||
// Titre
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: TypographyTokens.titleLarge.copyWith(
|
||||
color: ColorTokens.onSurface,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Actions
|
||||
if (actions != null) ...actions!,
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Statistiques
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
SpacingTokens.lg,
|
||||
0,
|
||||
SpacingTokens.lg,
|
||||
SpacingTokens.md,
|
||||
),
|
||||
child: Row(
|
||||
children: stats.map((stat) {
|
||||
final isLast = stat == stats.last;
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
right: isLast ? 0 : SpacingTokens.sm,
|
||||
),
|
||||
child: _buildStatItem(stat),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
|
||||
// Divider
|
||||
Divider(
|
||||
height: 1,
|
||||
thickness: 1,
|
||||
color: ColorTokens.outline.withOpacity(0.1),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatItem(UFHeaderStat stat) {
|
||||
return UFContainer.rounded(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: SpacingTokens.md,
|
||||
vertical: SpacingTokens.sm,
|
||||
),
|
||||
color: (stat.color ?? ColorTokens.primary).withOpacity(0.05),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
stat.value,
|
||||
style: TypographyTokens.titleMedium.copyWith(
|
||||
color: stat.color ?? ColorTokens.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: SpacingTokens.xs),
|
||||
Text(
|
||||
stat.label,
|
||||
style: TypographyTokens.labelSmall.copyWith(
|
||||
color: ColorTokens.onSurfaceVariant,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Statistique pour UFPageHeaderWithStats
|
||||
class UFHeaderStat {
|
||||
final String label;
|
||||
final String value;
|
||||
final Color? color;
|
||||
|
||||
const UFHeaderStat({
|
||||
required this.label,
|
||||
required this.value,
|
||||
this.color,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Design System UnionFlow - Tokens de design centralisés
|
||||
///
|
||||
/// Ce fichier centralise tous les tokens de design pour garantir
|
||||
/// la cohérence visuelle dans toute l'application UnionFlow.
|
||||
class UnionFlowDesignTokens {
|
||||
// ==================== COULEURS ====================
|
||||
|
||||
/// Couleurs primaires
|
||||
static const Color primaryColor = Color(0xFF6C5CE7);
|
||||
static const Color primaryDark = Color(0xFF5A4FCF);
|
||||
static const Color primaryLight = Color(0xFF8B7EE8);
|
||||
|
||||
/// Couleurs secondaires
|
||||
static const Color secondaryColor = Color(0xFF0984E3);
|
||||
static const Color secondaryDark = Color(0xFF0770C2);
|
||||
static const Color secondaryLight = Color(0xFF3498E8);
|
||||
|
||||
/// Couleurs de statut
|
||||
static const Color successColor = Color(0xFF00B894);
|
||||
static const Color warningColor = Color(0xFFE17055);
|
||||
static const Color errorColor = Color(0xFFE74C3C);
|
||||
static const Color infoColor = Color(0xFF00CEC9);
|
||||
|
||||
/// Couleurs neutres
|
||||
static const Color backgroundColor = Color(0xFFF8F9FA);
|
||||
static const Color surfaceColor = Colors.white;
|
||||
static const Color cardColor = Colors.white;
|
||||
|
||||
/// Couleurs de texte
|
||||
static const Color textPrimary = Color(0xFF1F2937);
|
||||
static const Color textSecondary = Color(0xFF6B7280);
|
||||
static const Color textTertiary = Color(0xFF9CA3AF);
|
||||
static const Color textOnPrimary = Colors.white;
|
||||
|
||||
/// Couleurs de bordure
|
||||
static const Color borderLight = Color(0xFFE5E7EB);
|
||||
static const Color borderMedium = Color(0xFFD1D5DB);
|
||||
static const Color borderDark = Color(0xFF9CA3AF);
|
||||
|
||||
// ==================== TYPOGRAPHIE ====================
|
||||
|
||||
/// Tailles de police
|
||||
static const double fontSizeXS = 10.0;
|
||||
static const double fontSizeSM = 12.0;
|
||||
static const double fontSizeBase = 14.0;
|
||||
static const double fontSizeLG = 16.0;
|
||||
static const double fontSizeXL = 18.0;
|
||||
static const double fontSize2XL = 20.0;
|
||||
static const double fontSize3XL = 24.0;
|
||||
static const double fontSize4XL = 28.0;
|
||||
|
||||
/// Poids de police
|
||||
static const FontWeight fontWeightNormal = FontWeight.w400;
|
||||
static const FontWeight fontWeightMedium = FontWeight.w500;
|
||||
static const FontWeight fontWeightSemiBold = FontWeight.w600;
|
||||
static const FontWeight fontWeightBold = FontWeight.w700;
|
||||
|
||||
// ==================== ESPACEMENT ====================
|
||||
|
||||
/// Espacements
|
||||
static const double spaceXS = 4.0;
|
||||
static const double spaceSM = 8.0;
|
||||
static const double spaceBase = 12.0;
|
||||
static const double spaceMD = 16.0;
|
||||
static const double spaceLG = 20.0;
|
||||
static const double spaceXL = 24.0;
|
||||
static const double space2XL = 32.0;
|
||||
static const double space3XL = 48.0;
|
||||
|
||||
// ==================== RAYONS DE BORDURE ====================
|
||||
|
||||
/// Rayons de bordure
|
||||
static const double radiusXS = 4.0;
|
||||
static const double radiusSM = 8.0;
|
||||
static const double radiusBase = 12.0;
|
||||
static const double radiusLG = 16.0;
|
||||
static const double radiusXL = 20.0;
|
||||
static const double radiusFull = 999.0;
|
||||
|
||||
// ==================== OMBRES ====================
|
||||
|
||||
/// Ombres prédéfinies
|
||||
static List<BoxShadow> get shadowSM => [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 5,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
];
|
||||
|
||||
static List<BoxShadow> get shadowBase => [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
];
|
||||
|
||||
static List<BoxShadow> get shadowLG => [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 15,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
];
|
||||
|
||||
static List<BoxShadow> get shadowXL => [
|
||||
BoxShadow(
|
||||
color: primaryColor.withOpacity(0.3),
|
||||
blurRadius: 20,
|
||||
offset: const Offset(0, 8),
|
||||
),
|
||||
];
|
||||
|
||||
// ==================== GRADIENTS ====================
|
||||
|
||||
/// Gradients prédéfinis
|
||||
static const LinearGradient primaryGradient = LinearGradient(
|
||||
colors: [primaryColor, primaryDark],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
);
|
||||
|
||||
static const LinearGradient secondaryGradient = LinearGradient(
|
||||
colors: [secondaryColor, secondaryDark],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
);
|
||||
|
||||
// ==================== STYLES DE TEXTE ====================
|
||||
|
||||
/// Styles de texte prédéfinis
|
||||
static const TextStyle headingXL = TextStyle(
|
||||
fontSize: fontSize3XL,
|
||||
fontWeight: fontWeightBold,
|
||||
color: textPrimary,
|
||||
height: 1.2,
|
||||
);
|
||||
|
||||
static const TextStyle headingLG = TextStyle(
|
||||
fontSize: fontSize2XL,
|
||||
fontWeight: fontWeightBold,
|
||||
color: textPrimary,
|
||||
height: 1.3,
|
||||
);
|
||||
|
||||
static const TextStyle headingMD = TextStyle(
|
||||
fontSize: fontSizeXL,
|
||||
fontWeight: fontWeightSemiBold,
|
||||
color: textPrimary,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
static const TextStyle bodySM = TextStyle(
|
||||
fontSize: fontSizeSM,
|
||||
fontWeight: fontWeightNormal,
|
||||
color: textSecondary,
|
||||
height: 1.5,
|
||||
);
|
||||
|
||||
static const TextStyle bodyBase = TextStyle(
|
||||
fontSize: fontSizeBase,
|
||||
fontWeight: fontWeightNormal,
|
||||
color: textPrimary,
|
||||
height: 1.5,
|
||||
);
|
||||
|
||||
static const TextStyle bodyLG = TextStyle(
|
||||
fontSize: fontSizeLG,
|
||||
fontWeight: fontWeightNormal,
|
||||
color: textPrimary,
|
||||
height: 1.5,
|
||||
);
|
||||
|
||||
static const TextStyle caption = TextStyle(
|
||||
fontSize: fontSizeXS,
|
||||
fontWeight: fontWeightNormal,
|
||||
color: textTertiary,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
static const TextStyle buttonText = TextStyle(
|
||||
fontSize: fontSizeBase,
|
||||
fontWeight: fontWeightSemiBold,
|
||||
color: textOnPrimary,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/// Tokens d'ombres pour le design system
|
||||
/// Définit les ombres standardisées de l'application
|
||||
library shadow_tokens;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'color_tokens.dart';
|
||||
|
||||
/// Tokens d'ombres standardisés
|
||||
///
|
||||
/// Utilisation cohérente des ombres dans toute l'application.
|
||||
/// Basé sur les principes de Material Design 3.
|
||||
class ShadowTokens {
|
||||
ShadowTokens._();
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// OMBRES STANDARDS
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// Ombre minimale - Pour éléments subtils
|
||||
static final List<BoxShadow> xs = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.shadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
];
|
||||
|
||||
/// Ombre petite - Pour cards et boutons
|
||||
static final List<BoxShadow> sm = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.shadow,
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
];
|
||||
|
||||
/// Ombre moyenne - Pour cards importantes
|
||||
static final List<BoxShadow> md = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.shadow,
|
||||
blurRadius: 12,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
];
|
||||
|
||||
/// Ombre large - Pour modals et dialogs
|
||||
static final List<BoxShadow> lg = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.shadowMedium,
|
||||
blurRadius: 16,
|
||||
offset: const Offset(0, 6),
|
||||
),
|
||||
];
|
||||
|
||||
/// Ombre très large - Pour éléments flottants
|
||||
static final List<BoxShadow> xl = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.shadowMedium,
|
||||
blurRadius: 24,
|
||||
offset: const Offset(0, 8),
|
||||
),
|
||||
];
|
||||
|
||||
/// Ombre extra large - Pour éléments héroïques
|
||||
static final List<BoxShadow> xxl = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.shadowHigh,
|
||||
blurRadius: 32,
|
||||
offset: const Offset(0, 12),
|
||||
spreadRadius: -4,
|
||||
),
|
||||
];
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// OMBRES COLORÉES
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// Ombre primaire - Pour éléments avec couleur primaire
|
||||
static final List<BoxShadow> primary = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.primary.withOpacity(0.15),
|
||||
blurRadius: 16,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
];
|
||||
|
||||
/// Ombre secondaire - Pour éléments avec couleur secondaire
|
||||
static final List<BoxShadow> secondary = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.secondary.withOpacity(0.15),
|
||||
blurRadius: 16,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
];
|
||||
|
||||
/// Ombre success - Pour éléments de succès
|
||||
static final List<BoxShadow> success = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.success.withOpacity(0.15),
|
||||
blurRadius: 16,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
];
|
||||
|
||||
/// Ombre error - Pour éléments d'erreur
|
||||
static final List<BoxShadow> error = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.error.withOpacity(0.15),
|
||||
blurRadius: 16,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
];
|
||||
|
||||
/// Ombre warning - Pour éléments d'avertissement
|
||||
static final List<BoxShadow> warning = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.warning.withOpacity(0.15),
|
||||
blurRadius: 16,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
];
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// OMBRES SPÉCIALES
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// Ombre interne - Pour effets enfoncés
|
||||
static final List<BoxShadow> inner = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.shadow,
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
spreadRadius: -2,
|
||||
),
|
||||
];
|
||||
|
||||
/// Ombre diffuse - Pour glassmorphism
|
||||
static final List<BoxShadow> diffuse = [
|
||||
BoxShadow(
|
||||
color: ColorTokens.shadow.withOpacity(0.05),
|
||||
blurRadius: 20,
|
||||
offset: const Offset(0, 4),
|
||||
spreadRadius: 2,
|
||||
),
|
||||
];
|
||||
|
||||
/// Pas d'ombre
|
||||
static const List<BoxShadow> none = [];
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/// Export de tous les tokens de design
|
||||
/// Facilite l'importation des tokens dans l'application
|
||||
library tokens;
|
||||
|
||||
// Tokens de couleur
|
||||
export 'color_tokens.dart';
|
||||
|
||||
// Tokens de typographie
|
||||
export 'typography_tokens.dart';
|
||||
|
||||
// Tokens d'espacement
|
||||
export 'spacing_tokens.dart';
|
||||
|
||||
// Tokens de rayon
|
||||
export 'radius_tokens.dart';
|
||||
@@ -0,0 +1,58 @@
|
||||
/// UnionFlow Design System - Point d'entrée unique
|
||||
///
|
||||
/// Ce fichier centralise tous les tokens et composants du Design System UnionFlow.
|
||||
/// Importer ce fichier pour accéder à tous les éléments de design.
|
||||
///
|
||||
/// Palette de couleurs: Bleu Roi (#4169E1) + Bleu Pétrole (#2C5F6F)
|
||||
/// Basé sur Material Design 3 et les tendances UI/UX 2024-2025
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// import 'package:unionflow_mobile_apps/core/design_system/unionflow_design_system.dart';
|
||||
///
|
||||
/// // Utiliser les tokens
|
||||
/// Container(
|
||||
/// color: ColorTokens.primary,
|
||||
/// padding: EdgeInsets.all(SpacingTokens.xl),
|
||||
/// child: Text(
|
||||
/// 'UnionFlow',
|
||||
/// style: TypographyTokens.headlineMedium,
|
||||
/// ),
|
||||
/// );
|
||||
/// ```
|
||||
library unionflow_design_system;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// TOKENS - Valeurs de design fondamentales
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// Tokens de couleurs (Bleu Roi + Bleu Pétrole)
|
||||
export 'tokens/color_tokens.dart';
|
||||
|
||||
/// Tokens de typographie (Inter, SF Pro Display, JetBrains Mono)
|
||||
export 'tokens/typography_tokens.dart';
|
||||
|
||||
/// Tokens d'espacement (Grille 4px)
|
||||
export 'tokens/spacing_tokens.dart';
|
||||
|
||||
/// Tokens de rayons de bordure
|
||||
export 'tokens/radius_tokens.dart';
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// THÈME - Configuration Material Design 3
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// Thème sophistiqué (Light + Dark)
|
||||
export 'theme/app_theme_sophisticated.dart';
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// COMPOSANTS - Widgets réutilisables (à ajouter progressivement)
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
// TODO: Ajouter les composants au fur et à mesure de leur création
|
||||
// export 'components/buttons/uf_buttons.dart';
|
||||
// export 'components/cards/uf_cards.dart';
|
||||
// export 'components/inputs/uf_inputs.dart';
|
||||
// export 'components/navigation/uf_navigation.dart';
|
||||
// export 'components/feedback/uf_feedback.dart';
|
||||
|
||||
Reference in New Issue
Block a user