# 🎯 Prompt Windsurf β€” ObsiViewer Nimbus UI (Desktop + Mobile) ## ObsiViewer β†’ Interface "Nimbus-like" 100% Responsive **RΓ΄le & mode :** Agis comme **Staff Frontend Engineer Angular 20 + UX Designer** expert. 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 + Tablet). Un **bouton toggle** dans la navbar permet de basculer entre l'ancienne interface et la nouvelle sans perte d'Γ©tat. --- ## Contexte * **Projet** : ObsiViewer (Angular 20 + Tailwind, Node/Express backend) * **Objectif** : Refondre l'interface selon un design **Nimbus Notes/FuseBase**-like avec responsive design complet * **CΕ“urs d'usage** : navigation par **dossiers**, **tags**, **recherche**, **lecture markdown** plein Γ©cran, **ToC** Γ  droite, **tri et filtres** rapides[1][2][3] * **NouveautΓ©** : Design adaptatif complet (Desktop/Mobile/Tablet) avec UI toggle persistΓ© *** ## 🎯 Architecture Responsive Cible ### Desktop (β‰₯1024px) - Layout 3 Colonnes ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ NAVBAR (Dark, fixed, h-14) + Toggle UI β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”‚ β”‚ SIDEBAR β”‚ RESULT LIST β”‚ NOTE VIEW + TOC β”‚ β”‚ (240-440px) β”‚ (virtualized) β”‚ (Resizable) β”‚ β”‚ Resizable β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - Quick Links β”‚ - Search bar β”‚ - Markdown β”‚ β”‚ - Folders β”‚ - Chips filters β”‚ - ToC drawer β”‚ β”‚ - Tags β”‚ - Items (80px) β”‚ - Actions bar β”‚ β”‚ β”‚ - Pagination β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Mobile (<768px) - Navigation par Onglets ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ NAVBAR (compact, h-12) β”‚ β”‚ [≑] [Search] [Toggle] β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ CONTENT AREA (Full-width) β”‚ β”‚ - Drawer sidebar (80vw gauche) β”‚ β”‚ - Liste swipeable (tab liste) β”‚ β”‚ - Markdown full-screen (page) β”‚ β”‚ - ToC inline (toggle button) β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ BOTTOM NAVIGATION (sticky) β”‚ β”‚ [πŸ“] [πŸ”] [πŸ“„] [πŸ“‹] (4 onglets) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Tablet (768px ≀ width < 1024px) - Hybride ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ NAVBAR + Toggle (fixed, h-14) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ TAB NAVIGATION (3 onglets) β”‚ β”‚ [Sidebar] [List] [Page] β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ ACTIVE TAB CONTENT (scrollable) β”‚ β”‚ - Panneau full-width par tab β”‚ β”‚ - Drawer si besoin β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` *** ## πŸ“‹ Architecture Feature Flag & Toggle ### 1) Toggle UI dans la NavBar Ajouter un **bouton toggle** dans `src/app/layout/app-navbar/app-navbar.component.ts` :[4] ```html
``` ### 2) Service de Gestion du Mode UI CrΓ©er `src/app/shared/services/ui-mode.service.ts` : ```typescript import { Injectable, signal, effect } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class UiModeService { // Signal pour rΓ©activitΓ© fine-grained[3] isNimbusMode = signal(this.loadUIMode()); constructor() { // Persister les changements automatiquement effect(() => { if (typeof localStorage !== 'undefined') { localStorage.setItem('obsiviewer-ui-mode', this.isNimbusMode() ? 'nimbus' : 'legacy'); } }); } toggleUIMode() { const newMode = !this.isNimbusMode(); this.isNimbusMode.set(newMode); } private loadUIMode(): boolean { if (typeof localStorage === 'undefined') return true; 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 (Mobile-First)[5][6] ```javascript // 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 }, extend: { // Tokens personnalisΓ©s Nimbus-like colors: { nimbus: { 50: '#f0f9ff', 500: '#0ea5e9', // Turquoise actions 900: '#0c4a6e' // Dark mode } } } }, }; ``` ### Service de DΓ©tection Responsive ```typescript // src/shared/services/breakpoint.service.ts import { Injectable, signal, inject } from '@angular/core'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; import { map } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class ResponsiveService { private breakpointObserver = inject(BreakpointObserver); // Signaux rΓ©actifs pour chaque breakpoint[25][28] isMobile = signal(false); isTablet = signal(false); isDesktop = signal(false); constructor() { // Mobile (< 768px) this.breakpointObserver.observe('(max-width: 767px)').subscribe(result => { this.isMobile.set(result.matches); }); // Tablet (768px - 1023px) this.breakpointObserver.observe('(min-width: 768px) and (max-width: 1023px)').subscribe(result => { this.isTablet.set(result.matches); }); // Desktop (>= 1024px) this.breakpointObserver.observe('(min-width: 1024px)').subscribe(result => { this.isDesktop.set(result.matches); }); } } ``` *** ## πŸ“± Composants Responsifs SpΓ©cifiques ### 1) Shell Principal Nimbus (Responsive) ```typescript // app-shell-nimbus.component.ts import { Component, inject } from '@angular/core'; import { ResponsiveService } from '@app/shared/services/responsive.service'; @Component({ selector: 'app-shell-nimbus-layout', template: `
`, standalone: true, imports: [/* tous les composants */], }) export class AppShellNimbusLayoutComponent { responsive = inject(ResponsiveService); } ``` ### 2) Bottom Navigation Mobile ```typescript // app-bottom-navigation.component.ts import { Component, inject } from '@angular/core'; import { MobileNavService } from '@app/shared/services/mobile-nav.service'; @Component({ selector: 'app-bottom-navigation', template: ` `, standalone: true, }) export class AppBottomNavigationComponent { mobileNav = inject(MobileNavService); tabs = [ { id: 'sidebar', icon: 'πŸ“', label: 'Dossiers' }, { id: 'list', icon: 'πŸ”', label: 'Liste' }, { id: 'page', icon: 'πŸ“„', label: 'Page' }, { id: 'toc', icon: 'πŸ“‹', label: 'Sommaire' } ]; setActiveTab(tabId: string) { this.mobileNav.setActiveTab(tabId as any); } } ``` ### 3) Service Navigation Mobile ```typescript // src/shared/services/mobile-nav.service.ts import { Injectable, signal } from '@angular/core'; type MobileTab = 'sidebar' | 'list' | 'page' | 'toc'; @Injectable({ providedIn: 'root' }) export class MobileNavService { activeTab = signal('list'); // Γ‰tat des drawers sidebarOpen = signal(false); tocOpen = signal(false); setActiveTab(tab: MobileTab) { this.activeTab.set(tab); // Auto-fermer les drawers quand on change d'onglet if (tab !== 'sidebar') this.sidebarOpen.set(false); if (tab !== 'toc') this.tocOpen.set(false); } toggleSidebar() { this.sidebarOpen.update(open => !open); } toggleToc() { this.tocOpen.update(open => !open); } } ``` ### 4) Drawer Sidebar Mobile ```typescript // app-sidebar-drawer.component.ts import { Component, inject } from '@angular/core'; import { MobileNavService } from '@app/shared/services/mobile-nav.service'; @Component({ selector: 'app-sidebar-drawer', template: `
`, standalone: true, imports: [AppSidebarContentComponent], }) export class AppSidebarDrawerComponent { mobileNav = inject(MobileNavService); } ``` ### 5) Search Bar Responsive ```typescript // app-search-bar.component.ts import { Component, inject } from '@angular/core'; import { ResponsiveService } from '@app/shared/services/responsive.service'; import { MobileNavService } from '@app/shared/services/mobile-nav.service'; @Component({ selector: 'app-search-bar', template: `
{{ badge }}
πŸ”
`, standalone: true, }) export class AppSearchBarComponent { responsive = inject(ResponsiveService); mobileNav = inject(MobileNavService); searchQuery = ''; activeFilters: string[] = []; openFilters() { /* */ } removeFilter(filter: string) { /* */ } openFolderPicker() { /* */ } openTagPicker() { /* */ } openPagePicker() { /* */ } } ``` ### 6) Liste de RΓ©sultats Responsive ```typescript // app-result-list.component.ts import { Component, inject, Input } from '@angular/core'; import { ResponsiveService } from '@app/shared/services/responsive.service'; @Component({ selector: 'app-result-list', template: ` dk-virtual-scroll-viewport [itemSize]="responsive.isMobile() ? 70 : 80" class="h"h-full"> `, standalone: true, imports: [ScrollingModule], }) export class AppResultListComponent { responsive = inject(ResponsiveService); @Input() items: any[] = []; trackByFn(index: number, item: any) { return item.id; } openNote(item: any) { // Navigation vers la note } } ``` ### 7) Item de RΓ©sultat Mobile-Optimized ```typescript // app-result-list-item.component.ts @Component({ selector: 'app-result-list-item', template: `

{{ item.title }}

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

{{ item.excerpt }}

`, standalone: true, }) export class AppResultListItemComponent { @Input() item: any; @Input() compact = false; } ``` ### 8) Markdown Viewer avec ToC Responsive ```typescript // app-markdown-viewer.component.ts import { Component, inject } from '@angular/core'; import { ResponsiveService } from '@app/shared/services/responsive.service'; import { MobileNavService } from '@app/shared/services/mobile-nav.service'; @Component({ selector: 'app-markdown-viewer', template: `

{{ currentNote?.title }}

`, standalone: true, }) export class AppMarkdownViewerComponent { responsive = inject(ResponsiveService); mobileNav = inject(MobileNavService); @Input() currentNote: any; @Input() markdownHTML = ''; @Input() headings: any[] = []; } ``` *** ## 🎬 Gestures & Navigation Tactile ### Directive Swipe Navigation ```typescript // src/shared/directives/swipe-nav.directive.ts 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; private startY = 0; private threshold = 50; // Minimum distance private restraint = 100; // Maximum perpendicular distance @HostListener('touchstart', ['$event']) onTouchStart(e: TouchEvent) { const touch = e.touches[0]; this.startX = touch.clientX; this.startY = touch.clientY; } @HostListener('touchend', ['$event']) onTouchEnd(e: TouchEvent) { const touch = e.changedTouches[0]; const endX = touch.clientX; const endY = touch.clientY; const distX = this.startX - endX; const distY = Math.abs(this.startY - endY); // Vérifier que c'est bien un swipe horizontal if (Math.abs(distX) >= this.threshold && distY <= this.restraint) { if (distX > 0) { this.swipeLeft.emit(); } else { this.swipeRight.emit(); } } } } ``` ### Usage Mobile avec Swipe ```html
``` *** ## ⚑ Performance & Optimisations Mobile ### Critical Optimizations[7][8] ```typescript // Lazy loading des images // app-image-lazy.directive.ts @Directive({ selector: 'img[appLazyLoad]' }) export class LazyLoadDirective implements OnInit { @Input() src!: string; @Input() alt = ''; ngOnInit() { const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target as HTMLImageElement; img.src = this.src; img.alt = this.alt; observer.unobserve(img); } }); }); observer.observe(this.el.nativeElement); } } ``` ### Skeleton Loaders Mobile ```typescript // app-skeleton.component.ts @Component({ selector: 'app-skeleton', template: `
`, standalone: true, }) export class AppSkeletonComponent { responsive = inject(ResponsiveService); } ``` *** ## πŸ“… Plan d'ImplΓ©mentation PriorisΓ© ### Phase 1: Infrastructure (2-3j) - βœ… `UiModeService` + localStorage persistence - βœ… `ResponsiveService` avec BreakpointObserver[9][10] - βœ… `AppShellAdaptiveComponent` wrapper - βœ… Toggle button dans navbar - βœ… Breakpoints Tailwind mobile-first[6][5] ### Phase 2: Layout Desktop (3-4j) - βœ… Desktop layout 3 colonnes (β‰₯1024px) - βœ… Sidebar resizable avec dossiers/tags - βœ… Liste virtualisΓ©e performante - βœ… ToC panel fixe Γ  droite - βœ… Search bar avec chips de filtres[2][1] ### Phase 3: Navigation Mobile (2-3j) - βœ… `MobileNavService` (state management) - βœ… `BottomNavigationComponent` (4 onglets)[11][12] - βœ… Tab routing et state persistence - βœ… Swipe gestures directive[13][14] ### Phase 4: Composants Mobile (3-4j) - βœ… Drawer sidebar mobile[15][16] - βœ… Search bar responsive compacte - βœ… Result list item mobile-optimized - βœ… Markdown viewer full-screen mobile - βœ… ToC overlay mobile avec animations ### Phase 5: Tablet & Transitions (1-2j) - βœ… Layout hybride tablet (768-1023px) - βœ… Animations fluides entre breakpoints - βœ… Touch targets β‰₯ 44px[6] - βœ… Gesture handling avancΓ© ### Phase 6: Testing & Polish (2-3j) - βœ… Tests E2E (toggle, breakpoints, gestures) - βœ… Lighthouse mobile audit (β‰₯85 perf, β‰₯95 a11y) - βœ… Visual regression (3 breakpoints) - βœ… Keyboard navigation complΓ¨te - βœ… WCAG 2.1 AA compliance **Total estimΓ©** : 13-19 jours (Γ©quipe 1 FE engineer) *** ## πŸ—‚οΈ Structure des Fichiers ``` src/app/ β”œβ”€β”€ layout/ β”‚ β”œβ”€β”€ app-shell-adaptive/ β”‚ β”‚ └── app-shell-adaptive.component.ts # Feature flag wrapper β”‚ β”œβ”€β”€ app-shell-nimbus/ β”‚ β”‚ β”œβ”€β”€ app-shell-nimbus.component.ts # Layout responsive β”‚ β”‚ β”œβ”€β”€ app-shell-nimbus.desktop.html # Template desktop β”‚ β”‚ β”œβ”€β”€ app-shell-nimbus.tablet.html # Template tablet β”‚ β”‚ └── app-shell-nimbus.mobile.html # Template mobile β”‚ └── app-navbar/ β”‚ β”œβ”€β”€ app-navbar.component.ts β”‚ β”œβ”€β”€ app-navbar.desktop.html # NavBar desktop β”‚ └── app-navbar.mobile.html # NavBar mobile compact β”‚ β”œβ”€β”€ features/ β”‚ β”œβ”€β”€ sidebar/ β”‚ β”‚ β”œβ”€β”€ app-left-sidebar.component.ts # Desktop sidebar β”‚ β”‚ β”œβ”€β”€ app-sidebar-drawer.component.ts # Mobile drawer[39] β”‚ β”‚ └── app-sidebar-content.component.ts # Contenu partagΓ© β”‚ β”‚ β”‚ β”œβ”€β”€ search-bar/ β”‚ β”‚ β”œβ”€β”€ app-search-bar.component.ts # Responsive wrapper β”‚ β”‚ β”œβ”€β”€ app-search-desktop.component.ts # Desktop full β”‚ β”‚ └── app-search-mobile.component.ts # Mobile compact β”‚ β”‚ β”‚ β”œβ”€β”€ result-list/ β”‚ β”‚ β”œβ”€β”€ app-result-list.component.ts # Liste virtualisΓ©e β”‚ β”‚ └── app-result-list-item.component.ts # Item responsive β”‚ β”‚ β”‚ β”œβ”€β”€ note-view/ β”‚ β”‚ β”œβ”€β”€ app-markdown-viewer.component.ts # Viewer responsive β”‚ β”‚ β”œβ”€β”€ app-toc-panel.component.ts # ToC desktop fixe β”‚ β”‚ └── app-toc-overlay.component.ts # ToC mobile overlay β”‚ β”‚ β”‚ β”œβ”€β”€ bottom-nav/ [NEW] β”‚ β”‚ β”œβ”€β”€ app-bottom-navigation.component.ts # Navigation mobile[40] β”‚ β”‚ └── app-tab-navigation.component.ts # Navigation tablet β”‚ β”‚ β”‚ └── mobile-content/ [NEW] β”‚ β”œβ”€β”€ app-mobile-content.component.ts # Container mobile β”‚ └── app-tab-content.component.ts # Container tablet β”‚ β”œβ”€β”€ shared/ β”‚ β”œβ”€β”€ services/ β”‚ β”‚ β”œβ”€β”€ ui-mode.service.ts # Toggle UI management β”‚ β”‚ β”œβ”€β”€ responsive.service.ts # Breakpoint detection[25] β”‚ β”‚ └── mobile-nav.service.ts # Tab/drawer state mobile β”‚ β”‚ β”‚ β”œβ”€β”€ directives/ β”‚ β”‚ β”œβ”€β”€ swipe-nav.directive.ts # Gesture detection[41] β”‚ β”‚ └── lazy-load.directive.ts # Image lazy loading β”‚ β”‚ β”‚ └── components/ β”‚ β”œβ”€β”€ skeleton/ β”‚ β”‚ └── app-skeleton.component.ts # Loading states β”‚ └── filter-chip/ β”‚ └── app-filter-chip.component.ts # Chips rΓ©utilisables[1] β”‚ └── styles/ β”œβ”€β”€ tokens.scss # Variables Nimbus β”œβ”€β”€ responsive.scss # Utilitaires responsive[21] β”œβ”€β”€ mobile.scss # Styles mobile-specific └── animations.scss # Transitions smooth ``` *** ## βœ… CritΓ¨res d'Acceptation ### βœ… Desktop (β‰₯1024px) - Layout 3 colonnes (sidebar fixe/resizable, liste, page+ToC)[1][2] - Changement dossier/tag/tri reflΓ©tΓ© en URL - 1000+ items fluide (60fps virtual scroll) - ToC synchronisΓ© + repliable cΓ΄tΓ© droit - Navigation clavier-seule possible partout ### βœ… Mobile (<768px) - Drawer sidebar (80vw max) avec backdrop[16][15] - Bottom nav (4 onglets) sticky[12][11] - Search bar compact (menu + search + filters) - List items optimisΓ©s (titre + date + excerpt) - Markdown full-screen avec ToC overlay - Touch targets β‰₯ 44x44px[6] - Swipe navigation entre onglets[13] ### βœ… Tablet (768-1023px) - Navigation par 3 onglets principaux - Contenu full-width par tab - Drawer optionnel selon besoin - Bottom navigation hybride ### βœ… Feature Flag - Toggle UI visible dans navbar - Γ‰tat persistΓ© (localStorage) - Pas de perte d'Γ©tat lors du switch - Legacy UI reste intacte et fonctionnelle ### βœ… Performance & AccessibilitΓ© - TTI < 2.5s cold start - Scroll 60fps sur 1000+ items - Lighthouse Mobile β‰₯ 85 perf, β‰₯ 95 a11y[8][7] - WCAG 2.1 AA sur tous les breakpoints - Keyboard navigation complΓ¨te (Tab, Arrow, Enter) - Focus visible partout, zoom ≀ 200% sans scroll horizontal *** ## πŸš€ Scripts & Commandes ```bash # Dev complet (Nimbus activΓ© par dΓ©faut) npm run dev # Build production avec optimisations mobile npm run build:mobile # 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 NIMBUS_UI=true npm run dev # Force Nimbus UI # Screenshots responsive pour tests visuels npm run screenshot:all-breakpoints ``` *** ## πŸ“– Documentation Γ  Produire 1. **README_UI_RESPONSIVE.md** : Architecture, breakpoints, captures d'Γ©cran 3 formats 2. **MOBILE_GUIDE.md** : Navigation onglets, gestures, patterns drawer 3. **RESPONSIVE_CHECKLIST.md** : Tests par breakpoint, device testing 4. **DEPLOYMENT_PROGRESSIVE.md** : Feature flag pour migration douce 5. **PERFORMANCE_MOBILE.md** : Optimisations, lazy loading, metrics *** ## πŸ’‘ Notes Cruciales - **Mobile First Absolu** : DΓ©velopper mobile d'abord, puis enrichir tablet/desktop[5][6] - **Zero Regression** : L'interface legacy reste 100% intacte et fonctionnelle - **Γ‰tat Persistant** : Toggle UI, filtres actifs, tab mobile via localStorage - **Performance** : Virtual scroll adaptΓ© mobile, lazy-load images, skeleton loaders[7] - **Accessibility** : 44px touch targets, ARIA labels complets, keyboard nav[6] - **Testing** : Visual regression sur 3 breakpoints clΓ©s (375px/768px/1440px) - **Gestures** : Swipe navigation fluide, long-press menus, pull-to-refresh optionnel[14][13] *** **ExΓ©cute maintenant ce plan complet** : crΓ©e tous les composants responsifs, implΓ©mente les services de state management, configure les breakpoints Tailwind mobile-first, branche la navigation tactile avec gestures, et livre le MR conforme aux critΓ¨res ci-dessus avec toggle UI et compatibilitΓ© 100% Desktop/Tablet/Mobile.[5][13] [1](https://nimbuslearning.com/team_member/aaron-lee/) [2](https://thefusebase.com/guides/android-ios/mobile-apps/) [3](https://thefusebase.com/guides/getting-started/structure-in-nimbus-note/) [4](https://blog.angular-university.io/angular-responsive-design/) [5](https://tailwindcss.com/docs/responsive-design) [6](https://dev.to/hitesh_developer/20-tips-for-designing-mobile-first-with-tailwind-css-36km) [7](https://www.youtube.com/watch?v=S2eyA3zk0BQ) [8](https://www.linkedin.com/pulse/designing-responsive-uis-angular-mobile-first-adaptive-yeturi-sx1wc) [9](https://material.angular.dev/cdk/layout/overview) [10](https://www.thisdot.co/blog/how-to-manage-breakpoints-using-breakpointobserver-in-angular) [11](https://m2.material.io/components/bottom-navigation) [12](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tabbar) [13](https://stackoverflow.com/questions/42592156/what-is-the-best-way-to-implement-swipe-navigation-in-angular-2) [14](https://js.devexpress.com/Angular/Documentation/Guide/UI_Components/List/End-User_Interaction/Touch-Screen_Gestures/) [15](https://material.angular.dev/components/sidenav/overview) [16](https://dev.to/davidihl/how-to-create-a-responsive-sidebar-and-mini-navigation-with-material-angular-o5l) [17](https://smart-interface-design-patterns.com) [18](https://www.reddit.com/r/angular/comments/1gjjkpt/responsive_design_best_practice/) [19](https://smashingconf.com/online-workshops/workshops/interface-design-course-vitaly-friedman-spring/) [20](https://www.youtube.com/watch?v=svetVZJewDk) [21](https://blog.pixelfreestudio.com/how-to-implement-mobile-first-design-in-angular/) [22](https://devoxsoftware.com/blog/improve-engagement-of-your-saas-with-ux-ui-design-best-practices/) [23](https://appsumo.com/products/fusebase/questions/pavel-1430723/) [24](https://thefusebase.com/note/) [25](https://www.youtube.com/watch?v=bGoemPZfQzk) [26](https://angular.love/responsive-angular-components) [27](https://www.thedesignership.com/blog/the-ultimate-guide-to-ux-ui-design-in-2024) [28](https://fivetaco.com/products/fusebase) [29](https://help.luware.com/best-practices-category/best-practices-designing-messages-and-adaptive-cards-in-ms-teams) [30](https://www.reddit.com/r/FlutterDev/comments/1alapqu/should_i_separate_the_codebase_for_desktop_and/) [31](https://stackoverflow.com/questions/65782044/without-media-queries-how-to-achieve-3-column-desktop-to-1-column-mobile-layout) [32](https://m2.material.io/design/layout/responsive-layout-grid.html) [33](https://tailwindcss.com/plus/templates/pocket) [34](https://www.w3schools.com/howto/howto_css_three_columns.asp) [35](https://stackoverflow.com/questions/78141479/how-to-change-desktop-first-design-code-to-mobile-first-with-tailwind-css-respo) [36](https://www.linkedin.com/posts/angular-material-dev_angular-angularmaterial-webdevelopment-activity-7354526847910445056-jqNb) [37](https://stackoverflow.com/questions/72945583/breakpointobserver-angular) [38](https://www.reddit.com/r/Frontend/comments/1fevx2e/anyone_switched_from_desktop_first_to_mobile/) [39](https://teamtreehouse.com/community/three-column-layout-that-is-responsive) [40](https://www.youtube.com/watch?v=I13uAoOGU_4) [41](https://dev.to/slyskillet/mobile-first-design-with-tailwind-css-3phd) [42](https://www.telerik.com/kendo-angular-ui/components/grid/styling-and-appearance/responsive-design) [43](https://www.digitalocean.com/community/tutorials/angular-breakpoints-angular-cdk) [44](https://www.bootstrapdash.com/blog/tailwind-responsive-design-tips) [45](https://www.reddit.com/r/Angular2/comments/w0co1t/how_to_implement_gestures_swipe_left_slider_in_an/) [46](https://www.youtube.com/watch?v=4CYuOiRHHA8) [47](https://www.telerik.com/kendo-angular-ui/bottomnavigation) [48](https://developer.mozilla.org/en-US/docs/Web/API/Touch_events) [49](https://stackoverflow.com/questions/57885511/angular-material-nav-sidebar-only-shows-on-responsive-resizing) [50](https://stackoverflow.com/questions/50445545/create-mobile-bottom-navigation-with-angular-material) [51](https://material.angular.dev/components/sidenav) [52](https://material.angular.dev/components/tabs/overview) [53](https://30dayscoding.com/blog/angular-animations-and-gesture-support) [54](https://stackoverflow.com/questions/63642803/angular-material-sidenav-rail-mode-hidden-on-mobile) [55](https://demo.mobiscroll.com/angular/navigation/bottom-navigation) [56](https://angular.love/gestures-in-an-angular-application) [57](https://stackblitz.com/edit/angular-closing-side-nav-in-mobile?file=app%2Fsidenav-responsive-example.html) [58](https://www.reddit.com/r/ionic/comments/1jwmsnr/iontabbar_and_transparent_device_navbar/)