ObsiViewer/docs/MIGRATION_INLINE_TOOLBAR.md
Bruno Charest ee3085ce38 feat: add Nimbus Editor with Unsplash integration
- Integrated Unsplash API for image search functionality with environment configuration
- Added new Nimbus Editor page component with navigation from sidebar and mobile drawer
- Enhanced TOC with highlight animation for editor heading navigation
- Improved CDK overlay z-index hierarchy for proper menu layering
- Removed obsolete logging validation script
2025-11-11 11:38:27 -05:00

6.7 KiB
Raw Blame History

Guide de migration - Toolbar fixe → Toolbar inline

📌 Résumé des changements

Avant (Toolbar fixe)

┌─────────────────────────────────────────┐
│ [Titre du document]                     │
│                                         │
│ ┌─────────────────────────────────────┐ │
│ │ Start writing... [🤖][☑][1.][•][⊞]│ │ ← Barre fixe
│ └─────────────────────────────────────┘ │
│                                         │
│ Bloc 1: Paragraphe                      │
│ Bloc 2: Table                           │
│ Bloc 3: Image                           │
└─────────────────────────────────────────┘

Après (Toolbar inline)

┌─────────────────────────────────────────┐
│ [Titre du document]                     │
│                                         │
│ ⋮⋮ Start writing... [🤖][☑][1.][⊞][⬇] │ ← Inline dans le bloc
│                                         │
│ ⋮⋮ Bloc 1: Paragraphe [icônes...]      │ ← Chaque bloc a sa toolbar
│ ⋮⋮ Bloc 2: Table [icônes...]           │
│ ⋮⋮ Bloc 3: Image [icônes...]           │
└─────────────────────────────────────────┘

🔄 Composants modifiés

1. EditorShellComponent

Supprimé:

// ❌ ANCIEN - Toolbar fixe au niveau shell
<div class="mb-4">
  <app-editor-toolbar (action)="onToolbarAction($event)" />
</div>

Résultat: Plus de toolbar globale, chaque bloc gère la sienne.

2. ParagraphBlockComponent

Avant:

<div
  contenteditable="true"
  placeholder="Start writing or type '/', '@'"
></div>

Après:

<div (mouseenter)="isHovered.set(true)" (mouseleave)="isHovered.set(false)">
  <app-block-inline-toolbar
    [isFocused]="isFocused"
    [isHovered]="isHovered"
    (action)="onToolbarAction($event)"
  >
    <div
      contenteditable="true"
      (focus)="isFocused.set(true)"
      (blur)="isFocused.set(false)"
    ></div>
  </app-block-inline-toolbar>
</div>

Changements:

  • Wrapper avec gestion hover/focus
  • Intégration BlockInlineToolbarComponent
  • Signals pour états visuels
  • Détection "/" pour menu

3. BlockMenuComponent

Avant:

// Position fixe centrée
style="top: 20%; left: 50%; transform: translateX(-50%)"
width: 680px
height: 600px

Après:

// Position contextuelle près du curseur
[style.top.px]="menuPosition().top"
[style.left.px]="menuPosition().left"
width: 420px
height: 500px

Changements:

  • Taille réduite (420×500 vs 680×600)
  • Position dynamique basée sur bloc actif
  • Design compact (spacing réduit)
  • Headers sticky optimisés

📝 Checklist de migration pour autres blocs

Pour migrer un autre type de bloc (heading, list, table, etc.):

Étape 1: Imports

import { signal } from '@angular/core';
import { BlockInlineToolbarComponent } from '../block-inline-toolbar.component';
import { PaletteService } from '../../../services/palette.service';

@Component({
  imports: [..., BlockInlineToolbarComponent],
})

Étape 2: Ajouter les signals

export class YourBlockComponent {
  isFocused = signal(false);
  isHovered = signal(false);
  private paletteService = inject(PaletteService);
}

Étape 3: Wrapper le template

<div 
  (mouseenter)="isHovered.set(true)"
  (mouseleave)="isHovered.set(false)"
>
  <app-block-inline-toolbar
    [isFocused]="isFocused"
    [isHovered]="isHovered"
    (action)="onToolbarAction($event)"
  >
    <!-- Votre contenu existant -->
  </app-block-inline-toolbar>
</div>

Étape 4: Gérer focus/blur

<!-- Dans votre élément éditable -->
<div
  contenteditable="true"
  (focus)="isFocused.set(true)"
  (blur)="isFocused.set(false)"
>

Étape 5: Implémenter onToolbarAction

onToolbarAction(action: string): void {
  if (action === 'more' || action === 'menu') {
    this.paletteService.open();
  } else {
    // Logique spécifique au bloc
    this.handleQuickAction(action);
  }
}

🎯 Nouveaux comportements

Détection du "/"

onKeyDown(event: KeyboardEvent): void {
  if (event.key === '/') {
    const text = (event.target as HTMLElement).textContent || '';
    if (text.length === 0 || text.endsWith(' ')) {
      event.preventDefault();
      this.paletteService.open(); // Ouvre le menu
    }
  }
}

États visuels

État Drag handle Icônes Background
Défaut Caché Cachées Transparent
Hover Visible Semi-visibles bg-neutral-800/30
Focus Visible Visibles Transparent

🐛 Points d'attention

1. Z-index et layering

  • Drag handle: absolute -left-8 (en dehors du flux)
  • Menu: z-[9999] (au dessus de tout)
  • Sticky headers: z-10 (dans le menu)

2. Responsive

Le drag handle peut déborder sur mobile. Considérer:

@media (max-width: 640px) {
  .drag-handle {
    position: relative;
    left: 0;
  }
}

3. Performance

Les signals sont efficients, mais éviter:

// ❌ MAUVAIS - Recalcul à chaque render
[isFocused]="someComplexComputation()"

// ✅ BON - Signal mis à jour explicitement
[isFocused]="isFocused"

📊 Comparaison des fichiers

Fichier Avant Après Statut
editor-toolbar.component.ts Toolbar globale N/A ⚠️ Peut être supprimé
block-inline-toolbar.component.ts N/A Toolbar par bloc Nouveau
paragraph-block.component.ts Simple contenteditable Wrapper + toolbar Migré
block-menu.component.ts Position fixe centrée Position contextuelle Optimisé
editor-shell.component.ts Contient toolbar Seulement blocks Simplifié

🔮 Prochaines étapes

  1. Migrer les autres blocs (heading, list, table, etc.)
  2. Implémenter le drag & drop via le drag handle
  3. Menu bloc contextuel (clic sur ⋮⋮)
  4. Toolbar flottante pour formatage texte (Bold, Italic, etc.)
  5. Tests E2E pour valider les interactions

Note: L'ancien EditorToolbarComponent peut être conservé temporairement pour référence, mais n'est plus utilisé dans le shell.