ObsiViewer/docs/PROMPTS/Nimbus_Interface/ObsiViewer_NewInterface_Nimbus_V2_deepseek.md

16 KiB
Raw Blame History

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

  1. Toggle UI Nimbus/Legacy avec persistence
  2. Layout 3 colonnes desktop fidèle Nimbus
  3. Navigation responsive tablette/mobile
  4. Composants Nimbus : Chips, Pickers, Outline, Bookmark cards
  5. Gestes mobiles : swipe, pull-to-refresh
  6. Thème clair/sombre Nimbus-like
  7. 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.