9.7 KiB
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 Momento est construit sur 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 :
- 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.
- 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.
- Bloc Database Inline : Porter le composant de base de données relationnelle du prototype ModernBlockNoteEditor.tsx 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 Momento
- Quand je survole une ligne de texte (paragraphe, titre, liste, citation, etc.) avec mon curseur de souris
- Alors une poignée de glissement (
::drag-handleflottante) 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 dessousTransformer 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éesCopier la référence-> Génère/copie le lien unique du bloc (utilisant sonUniqueIDTiptap) 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
blockIdunique 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) 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— 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
/databaseou/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
databaseBlockHTML, 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,notebookIdrenseigné - 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
mouseoveretmousemovesur l'éditeur ProseMirror. - Utiliser
view.posAtCoordspour localiser le nœud survolé. - Repositionner l'élément HTML de la poignée en modifiant ses styles CSS
topetleft. - 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]legacydatabase-block-*(Auteurs & Œuvres)[MODIFY]memento-note/locales/en.json+fr.json— clésstructuredViewBlock.*(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 :
- 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.
- Vérification Menu : Cliquer sur la poignée, dupliquer le bloc, supprimer le bloc, et le transformer en d'autres types.
- 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. - Vérification Base inline (US-4) :
/databaseou/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").