Files
Momento/docs/story-nextgen-editor.md
Antigravity 96e7902f01
Some checks failed
CI / Lint, Unit Tests & Build (push) Failing after 1m22s
CI / Deploy production (on server) (push) Has been skipped
feat: publication IA (magazine/brief/essay) + fixes critique
Publication IA:
- 4 templates (magazine, brief, essay, simple) avec CSS riche
- Rewrite IA (article/exercises/tutorial/reference/mixed)
- Modération avec timeout 12s + fallback safe
- Quotas publish_enhance par tier (basic=2, pro=15, business=100)
- Détection contenu stale (hash)
- Migration DB publishedContent/publishedTemplate/publishedSourceHash

Fixes:
- cheerio v1.2: Element -> AnyNode (domhandler), decodeEntities cast
- _isShared ajouté au type Note (champ virtuel serveur)
- callout colors PDF export: extraction fonction pure testable
- admin/published: guard note.userId null
- Cmd+S fonctionne en mode dialog (pas seulement fullPage)

i18n:
- 23 clés publish* traduites dans les 15 locales
- Extension Web Clipper: 13 locales mise à jour

Tests:
- callout-colors.test.ts (6 tests)
- note-visible-in-view.test.ts (5 tests)
- entitlements.test.ts + byok-entitlements.test.ts: mock usageLog + unstubAllEnvs
- 199/199 tests passent

Tracker: user-stories.md sync avec sprint-status.yaml
2026-06-28 07:32:57 +00:00

138 lines
9.7 KiB
Markdown

# Story: Éditeur Next-Gen — Poignée Gutter & Base de Données Inline
> **Epic:** Éditeur de Notes et Saisie Intuitive (Next-Gen)
> **Priority:** High
> **Status:** ready-for-dev
> **Depends on:** US-LIVING-BLOCKS (UniqueID et transclusion), US-STRUCTURED-VIEWS (NotebookSchema et propriétés)
> **Blocks:** —
---
## Context
L'éditeur de notes actuel de Memento est construit sur [rich-text-editor.tsx](file:///home/devparsa/dev/Memento/memento-note/components/rich-text-editor.tsx) avec Tiptap/ProseMirror. Bien qu'il supporte des fonctionnalités avancées (Blocs Vivants, Résonance Sémantique), l'interaction utilisateur de saisie reste celle d'un traitement de texte classique (document linéaire à curseur unique).
Pour offrir une expérience de saisie supérieure à celle de Notion (plus performante, plus fluide à l'écriture) tout en conservant les avantages de la manipulation de blocs, nous implémentons une approche hybride :
1. **Gutter & Drag Handle Flottant :** Au lieu d'avoir un composant React lourd pour chaque paragraphe (comme dans Notion), un unique bouton de poignée de glissement suit le curseur de la souris dans la marge de l'éditeur en ProseMirror pur, éliminant tout décalage à la saisie.
2. **Transclusion au Collage :** Faciliter la création de Blocs Vivants en interceptant les liens de blocs copiés et en proposant de les coller en tant que transclusion synchrone.
3. **Bloc Database Inline :** Porter le composant de base de données relationnelle du prototype [ModernBlockNoteEditor.tsx](file:///home/devparsa/dev/Memento/architectural-grid1/src/components/ModernBlockNoteEditor.tsx#L1711) pour permettre aux utilisateurs d'insérer des tableaux/fiches interactives avec Rollups dynamiques directement au sein de leurs notes.
---
## User Stories
### US-1: Poignée de Glissement Gutter Unique (Hover Drag Handle)
**En tant que** rédacteur,
**Je veux** voir apparaître une poignée de glissement discrète dans la marge gauche du bloc que je survole avec ma souris,
**Afin de** pouvoir réordonner mes blocs par glisser-déposer de manière fluide.
#### Critères d'Acceptation :
* **Étant donné** que j'ai une note ouverte dans l'éditeur de Memento
* **Quand** je survole une ligne de texte (paragraphe, titre, liste, citation, etc.) avec mon curseur de souris
* **Alors** une poignée de glissement (`::drag-handle` flottante) apparaît dans le gutter gauche à la hauteur exacte du bloc survolé
* **Et** le bouton suit mes déplacements de souris d'un bloc à l'autre sans latence et sans dupliquer les nœuds DOM (une seule poignée réutilisée)
* **Quand** je clique-glisse sur cette poignée
* **Alors** le bloc ProseMirror entier sous-jacent est sélectionné visuellement et je peux le déplacer vers le haut ou vers le bas, avec un indicateur visuel de la ligne d'insertion
* **Et** la poignée est masquée sur les terminaux mobiles / écrans tactiles pour éviter d'entraver l'ergonomie.
---
### US-2: Menu Action Rapide de Bloc
**En tant que** créateur de contenu,
**Je veux** pouvoir cliquer sur la poignée de bloc pour ouvrir un menu contextuel d'actions rapides,
**Afin de** manipuler la structure de mes documents sans avoir à utiliser les sélections de texte complexes ou des raccourcis clavier obscurs.
#### Critères d'Acceptation :
* **Étant donné** que la poignée de bloc est visible à côté d'un bloc
* **Quand** je clique sur cette poignée
* **Alors** un menu contextuel (dropdown à base de glassmorphism fluide) apparaît
* **Et** il propose les options suivantes :
* `Supprimer` -> Efface le bloc ProseMirror ciblé
* `Dupliquer` -> Duplique le bloc ProseMirror immédiatement en dessous
* `Transformer en` -> Sous-menu pour convertir en : Titre 1, Titre 2, Titre 3, Liste à puces, Liste numérotée, Liste de tâches, Citation, Bloc de code, ou Base de données
* `Copier la référence` -> Génère/copie le lien unique du bloc (utilisant son `UniqueID` Tiptap) dans le presse-papier.
---
### US-3: Transclusion intelligente au Collage (Smart Paste)
**En tant que** chercheur,
**Je veux** pouvoir coller un lien de bloc copié et le transformer instantanément en bloc connecté synchrone,
**Afin de** lier et synchroniser des informations à travers différentes notes sans effort manuel.
#### Critères d'Acceptation :
* **Étant donné** que j'ai copié la référence d'un bloc (contenant l'ID de la note source et le `blockId` unique du paragraphe)
* **Quand** je colle (Ctrl+V ou Cmd+V) ce lien dans un paragraphe vide d'une autre note
* **Alors** un petit menu interactif en ligne s'affiche : *"Coller en tant que Bloc Connecté (Live)"* ou *"Coller en tant que texte / lien simple"*
* **Quand** je sélectionne *"Bloc Connecté"*,
* **Alors** le bloc ProseMirror est remplacé par un nœud de type `liveBlock` (provenant de notre [LiveBlockExtension](file:///home/devparsa/dev/Memento/memento-note/components/tiptap-live-block-extension.tsx#L159)) synchronisant le contenu en temps réel.
---
### US-4: Base de Données Inline (`structuredViewBlock`)
> ⚠️ **Rejeté et supprimé :** l'ancien bloc marketing « Auteurs & Œuvres » (`tiptap-database-block-extension.tsx`, `database-block-editor.tsx`, `database-block-types.ts`).
> **Spec historique embed-only carnet :** [`docs/story-nextgen-editor-us4-redesign.md`](./story-nextgen-editor-us4-redesign.md) — **non retenue** ; le produit livré est le **dual-mode** ci-dessous.
**En tant que** rédacteur,
**Je veux** insérer un tableau interactif type Notion directement dans ma note, avec option de le lier au carnet structuré,
**Afin de** gérer des données en contexte ou synchroniser avec les notes du carnet.
#### Deux modes (même nœud TipTap `structuredViewBlock`) :
| Mode | Déclencheur par défaut | Données | UI |
|------|------------------------|---------|-----|
| **Base locale autonome** | `/database`, `/vue`, menu « Transformer en → Base de données » | Colonnes/lignes dans `localColumnsJson` / `localRowsJson` (attrs TipTap) | Tableau éditable, analyses, Memory Echo, conversion en carnet |
| **Vue liée au carnet** | Bouton « Lier à un carnet » ou sélecteur de carnet | API schéma + notes du carnet (`notebookId`) | Table / Galerie via `StructuredViewsContainer` |
#### Critères d'Acceptation :
* **Étant donné** une note ouverte, **quand** je tape `/database` ou `/vue`, **alors** un bloc **base locale autonome** s'insère (tableau vide éditable, pas de démo Auteurs/Œuvres).
* **Étant donné** un bloc local, **quand** je clique « Lier à un carnet », **alors** je peux afficher la vue structurée d'un carnet (table/galerie, données réelles).
* **Étant donné** un carnet lié sans schéma, **alors** callout vers le wizard — pas de crash.
* **Étant donné** un ancien `databaseBlock` HTML, **alors** migration vers bloc local par défaut — note charge sans crash.
* **Étant donné** n'importe quelle locale (dont `fa`), **alors** tous les libellés UI passent par i18n (`structuredViewBlock.*`) — pas de texte FR en dur dans l'embed.
---
## Spécifications Techniques d'Implémentation
### 1. Structure du Nœud `structuredViewBlock` (TipTap) — *US-4*
Extension `StructuredViewBlockExtension` (`tiptap-structured-view-block-extension.tsx`) :
- Attributs partagés : `notebookId`, `displayMode` ('table'|'gallery'), `filterJson`
- Mode local : `isLocal: true`, `localColumnsJson`, `localRowsJson` (insertion par défaut)
- Mode carnet : `isLocal: false`, `notebookId` renseigné
- NodeView React → `structured-view-block-embed.tsx` (dual-mode, i18n complet)
### 2. Le Plugin Drag Handle & Gutter en ProseMirror *(US-1, inchangé)*
Développer un plugin custom dans `/components/tiptap-drag-handle-plugin.ts` :
* Attacher un écouteur `mouseover` et `mousemove` sur l'éditeur ProseMirror.
* Utiliser `view.posAtCoords` pour localiser le nœud survolé.
* Repositionner l'élément HTML de la poignée en modifiant ses styles CSS `top` et `left`.
* Gérer le glissement avec `@tiptap/extension-drag-handle-react` (spec officielle).
### 3. Fichiers à modifier / créer / supprimer :
* `[NEW]` `memento-note/components/tiptap-drag-handle-plugin.ts` — Plugin Gutter (US-1)
* `[LIVRÉ]` `memento-note/components/tiptap-structured-view-block-extension.tsx` — Nœud dual-mode
* `[LIVRÉ]` `memento-note/components/structured-view-block-embed.tsx` — UI base locale + vue carnet
* `[DELETE]` legacy `database-block-*` (Auteurs & Œuvres)
* `[MODIFY]` `memento-note/locales/en.json` + `fr.json` — clés `structuredViewBlock.*` (i18n embed)
* `[MODIFY]` `memento-note/components/note-content-area.tsx``notebookId` → éditeur
* `[MODIFY]` `memento-note/components/rich-text-editor.tsx` — slash `/database` + `/vue`
* `[MODIFY]` `memento-note/components/block-action-menu.tsx` — « Transformer en → Base de données »
* `[MODIFY]` `memento-note/app/globals.css` — Gutter, poignée, glassmorphic dropdowns
---
## Plan de Vérification
### Tests Manuels :
1. **Vérification Gutter :** Survoler des textes longs et vérifier que la poignée se positionne correctement à gauche. Glisser un paragraphe sur un autre et valider le réordonnancement.
2. **Vérification Menu :** Cliquer sur la poignée, dupliquer le bloc, supprimer le bloc, et le transformer en d'autres types.
3. **Vérification Paste :** Copier une référence de bloc, la coller, et vérifier que la transclusion est proposée et s'insère sous forme de `LiveBlock`.
4. **Vérification Base inline (US-4) :**
- `/database` ou `/vue` → base locale autonome (tableau éditable, design actuel).
- « Lier à un carnet » → vue table/galerie du carnet choisi.
- Carnet sans schéma → callout wizard.
- Ancien `databaseBlock` → charge sans crash.
- Locale `fa` → libellés i18n, RTL (`dir="auto"`).