# 🎨 Guide des Bonnes Pratiques - Composants Frontend
> **Guide**: Design System Notytex
> **Audience**: Développeurs Frontend & UI/UX Designers
> **Version**: 1.0
> **Mise à jour**: 7 août 2025
## 🎯 **Philosophie du Design System**
Notytex adopte une approche **moderne, cohérente et accessible** pour ses composants frontend. Chaque composant doit être **réutilisable**, **maintenable** et **évolutif**.
### 🏗️ **Principes Fondamentaux**
- **🔄 Réutilisabilité** : Un composant = plusieurs contextes
- **🎨 Cohérence** : Design tokens centralisés
- **📱 Responsive-first** : Mobile d'abord
- **♿ Accessibilité** : WCAG 2.1 AA minimum
- **⚡ Performance** : Optimisation native
---
## 📁 **Architecture des Composants**
### **Structure de Répertoires**
```
templates/components/
├── common/
│ ├── macros.html # Macros réutilisables
│ └── base_components.html # Composants de base
├── assessment/
│ └── assessment_card.html # Cartes d'évaluation
├── class/
│ └── class_card.html # Cartes de classe
├── forms/
│ ├── form_inputs.html # Champs de formulaire
│ └── form_validation.html # Validation UI
└── ui/
├── buttons.html # Système de boutons
├── modals.html # Modales
└── notifications.html # Toasts/Alerts
```
### **Convention de Nommage**
```
Type_Domain_Component.html
│ │ │
│ │ └─ Nom spécifique (card, button, modal...)
│ └──────── Domaine métier (assessment, class, user...)
└───────────── Type (component, macro, layout...)
```
**📝 Exemples:**
- `assessment_card.html` ✅
- `class_list_item.html` ✅
- `user_profile_widget.html` ✅
- `genericCard.html` ❌ (PascalCase)
- `card.html` ❌ (trop générique)
---
## 🎨 **Design Tokens & Cohérence**
### **Palette de Couleurs Système**
```scss
// Couleurs Primaires
$blue: from-blue-500 to-blue-600 // Actions principales
$green: from-green-500 to-green-600 // Succès, validation
$purple: from-purple-500 to-purple-600 // Évaluations, analytique
$orange: from-orange-500 to-orange-600 // Avertissement, en cours
$red: from-red-500 to-red-600 // Erreur, critique
$pink: from-pink-500 to-pink-600 // Spécial, mise en avant
// Couleurs Neutres
$gray-50: #f9fafb // Fond très clair
$gray-100: #f3f4f6 // Fond clair
$gray-600: #4b5563 // Texte secondaire
$gray-900: #111827 // Texte principal
```
### **Typography Scale**
```scss
// Hiérarchie Textuelle
.text-4xl { font-size: 2.25rem } // Titres Hero
.text-3xl { font-size: 1.875rem } // Titres principaux
.text-2xl { font-size: 1.5rem } // Titres sections
.text-xl { font-size: 1.25rem } // Sous-titres
.text-lg { font-size: 1.125rem } // Texte large
.text-base { font-size: 1rem } // Texte standard
.text-sm { font-size: 0.875rem } // Texte petit
.text-xs { font-size: 0.75rem } // Métadonnées
```
### **Spacing System**
```scss
// Système d'espacement (Tailwind)
space-1: 0.25rem // 4px
space-2: 0.5rem // 8px
space-3: 0.75rem // 12px
space-4: 1rem // 16px
space-6: 1.5rem // 24px
space-8: 2rem // 32px
space-12: 3rem // 48px
```
---
## 🧩 **Anatomie d'un Composant**
### **Template Structure**
```jinja2
{# 1. Commentaire de description #}
{# Composant pour [FONCTION] dans [CONTEXTE] #}
{# 2. Import des dépendances #}
{% from 'components/common/macros.html' import helper_macro %}
{# 3. Définition du macro principal #}
{% macro component_name(required_param, optional_param=default) %}
{# 4. Logique de configuration #}
{% set config = {
'variant': optional_param,
'classes': 'base-classes ' + (additional_classes if condition else '')
} %}
{# 5. Structure HTML avec données dynamiques #}
{% if caller %}
{{ caller() }}
{% else %}
{% endif %}
{# 6. Fin du macro #}
{% endmacro %}
```
### **Exemple Concret : Button Component**
```jinja2
{# Composant bouton avec variants et états #}
{% macro button(
text,
url=None,
type="primary",
size="md",
icon=None,
disabled=False,
classes=""
) %}
{# Configuration des variants #}
{% set variants = {
'primary': 'bg-gradient-to-r from-blue-500 to-blue-600 text-white',
'secondary': 'bg-gray-50 text-gray-700 border border-gray-300',
'danger': 'bg-gradient-to-r from-red-500 to-red-600 text-white'
} %}
{% set sizes = {
'sm': 'px-3 py-2 text-sm',
'md': 'px-4 py-2 text-base',
'lg': 'px-6 py-3 text-lg'
} %}
{# Classes finales #}
{% set button_classes = [
'inline-flex items-center justify-center',
'rounded-xl font-semibold transition-all duration-300',
'hover:shadow-lg transform hover:scale-105',
variants[type],
sizes[size],
'opacity-50 cursor-not-allowed' if disabled else '',
classes
]|join(' ') %}
{# Rendu conditionnel (lien vs bouton) #}
{% if url and not disabled %}
{% else %}
{% else %}{% endif %}
{% endmacro %}
```
---
## 🎛️ **API des Composants**
### **Paramètres Standards**
Chaque composant doit exposer une API cohérente :
```jinja2
{% macro component_name(
# === OBLIGATOIRES ===
data, # Données principales
title, # Titre/Label
# === OPTIONNELS ===
variant="default", # Type/Style (primary, secondary, danger...)
size="md", # Taille (sm, md, lg, xl)
classes="", # Classes CSS additionnelles
# === COMPORTEMENT ===
clickable=True, # Interactif ou non
disabled=False, # État désactivé
loading=False, # État de chargement
# === CONTENU ===
icon=None, # Icône SVG
badge=None, # Badge/Compteur
actions=[], # Liste d'actions
# === TECHNIQUE ===
id=None, # ID HTML personnalisé
attrs={} # Attributs HTML additionnels
) %}
```
### **Exemple d'Utilisation**
```jinja2
{# Usage simple #}
{{ button("Sauvegarder") }}
{# Usage avancé #}
{{ button(
text="Créer évaluation",
url=url_for('assessments.new'),
type="primary",
size="lg",
icon='',
classes="w-full md:w-auto"
) }}
```
---
## 🔄 **États et Variants**
### **États Standardisés**
Tous les composants interactifs doivent gérer ces états :
```scss
// États de base
.default // État normal
.hover // Survol
.active // Actif/Pressé
.focus // Focus clavier
.disabled // Désactivé
// États applicatifs
.loading // Chargement en cours
.success // Succès/Validation
.error // Erreur
.warning // Avertissement
```
### **Variants de Style**
```scss
// Variants visuels
.primary // Action principale (bleu)
.secondary // Action secondaire (gris)
.success // Succès (vert)
.warning // Attention (orange)
.danger // Danger (rouge)
.ghost // Transparent
.outline // Contour seulement
```
### **Exemple : Card States**
```jinja2
{# États d'une carte #}
{% set card_states = {
'default': 'bg-white shadow-lg hover:shadow-xl',
'active': 'bg-blue-50 border-2 border-blue-200 shadow-xl',
'disabled': 'bg-gray-50 opacity-50 cursor-not-allowed',
'loading': 'bg-gray-50 animate-pulse'
} %}
{% if state == 'loading' %}
{% else %}
{% endif %}
```
---
## 📱 **Responsive Design**
### **Breakpoints Standard**
```scss
// Mobile First approach
sm: 640px // Téléphone large / Tablette portrait
md: 768px // Tablette
lg: 1024px // Desktop
xl: 1280px // Large desktop
2xl: 1536px // Ultra wide
```
### **Grilles Responsives**
```jinja2
{# Grille adaptative standard #}
{% for item in items %}
{{ item_card(item) }}
{% endfor %}
{# Navigation responsive #}
```
### **Typography Responsive**
```scss
// Échelle typographique adaptative
.hero-title {
@apply text-2xl md:text-4xl lg:text-5xl;
}
.section-title {
@apply text-lg md:text-xl lg:text-2xl;
}
.body-text {
@apply text-sm md:text-base;
}
```
---
## ♿ **Accessibilité**
### **Checklist Obligatoire**
- [ ] **Contraste** ≥ 4.5:1 pour texte normal
- [ ] **Contraste** ≥ 3:1 pour texte large
- [ ] **Navigation clavier** complète
- [ ] **ARIA labels** sur éléments interactifs
- [ ] **Focus indicators** visibles
- [ ] **Screen reader** compatible
### **Implémentation**
```jinja2
{# Bouton accessible #}
{# Card interactive accessible #}
```
### **ARIA Patterns**
```html