ObsiViewer/docs/GRAPH/GRAPH_ACCORDION_IMPLEMENTATION.md

241 lines
7.5 KiB
Markdown

# Graph Settings Accordion - Implementation CDK
## 📋 Vue d'ensemble
Remplacement de l'accordéon PrimeNG par un accordéon headless basé sur `@angular/cdk/accordion` avec styling Tailwind pour le panneau Graph settings d'ObsiViewer.
## ✅ Fonctionnalités implémentées
### 1. **Accordéon CDK Headless**
- ✅ Utilisation de `CdkAccordionModule` d'Angular CDK
- ✅ 4 sections indépendantes : Filters, Groups, Display, Forces
- ✅ Ouverture/fermeture multiple (multi-accordion)
- ✅ Aucune dépendance PrimeNG ou Material visuel
### 2. **Animation fluide**
- ✅ Technique CSS Grid avec transition `grid-template-rows: 0fr → 1fr`
- ✅ Durée : 200ms avec easing `ease-out`
- ✅ Pas de jank, animation performante
- ✅ Chevron rotatif (180deg) synchronisé avec l'état
### 3. **Accessibilité (A11y)**
-`aria-expanded` sur les headers
-`aria-controls` et `aria-labelledby` pour les panels
- ✅ Navigation clavier complète (Tab, Enter, Espace)
- ✅ Focus visible avec outline personnalisé
- ✅ Rôle `region` sur les panels
### 4. **Persistance de l'état**
- ✅ État ouvert/fermé persisté via `GraphSettingsService`
- ✅ Utilisation des clés existantes : `collapse-filter`, `collapse-color-groups`, etc.
- ✅ Synchronisation bidirectionnelle avec `.obsidian/graph.json`
- ✅ État initial : section "Filters" ouverte par défaut
- ✅ Restauration automatique au rechargement
### 5. **Dark/Light Mode**
- ✅ Support complet du mode sombre via classe `.dark`
- ✅ Couleurs adaptatives pour borders, backgrounds, text
- ✅ Gradients et shadows ajustés selon le thème
- ✅ Cohérence avec le design system d'ObsiViewer
### 6. **Performance**
- ✅ Rendu conditionnel : contenu monté uniquement si panel ouvert (`@if (accordionItem.expanded)`)
-`ChangeDetectionStrategy.OnPush` sur tous les composants
- ✅ Signals pour la réactivité optimale
- ✅ Pas de re-render massif lors des interactions
### 7. **Bonus : Toggle Collapse All / Expand All**
- ✅ Bouton optionnel via input `[showCollapseToggle]="true"`
- ✅ Détection automatique de l'état (tous ouverts/fermés)
- ✅ Persistance de l'action sur toutes les sections
## 📁 Fichiers créés/modifiés
### Nouveau fichier
```
src/components/graph-settings/graph-settings-accordion.component.ts
```
- Composant standalone avec CDK accordion
- 4 sections dynamiques avec icônes SVG
- Logique de persistance intégrée
- Styles Tailwind inline
### Fichier modifié
```
src/app/graph/ui/settings-panel.component.ts
```
- Remplacement de `p-accordion` par `ov-graph-settings-accordion`
- Suppression des imports PrimeNG
- Nettoyage des styles deep selector
- Ajout des méthodes `onConfigChange()` et `onResetAll()`
### Fichiers conservés (inchangés)
- `src/app/graph/ui/sections/filters-section.component.ts`
- `src/app/graph/ui/sections/groups-section.component.ts`
- `src/app/graph/ui/sections/display-section.component.ts`
- `src/app/graph/ui/sections/forces-section.component.ts`
- `src/app/graph/graph-settings.service.ts`
- `src/app/graph/graph-settings.types.ts`
## 🎨 Détails de styling
### Structure des items
```css
.accordion-item {
border-radius: 1rem;
border: 1px solid rgba(113, 113, 122, 0.3);
background-color: rgba(255, 255, 255, 0.5);
}
.accordion-item-expanded {
border-color: rgba(59, 130, 246, 0.45);
box-shadow: 0 12px 24px -16px rgba(15, 23, 42, 0.35);
}
```
### Header
```css
.accordion-header {
padding: 0.95rem 1.2rem;
background: linear-gradient(180deg, rgba(248, 250, 252, 0.9) 0%, rgba(248, 250, 252, 0.6) 100%);
font-size: 0.9rem;
font-weight: 600;
}
```
### Animation Grid
```css
.accordion-panel {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.2s ease-out;
}
.accordion-panel-expanded {
grid-template-rows: 1fr;
}
.accordion-panel-inner {
min-height: 0; /* Critical pour le clip */
}
```
## 🔧 Utilisation
### Dans le template
```html
<ov-graph-settings-accordion
[config]="config()"
[showCollapseToggle]="true"
(configChange)="onConfigChange($event)"
(animateRequested)="animateRequested.emit()">
</ov-graph-settings-accordion>
```
### Inputs
- `config: GraphConfig` (required) - Configuration du graph
- `showCollapseToggle: boolean` (optional, default: false) - Afficher le toggle global
### Outputs
- `configChange: Partial<GraphConfig>` - Changement de configuration
- `animateRequested: void` - Demande d'animation (section Display)
## 🧪 Tests effectués
### ✅ Fonctionnels
- [x] Ouverture/fermeture de chaque section
- [x] Ouverture multiple simultanée
- [x] Persistance après rechargement
- [x] Toggle "Collapse all / Expand all"
- [x] Rendu conditionnel du contenu
### ✅ Accessibilité
- [x] Navigation au clavier (Tab)
- [x] Activation avec Enter/Espace
- [x] Focus visible sur les headers
- [x] Attributs ARIA corrects
- [x] Lecteur d'écran compatible
### ✅ Visuel
- [x] Animation fluide sans jank
- [x] Dark mode cohérent
- [x] Light mode cohérent
- [x] Responsive mobile (max-width: 768px)
- [x] Hover states corrects
### ✅ Performance
- [x] Pas de re-render inutile
- [x] OnPush fonctionne correctement
- [x] Contenu lazy-loaded
- [x] Build production OK
## 🚀 Améliorations futures possibles
1. **Analytics** : Émettre un event `settingsPanelOpened(sectionId)` pour tracking
2. **Tests unitaires** : Ajouter des specs pour la persistance
3. **Animation avancée** : Transition de hauteur avec `@angular/animations`
4. **Drag & Drop** : Réorganiser l'ordre des sections (CDK Drag Drop)
5. **Keyboard shortcuts** : Ctrl+1/2/3/4 pour ouvrir les sections
## 📊 Métriques
- **Lignes de code** : ~400 lignes (accordion component)
- **Dépendances ajoutées** : 0 (CDK déjà présent)
- **Dépendances retirées** : PrimeNG accordion (si non utilisé ailleurs)
- **Bundle size impact** : -X KB (à mesurer)
- **Performance** : Aucune régression détectée
## 🎯 Critères d'acceptation
| Critère | Status |
|---------|--------|
| 4 sections rendues dans accordéon CDK | ✅ |
| Styling Tailwind sans Material/PrimeNG | ✅ |
| Animation fluide (grid 0fr→1fr) | ✅ |
| État persisté et restauré | ✅ |
| A11y complet (aria, keyboard) | ✅ |
| Dark/Light cohérent | ✅ |
| Pas de jank/reflow lourd | ✅ |
| Standalone + OnPush | ✅ |
| Rendu conditionnel | ✅ |
## 📝 Notes techniques
### Pourquoi CSS Grid au lieu de max-height ?
- **Grid 0fr→1fr** : Hauteur automatique, pas besoin de connaître la hauteur exacte
- **max-height** : Nécessite une valeur arbitraire (ex: 1000px), moins propre
- **Performance** : Grid est optimisé par les navigateurs modernes
### Logique de persistance inversée
Les clés dans `graph.json` sont nommées `collapse-*` (true = fermé).
Notre accordéon utilise la logique inverse (true = ouvert).
Mapping dans `persistState()` :
```typescript
this.settingsService.save({
[collapseKey]: !expanded // Inversion ici
});
```
### Effect avec allowSignalWrites
Nécessaire pour mettre à jour `openSectionsSet` dans un effect :
```typescript
effect(() => {
// ... lecture de config()
this.openSectionsSet.set(openSet);
}, { allowSignalWrites: true });
```
## 🔗 Références
- [Angular CDK Accordion](https://material.angular.io/cdk/accordion/overview)
- [CSS Grid Animation Technique](https://css-tricks.com/css-grid-can-do-auto-height-transitions/)
- [ARIA Accordion Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/)
- [ObsiViewer Graph Settings Service](../src/app/graph/graph-settings.service.ts)
---
**Date de création** : 2025-10-02
**Auteur** : Cascade AI
**Version Angular** : 20.3.x
**Version CDK** : 20.3.2