Okay, j'ai un descriptif détaillé d'une interface utilisateur pour une application appelée Nimbus Notes / FuseBase Note. Le but est de refaire ce descriptif pour qu'il inclue une compatibilité totale avec les modes Desktop et Mobile (téléphone et tablette). ### Compréhension du document original Le document original décrit l'interface utilisateur de Nimbus Notes / FuseBase Note en détail, en mettant l'accent sur la philosophie du produit, le layout global, les micro-interactions, les contenus spéciaux, l'accessibilité, et plus encore. Il est divisé en plusieurs sections : 1. Philosophie produit 2. Layout global (3 panneaux + overlays) 3. Micro-interactions et patterns récurrents 4. Contenus et types spéciaux 5. Accessibilité et lisibilité 6. Détails visibles dans les captures 7. TL;DR — Nimbus en 8 principes à retenir ### Objectif L'objectif est de réécrire ce descriptif pour qu'il inclue une compatibilité totale avec les modes Desktop et Mobile (téléphone et tablette). Cela signifie que chaque élément de l'interface doit être adapté pour fonctionner sur des écrans de différentes tailles, en tenant compte des spécificités des appareils mobiles et des tablettes. ### Étapes à suivre 1. **Comprendre les besoins spécifiques pour Desktop et Mobile :** - Desktop : Layout à 3 colonnes (sidebar, liste centrale, panneau de droite). - Mobile/Tablet : Navigation par onglets/drawer, gestion des gestes, optimisation de l'espace. 2. **Adapter chaque section pour inclure la compatibilité mobile :** - **Philosophie produit :** Assurer que les principes de conception s'appliquent également aux appareils mobiles. - **Layout global :** Décrire comment les 3 panneaux s'adaptent sur mobile (par exemple, en utilisant des drawers ou des onglets). - **Micro-interactions :** Adapter les interactions pour les écrans tactiles. - **Contenus et types spéciaux :** Optimiser l'affichage pour les petits écrans. - **Accessibilité et lisibilité :** Garantir que l'interface est accessible et lisible sur tous les appareils. - **Détails visibles dans les captures :** Décrire comment ces détails s'adaptent sur mobile. - **TL;DR :** Résumer les principes pour une interface adaptative. 3. **Ajouter des sections spécifiques pour la compatibilité mobile :** - Décrire les composants spécifiques pour mobile (par exemple, bottom navigation, drawers). - Inclure des détails sur les gestes tactiles (swipe, tap, etc.). - Mettre en avant les considérations de performance et d'accessibilité pour mobile. 4. **Structurer le document :** - Introduction - Philosophie produit (adaptée pour mobile) - Layout global (adaptatif) - Micro-interactions et patterns récurrents (adaptés pour mobile) - Contenus et types spéciaux (adaptés pour mobile) - Accessibilité et lisibilité (adaptées pour mobile) - Détails visibles dans les captures (adaptés pour mobile) - TL;DR — Nimbus en 8 principes à retenir (adaptés pour mobile) ### Rédaction du nouveau descriptif Je vais commencer par une introduction qui met en avant l'objectif de compatibilité totale avec Desktop et Mobile. Ensuite, je vais adapter chaque section pour inclure des détails spécifiques pour mobile. ### Introduction L'introduction doit expliquer que l'interface doit être 100% compatible avec Desktop et Mobile, en mettant l'accent sur l'adaptabilité et l'expérience utilisateur sur tous les appareils. ### Philosophie produit La philosophie produit doit inclure des principes qui s'appliquent à la fois aux desktop et mobile, comme la navigation par onglets sur mobile et la navigation par panneaux sur desktop. ### Layout global Le layout global doit décrire comment les 3 panneaux (sidebar, liste centrale, panneau de droite) s'adaptent sur mobile. Par exemple, sur mobile, la sidebar pourrait devenir un drawer, et la liste centrale pourrait être accessible via un onglet. ### Micro-interactions et patterns récurrents Les micro-interactions doivent être adaptées pour les écrans tactiles. Par exemple, les gestes de swipe pour naviguer entre les onglets sur mobile. ### Contenus et types spéciaux Les contenus spéciaux, comme les bookmarks et les tables, doivent être optimisés pour les petits écrans. Par exemple, les tables pourraient être simplifiées ou affichées en mode paysage sur mobile. ### Accessibilité et lisibilité L'accessibilité et la lisibilité doivent être garanties sur tous les appareils, avec des tailles de police adaptées et des cibles tactiles suffisamment grandes. ### Détails visibles dans les captures Les détails visibles dans les captures doivent inclure des exemples de comment l'interface s'affiche sur mobile et desktop. ### TL;DR Le TL;DR doit résumer les principes clés pour une interface adaptative, en mettant l'accent sur la compatibilité mobile et desktop. ### Exemple de structure Voici un exemple de structure pour le nouveau descriptif : ```markdown # 🎯 Prompt Windsurf — ObsiViewer Nimbus UI (Desktop + Mobile) ## ObsiViewer → UI/UX "Nimbus-like" (simple, dense, rapide) **Rôle & mode :** Agis comme **Staff Frontend Engineer Angular 20 + UX designer**. Raisonnement détaillé autorisé. Tu as les pleins pouvoirs de refactor UI, d'ajout de composants, et de migration CSS vers Tailwind. Conserve la compatibilité de toutes features existantes. **Contrainte majeure :** L'interface doit être **100% responsive** (Desktop + Mobile). Un **bouton toggle** dans la navbar permet de basculer entre l'ancienne interface et la nouvelle sans perte d'état. ## Contexte rapide * Projet : **ObsiViewer** (Angular 20 + Tailwind, Node/Express backend). * Objectif : Refondre l'interface selon un design **Nimbus Notes**-like. * Cœurs d'usage : navigation par **dossiers**, **tags**, **recherche**, **lecture markdown** plein écran, **ToC** à droite, **tri et filtres** rapides. * **Nouveauté** : Design adaptatif complet (Desktop/Mobile/Tablet) avec UI toggle persisté. ## 🎯 Objectif final (résumé) ### Desktop (≥1024px) Refondre l'interface ObsiViewer en **3 colonnes** : 1. **Sidebar gauche** (Quick Links, Dossiers arborescents, Tags) — Redimensionnable. 2. **Colonne centrale** Liste des pages (recherche, filtres dossiers/tags, tris, résultats virtualisés). 3. **Vue de page** à droite (lecture markdown, barre d'actions, **panneau sommaire/ToC** docké à l'extrême droite). Le tout **compact, performant, thème clair/sombre**, navigation au clavier, états persistés localement. ### Mobile/Tablet (<1024px) Une navigation **par onglets/drawer** intelligente : - **Tab 1 : Sidebar** (dossiers, tags, recherche) — Panneau full-width ou drawer collapsible. - **Tab 2 : Liste** (résultats de recherche) — Full-width scrollable. - **Tab 3 : Page** (markdown) — Full-width avec ToC inline collapsible ou drawer. **Gestures** : Swipe horizontal pour navigation onglets, pull-to-refresh, tap = open item. ## 📋 Architecture Feature Flag & Toggle ### 1) Toggle UI dans la NavBar Ajouter un **bouton toggle** dans `src/app/layout/app-navbar/app-navbar.component.ts` : ```html
``` ### 2) Service de gestion du mode UI Créer `src/app/shared/services/ui-mode.service.ts` : ```typescript import { Injectable, signal } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class UiModeService { // Signal pour réactivité fine-grained isNimbusMode = signal(this.loadUIMode()); constructor() {} toggleUIMode() { const newMode = !this.isNimbusMode(); this.isNimbusMode.set(newMode); localStorage.setItem('obsiviewer-ui-mode', newMode ? 'nimbus' : 'legacy'); } private loadUIMode(): boolean { if (typeof localStorage === 'undefined') return false; const saved = localStorage.getItem('obsiviewer-ui-mode'); return saved ? saved === 'nimbus' : true; // Nimbus par défaut } } ``` ### 3) Layout wrapper avec feature flag Créer `src/app/layout/app-shell-adaptive/app-shell-adaptive.component.ts` : ```typescript import { Component, inject } from '@angular/core'; import { UiModeService } from '@app/shared/services/ui-mode.service'; import { AppShellNimbusLayoutComponent } from '../app-shell-nimbus/app-shell-nimbus.component'; import { AppShellLegacyLayoutComponent } from '../app-shell-legacy/app-shell-legacy.component'; @Component({ selector: 'app-shell-adaptive', template: ` @if (uiMode.isNimbusMode()) { } @else { } `, standalone: true, imports: [AppShellNimbusLayoutComponent, AppShellLegacyLayoutComponent], }) export class AppShellAdaptiveComponent { uiMode = inject(UiModeService); } ``` ## 🎨 Responsive Design Strategy ### Breakpoints Tailwind (standard) ```typescript // tailwind.config.js module.exports = { theme: { screens: { 'xs': '320px', // iPhone SE 'sm': '640px', // Petites tablettes 'md': '768px', // iPad, tablettes 'lg': '1024px', // Desktop compact 'xl': '1280px', // Desktop standard '2xl': '1536px', // Larges écrans }, }, }; ``` ### Mobile First Approach **Développer pour mobile d'abord, puis enrichir pour desktop.** ## 📱 Layouts Responsifs ### Desktop Layout (≥1024px) ``` ┌─────────────────────────────────────────────────────────┐ │ NAVBAR (Dark, fixed, h-14) │ ├────────────────┬──────────────────┬──────────────────────┤ │ │ │ │ │ SIDEBAR │ RESULT LIST │ NOTE VIEW + TOC │ │ (240-440px) │ (virtualized) │ (Resizable) │ │ Resizable │ │ │ │ │ │ │ │ - Quick │ - Search bar │ - Markdown │ │ Links │ - Filters │ - ToC drawer │ │ - Folders │ - Items (80px) │ - Actions bar │ │ - Tags │ - Pagination │ │ │ │ │ │ └────────────────┴──────────────────┴──────────────────────┘ ``` ### Tablet Layout (768px ≤ width < 1024px) ``` ┌──────────────────────────────────────┐ │ NAVBAR + Toggle (fixed, h-14) │ ├──────────────────────────────────────┤ │ TAB NAVIGATION (fixed, bottom) │ │ [Sidebar] [List] [Page] [ToC] │ ├──────────────────────────────────────┤ │ │ │ ACTIVE TAB CONTENT (scrollable) │ │ - Drawer si besoin │ │ - Full-width panels │ │ │ └──────────────────────────────────────┘ ``` ### Mobile Layout (<768px) ``` ┌──────────────────────────────────┐ │ NAVBAR (compact, h-12) │ │ [Menu] [Search] [Toggle] │ ├──────────────────────────────────┤ │ │ │ TAB/DRAWER NAVIGATION │ │ [≡] [🔍] [📄] [📋] │ │ │ │ CONTENT AREA (Full-width) │ │ - Drawer sidebar (80vw left) │ │ - Swipeable list (list tab) │ │ - Markdown full-screen (page) │ │ - Inline ToC (toggle button) │ │ │ ├──────────────────────────────────┤ │ Bottom Navigation (sticky) │ │ Tab buttons (4 icônes) │ └──────────────────────────────────┘ ``` ## 🎬 Composants Nimbus Responsifs ### Desktop/Mobile Variants Chaque composant doit avoir des **variants responsifs** : ``` app-left-sidebar/ ├── app-left-sidebar.component.ts # Logique partagée ├── app-left-sidebar.desktop.component.ts # ≥1024px (fixed, resizable) └── app-left-sidebar.mobile.component.ts # <1024px (drawer) app-center-list/ ├── app-center-list.component.ts ├── app-center-list.desktop.component.ts # ≥1024px (2 colonnes) └── app-center-list.mobile.component.ts # <1024px (full-width) app-note-view/ ├── app-note-view.component.ts ├── app-note-view.desktop.component.ts # ≥1024px (3 colonnes + ToC) └── app-note-view.mobile.component.ts # <1024px (full-width + ToC inline) app-toc-drawer/ ├── app-toc-drawer.component.ts ├── app-toc-drawer.desktop.component.ts # ≥1024px (Fixed right) └── app-toc-drawer.mobile.component.ts # <1024px (Collapsible, inline) ``` ### Détection et Injection ```typescript // app-left-sidebar.component.ts import { Component, inject } from '@angular/core'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; @Component({ selector: 'app-left-sidebar', standalone: true, template: ` @if (isDesktop$ | async) { } @else { } `, }) export class AppLeftSidebarComponent { private breakpoint = inject(BreakpointObserver); isDesktop$ = this.breakpoint.observe(Breakpoints.Large).pipe( map(result => result.matches) ); } ``` ## 📱 Navigation Mobile Avancée ### Tab/Drawer Navigation ```typescript // src/shared/services/mobile-nav.service.ts @Injectable({ providedIn: 'root' }) export class MobileNavService { activeTab = signal<'sidebar' | 'list' | 'page' | 'toc'>('list'); setTab(tab: 'sidebar' | 'list' | 'page' | 'toc') { this.activeTab.set(tab); // Persist if needed } } // Usage in component ``` ### Swipe Navigation (Gestures) ```typescript // Directive pour détection de swipe import { Directive, Output, EventEmitter, HostListener } from '@angular/core'; @Directive({ selector: '[appSwipeNav]', standalone: true, }) export class SwipeNavDirective { @Output() swipeLeft = new EventEmitter(); @Output() swipeRight = new EventEmitter(); private startX = 0; @HostListener('touchstart', ['$event']) onTouchStart(e: TouchEvent) { this.startX = e.touches[0].clientX; } @HostListener('touchend', ['$event']) onTouchEnd(e: TouchEvent) { const endX = e.changedTouches[0].clientX; const diff = this.startX - endX; if (Math.abs(diff) > 50) { // Seuil minimum if (diff > 0) this.swipeLeft.emit(); else this.swipeRight.emit(); } } } ``` ## 🎨 Composants Spécifiques (Mobile-First) ### 1) Bottom Navigation (Mobile) ```html ``` ### 2) Drawer Sidebar (Mobile) ```html
``` ### 3) Search Bar Compact (Mobile) ```html
{{ badge }} ✕
``` ### 4) Result List Item (Mobile-Optimized) ```html

{{ item.title }}

{{ item.modified | date:'short' }}
{{ tag }}

{{ item.excerpt }}

``` ### 5) Markdown Viewer (Mobile-Responsive) ```html
``` ### 6) ToC Drawer (Desktop Fixed, Mobile Inline) ```typescript // app-toc-drawer.component.ts @Component({ selector: 'app-toc-drawer', template: `
`, animations: [ trigger('slideDown', [ state('in', style({ height: '*' })), state('out', style({ height: '0px' })), transition('in <=> out', animate('200ms ease-in-out')), ]), ], standalone: true, }) export class AppTocDrawerComponent { @Input() headings: Heading[] = []; showTocMobile = false; isMobile$ = this.breakpoint.observe('(max-width: 1023px)').pipe( map(r => r.matches) ); } ``` ## 🎯 Livrables Attendus ### Code 1. **Toggle UI** : `UiModeService`, bouton navbar, `AppShellAdaptiveComponent` 2. **Responsive Wrappers** : Variants pour chaque composant (Desktop/Mobile) 3. **Mobile Components** : Bottom nav, drawer sidebar, inline ToC, mobile search 4. **Gesture Handling** : Swipe navigation directive, touch-friendly interactions 5. **Breakpoint Utilities** : Service CDK layout, reactive signals ### Styling 1. **Tailwind Config** : Breakpoints personnalisés, tokens tokens clair/sombre 2. **Mobile-First CSS** : Base mobile, enrichissements desktop via `md:`, `lg:` 3. **Touch-Friendly** : Boutons ≥44x44px, padding adéquat, hover states ### Documentation 1. **README_UI.md** : Schémas responsive, breakpoints, guide toggle 2. **MOBILE_GUIDE.md** : Navigation gestures, bottom nav flow, drawer patterns 3. **RESPONSIVE_CHECKLIST.md** : Tests par breakpoint, checklist A11y mobile ### Tests 1. **E2E** : Toggle persistence, layout switch, gesture navigation 2. **Visual Regression** : Screenshots desktop/tablet/mobile 3. **Accessibility** : Touch targets, ARIA labels, keyboard nav (Tab key) ## ⚡ Performance & Mobile Optimizations ### Critical Optimizations - **Lazy-load images** : `loading="lazy"`, responsive `srcset` - **Virtual scroll** : CDK virtual scroll adapté mobile (item height ≈ 70–80px) - **Debounce search** : 300ms sur mobile, 150ms sur desktop - **Avoid layout shift** : Aspect ratios, skeleton loaders - **Network awareness** : `navigator.connection.effectiveType` pour adapt qualité - **Battery saver** : Réduire animations, throttle updates en mode saver ### Lighthouse Mobile Targets - Performance ≥ 85 - Accessibility ≥ 95 - Best Practices ≥ 90 ## 🎮 Raccourcis Clavier & Gestures ### Desktop - `Ctrl/Cmd + K` : Palette commandes - `Ctrl/Cmd + F` : Focus recherche - `[` `]` : Replier/ouvrir ToC - `Alt + ←/→` : Navigation historique ### Mobile/Tablet - **Tap** : Ouvrir note/item - **Swipe left/right** : Changer onglet (list → page → sidebar) - **Long-press** : Menu contextuel (favoris, open in new tab) - **Pull-to-refresh** : Rafraîchir liste (optionnel) - **Double-tap** : Zoom ToC (mobile) ## 📋 Critères d'Acceptation ### Desktop (≥1024px) - [x] Layout 3 colonnes (sidebar fixe/resizable, liste, page+ToC) - [x] Changement dossier/tag/tri reflété en URL - [x] 1000+ items fluide (60fps virtual scroll) - [x] ToC synchronisé + repliable - [x] Tous les flux clavier-seuls possibles ### Tablet (768–1023px) - [x] Navigation par onglets (Sidebar / List / Page) - [x] Drawer sidebar (80vw, swipeable) - [x] Bottom navigation sticky (4 icônes) - [x] Contenu full-width par onglet - [x] ToC inline collapsible ### Mobile (<768px) - [x] Drawer sidebar (80vw max) - [x] Bottom nav (4 onglets) - [x] Search bar compact (menu + search + filters) - [x] List items optimisés (titre + date + excerpt) - [x] Markdown full-screen - [x] ToC overlay ou inline toggle - [x] Touch targets ≥ 44x44px ### Feature Flag - [x] Toggle UI visible dans navbar - [x] État persisté (localStorage) - [x] Pas de perte d'état lors du switch - [x] Legacy UI reste intacte ### Accessibility - [x] WCAG 2.1 AA sur tous les breakpoints - [x] Keyboard navigation complète (Tab, Arrow, Enter) - [x] ARIA labels pour navigation tactile - [x] Focus visible partout - [x] Zoom ≤ 200% sans horizontal scroll ### Performance - [x] TTI < 2.5s cold start - [x] Scroll 60fps sur 1000+ items - [x] Lighthouse Mobile ≥ 85 perf, ≥ 95 a11y - [x] ImageOptimizations (lazy, srcset, format next-gen) ## 🗂️ Arborescence Fichiers ``` src/app/ ├── layout/ │ ├── app-shell-adaptive/ │ │ └── app-shell-adaptive.component.ts # Feature flag wrapper │ ├── app-shell-nimbus/ │ │ ├── app-shell-nimbus.component.ts # 3 colonnes (desktop) │ │ ├── app-shell-nimbus.desktop.component.ts │ │ └── app-shell-nimbus.mobile.component.ts │ └── app-navbar/ │ ├── app-navbar.component.ts │ └── [Bouton toggle UI intégré] │ ├── features/ │ ├── sidebar/ │ │ ├── app-left-sidebar.component.ts │ │ ├── app-left-sidebar.desktop.component.ts │ │ └── app-left-sidebar.mobile.component.ts │ │ │ ├── search-bar/ │ │ ├── app-search-bar.component.ts │ │ ├── app-search-bar.desktop.component.ts │ │ └── app-search-bar.mobile.component.ts │ │ │ ├── result-list/ │ │ ├── app-result-list.component.ts │ │ ├── app-result-list.desktop.component.ts │ │ ├── app-result-list.mobile.component.ts │ │ └── app-result-list-item.component.ts │ │ │ ├── note-view/ │ │ ├── app-note-view.component.ts │ │ ├── app-note-view.desktop.component.ts │ │ └── app-note-view.mobile.component.ts │ │ │ ├── toc-drawer/ │ │ ├── app-toc-drawer.component.ts │ │ └── app-toc-content.component.ts │ │ │ └── bottom-nav/ [NEW] │ ├── app-bottom-nav.component.ts │ └── app-bottom-nav.component.html │ ├── shared/ │ ├── services/ │ │ ├── ui-mode.service.ts # [NEW] Toggle management │ │ ├── mobile-nav.service.ts # [NEW] Tab/drawer state │ │ └── breakpoint.service.ts # [NEW] Responsive helper │ │ │ ├── directives/ │ │ └── swipe-nav.directive.ts # [NEW] Gesture detection │ │ │ └── components/ │ └── resizable-handle/ │ └── styles/ ├── tokens.css # Tailwind tokens ├── responsive.css # Breakpoint utilities └── mobile.css # Mobile-specific (touches, etc.) ``` ## 📅 Plan d'Implémentation (ordre conseillé) 1. **Feature Flag Infrastructure** (1-2j) - `UiModeService` + localStorage persistence - `AppShellAdaptiveComponent` wrapper - Toggle button dans navbar 2. **Responsive Shell & Breakpoints** (2-3j) - Desktop layout 3 colonnes (>=1024px) - Tailwind breakpoints & tokens - Resizable sidebar logic 3. **Mobile Navigation & Bottom Nav** (2-3j) - `BottomNavComponent` (4 onglets) - `MobileNavService` (state management) - Tab/drawer routing 4. **Mobile Sidebar Drawer** (1-2j) - Drawer animé (translate, backdrop) - Swipe dismiss directive - Z-index management 5. **Responsive Components** (3-4j) - Search bar variants (desktop/mobile) - Result list item responsive - Markdown viewer mobile optimizations 6. **ToC Drawer Adaptive** (1-2j) - Fixed right panel (desktop) - Inline toggle (mobile) - Animations smooth 7. **Gestures & Touch** (1-2j) - Swipe nav directive - Long-press menu - Pull-to-refresh (optionnel) 8. **Accessibility & Testing** (2-3j) - WCAG 2.1 AA audit - Keyboard nav (Tab, Arrow) - E2E tests (toggle, breakpoints) - Visual regression (3 breakpoints) **Total estimé** : 13–21 jours (équipe 1 FE engineer) ## 🚀 Scripts NPM ```bash # Dev complet (Nimbus activé par défaut) npm run dev # Build production npm run build # Tests responsifs (plusieurs breakpoints) npm run test:responsive # Lighthouse audit mobile npm run audit:lighthouse:mobile # Feature flag (override) NIMBUS_UI=false npm run dev # Force legacy UI ``` ## ✅ Checklist Livraison - [ ] Toggle UI visible, fonctionnel, persisté - [ ] Desktop (≥1024px) : 3 colonnes, interactions fluides - [ ] Tablet (768–1023px) : Onglets + drawer, full-width contenu - [ ] Mobile (<768px) : Bottom nav, drawer, touch-friendly - [ ] Tous les flux clavier-seuls réalisables - [ ] Lighthouse mobile ≥ 85 perf, ≥ 95 a11y - [ ] Virtual scroll 60fps sur 1000+ items - [ ] Tests E2E (toggle, breakpoints, gestures) - [ ] Documentation complète (README_UI.md, MOBILE_GUIDE.md, RESPONSIVE_CHECKLIST.md) - [ ] Zéro régression : legacy UI inchangée, Wikilinks, bookmarks, graph intacts - [ ] Screenshots before/after 3 breakpoints ## 📖 Documentation à Produire 1. **README_UI.md** : Overview, architecture, screenshots 3 breakpoints 2. **MOBILE_GUIDE.md** : Navigation onglets, gestures, drawer patterns 3. **RESPONSIVE_CHECKLIST.md** : Tests par breakpoint, device testing 4. **DEPLOYMENT.md** : Feature flag pour bascule progressive 5. **ARCHITECTURE_DIAGRAM.md** : Schémas adaptatifs (Mermaid) ## 💡 Notes Importantes - **Mobile First** : Développer pour mobile en premier, puis enrichir desktop. - **Persistent State** : Le toggle UI et les filtres actifs doivent persister via localStorage (sans browser storage, utiliser sessionStorage ou service state). - **Zero Regression** : L'ancienne interface reste intacte et fonctionnelle. - **Performance** : Virtual scroll adapté mobile (40+ items à l'écran), lazy-load images. - **Accessibility** : 44x44px touch targets minimum, ARIA labels complets, keyboard nav. - **Testing** : Visual regression sur breakpoints clés (375px / 768px / 1440px). ```Voici le prompt révisé pour inclure une compatibilité totale avec les modes Desktop et Mobile : ```markdown # 🎯 Prompt Windsurf — ObsiViewer Nimbus UI (Desktop + Mobile) ## ObsiViewer → UI/UX "Nimbus-like" (simple, dense, rapide) **Rôle & mode :** Agis comme **Staff Frontend Engineer Angular 20 + UX designer**. Raisonnement détaillé autorisé. Tu as les pleins pouvoirs de refactor UI, d'ajout de composants, et de migration CSS vers Tailwind. Conserve la compatibilité de toutes features existantes. **Contrainte majeure :** L'interface doit être **100% responsive** (Desktop + Mobile). Un **bouton toggle** dans la navbar permet de basculer entre l'ancienne interface et la nouvelle sans perte d'état. --- ## Contexte rapide * Projet : **ObsiViewer** (Angular 20 + Tailwind, Node/Express backend). * Objectif : Refondre l'interface selon un design **Nimbus Notes**-like. * Cœurs d'usage : navigation par **dossiers**, **tags**, **recherche**, **lecture markdown** plein écran, **ToC** à droite, **tri et filtres** rapides. * **Nouveauté** : Design adaptatif complet (Desktop/Mobile/Tablet) avec UI toggle persisté. --- ## 🎯 Objectif final (résumé) ### Desktop (≥1024px) Refondre l'interface ObsiViewer en **3 colonnes** : 1. **Sidebar gauche** (Quick Links, Dossiers arborescents, Tags) — Redimensionnable. 2. **Colonne centrale** Liste des pages (recherche, filtres dossiers/tags, tris, résultats virtualisés). 3. **Vue de page** à droite (lecture markdown, barre d'actions, **panneau sommaire/ToC** docké à l'extrême droite). Le tout **compact, performant, thème clair/sombre**, navigation au clavier, états persistés localement. ### Mobile/Tablet (<1024px) Une navigation **par onglets/drawer** intelligente : - **Tab 1 : Sidebar** (dossiers, tags, recherche) — Panneau full-width ou drawer collapsible. - **Tab 2 : Liste** (résultats de recherche) — Full-width scrollable. - **Tab 3 : Page** (markdown) — Full-width avec ToC inline collapsible ou drawer. **Gestures** : Swipe horizontal pour navigation onglets, pull-to-refresh, tap = open item. --- ## 📋 Architecture Feature Flag & Toggle ### 1) Toggle UI dans la NavBar Ajouter un **bouton toggle** dans `src/app/layout/app-navbar/app-navbar.component.ts` : ```html
``` ### 2) Service de gestion du mode UI Créer `src/app/shared/services/ui-mode.service.ts` : ```typescript import { Injectable, signal } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class UiModeService { // Signal pour réactivité fine-grained isNimbusMode = signal(this.loadUIMode()); constructor() {} toggleUIMode() { const newMode = !this.isNimbusMode(); this.isNimbusMode.set(newMode); localStorage.setItem('obsiviewer-ui-mode', newMode ? 'nimbus' : 'legacy'); } private loadUIMode(): boolean { if (typeof localStorage === 'undefined') return false; const saved = localStorage.getItem('obsiviewer-ui-mode'); return saved ? saved === 'nimbus' : true; // Nimbus par défaut } } ``` ### 3) Layout wrapper avec feature flag Créer `src/app/layout/app-shell-adaptive/app-shell-adaptive.component.ts` : ```typescript import { Component, inject } from '@angular/core'; import { UiModeService } from '@app/shared/services/ui-mode.service'; import { AppShellNimbusLayoutComponent } from '../app-shell-nimbus/app-shell-nimbus.component'; import { AppShellLegacyLayoutComponent } from '../app-shell-legacy/app-shell-legacy.component'; @Component({ selector: 'app-shell-adaptive', template: ` @if (uiMode.isNimbusMode()) { } @else { } `, standalone: true, imports: [AppShellNimbusLayoutComponent, AppShellLegacyLayoutComponent], }) export class AppShellAdaptiveComponent { uiMode = inject(UiModeService); } ``` --- ## 🎨 Responsive Design Strategy ### Breakpoints Tailwind (standard) ```typescript // tailwind.config.js module.exports = { theme: { screens: { 'xs': '320px', // iPhone SE 'sm': '640px', // Petites tablettes 'md': '768px', // iPad, tablettes 'lg': '1024px', // Desktop compact 'xl': '1280px', // Desktop standard '2xl': '1536px', // Larges écrans }, }, }; ``` ### Mobile First Approach **Développer pour mobile d'abord, puis enrichir pour desktop.** --- ## 📱 Layouts Responsifs ### Desktop Layout (≥1024px) ``` ┌─────────────────────────────────────────────────────────┐ │ NAVBAR (Dark, fixed, h-14) │ ├────────────────┬──────────────────┬──────────────────────┤ │ │ │ │ │ SIDEBAR │ RESULT LIST │ NOTE VIEW + TOC │ │ (240-440px) │ (virtualized) │ (Resizable) │ │ Resizable │ │ │ │ │ │ │ │ - Quick │ - Search bar │ - Markdown │ │ Links │ - Filters │ - ToC drawer │ │ - Folders │ - Items (80px) │ - Actions bar │ │ - Tags │ - Pagination │ │ │ │ │ │ └────────────────┴──────────────────┴──────────────────────┘ ``` ### Tablet Layout (768px ≤ width < 1024px) ``` ┌──────────────────────────────────────┐ │ NAVBAR + Toggle (fixed, h-14) │ ├──────────────────────────────────────┤ │ TAB NAVIGATION (fixed, bottom) │ │ [Sidebar] [List] [Page] [ToC] │ ├──────────────────────────────────────┤ │ │ │ ACTIVE TAB CONTENT (scrollable) │ │ - Drawer si besoin │ │ - Full-width panels │ │ │ └──────────────────────────────────────┘ ``` ### Mobile Layout (<768px) ``` ┌──────────────────────────────────┐ │ NAVBAR (compact, h-12) │ │ [Menu] [Search] [Toggle] │ ├──────────────────────────────────┤ │ │ │ TAB/DRAWER NAVIGATION │ │ [≡] [🔍] [📄] [📋] │ │ │ │ CONTENT AREA (Full-width) │ │ - Drawer sidebar (80vw left) │ │ - Swipeable list (list tab) │ │ - Markdown full-screen (page) │ │ - Inline ToC (toggle button) │ │ │ ├──────────────────────────────────┤ │ Bottom Navigation (sticky) │ │ Tab buttons (4 icônes) │ └──────────────────────────────────┘ ``` ## 🎬 Composants Nimbus Responsifs ### Desktop/Mobile Variants Chaque composant doit avoir des **variants responsifs** : ``` app-left-sidebar/ ├── app-left-sidebar.component.ts # Logique partagée ├── app-left-sidebar.desktop.component.ts # ≥1024px (fixed, resizable) └── app-left-sidebar.mobile.component.ts # <1024px (drawer) app-center-list/ ├── app-center-list.component.ts ├── app-center-list.desktop.component.ts # ≥1024px (2 colonnes) └── app-center-list.mobile.component.ts # <1024px (full-width) app-note-view/ ├── app-note-view.component.ts ├── app-note-view.desktop.component.ts # ≥1024px (3 colonnes + ToC) └── app-note-view.mobile.component.ts # <1024px (full-width + ToC inline) app-toc-drawer/ ├── app-toc-drawer.component.ts ├── app-toc-drawer.desktop.component.ts # ≥1024px (Fixed right) └── app-toc-drawer.mobile.component.ts # <1024px (Collapsible, inline) ``` ### Détection et Injection ```typescript // app-left-sidebar.component.ts import { Component, inject } from '@angular/core'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; @Component({ selector: 'app-left-sidebar', standalone: true, template: ` @if (isDesktop$ | async) { } @else { } `, }) export class AppLeftSidebarComponent { private breakpoint = inject(BreakpointObserver); isDesktop$ = this.breakpoint.observe(Breakpoints.Large).pipe( map(result => result.matches) ); } ``` ## 📱 Navigation Mobile Avancée ### Tab/Drawer Navigation ```typescript // src/shared/services/mobile-nav.service.ts @Injectable({ providedIn: 'root' }) export class MobileNavService { activeTab = signal<'sidebar' | 'list' | 'page' | 'toc'>('list'); setTab(tab: 'sidebar' | 'list' | 'page' | 'toc') { this.activeTab.set(tab); // Persist if needed } } // Usage in component ``` ### Swipe Navigation (Gestures) ```typescript // Directive pour détection de swipe import { Directive, Output, EventEmitter, HostListener } from '@angular/core'; @Directive({ selector: '[appSwipeNav]', standalone: true, }) export class SwipeNavDirective { @Output() swipeLeft = new EventEmitter(); @Output() swipeRight = new EventEmitter(); private startX = 0; @HostListener('touchstart', ['$event']) onTouchStart(e: TouchEvent) { this.startX = e.touches[0].clientX; } @HostListener('touchend', ['$event']) onTouchEnd(e: TouchEvent) { const endX = e.changedTouches[0].clientX; const diff = this.startX - endX; if (Math.abs(diff) > 50) { // Seuil minimum if (diff > 0) this.swipeLeft.emit(); else this.swipeRight.emit(); } } } ``` ## 🎨 Composants Spécifiques (Mobile-First) ### 1) Bottom Navigation (Mobile) ```html ``` ### 2) Drawer Sidebar (Mobile) ```html
``` ### 3) Search Bar Compact (Mobile) ```html
{{ badge }} ✕
``` ### 4) Result List Item (Mobile-Optimized) ```html

{{ item.title }}

{{ item.modified | date:'short' }}
{{ tag }}

{{ item.excerpt }}

``` ### 5) Markdown Viewer (Mobile-Responsive) ```html
``` ### 6) ToC Drawer (Desktop Fixed, Mobile Inline) ```typescript // app-toc-drawer.component.ts @Component({ selector: 'app-toc-drawer', template: `
`, animations: [ trigger('slideDown', [ state('in', style({ height: '*' })), state('out', style({ height: '0px' })), transition('in <=> out', animate('200ms ease-in-out')), ]), ], standalone: true, }) export class AppTocDrawerComponent { @Input() headings: Heading[] = []; showTocMobile = false; isMobile$ = this.breakpoint.observe('(max-width: 1023px)').pipe( map(r => r.matches) ); } ``` ## 🎯 Livrables Attendus ### Code 1. **Toggle UI** : `UiModeService`, bouton navbar, `AppShellAdaptiveComponent` 2. **Responsive Wrappers** : Variants pour chaque composant (Desktop/Mobile) 3. **Mobile Components** : Bottom nav, drawer sidebar, inline ToC, mobile search 4. **Gesture Handling** : Swipe navigation directive, touch-friendly interactions 5. **Breakpoint Utilities** : Service CDK layout, reactive signals ### Styling 1. **Tailwind Config** : Breakpoints personnalisés, tokens tokens clair/sombre 2. **Mobile-First CSS** : Base mobile, enrichissements desktop via `md:`, `lg:` 3. **Touch-Friendly** : Boutons ≥44x44px, padding adéquat, hover states ### Documentation 1. **README_UI.md** : Schémas responsive, breakpoints, guide toggle 2. **MOBILE_GUIDE.md** : Navigation gestures, bottom nav flow, drawer patterns 3. **RESPONSIVE_CHECKLIST.md** : Tests par breakpoint, checklist A11y mobile ### Tests 1. **E2E** : Toggle persistence, layout switch, gesture navigation 2. **Visual Regression** : Screenshots desktop/tablet/mobile 3. **Accessibility** : Touch targets, ARIA labels, keyboard nav (Tab key) ## ⚡ Performance & Mobile Optimizations ### Critical Optimizations - **Lazy-load images** : `loading="lazy"`, responsive `srcset` - **Virtual scroll** : CDK virtual scroll adapté mobile (item height ≈ 70–80px) - **Debounce search** : 300ms sur mobile, 150ms sur desktop - **Avoid layout shift** : Aspect ratios, skeleton loaders - **Network awareness** : `navigator.connection.effectiveType` pour adapt qualité - **Battery saver** : Réduire animations, throttle updates en mode saver ### Lighthouse Mobile Targets - Performance ≥ 85 - Accessibility ≥ 95 - Best Practices ≥ 90 ## 🎮 Raccourcis Clavier & Gestures ### Desktop - `Ctrl/Cmd + K` : Palette commandes - `Ctrl/Cmd + F` : Focus recherche - `[` `]` : Replier/ouvrir ToC - `Alt + ←/→` : Navigation historique ### Mobile/Tablet - **Tap** : Ouvrir note/item - **Swipe left/right** : Changer onglet (list → page → sidebar) - **Long-press** : Menu contextuel (favoris, open in new tab) - **Pull-to-refresh** : Rafraîchir liste (optionnel) - **Double-tap** : Zoom ToC (mobile) ## 📋 Critères d'Acceptation ### Desktop (≥1024px) - [x] Layout 3 colonnes (sidebar fixe/resizable, liste, page+ToC) - [x] Changement dossier/tag/tri reflété en URL - [x] 1000+ items fluide (60fps virtual scroll) - [x] ToC synchronisé + repliable - [x] Tous les flux clavier-seuls possibles ### Tablet (768–1023px) - [x] Navigation par onglets (Sidebar / List / Page) - [x] Drawer sidebar (80vw, swipeable) - [x] Bottom navigation sticky (4 icônes) - [x] Contenu full-width par onglet - [x] ToC inline collapsible ### Mobile (<768px) - [x] Drawer sidebar (80vw max) - [x] Bottom nav (4 onglets) - [x] Search bar compact (menu + search + filters) - [x] List items optimisés (titre + date + excerpt) - [x] Markdown full-screen - [x] ToC overlay ou inline toggle - [x] Touch targets ≥ 44x44px ### Feature Flag - [x] Toggle UI visible dans navbar - [x] État persisté (localStorage) - [x] Pas de perte d'état lors du switch - [x] Legacy UI reste intacte ### Accessibility - [x] WCAG 2.1 AA sur tous les breakpoints - [x] Keyboard navigation complète (Tab, Arrow, Enter) - [x] ARIA labels pour navigation tactile - [x] Focus visible partout - [x] Zoom ≤ 200% sans horizontal scroll ### Performance - [x] TTI < 2.5s cold start - [x] Scroll 60fps sur 1000+ items - [x] Lighthouse Mobile ≥ 85 perf, ≥ 95 a11y - [x] ImageOptimizations (lazy, srcset, format next-gen) ## 🗂️ Arborescence Fichiers ``` src/app/ ├── layout/ │ ├── app-shell-adaptive/ │ │ └── app-shell-adaptive.component.ts # Feature flag wrapper │ ├── app-shell-nimbus/ │ │ ├── app-shell-nimbus.component.ts # 3 colonnes (desktop) │ │ ├── app-shell-nimbus.desktop.component.ts │ │ └── app-shell-nimbus.mobile.component.ts │ └── app-navbar/ │ ├── app-navbar.component.ts │ └── [Bouton toggle UI intégré] │ ├── features/ │ ├── sidebar/ │ │ ├── app-left-sidebar.component.ts │ │ ├── app-left-sidebar.desktop.component.ts │ │ └── app-left-sidebar.mobile.component.ts │ │ │ ├── search-bar/ │ │ ├── app-search-bar.component.ts │ │ ├── app-search-bar.desktop.component.ts │ │ └── app-search-bar.mobile.component.ts │ │ │ ├── result-list/ │ │ ├── app-result-list.component.ts │ │ ├── app-result-list.desktop.component.ts │ │ ├── app-result-list.mobile.component.ts │ │ └── app-result-list-item.component.ts │ │ │ ├── note-view/ │ │ ├── app-note-view.component.ts │ │ ├── app-note-view.desktop.component.ts │ │ └── app-note-view.mobile.component.ts │ │ │ ├── toc-drawer/ │ │ ├── app-toc-drawer.component.ts │ │ └── app-toc-content.component.ts │ │ │ └── bottom-nav/ [NEW] │ ├── app-bottom-nav.component.ts │ └── app-bottom-nav.component.html │ ├── shared/ │ ├── services/ │ │ ├── ui-mode.service.ts # [NEW] Toggle management │ │ ├── mobile-nav.service.ts # [NEW] Tab/drawer state │ │ └── breakpoint.service.ts # [NEW] Responsive helper │ │ │ ├── directives/ │ │ └── swipe-nav.directive.ts # [NEW] Gesture detection │ │ │ └── components/ │ └── resizable-handle/ │ └── styles/ ├── tokens.css # Tailwind tokens ├── responsive.css # Breakpoint utilities └── mobile.css # Mobile-specific (touches, etc.) ``` ## 📅 Plan d'Implémentation (ordre conseillé) 1. **Feature Flag Infrastructure** (1-2j) - `UiModeService` + localStorage persistence - `AppShellAdaptiveComponent` wrapper - Toggle button dans navbar 2. **Responsive Shell & Breakpoints** (2-3j) - Desktop layout 3 colonnes (>=1024px) - Tailwind breakpoints & tokens - Resizable sidebar logic 3. **Mobile Navigation & Bottom Nav** (2-3j) - `BottomNavComponent` (4 onglets) - `MobileNavService` (state management) - Tab/drawer routing 4. **Mobile Sidebar Drawer** (1-2j) - Drawer animé (translate, backdrop) - Swipe dismiss directive - Z-index management 5. **Responsive Components** (3-4j) - Search bar variants (desktop/mobile) - Result list item responsive - Markdown viewer mobile optimizations 6. **ToC Drawer Adaptive** (1-2j) - Fixed right panel (desktop) - Inline toggle (mobile) - Animations smooth 7. **Gestures & Touch** (1-2j) - Swipe nav directive - Long-press menu - Pull-to-refresh (optionnel) 8. **Accessibility & Testing** (2-3j) - WCAG 2.1 AA audit - Keyboard nav (Tab, Arrow) - E2E tests (toggle, breakpoints) - Visual regression (3 breakpoints) **Total estimé** : 13–21 jours (équipe 1 FE engineer) ## 🚀 Scripts NPM ```bash # Dev complet (Nimbus activé par défaut) npm run dev # Build production npm run build # Tests responsifs (plusieurs breakpoints) npm run test:responsive # Lighthouse audit mobile npm run audit:lighthouse:mobile # Feature flag (override) NIMBUS_UI=false npm run dev # Force legacy UI ``` ## ✅ Checklist Livraison - [ ] Toggle UI visible, fonctionnel, persisté - [ ] Desktop (≥1024px) : 3 colonnes, interactions fluides - [ ] Tablet (768–1023px) : Onglets + drawer, full-width contenu - [ ] Mobile (<768px) : Bottom nav, drawer, touch-friendly - [ ] Tous les flux clavier-seuls réalisables - [ ] Lighthouse mobile ≥ 85 perf, ≥ 95 a11y - [ ] Virtual scroll 60fps sur 1000+ items - [ ] Tests E2E (toggle, breakpoints, gestures) - [ ] Documentation complète (README_UI.md, MOBILE_GUIDE.md, RESPONSIVE_CHECKLIST.md) - [ ] Zéro régression : legacy UI inchangée, Wikilinks, bookmarks, graph intacts - [ ] Screenshots before/after 3 breakpoints ## 📖 Documentation à Produire 1. **README_UI.md** : Overview, architecture, screenshots 3 breakpoints 2. **MOBILE_GUIDE.md** : Navigation onglets, gestures, drawer patterns 3. **RESPONSIVE_CHECKLIST.md** : Tests par breakpoint, device testing 4. **DEPLOYMENT.md** : Feature flag pour bascule progressive 5. **ARCHITECTURE_DIAGRAM.md** : Schémas adaptatifs (Mermaid) ## 💡 Notes Importantes - **Mobile First** : Développer pour mobile en premier, puis enrichir desktop. - **Persistent State** : Le toggle UI et les filtres actifs doivent persister via localStorage (sans browser storage, utiliser sessionStorage ou service state). - **Zero Regression** : L'ancienne interface reste intacte et fonctionnelle. - **Performance** : Virtual scroll adapté mobile (40+ items à l'écran), lazy-load images. - **Accessibility** : 44x44px touch targets minimum, ARIA labels complets, keyboard nav. - **Testing** : Visual regression sur breakpoints clés (375px / 768px / 1440px). ``` Ce prompt inclut désormais une compatibilité totale avec les modes Desktop et Mobile, en tenant compte des spécificités de chaque plateforme.