16 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	Voici le prompt refondu pour inclure la compatibilité mobile/tablet complète tout en conservant la philosophie Nimbus :
🎯 Prompt Windsurf — ObsiViewer Nimbus UI (Desktop + Mobile)
ObsiViewer → UI/UX "Nimbus-like" (responsive, 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 ≥1024px / Tablet 768-1023px / Mobile <768px). Un bouton toggle dans la navbar permet de basculer entre l'ancienne interface et la nouvelle sans perte d'état.
📋 Architecture Nimbus Responsive
Desktop (≥1024px) - Layout 3 colonnes
┌─────────────────────────────────────────────────────────┐
│ NAVBAR (Search centré + CTA "+ Page" + Actions droite)  │
├─────────────┬─────────────────────┬─────────────────────┤
│ SIDEBAR     │ CENTER COLUMN       │ NOTE + TOC          │
│ Navigation  │ • Chips filtres     │ • Édition riche     │
│ Dossiers/Tags│ • Liste résultats   │ • Outline contextuel│
│ Quick Links │ • Virtual scroll    │ • Barre actions     │
└─────────────┴─────────────────────┴─────────────────────┘
Tablet (768-1023px) - Navigation par onglets
┌────────────────────────────────────┐
│ NAVBAR (Search + Toggle UI)        │
├────────────────────────────────────┤
│ [≡] [📄] [🔍] [📋] Tabs bottom     │
├────────────────────────────────────┤
│                                    │
│  CONTENU ACTIF FULL-WIDTH          │
│  • Sidebar: Drawer 80vw            │
│  • Liste: Cards compactes          │
│  • Note: Markdown + ToC inline     │
│                                    │
└────────────────────────────────────┘
Mobile (<768px) - Navigation bottom + Drawers
┌──────────────────────────────────┐
│ NAVBAR compacte (Menu + Search)  │
├──────────────────────────────────┤
│          CONTENT AREA            │
│ • Sidebar: Drawer full           │
│ • Liste: Items optimisés         │
│ • Note: Plein écran              │
├──────────────────────────────────┤
│ [≡][📄][+][🔍][📋] Bottom Nav     │
└──────────────────────────────────┘
🎯 Composants Nimbus Spécifiques à Reproduire
1) Top Bar Nimbus (Responsive)
// Desktop: Search centré + CTA turquoise
<header class="flex items-center justify-between p-4">
  <!-- Gauche: Logo/Worspace -->
  <div class="w-1/4">Workspace Selector</div>
  
  <!-- Centre: Search large + filtre -->
  <div class="flex-1 max-w-2xl">
    <div class="relative">
      <input type="text" placeholder="Search..." class="w-full pl-10 pr-4 py-2 rounded-lg border">
      <span class="absolute left-3 top-2.5">🔍</span>
      <button class="absolute right-3 top-2.5">⏷</button>
    </div>
  </div>
  
  <!-- Droite: CTA + Actions -->
  <div class="w-1/4 flex justify-end gap-2">
    <button class="bg-cyan-500 text-white px-4 py-2 rounded-lg">+ Page</button>
    <button>Ask AI</button>
    <button>Share</button>
  </div>
</header>
// Mobile: Stacked + icons
<header class="p-3 space-y-2">
  <div class="flex justify-between">
    <button>☰</button>
    <button class="bg-cyan-500 text-white px-3 py-1 rounded">+</button>
  </div>
  <div class="relative">
    <input type="text" placeholder="Search..." class="w-full pl-8 pr-3 py-1 rounded border">
    <span class="absolute left-2 top-1.5">🔍</span>
  </div>
</header>
2) Chips de Filtres Nimbus (Responsive)
// Desktop: Chips horizontales
<div class="flex gap-2 p-4 border-b">
  <div class="chip-filter">
    <span>All folders</span>
    <span class="badge">+2</span>
    <span>▾</span>
  </div>
  <div class="chip-filter">
    <span>All tags</span>
    <span class="badge">+1</span>
    <span>▾</span>
  </div>
  <div class="chip-filter">
    <span>All pages</span>
    <span>▾</span>
  </div>
</div>
// Mobile: Chips scrollables horizontalement
<div class="flex gap-1 p-3 border-b overflow-x-auto">
  <div class="chip-filter flex-shrink-0">
    <span>Folders</span>
    <span>▾</span>
  </div>
  <div class="chip-filter flex-shrink-0">
    <span>Tags</span>
    <span>▾</span>
  </div>
  <!-- ... -->
</div>
3) Picker Overlays Nimbus (Responsive)
// Desktop: Overlay centré
<div class="fixed inset-0 bg-black/20 z-50 flex items-start justify-center pt-20">
  <div class="bg-white rounded-lg shadow-xl w-96 max-h-96 overflow-hidden">
    <!-- Header avec recherche -->
    <div class="p-3 border-b">
      <input type="text" placeholder="Search folders..." class="w-full p-2 border rounded">
    </div>
    
    <!-- Liste avec hiérarchie -->
    <div class="overflow-y-auto max-h-64">
      <div class="flex items-center p-2 hover:bg-gray-100">
        <input type="checkbox" class="mr-2">
        <span>📁</span>
        <span class="ml-2 flex-1">Workspace</span>
        <span>›</span>
      </div>
      <!-- Sous-dossiers indentés -->
      <div class="flex items-center p-2 pl-6 hover:bg-gray-100">
        <input type="checkbox" class="mr-2">
        <span>📁</span>
        <span class="ml-2 flex-1">Projects</span>
        <span class="text-xs text-gray-500">15</span>
      </div>
    </div>
    
    <!-- Footer actions -->
    <div class="flex justify-between p-3 border-t">
      <button class="text-gray-600">Clear</button>
      <button class="bg-cyan-500 text-white px-4 py-1 rounded">Done</button>
    </div>
  </div>
</div>
// Mobile: Picker full-screen
<div class="fixed inset-0 bg-white z-50">
  <div class="p-4 border-b flex justify-between items-center">
    <h3 class="font-semibold">Select Folders</h3>
    <button class="text-cyan-500">Done</button>
  </div>
  
  <div class="p-3 border-b">
    <input type="text" placeholder="Search folders..." class="w-full p-2 border rounded">
  </div>
  
  <div class="overflow-y-auto h-full pb-20">
    <!-- Liste mobile-optimisée -->
  </div>
</div>
4) Outline Contextuel Nimbus (Responsive)
// Desktop: Panneau droit fixe
<aside class="fixed right-0 top-14 bottom-0 w-64 border-l bg-gray-50 overflow-y-auto hidden lg:block">
  <div class="p-4">
    <h4 class="font-semibold mb-3">Outline</h4>
    <nav class="space-y-1">
      <a class="block py-1 text-sm text-gray-600 hover:text-gray-900"># Introduction</a>
      <a class="block py-1 pl-4 text-sm text-gray-600 hover:text-gray-900">## Getting Started</a>
      <!-- ... -->
    </nav>
  </div>
</aside>
// Mobile: Bouton flottant + overlay
<button class="fixed bottom-20 right-4 w-12 h-12 bg-cyan-500 text-white rounded-full shadow-lg lg:hidden"
        (click)="showTocMobile = true">
  📋
</button>
<div *ngIf="showTocMobile" class="fixed inset-0 bg-white z-50 lg:hidden">
  <div class="p-4 border-b flex justify-between">
    <h3 class="font-semibold">Table of Contents</h3>
    <button (click)="showTocMobile = false">✕</button>
  </div>
  <div class="p-4 overflow-y-auto h-full">
    <!-- Contenu ToC -->
  </div>
</div>
🎨 Palette Nimbus & Design Tokens
/* Tokens Nimbus (light/dark) */
:root {
  /* Couleurs primaires */
  --nimbus-cyan: #06b6d4;
  --nimbus-cyan-dark: #0891b2;
  
  /* Gris scale */
  --nimbus-gray-50: #f9fafb;
  --nimbus-gray-100: #f3f4f6;
  --nimbus-gray-800: #1f2937;
  --nimbus-gray-900: #111827;
  
  /* Espacements */
  --nimbus-space-1: 0.25rem;
  --nimbus-space-2: 0.5rem;
  --nimbus-space-3: 0.75rem;
  
  /* Typographie */
  --nimbus-text-sm: 0.875rem;
  --nimbus-text-base: 1rem;
}
.dark {
  --nimbus-bg: var(--nimbus-gray-900);
  --nimbus-surface: var(--nimbus-gray-800);
}
📱 Gestes Mobiles Spécifiques Nimbus
Swipe Navigation
@Directive({
  selector: '[appSwipeNav]',
  standalone: true
})
export class SwipeNavDirective {
  private startX = 0;
  private startY = 0;
  
  @HostListener('touchstart', ['$event'])
  onTouchStart(e: TouchEvent) {
    this.startX = e.touches[0].clientX;
    this.startY = e.touches[0].clientY;
  }
  
  @HostListener('touchend', ['$event'])
  onTouchEnd(e: TouchEvent) {
    const endX = e.changedTouches[0].clientX;
    const endY = e.changedTouches[0].clientY;
    const diffX = this.startX - endX;
    const diffY = this.startY - endY;
    
    // Seulement swipe horizontal significatif
    if (Math.abs(diffX) > 50 && Math.abs(diffY) < 30) {
      if (diffX > 0) {
        this.swipeLeft.emit(); // → Tab suivant
      } else {
        this.swipeRight.emit(); // ← Tab précédent
      }
    }
  }
  
  @Output() swipeLeft = new EventEmitter<void>();
  @Output() swipeRight = new EventEmitter<void>();
}
Hover-reveal Adaptatif (Desktop seulement)
// Seulement sur desktop
<div class="group relative">
  <div class="flex items-center">
    <span>📁 Projects</span>
    <button class="opacity-0 group-hover:opacity-100 transition-opacity lg:block hidden ml-2">
      +
    </button>
  </div>
</div>
// Mobile: Toujours visible ou menu contextuel
<div class="flex items-center justify-between lg:justify-start">
  <span>📁 Projects</span>
  <button class="lg:hidden ml-2">+</button>
</div>
🔧 Service UI Mode & Responsive State
@Injectable({ providedIn: 'root' })
export class UiModeService {
  // Signal pour le mode Nimbus vs Legacy
  isNimbusMode = signal<boolean>(this.loadUIMode());
  
  // Signal pour le breakpoint actif
  currentBreakpoint = signal<'mobile' | 'tablet' | 'desktop'>('desktop');
  
  constructor(private breakpointObserver: BreakpointObserver) {
    // Surveillance des breakpoints
    this.breakpointObserver.observe([
      '(max-width: 767px)',
      '(min-width: 768px) and (max-width: 1023px)', 
      '(min-width: 1024px)'
    ]).subscribe(result => {
      const breakpoints = result.breakpoints;
      if (breakpoints['(max-width: 767px)']) {
        this.currentBreakpoint.set('mobile');
      } else if (breakpoints['(min-width: 768px) and (max-width: 1023px)']) {
        this.currentBreakpoint.set('tablet');
      } else {
        this.currentBreakpoint.set('desktop');
      }
    });
  }
  
  toggleUIMode() {
    const newMode = !this.isNimbusMode();
    this.isNimbusMode.set(newMode);
    localStorage.setItem('obsiviewer-ui-mode', newMode ? 'nimbus' : 'legacy');
  }
  
  private loadUIMode(): boolean {
    return localStorage?.getItem('obsiviewer-ui-mode') !== 'legacy';
  }
}
🚀 Composants Spécifiques Nimbus
1) Bookmark Card (Responsive)
// Desktop: Carte horizontale
<div class="border rounded-lg p-3 hover:shadow-md transition-shadow">
  <div class="flex gap-3">
    <img src="thumbnail.jpg" class="w-20 h-20 rounded object-cover flex-shrink-0">
    <div class="flex-1 min-w-0">
      <h4 class="font-semibold truncate">Article Title</h4>
      <p class="text-sm text-gray-600 line-clamp-2">Description of the bookmarked content...</p>
      <div class="flex items-center gap-2 mt-1">
        <span class="text-xs text-gray-500">example.com</span>
        <span class="text-xs text-gray-500">2 days ago</span>
      </div>
    </div>
  </div>
</div>
// Mobile: Carte verticale
<div class="border rounded-lg p-3 hover:shadow-md transition-shadow">
  <img src="thumbnail.jpg" class="w-full h-32 rounded object-cover mb-2">
  <h4 class="font-semibold truncate">Article Title</h4>
  <p class="text-sm text-gray-600 line-clamp-2">Description...</p>
  <div class="flex justify-between items-center mt-2">
    <span class="text-xs text-gray-500">example.com</span>
    <span class="text-xs text-gray-500">2 days ago</span>
  </div>
</div>
2) Result List Item Nimbus
// Desktop: Ligne compacte
<div class="flex items-center gap-3 p-3 border-b hover:bg-gray-50 cursor-pointer">
  <div class="w-6 h-6 rounded bg-blue-100 flex items-center justify-center text-sm">📄</div>
  <div class="flex-1 min-w-0">
    <h4 class="font-medium truncate">Document Title</h4>
    <p class="text-sm text-gray-600 truncate">First few lines of content as preview...</p>
  </div>
  <div class="flex items-center gap-3 text-sm text-gray-500">
    <span>2h ago</span>
    <div class="flex gap-1">
      <span class="bg-gray-100 px-2 py-0.5 rounded text-xs">work</span>
    </div>
  </div>
</div>
// Mobile: Stack vertical
<div class="p-3 border-b hover:bg-gray-50 cursor-pointer">
  <div class="flex items-start gap-2">
    <div class="w-6 h-6 rounded bg-blue-100 flex items-center justify-center text-sm mt-0.5">📄</div>
    <div class="flex-1 min-w-0">
      <h4 class="font-medium">Document Title</h4>
      <p class="text-sm text-gray-600 line-clamp-2">First few lines of content as preview...</p>
      <div class="flex items-center justify-between mt-1">
        <span class="text-xs text-gray-500">2h ago</span>
        <div class="flex gap-1">
          <span class="bg-gray-100 px-2 py-0.5 rounded text-xs">work</span>
        </div>
      </div>
    </div>
  </div>
</div>
📋 Critères d'Acceptation Nimbus
Desktop (≥1024px)
- Layout 3 colonnes fidèle à Nimbus
- Top bar avec search centré + CTA "+ Page" turquoise
- Chips filtres "All folders ▾", "All tags ▾", "All pages ▾" avec badges
- Pickers overlays avec recherche locale + hiérarchie
- Outline contextuel panneau droit fixe
- Hover-reveal création sous-dossiers
- Workspace switcher dans sidebar
Tablet (768-1023px)
- Navigation par onglets [Sidebar] [List] [Page] [ToC]
- Drawer sidebar 80vw avec arborescence
- Chips scrollables horizontalement
- Pickers full-screen avec Done/Clear
- ToC inline collapsible
Mobile (<768px)
- Bottom navigation 5 onglets [Menu] [List] [+] [Search] [ToC]
- Drawers full-width pour sidebar/pickers
- Search bar compacte dans header
- Touch targets ≥ 44px
- Swipe gestures changement onglets
- Pull-to-refresh liste résultats
Fidélité Nimbus
- Philosophie workspace-first avec sélecteur d'espace
- Organisation bi-axiale dossiers + tags
- Recherche d'abord avec filtres persistants
- Progressive disclosure (menus contextuels)
- Bookmarks avec cartes enrichies
- Boutons Share/Add to portal visibles
Performance & Accessibilité
- Virtual scroll 1000+ items fluide
- Lighthouse Mobile ≥ 85 perf, ≥ 95 a11y
- Keyboard navigation complète
- WCAG 2.1 AA tous breakpoints
- Toggle UI persisté sans perte état
🎯 Livrables Exacts
- Toggle UI Nimbus/Legacy avec persistence
- Layout 3 colonnes desktop fidèle Nimbus
- Navigation responsive tablette/mobile
- Composants Nimbus : Chips, Pickers, Outline, Bookmark cards
- Gestes mobiles : swipe, pull-to-refresh
- Thème clair/sombre Nimbus-like
- Documentation responsive + patterns Nimbus
État initial : Toggle sur "Nimbus" par défaut, legacy UI intacte Testing : 3 breakpoints + gestures + accessibility Performance : 60fps virtual scroll, lazy loading images
Exécute maintenant cette implémentation en respectant scrupuleusement les patterns UI/UX de Nimbus Notes tout en garantissant la compatibilité 100% responsive mobile/tablet/desktop.