📝(docs) archive calendar-central-design change

Archive completed OpenSpec change with all artifacts:
- proposal.md: Initial design requirements
- design.md: Architecture decisions
- specs/: calendar-theme and scheduler-toolbar specifications
- tasks.md: 34/34 tasks completed

Sync delta specs to main specs:
- openspec/specs/calendar-theme/spec.md
- openspec/specs/scheduler-toolbar/spec.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Nathan Panchout
2026-01-28 12:56:18 +01:00
parent 9e7c6fbff1
commit 92bea3fd96
8 changed files with 632 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-01-28

View File

@@ -0,0 +1,78 @@
## Context
L'application utilise @event-calendar/core (vkurko/calendar), une bibliothèque Svelte qui expose des variables CSS `--ec-*` et des classes CSS `.ec-*` pour la personnalisation. Le design system Cunningham (@gouvfr-lasuite/cunningham-react) fournit les tokens visuels via des variables CSS `--c--globals--*`.
État actuel : le calendrier utilise les styles par défaut d'EventCalendar qui ne s'intègrent pas visuellement avec La Suite.
Contraintes :
- EventCalendar est une bibliothèque Svelte, pas React - on ne peut pas modifier ses composants internes
- La toolbar native ne supporte pas de dropdown React pour le sélecteur de vues
- Les variables CSS seules ne suffisent pas pour tous les aspects visuels
## Goals / Non-Goals
**Goals:**
- Aligner visuellement le calendrier central avec le design system Cunningham
- Créer une toolbar custom React avec navigation et sélecteur de vues
- Override les styles EventCalendar via variables CSS et classes CSS
- Supporter automatiquement le dark mode via les tokens Cunningham
**Non-Goals:**
- Différenciation visuelle des weekends (reporté)
- Redesign du mini-calendrier ou de la sidebar gauche
- Modification des modals d'événements
- Color picker pour les calendriers (futur)
## Decisions
### 1. Toolbar custom React vs Override CSS de la toolbar native
**Décision** : Toolbar custom React
**Alternatives considérées** :
- Override CSS des boutons natifs : limité pour le dropdown, moins de contrôle
- Modification du DOM via JavaScript : fragile, maintenance difficile
**Rationale** :
- Contrôle total sur le layout et les interactions
- Meilleure intégration avec le reste de l'app React
- Utilise les méthodes API d'EventCalendar (`prev()`, `next()`, `setOption()`, `getView()`)
- DropdownMenu custom (plutôt que Select Cunningham) pour une meilleure accessibilité clavier (Escape, Arrow, Enter)
### 2. Fichier de thème séparé vs Inline dans Scheduler.scss
**Décision** : Fichier `scheduler-theme.scss` séparé
**Rationale** :
- Séparation des responsabilités (thème vs composant)
- Facilite la maintenance et l'évolution du thème
- Permet de trouver facilement tous les overrides EventCalendar
### 3. Style "aujourd'hui" - Encadré vs Fond coloré
**Décision** : Encadré fin autour du numéro de jour, pas de fond
**Rationale** :
- Plus subtil et moderne
- Conforme à la maquette fournie
- Meilleure lisibilité (pas de conflit de couleurs)
### 4. Now indicator - Style existant vs Custom
**Décision** : Garder le style natif (ligne + point) avec couleur brand
**Rationale** :
- EventCalendar inclut déjà un cercle via `::before`
- Correspond à l'Option B identifiée (Google Calendar style)
- Seule la couleur nécessite un override
## Risks / Trade-offs
**[Couplage avec la structure DOM d'EventCalendar]**
→ Les sélecteurs CSS comme `.ec-col-head.ec-today time` dépendent de la structure HTML interne. Une mise à jour de la lib pourrait casser les styles. Mitigation : épingler la version et tester lors des mises à jour.
**[Synchronisation toolbar ↔ calendrier]**
→ La toolbar custom doit rester synchronisée avec l'état interne du calendrier (vue courante, dates). Mitigation : utiliser `getView()` et le callback `datesSet` pour maintenir la sync.
**[Performance des overrides CSS]**
→ Les sélecteurs imbriqués peuvent avoir un léger impact. Mitigation : sélecteurs simples, éviter les sélecteurs universels.

View File

@@ -0,0 +1,34 @@
## Why
L'application calendrier n'a actuellement aucun design établi. Le composant EventCalendar utilise les styles par défaut de la bibliothèque @event-calendar/core qui ne correspondent pas à l'identité visuelle de La Suite (design system Cunningham). Cette première itération vise à créer un design épuré et moderne pour le calendrier central.
## What Changes
- Création d'une toolbar custom React remplaçant la toolbar native d'EventCalendar
- Override des variables CSS `--ec-*` pour utiliser les tokens Cunningham
- Override des classes CSS pour personnaliser les événements, headers de jours, sidebar
- Style "aujourd'hui" avec encadré fin (sans fond coloré)
- Événements avec coins arrondis, sans ombre, titre en gras
- Now indicator avec couleur brand
- Sidebar heures avec style discret
## Capabilities
### New Capabilities
- `calendar-theme`: Thème visuel du calendrier central aligné sur le design system Cunningham. Couvre les variables CSS, les overrides de classes, et les styles des événements.
- `scheduler-toolbar`: Toolbar custom React pour la navigation et le changement de vue du calendrier. Remplace la toolbar native d'EventCalendar.
### Modified Capabilities
_(Aucune capability existante modifiée)_
## Impact
- **Frontend** : Nouveaux fichiers SCSS et composants React dans `src/frontend/apps/calendars/src/features/calendar/components/scheduler/`
- **Fichiers modifiés** :
- `useSchedulerInit.ts` : désactivation de la toolbar native (`headerToolbar: false`)
- `Scheduler.tsx` : intégration de la toolbar custom
- `globals.scss` : import du nouveau fichier de thème
- **Dépendances** : Utilise les composants Cunningham existants (Button, Select)
- **API EventCalendar** : Utilise les méthodes `prev()`, `next()`, `setOption()`, `getView()`

View File

@@ -0,0 +1,113 @@
## ADDED Requirements
### Requirement: Variables CSS Cunningham
Le thème DOIT remapper les variables CSS d'EventCalendar (`--ec-*`) vers les tokens Cunningham (`--c--globals--*`).
#### Scenario: Couleurs de base appliquées
- **WHEN** le calendrier est rendu
- **THEN** le fond utilise `--c--globals--colors--gray-000`
- **AND** les bordures utilisent `--c--globals--colors--gray-100`
- **AND** le texte utilise `--c--globals--colors--gray-800`
#### Scenario: Dark mode automatique
- **WHEN** le système est en dark mode
- **THEN** les couleurs s'adaptent automatiquement via les tokens Cunningham
---
### Requirement: Style du jour actuel
Le jour actuel DOIT être affiché avec un encadré fin autour du numéro, sans fond coloré.
#### Scenario: Header du jour actuel
- **WHEN** un jour est le jour actuel
- **THEN** le numéro du jour est entouré d'une bordure fine (1px)
- **AND** la bordure a un border-radius de 4px
- **AND** le fond de la colonne header reste transparent
---
### Requirement: Style des événements
Les événements DOIVENT avoir un style épuré avec coins arrondis.
#### Scenario: Apparence d'un événement
- **WHEN** un événement est affiché dans la grille
- **THEN** il a un border-radius de 6px
- **AND** il n'a pas de box-shadow
- **AND** le titre est en font-weight 600 (semi-bold)
- **AND** l'horaire est en font-weight 400 avec légère opacité
#### Scenario: Couleur d'un événement
- **WHEN** un événement appartient à un calendrier
- **THEN** il prend la couleur de ce calendrier en fond
- **AND** le texte est blanc
---
### Requirement: Style du now indicator
L'indicateur de l'heure actuelle DOIT utiliser la couleur brand.
#### Scenario: Apparence du now indicator
- **WHEN** l'heure actuelle est visible dans la vue
- **THEN** une ligne horizontale avec un point est affichée
- **AND** la couleur est `--c--globals--colors--brand-500`
---
### Requirement: Style de la sidebar heures
La sidebar affichant les heures DOIT avoir un style discret.
#### Scenario: Apparence des labels d'heure
- **WHEN** la sidebar des heures est affichée
- **THEN** la font-size est réduite (0.75rem)
- **AND** la couleur est `--c--globals--colors--gray-500`
---
### Requirement: Toolbar native masquée
La toolbar native d'EventCalendar DOIT être masquée.
#### Scenario: Toolbar native invisible
- **WHEN** le calendrier est rendu
- **THEN** l'élément `.ec-toolbar` a `display: none`
---
### Requirement: Lignes de grille simplifiées
Les lignes de grille DOIVENT afficher uniquement les heures pleines.
#### Scenario: Pas de lignes intermédiaires
- **WHEN** la vue semaine ou jour est affichée
- **THEN** seules les lignes horaires (chaque heure) sont visibles
- **AND** les lignes intermédiaires (30 min) sont masquées
---
### Requirement: Header unifié
Le header (en-têtes de colonnes + section all-day) DOIT avoir un aspect unifié.
#### Scenario: Pas de bordures internes
- **WHEN** le header est affiché
- **THEN** les éléments `.ec-col-head` et `.ec-all-day` n'ont pas de bordures
- **AND** les `.ec-day` dans `.ec-all-day` n'ont pas de bordure droite
#### Scenario: Sidebar header masquée
- **WHEN** le header est affiché
- **THEN** le texte du timezone dans `.ec-sidebar` du header est invisible
---
### Requirement: Bordure de grille
La grille du body DOIT avoir une bordure en bas et à droite.
#### Scenario: Bordures de la grille
- **WHEN** la grille du calendrier est affichée
- **THEN** `.ec-grid` dans `.ec-body` a une bordure bottom et right

View File

@@ -0,0 +1,115 @@
## ADDED Requirements
### Requirement: Layout de la toolbar
La toolbar DOIT afficher les éléments de navigation et de sélection de vue.
#### Scenario: Structure de la toolbar
- **WHEN** la toolbar est affichée
- **THEN** elle contient à gauche : bouton "Aujourd'hui", boutons de navigation (précédent/suivant)
- **AND** elle contient au centre : le titre de la période (ex: "janv. févr. 2026")
- **AND** elle contient à droite : un dropdown pour sélectionner la vue
---
### Requirement: Bouton Aujourd'hui
Le bouton "Aujourd'hui" DOIT permettre de revenir à la date du jour.
#### Scenario: Clic sur Aujourd'hui
- **WHEN** l'utilisateur clique sur "Aujourd'hui"
- **THEN** le calendrier navigue vers la date actuelle
- **AND** la vue reste inchangée
#### Scenario: Style du bouton
- **WHEN** le bouton "Aujourd'hui" est affiché
- **THEN** il a un style "pill" (bordure arrondie)
- **AND** il utilise les styles Cunningham
---
### Requirement: Navigation précédent/suivant
Les boutons de navigation DOIVENT permettre de naviguer dans le temps.
#### Scenario: Clic sur précédent
- **WHEN** l'utilisateur clique sur le bouton précédent (◀)
- **THEN** le calendrier navigue vers la période précédente
#### Scenario: Clic sur suivant
- **WHEN** l'utilisateur clique sur le bouton suivant (▶)
- **THEN** le calendrier navigue vers la période suivante
#### Scenario: Style des boutons de navigation
- **WHEN** les boutons de navigation sont affichés
- **THEN** ils sont des IconButtons avec flèches
- **AND** ils utilisent les styles Cunningham
---
### Requirement: Titre de la période
Le titre DOIT afficher la période actuellement visible.
#### Scenario: Affichage du titre
- **WHEN** la vue est en mode semaine ou jour
- **THEN** le titre affiche le mois et l'année (ex: "janv. févr. 2026")
#### Scenario: Mise à jour du titre
- **WHEN** l'utilisateur navigue vers une autre période
- **THEN** le titre se met à jour pour refléter la nouvelle période
---
### Requirement: Sélecteur de vue
Le dropdown DOIT permettre de changer de vue via un menu déroulant custom.
#### Scenario: Options disponibles
- **WHEN** l'utilisateur clique sur le bouton trigger
- **THEN** un menu déroulant s'ouvre avec les options : Jour, Semaine, Mois, Liste
- **AND** l'option sélectionnée est mise en évidence avec un checkmark
#### Scenario: Changement de vue
- **WHEN** l'utilisateur sélectionne une vue différente
- **THEN** le calendrier change pour afficher cette vue
- **AND** le menu se ferme
- **AND** le bouton trigger affiche la vue sélectionnée
#### Scenario: Vue par défaut
- **WHEN** le calendrier est chargé
- **THEN** la vue "Semaine" est sélectionnée par défaut
#### Scenario: Fermeture du menu
- **WHEN** l'utilisateur clique en dehors du menu
- **THEN** le menu se ferme
---
### Requirement: Accessibilité clavier
Le sélecteur de vue DOIT être accessible au clavier.
#### Scenario: Navigation clavier
- **WHEN** le menu est ouvert
- **THEN** les touches ArrowUp/ArrowDown permettent de naviguer entre les options
- **AND** la touche Enter sélectionne l'option focalisée
- **AND** la touche Escape ferme le menu
#### Scenario: Focus visible
- **WHEN** une option est focalisée par le clavier
- **THEN** elle a un style visuel distinct (outline)
---
### Requirement: Synchronisation avec le calendrier
La toolbar DOIT rester synchronisée avec l'état du calendrier.
#### Scenario: Sync après navigation
- **WHEN** le calendrier change de période (via drag ou autre)
- **THEN** le titre de la toolbar se met à jour
#### Scenario: Sync après changement de vue externe
- **WHEN** la vue du calendrier change par un autre moyen
- **THEN** le dropdown affiche la vue correcte

View File

@@ -0,0 +1,62 @@
## 1. Setup fichiers de thème
- [x] 1.1 Créer le fichier `scheduler-theme.scss` dans `src/frontend/apps/calendars/src/features/calendar/components/scheduler/`
- [x] 1.2 Ajouter l'import de `scheduler-theme.scss` dans `globals.scss`
## 2. Variables CSS et overrides de base
- [x] 2.1 Définir les variables CSS `--ec-*` mappées vers les tokens Cunningham
- [x] 2.2 Ajouter le style `.ec-toolbar { display: none }` pour masquer la toolbar native
## 3. Style du jour actuel
- [x] 3.1 Override `.ec-col-head.ec-today` pour fond transparent
- [x] 3.2 Ajouter le style encadré sur `.ec-col-head.ec-today time`
## 4. Style des événements
- [x] 4.1 Override `.ec-event` : border-radius 6px, box-shadow none, padding ajusté
- [x] 4.2 Override `.ec-event-title` : font-weight 600
- [x] 4.3 Override `.ec-event-time` : font-weight 400, opacity 0.95
## 5. Style du now indicator et sidebar
- [x] 5.1 Override couleur du now indicator vers brand-500
- [x] 5.2 Override `.ec-sidebar` : font-size 0.75rem, couleur gray-500
## 6. Composant SchedulerToolbar
- [x] 6.1 Créer le fichier `SchedulerToolbar.tsx`
- [x] 6.2 Créer le fichier `SchedulerToolbar.scss`
- [x] 6.3 Implémenter le bouton "Aujourd'hui" avec appel à `setOption('date', new Date())`
- [x] 6.4 Implémenter les boutons de navigation avec appels à `prev()` et `next()`
- [x] 6.5 Implémenter le titre dynamique de la période avec `getView()`
- [x] 6.6 Implémenter le dropdown des vues avec `setOption('view', ...)`
## 7. Intégration
- [x] 7.1 Modifier `useSchedulerInit.ts` : ajouter `headerToolbar: false`
- [x] 7.2 Modifier `Scheduler.tsx` : intégrer `<SchedulerToolbar />` au-dessus du container
- [x] 7.3 Passer la ref du calendrier à la toolbar pour accéder aux méthodes API
## 8. Synchronisation toolbar ↔ calendrier
- [x] 8.1 Utiliser le callback `datesSet` pour mettre à jour le titre de la toolbar
- [x] 8.2 Synchroniser le dropdown avec la vue courante
## 9. Améliorations post-implémentation
- [x] 9.1 Supprimer les lignes intermédiaires (30 min) de la grille
- [x] 9.2 Unifier le header (ec-col-head + ec-all-day) sans bordures internes
- [x] 9.3 Masquer le texte timezone dans ec-sidebar du header
- [x] 9.4 Ajouter bordure bottom/right à ec-grid
- [x] 9.5 Remplacer Select par DropdownMenu custom pour le sélecteur de vue
- [x] 9.6 Ajouter navigation clavier au dropdown (Escape, Arrow, Enter)
- [x] 9.7 Ajouter les traductions calendar.navigation.previous/next (EN, FR, NL)
- [x] 9.8 Corriger le type CalendarApi dans CalendarContext
- [x] 9.9 Mémoiser les handlers avec useCallback
## 10. Vérification
- [x] 10.1 Vérifier le rendu visuel sur les 4 vues (Jour, Semaine, Mois, Liste)
- [x] 10.2 Vérifier la navigation et le changement de vue

View File

@@ -0,0 +1,113 @@
## ADDED Requirements
### Requirement: Variables CSS Cunningham
Le thème DOIT remapper les variables CSS d'EventCalendar (`--ec-*`) vers les tokens Cunningham (`--c--globals--*`).
#### Scenario: Couleurs de base appliquées
- **WHEN** le calendrier est rendu
- **THEN** le fond utilise `--c--globals--colors--gray-000`
- **AND** les bordures utilisent `--c--globals--colors--gray-100`
- **AND** le texte utilise `--c--globals--colors--gray-800`
#### Scenario: Dark mode automatique
- **WHEN** le système est en dark mode
- **THEN** les couleurs s'adaptent automatiquement via les tokens Cunningham
---
### Requirement: Style du jour actuel
Le jour actuel DOIT être affiché avec un encadré fin autour du numéro, sans fond coloré.
#### Scenario: Header du jour actuel
- **WHEN** un jour est le jour actuel
- **THEN** le numéro du jour est entouré d'une bordure fine (1px)
- **AND** la bordure a un border-radius de 4px
- **AND** le fond de la colonne header reste transparent
---
### Requirement: Style des événements
Les événements DOIVENT avoir un style épuré avec coins arrondis.
#### Scenario: Apparence d'un événement
- **WHEN** un événement est affiché dans la grille
- **THEN** il a un border-radius de 6px
- **AND** il n'a pas de box-shadow
- **AND** le titre est en font-weight 600 (semi-bold)
- **AND** l'horaire est en font-weight 400 avec légère opacité
#### Scenario: Couleur d'un événement
- **WHEN** un événement appartient à un calendrier
- **THEN** il prend la couleur de ce calendrier en fond
- **AND** le texte est blanc
---
### Requirement: Style du now indicator
L'indicateur de l'heure actuelle DOIT utiliser la couleur brand.
#### Scenario: Apparence du now indicator
- **WHEN** l'heure actuelle est visible dans la vue
- **THEN** une ligne horizontale avec un point est affichée
- **AND** la couleur est `--c--globals--colors--brand-500`
---
### Requirement: Style de la sidebar heures
La sidebar affichant les heures DOIT avoir un style discret.
#### Scenario: Apparence des labels d'heure
- **WHEN** la sidebar des heures est affichée
- **THEN** la font-size est réduite (0.75rem)
- **AND** la couleur est `--c--globals--colors--gray-500`
---
### Requirement: Toolbar native masquée
La toolbar native d'EventCalendar DOIT être masquée.
#### Scenario: Toolbar native invisible
- **WHEN** le calendrier est rendu
- **THEN** l'élément `.ec-toolbar` a `display: none`
---
### Requirement: Lignes de grille simplifiées
Les lignes de grille DOIVENT afficher uniquement les heures pleines.
#### Scenario: Pas de lignes intermédiaires
- **WHEN** la vue semaine ou jour est affichée
- **THEN** seules les lignes horaires (chaque heure) sont visibles
- **AND** les lignes intermédiaires (30 min) sont masquées
---
### Requirement: Header unifié
Le header (en-têtes de colonnes + section all-day) DOIT avoir un aspect unifié.
#### Scenario: Pas de bordures internes
- **WHEN** le header est affiché
- **THEN** les éléments `.ec-col-head` et `.ec-all-day` n'ont pas de bordures
- **AND** les `.ec-day` dans `.ec-all-day` n'ont pas de bordure droite
#### Scenario: Sidebar header masquée
- **WHEN** le header est affiché
- **THEN** le texte du timezone dans `.ec-sidebar` du header est invisible
---
### Requirement: Bordure de grille
La grille du body DOIT avoir une bordure en bas et à droite.
#### Scenario: Bordures de la grille
- **WHEN** la grille du calendrier est affichée
- **THEN** `.ec-grid` dans `.ec-body` a une bordure bottom et right

View File

@@ -0,0 +1,115 @@
## ADDED Requirements
### Requirement: Layout de la toolbar
La toolbar DOIT afficher les éléments de navigation et de sélection de vue.
#### Scenario: Structure de la toolbar
- **WHEN** la toolbar est affichée
- **THEN** elle contient à gauche : bouton "Aujourd'hui", boutons de navigation (précédent/suivant)
- **AND** elle contient au centre : le titre de la période (ex: "janv. févr. 2026")
- **AND** elle contient à droite : un dropdown pour sélectionner la vue
---
### Requirement: Bouton Aujourd'hui
Le bouton "Aujourd'hui" DOIT permettre de revenir à la date du jour.
#### Scenario: Clic sur Aujourd'hui
- **WHEN** l'utilisateur clique sur "Aujourd'hui"
- **THEN** le calendrier navigue vers la date actuelle
- **AND** la vue reste inchangée
#### Scenario: Style du bouton
- **WHEN** le bouton "Aujourd'hui" est affiché
- **THEN** il a un style "pill" (bordure arrondie)
- **AND** il utilise les styles Cunningham
---
### Requirement: Navigation précédent/suivant
Les boutons de navigation DOIVENT permettre de naviguer dans le temps.
#### Scenario: Clic sur précédent
- **WHEN** l'utilisateur clique sur le bouton précédent (◀)
- **THEN** le calendrier navigue vers la période précédente
#### Scenario: Clic sur suivant
- **WHEN** l'utilisateur clique sur le bouton suivant (▶)
- **THEN** le calendrier navigue vers la période suivante
#### Scenario: Style des boutons de navigation
- **WHEN** les boutons de navigation sont affichés
- **THEN** ils sont des IconButtons avec flèches
- **AND** ils utilisent les styles Cunningham
---
### Requirement: Titre de la période
Le titre DOIT afficher la période actuellement visible.
#### Scenario: Affichage du titre
- **WHEN** la vue est en mode semaine ou jour
- **THEN** le titre affiche le mois et l'année (ex: "janv. févr. 2026")
#### Scenario: Mise à jour du titre
- **WHEN** l'utilisateur navigue vers une autre période
- **THEN** le titre se met à jour pour refléter la nouvelle période
---
### Requirement: Sélecteur de vue
Le dropdown DOIT permettre de changer de vue via un menu déroulant custom.
#### Scenario: Options disponibles
- **WHEN** l'utilisateur clique sur le bouton trigger
- **THEN** un menu déroulant s'ouvre avec les options : Jour, Semaine, Mois, Liste
- **AND** l'option sélectionnée est mise en évidence avec un checkmark
#### Scenario: Changement de vue
- **WHEN** l'utilisateur sélectionne une vue différente
- **THEN** le calendrier change pour afficher cette vue
- **AND** le menu se ferme
- **AND** le bouton trigger affiche la vue sélectionnée
#### Scenario: Vue par défaut
- **WHEN** le calendrier est chargé
- **THEN** la vue "Semaine" est sélectionnée par défaut
#### Scenario: Fermeture du menu
- **WHEN** l'utilisateur clique en dehors du menu
- **THEN** le menu se ferme
---
### Requirement: Accessibilité clavier
Le sélecteur de vue DOIT être accessible au clavier.
#### Scenario: Navigation clavier
- **WHEN** le menu est ouvert
- **THEN** les touches ArrowUp/ArrowDown permettent de naviguer entre les options
- **AND** la touche Enter sélectionne l'option focalisée
- **AND** la touche Escape ferme le menu
#### Scenario: Focus visible
- **WHEN** une option est focalisée par le clavier
- **THEN** elle a un style visuel distinct (outline)
---
### Requirement: Synchronisation avec le calendrier
La toolbar DOIT rester synchronisée avec l'état du calendrier.
#### Scenario: Sync après navigation
- **WHEN** le calendrier change de période (via drag ou autre)
- **THEN** le titre de la toolbar se met à jour
#### Scenario: Sync après changement de vue externe
- **WHEN** la vue du calendrier change par un autre moyen
- **THEN** le dropdown affiche la vue correcte