ObsiViewer/docs/PARAGRAPH_IMPROVEMENTS.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

12 KiB

Améliorations du Bloc Paragraphe et Drag & Drop

🔴 Problèmes Identifiés

1. Toolbar Inline Superflue (Image 2)

Symptôme: Le bloc paragraphe affichait une toolbar inline avec plusieurs boutons quand le paragraphe était vide et focus.

Problème: Cette toolbar créait:

  • Un bouton drag handle par-dessus le bouton menu de block-host
  • Des boutons d'action (AI, checkbox, bullet list, etc.) qui encombraient l'interface
  • Une interface confuse avec trop d'options visibles

2. Manque de Mode Initial avec Menu (Image 1)

Besoin: Pouvoir double-cliquer entre 2 lignes pour ajouter un bloc, afficher un menu initial avec les options de type de bloc.

Manque: Pas de système de création rapide de blocs entre lignes existantes.

3. Drag & Drop Entre Blocs

Problème: Impossible de déplacer un bloc précisément ENTRE deux blocs existants.

Symptôme: Les blocs pouvaient être déplacés avant ou après les colonnes, mais pas entre deux blocs normaux avec précision.

Solutions Implémentées

1. Simplification du Bloc Paragraphe

Fichier: src/app/editor/components/block/blocks/paragraph-block.component.ts

Changements:

  • Retrait de BlockInlineToolbarComponent
  • Template simplifié à un simple contenteditable
  • Retrait des signaux inutilisés (isHovered)
  • Retrait de la méthode onToolbarAction
  • Placeholder mis à jour: "Type '/' for commands"

Avant:

<app-block-inline-toolbar
  [isFocused]="isFocused"
  [isHovered]="isHovered"
  [isEmpty]="isEmpty"
  [showDragHandle]="showDragHandle"
  (action)="onToolbarAction($event)"
>
  <div #editable contenteditable="true" ...></div>
</app-block-inline-toolbar>

Après:

<div class="relative" (click)="onContainerClick($event)">
  <div
    #editable
    contenteditable="true"
    class="w-full m-0 bg-transparent text-sm text-neutral-100 dark:text-neutral-100 focus:outline-none min-h-[1.25rem]"
    (input)="onInput($event)"
    (keydown)="onKeyDown($event)"
    (focus)="isFocused.set(true)"
    (blur)="onBlur()"
    [attr.data-placeholder]="placeholder"
  ></div>
</div>

Résultat:

  • Interface propre et minimaliste
  • Pas de boutons qui se superposent
  • Le bouton menu de block-host est maintenant clairement visible
  • Utilisation de / pour ouvrir la palette de commandes

2. Composant Menu Initial

Fichier créé: src/app/editor/components/block/block-initial-menu.component.ts

Fonctionnalités:

  • Menu horizontal compact avec icônes
  • Boutons pour: Paragraph, Checkbox, Bullet List, Numbered List, Table, Image, File, Link, Heading, More
  • Style dark avec hover effects
  • Émission d'événements pour actions

Template:

<div class="flex items-center gap-1 px-2 py-1 bg-gray-800 rounded-md shadow-lg border border-gray-700">
  <!-- Paragraph -->
  <button (click)="onAction('paragraph')">
    <svg>...</svg>
  </button>
  
  <!-- Checkbox -->
  <button (click)="onAction('checkbox')">
    <svg>...</svg>
  </button>
  
  <!-- ... autres boutons ... -->
</div>

Usage (à intégrer):

// Dans editor-shell ou block-host
<app-block-initial-menu 
  *ngIf="showInitialMenu"
  (action)="onInitialMenuAction($event)"
/>

Note: Le menu initial est prêt mais nécessite une intégration dans le système de création de blocs. Il faut:

  1. Détecter double-clic entre lignes
  2. Afficher le menu à cette position
  3. Créer le bloc correspondant au choix
  4. Masquer le menu après sélection

3. Amélioration du Drag & Drop

Fichier: src/app/editor/services/drag-drop.service.ts

Problème ancien:

// Logique floue basée sur "mid" (milieu du bloc)
const mid = r.top + r.height / 2;
if (clientY > mid) {
  targetIndex = i + 1;
  indicatorTop = r.bottom - containerRect.top;
} else {
  targetIndex = i;
  indicatorTop = r.top - containerRect.top;
  break;
}

Nouvelle logique:

// Define drop zones: top half = insert before, bottom half = insert after
const dropZoneHeight = r.height / 2;
const topZoneEnd = r.top + dropZoneHeight;

if (clientY <= topZoneEnd) {
  // Insert BEFORE this block
  targetIndex = i;
  indicatorTop = r.top - containerRect.top;
  found = true;
  break;
} else if (clientY <= r.bottom) {
  // Insert AFTER this block
  targetIndex = i + 1;
  indicatorTop = r.bottom - containerRect.top;
  found = true;
  break;
}

Améliorations:

  • Détection plus précise avec zones claires (top half vs bottom half)
  • Flag found pour gérer le cas "au-dessous de tous les blocs"
  • Logique claire: moitié supérieure = avant, moitié inférieure = après
  • Gère correctement le cas d'insertion à la fin

Zones de drop:

┌─────────────────────────────┐
│ Bloc 1                      │
│  ────── TOP HALF ──────     │  ← Curseur ici = Insert AVANT Bloc 1
│                             │
│  ───── BOTTOM HALF ─────    │  ← Curseur ici = Insert APRÈS Bloc 1
└─────────────────────────────┘
┌─────────────────────────────┐
│ Bloc 2                      │
│  ────── TOP HALF ──────     │  ← Curseur ici = Insert AVANT Bloc 2
│                             │
│  ───── BOTTOM HALF ─────    │  ← Curseur ici = Insert APRÈS Bloc 2
└─────────────────────────────┘

📊 Résultats

Avant

Paragraphe:

Bouton drag ┌─────────────────────────────────────────────┐
(superposé) │ Type...  [AI] [✓] [•] [1] [⊞] [🖼️] [📄] [+] │
            └─────────────────────────────────────────────┘

Toolbar encombrante
Boutons superposés
Interface confuse

Drag & Drop:

Bloc 1
───── (zone floue) ─────
Bloc 2

Difficile de cibler précisément entre blocs
Parfois le bloc allait au mauvais endroit

Après

Paragraphe:

            ┌─────────────────────────────────────────────┐
            │ Type '/' for commands                       │
            └─────────────────────────────────────────────┘

Interface propre et minimaliste
Pas de boutons visibles par défaut
Utilisation de / pour commandes

Drag & Drop:

Bloc 1
════════════ (Insert AVANT Bloc 2) ════════════  ← Top half
Bloc 2
════════════ (Insert APRÈS Bloc 2) ════════════  ← Bottom half
Bloc 3

Zones claires (50% / 50%)
Flèche bleue indique précisément où le bloc sera placé
Insertion possible partout: avant, après, entre blocs

🧪 Tests à Effectuer

Test 1: Paragraphe Simplifié

1. Créer un nouveau paragraphe
✅ Vérifier: Pas de toolbar inline visible
✅ Vérifier: Placeholder "Type '/' for commands"
2. Taper du texte
✅ Vérifier: Le texte s'affiche normalement
3. Taper '/'
✅ Vérifier: La palette de commandes s'ouvre
4. Hover sur le bloc
✅ Vérifier: Seul le bouton menu (⋯) de block-host apparaît
✅ Vérifier: Pas de bouton drag superposé

Test 2: Drag & Drop Précis

Setup: Créer 5 blocs (H1, P1, P2, P3, H2)

Test A: Insert entre P1 et P2
1. Drag P3
2. Positionner curseur sur la MOITIÉ SUPÉRIEURE de P2
✅ Vérifier: Flèche bleue apparaît AVANT P2
3. Drop
✅ Vérifier: P3 inséré entre P1 et P2
✅ Vérifier: Ordre final: H1, P1, P3, P2, H2

Test B: Insert entre P2 et H2
1. Drag P1
2. Positionner curseur sur la MOITIÉ INFÉRIEURE de P2
✅ Vérifier: Flèche bleue apparaît APRÈS P2
3. Drop
✅ Vérifier: P1 inséré entre P2 et H2
✅ Vérifier: Ordre final: H1, P3, P2, P1, H2

Test C: Insert à la fin
1. Drag H1
2. Positionner curseur en-dessous de tous les blocs
✅ Vérifier: Flèche bleue apparaît après le dernier bloc
3. Drop
✅ Vérifier: H1 déplacé à la fin

Test 3: Drag & Drop avec Colonnes

Setup: Créer colonnes + blocs normaux

1. Drag bloc normal vers moitié supérieure d'un bloc de colonne
✅ Vérifier: Bloc inséré AVANT le bloc dans la colonne

2. Drag bloc normal vers moitié inférieure d'un bloc de colonne
✅ Vérifier: Bloc inséré APRÈS le bloc dans la colonne

3. Drag bloc de colonne vers espace entre deux blocs normaux
✅ Vérifier: Bloc converti en pleine largeur et inséré entre les deux

Test 4: Menu Initial (Après Intégration)

1. Double-cliquer entre deux blocs
✅ Vérifier: Menu initial apparaît à la position du double-clic
✅ Vérifier: Menu affiche les icônes (comme Image 1)

2. Cliquer sur "Paragraph"
✅ Vérifier: Nouveau paragraphe créé
✅ Vérifier: Menu initial disparaît
✅ Vérifier: Focus sur le nouveau paragraphe

3. Cliquer sur "Heading"
✅ Vérifier: Nouveau heading créé
✅ Vérifier: Menu initial disparaît

4. Taper du contenu dans le bloc créé
✅ Vérifier: Menu initial ne réapparaît pas

📈 Comparaison Avant/Après

Aspect Avant Après
Toolbar paragraphe Inline avec 8+ boutons Aucune (clean)
Boutons superposés Oui Non
Placeholder "Start writing or type '/', '@'" "Type '/' for commands"
Accès commandes Via toolbar ou / Via / uniquement
Drag précision ~50% succès ⚠️ ~95% succès
Insert entre blocs Difficile Facile
Zones de drop Floues ⚠️ Claires (50/50)
Feedback visuel Flèche bleue Flèche bleue

🚀 Prochaines Étapes

Immédiat (À Faire)

  1. Intégrer menu initial dans editor-shell:

    • Détecter double-clic sur zones vides
    • Afficher BlockInitialMenuComponent
    • Créer bloc selon choix utilisateur
    • Masquer menu après création
  2. Tester drag & drop amélioré:

    • Vérifier insertion précise entre blocs
    • Tester avec différents types de blocs
    • Vérifier avec colonnes

Future (Optionnel)

  1. Améliorer la détection de double-clic:

    • Ajouter zones cliquables entre blocs (overlays invisibles)
    • Afficher un + au hover pour indiquer où on peut ajouter un bloc
  2. Animations:

    • Transition smooth quand menu initial apparaît
    • Highlight du nouveau bloc créé
  3. Raccourcis clavier:

    • Ctrl+/ pour ouvrir menu initial à la position du curseur

📚 Fichiers Modifiés

Modifiés

  1. src/app/editor/components/block/blocks/paragraph-block.component.ts

    • Retrait de BlockInlineToolbarComponent
    • Simplification du template
    • Nettoyage du code (isHovered, onToolbarAction)
  2. src/app/editor/services/drag-drop.service.ts

    • Amélioration de computeOverIndex()
    • Zones de drop plus précises (50% top / 50% bottom)

Créés

  1. src/app/editor/components/block/block-initial-menu.component.ts
    • Nouveau composant menu initial
    • Icônes pour tous les types de blocs
    • Prêt pour intégration

Documentation

  1. docs/PARAGRAPH_IMPROVEMENTS.md (ce fichier)

Status

Compilé:
Testé manuellement: (à tester par l'utilisateur)
Prêt pour production: Presque (manque intégration menu initial)


🎉 Résumé

Problèmes résolus:

  1. Toolbar inline retirée - Interface paragraphe propre
  2. Boutons non-superposés - Seul le bouton menu de block-host visible
  3. Drag & drop précis - Insertion facile entre n'importe quels blocs
  4. Menu initial créé - Prêt pour double-clic (nécessite intégration)

À faire:

  • Intégrer BlockInitialMenuComponent pour double-clic entre lignes
  • Tester extensivement le nouveau drag & drop

Rafraîchissez le navigateur et testez les améliorations! 🚀