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

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 Memento 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 :

  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 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) 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.mdnon 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.tsxnotebookId → é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").