Phase 2 : mind map bilaterale, relations, templates et Markdown
Format .mmap v4 : `node.side` (cote d'une branche de niveau 1) et `MindMap.relations` (relations secondaires). Migration v3 -> v4 sans perte, les cartes v1/v2/v3 restent ouvrables telles quelles. Une relation est une connexion purement visuelle : elle ne touche jamais parentId, order, les enfants, le repli ni l'auto-layout. `withEdges()` continue de deriver les liens de parentId et se contente de retirer les relations dont une extremite a disparu. Mind map bilaterale : repartition gloutonne et deterministe des branches selon la taille des sous-arbres, heritage du cote par sous-arbre, deux passes dagre recalees sur la racine. Choisir une disposition ne deplace plus la carte : seul Reorganiser applique. Ajoute aussi une galerie de huit modeles locaux, l'import Markdown (fichier ou texte, nouvelle carte ou sous-arbre) reutilisant l'analyseur d'outline existant, et l'export Markdown de la hierarchie. Corrige un bug de rendu : React Flow ne remesure pas les poignees quand elles changent de cote, ce qui faisait disparaitre les liens concernes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
112
README.md
112
README.md
@@ -227,10 +227,36 @@ double-clic, undo/redo, copier/coller, duplication, sauvegarde automatique.
|
||||
Bezier, branches repliables avec compteur d'elements masques.
|
||||
|
||||
**Auto-layout**, uniquement sur demande : mind map droite, mind map gauche,
|
||||
arbre horizontal, arbre vertical. L'espacement est configurable (distance
|
||||
parent/enfant et espacement entre branches), avec les presets Compact, Normal
|
||||
et Aere. Modifier l'espacement ne deplace rien tant que l'organisation n'est pas
|
||||
relancee.
|
||||
mind map bilaterale, arbre horizontal, arbre vertical. L'espacement est
|
||||
configurable (distance parent/enfant et espacement entre branches), avec les
|
||||
presets Compact, Normal et Aere. Choisir une disposition ou modifier
|
||||
l'espacement ne deplace rien : c'est *Reorganiser* qui applique, ce qui protege
|
||||
les positions placees a la main.
|
||||
|
||||
**Mind map bilaterale** : la racine reste au centre, les branches de niveau 1 se
|
||||
repartissent a gauche et a droite, et tous les descendants heritent du cote de
|
||||
leur branche. La repartition automatique equilibre les deux cotes selon la
|
||||
taille des sous-arbres ; le cote se change ensuite a la main (*Placer la branche
|
||||
a gauche / a droite*).
|
||||
|
||||
**Relations secondaires** : une connexion visuelle entre deux noeuds
|
||||
quelconques, independante de la hierarchie. Elle ne modifie ni le parent, ni
|
||||
l'ordre, ni le repli, et l'auto-layout l'ignore totalement. Libelle libre,
|
||||
trace (Bezier, courbe, droite), couleur, epaisseur, trait plein ou pointille,
|
||||
fleches aux deux extremites. Une relation dont une extremite est masquee par un
|
||||
repli disparait de l'affichage et revient au deploiement.
|
||||
|
||||
**Modeles** : galerie locale de huit modeles (carte vide, brainstorming, gestion
|
||||
de projet, architecture IT, reunion, SWOT, plan d'etude, planification
|
||||
personnelle). Choisir un modele en cree une copie : l'original n'est jamais
|
||||
modifie, et la carte obtenue est une carte comme les autres.
|
||||
|
||||
**Markdown** : import d'un fichier `.md` ou d'un texte colle, comme nouvelle
|
||||
carte depuis le tableau de bord ou comme sous-arbre d'un noeud existant. Les
|
||||
titres et les listes construisent la hierarchie ; les paragraphes et les blocs
|
||||
de code rejoignent la note du noeud, en texte brut. Export inverse en `.md` :
|
||||
contenu et hierarchie uniquement, sans positions ni couleurs, avec un
|
||||
avertissement si la carte contient des relations secondaires.
|
||||
|
||||
**Proprietes du noeud**, regroupees en sections repliables (Contenu,
|
||||
Typographie, Apparence, Mise en page, Branche) : texte, icone, URL, notes ;
|
||||
@@ -274,7 +300,7 @@ theme ne supprime jamais une personnalisation explicite d'un noeud.
|
||||
et mise en evidence temporaire du noeud, depliage automatique des branches
|
||||
repliees.
|
||||
|
||||
**Exports** : `.mmap` (format natif), PNG (x1, x2, fond transparent), SVG, PDF
|
||||
**Exports** : `.mmap` (format natif), Markdown (`.md`), PNG (x1, x2, fond transparent), SVG, PDF
|
||||
(A4/A3, portrait/paysage, marges, adapter a une page ou taille reelle, fond,
|
||||
titre, date), impression via `@media print`.
|
||||
|
||||
@@ -326,14 +352,20 @@ Le format est en **version 3**.
|
||||
| v1 | format initial | `style.width` devient `layout.width` |
|
||||
| v2 | mise en page des noeuds (`layout`, `iconStyle`, `branch`) | l'ordre des freres est materialise depuis leur position dans `nodes` |
|
||||
| v3 | ordre explicite des freres (`node.order`) | aucune |
|
||||
| v4 | cote des branches (`node.side`) et relations secondaires (`relations`) | aucune |
|
||||
|
||||
Les fichiers v1 et v2 restent lisibles, et les cartes deja enregistrees dans
|
||||
IndexedDB s'ouvrent sans modification. Le passage en v3 est justifie : l'ordre
|
||||
des freres fait desormais partie de la semantique du document, et un lecteur v2
|
||||
Les fichiers v1, v2 et v3 restent lisibles, et les cartes deja enregistrees dans
|
||||
IndexedDB s'ouvrent sans modification. Le passage en v3 etait justifie : l'ordre
|
||||
des freres fait partie de la semantique du document, et un lecteur v2
|
||||
l'ignorerait en reordonnant silencieusement la carte. Les noeuds sont malgre
|
||||
tout ecrits en parcours de profondeur, freres dans l'ordre, ce qui donne le bon
|
||||
resultat meme a un lecteur qui ignore `order`.
|
||||
|
||||
Le passage en v4 l'est aussi : un lecteur v3 ignorerait `relations` et perdrait
|
||||
donc une partie du document. La migration v3 -> v4 n'a en revanche rien a
|
||||
inventer : aucun cote defini signifie "a repartir automatiquement", aucune
|
||||
relation signifie "aucune". Une carte v3 s'affiche exactement comme avant.
|
||||
|
||||
Toute carte qui entre dans l'editeur passe par le meme point d'entree,
|
||||
`normalizeMapDocument()`, quelle que soit sa provenance :
|
||||
|
||||
@@ -362,6 +394,8 @@ vous la modifiez.
|
||||
"text": "Infrastructure",
|
||||
"position": { "x": 0, "y": 0 },
|
||||
"parentId": null,
|
||||
"order": 0,
|
||||
"side": "right",
|
||||
"collapsed": false,
|
||||
"icon": "\ud83d\udda5\ufe0f",
|
||||
"url": "https://exemple.fr",
|
||||
@@ -389,6 +423,19 @@ vous la modifiez.
|
||||
}
|
||||
],
|
||||
"edges": [{ "id": "e-a-b", "source": "a", "target": "b" }],
|
||||
"relations": [
|
||||
{
|
||||
"id": "r-uuid",
|
||||
"sourceId": "a",
|
||||
"targetId": "b",
|
||||
"label": "depend de",
|
||||
"style": "bezier",
|
||||
"color": "#a855f7",
|
||||
"width": 2,
|
||||
"dashed": true,
|
||||
"markerEnd": "arrow"
|
||||
}
|
||||
],
|
||||
"viewport": { "x": 0, "y": 0, "zoom": 1 },
|
||||
"settings": {
|
||||
"theme": "default",
|
||||
@@ -398,11 +445,21 @@ vous la modifiez.
|
||||
"layoutSpacing": { "parentGap": 100, "siblingGap": 50 },
|
||||
"snapToGrid": false,
|
||||
"snapGrid": 20,
|
||||
"alignmentGuides": true
|
||||
"alignmentGuides": true,
|
||||
"dragMovesBranch": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Deux precisions sur ce document :
|
||||
|
||||
- `edges` est **derive** de `parentId` : il est recalcule a chaque modification
|
||||
et n'est jamais une source de verite. `relations`, au contraire, est une
|
||||
donnee a part entiere, que rien ne permet de deduire de la hierarchie.
|
||||
- `side` n'a de sens que sur un enfant direct d'une racine. Tous ses descendants
|
||||
heritent du cote de leur branche, ce qui evite d'entretenir la meme
|
||||
information sur chaque noeud.
|
||||
|
||||
A l'import, le fichier est **valide et normalise** : structure, version, champs
|
||||
essentiels, limite de noeuds, assainissement des URL (`javascript:` et `data:`
|
||||
sont supprimes), rejet des styles invalides. Le contenu n'est jamais execute ni
|
||||
@@ -488,12 +545,17 @@ docker run --rm -v "$PWD/frontend:/app" -w /app node:20-alpine sh -c "npm ci &&
|
||||
Les tests backend couvrent : healthcheck, creation, lecture, mise a jour et
|
||||
suppression d'un partage, refus avec un mauvais jeton de gestion, refus sans
|
||||
jeton, partage inexistant, payload invalide, limites de taille et de noeuds,
|
||||
non-divulgation du jeton de gestion, repli SPA.
|
||||
non-divulgation du jeton de gestion, repli SPA, acceptation des documents v3 et
|
||||
v4 (ordre des freres, cotes, relations) et refus d'une relation incoherente.
|
||||
|
||||
Les tests frontend couvrent : stockage IndexedDB, serialisation et validation
|
||||
d'import, migrations, store Zustand (creation, suppression de branche,
|
||||
undo/redo, groupement du glisser-deposer, copier/coller, duplication, detection
|
||||
de boucle, recherche, auto-layout, lecture seule), assainissement des URL.
|
||||
d'import, migrations v1 -> v4, non-mutation et idempotence de la normalisation,
|
||||
store Zustand (creation, suppression de branche, undo/redo, groupement du
|
||||
glisser-deposer, copier/coller, duplication, detection de boucle, recherche,
|
||||
auto-layout, lecture seule), repartition et heritage des cotes, auto-layout
|
||||
bilateral, relations secondaires (creation, refus, style, repli, duplication,
|
||||
independance vis-a-vis de la hierarchie), analyse et export Markdown, galerie de
|
||||
modeles, assainissement des URL.
|
||||
|
||||
---
|
||||
|
||||
@@ -535,7 +597,8 @@ de boucle, recherche, auto-layout, lecture seule), assainissement des URL.
|
||||
├── hooks/ # routeur minimal, debounce
|
||||
├── components/ # briques d'interface reutilisables
|
||||
├── features/
|
||||
│ ├── editor/ # canvas, noeud, barre d'outils, panneaux, layout, themes
|
||||
│ ├── editor/ # canvas, noeud, barre d'outils, panneaux, layout, bilateral, relations, themes
|
||||
│ ├── templates/ # galerie et definitions des modeles
|
||||
│ ├── maps/ # tableau de bord
|
||||
│ ├── export/ # PNG, SVG, PDF, impression
|
||||
│ └── sharing/ # dialogue de partage, page publique
|
||||
@@ -583,9 +646,24 @@ de boucle, recherche, auto-layout, lecture seule), assainissement des URL.
|
||||
- **Gestion d'un partage** : le jeton de gestion vit dans l'IndexedDB du
|
||||
navigateur d'origine. Depuis un autre appareil, un partage ne peut etre ni mis
|
||||
a jour ni supprime.
|
||||
- **Dispositions reservees** : `mindmap-both`, `organization` et `freeform`
|
||||
existent dans le modele de donnees mais ne sont pas proposees dans
|
||||
l'interface.
|
||||
- **Dispositions reservees** : `organization` et `freeform` existent dans le
|
||||
modele de donnees mais ne sont pas proposees dans l'interface.
|
||||
- **Relations et export Markdown** : l'export `.md` decrit le contenu et la
|
||||
hierarchie. Les relations secondaires n'y ont pas de representation fidele et
|
||||
ne sont pas inventees ; un message le signale au moment de l'export.
|
||||
- **Relations et minimap** : la minimap n'affiche que les noeuds. Les relations
|
||||
y sont invisibles, comme les branches hierarchiques.
|
||||
- **Doublon de relation** : deux relations identiques (meme source vers meme
|
||||
cible) se superposeraient, la seconde serait donc invisible et impossible a
|
||||
selectionner. Une seule est acceptee par couple ; le sens inverse, lui, reste
|
||||
autorise.
|
||||
- **Relation dupliquee** : dupliquer ou coller une branche reporte les relations
|
||||
dont les deux extremites sont dans la branche. Une relation qui sort vers un
|
||||
noeud exterieur n'est pas recreee : rien ne dit que la copie doit viser la
|
||||
meme cible, et le deviner creerait un lien non demande.
|
||||
- **Bilaterale et racines multiples** : le recalage des deux cotes se fait sur
|
||||
la premiere racine. Une carte a plusieurs racines reste affichee, mais les
|
||||
racines suivantes ne sont pas recentrees individuellement.
|
||||
- **Types de noeuds reserves** : `note`, `image`, `group`, `link` et `task` sont
|
||||
acceptes par le format, mais la V1 ne produit que `root` et `standard`.
|
||||
- **Migrations de schema SQLite** : la V1 initialise le schema avec
|
||||
|
||||
Reference in New Issue
Block a user