- ROADMAP: ne garde que le travail a venir + index compact du complete (995 -> ~155 lignes); detail deplace vers docs/features/ et docs/archive/ - docs/features/: fiches detaillees #74, #75, #76, #77, #78, #79 - docs/archive/COMPLETED_v1-v2.md: detail des items courts livres - CHANGELOG: alignement sur les tags (2.0.0 date, 2.2.0/2.2.1 ajoutes, Unreleased = travail #79 post-2.2.1) - AGENTS.md + docs/DELIVERY_WORKFLOW.md: methode de livraison unique (Definition of Done) referencee par ROADMAP, CONTRIBUTING, ISSUES_TODOLIST
7.2 KiB
#75 — Éditeur multi-panneaux (Split View)
Statut : ✅ Terminé — 100% implémenté + 37 tests E2E (16 split-view.spec.js + 21 split-view-matrix.spec.js, 2026-09-08) Effort : 5-7 jours (réalisé) | Impact : 🟡 Références : Roadmap · Changelog — 2.1.0
-
Fichiers clés :
frontend/js/pane-manager.js(1082 loc),frontend/js/viewer.js(modifié),frontend/js/ui.js(modifié),frontend/js/dashboard.js(modifié),frontend/js/palette.js(modifié),frontend/style.css(modifié),tests/test_pane_manager.py(22 tests) -
Description : Système de panneaux divisés permettant d'afficher plusieurs documents côte à côte ou superposés, à la manière d'un éditeur de code (VS Code). Drag & drop des onglets entre les panneaux, drag-to-split, menu contextuel, raccourcis clavier, palette de commandes.
-
Architecture :
- PaneManager — orchestre la grille de panneaux (1-4), crée/détruit les instances PaneTabManager
- PaneTabManager (factory
createPaneTabManager(paneId)) — chaque panneau a son instance indépendante avec ses propres onglets, cache, état - Singleton TabManager — délègue automatiquement vers le PaneTabManager actif quand en mode split ; gère les onglets en single-pane
- Migration automatique — les onglets migrent singleton→PaneTabManager au premier split, et inversement au collapse
- getContentArea() — helper global dans viewer.js, priorise
window._activePaneContentArea(set par PaneTabManager)
-
Implémenté :
A. PaneManager — Gestionnaire de panneaux
- A1. Module
PaneManager+ factorycreatePaneTabManager— état indépendant par panneau - A2. Création dynamique du DOM —
.pane-gridavec.pane-container, IDs suffixés-N - A3. Redimensionnement — drag handles, double-clic reset 50/50, contrainte 20-80%, localStorage
- A4. Indépendance des panneaux — chaque panneau a ses propres onglets, scroll, cache, source view
B. Refactoring du TabManager
- B1. Découplage du DOM —
init(tabBar, tabList, contentArea)par paramètre - B2. Factory
createPaneTabManager(paneId)— instances indépendantes - B3. Compatibilité ascendante — pane 0 réutilise les IDs existants, panes 1+ suffixés
-N - B4. Synchronisation state global —
setActivePane()met à jourcurrentVault/currentPath
C. Actions de division
- C1. Menu contextuel — « Diviser à droite », « Diviser en bas », « Fermer le panneau »
- C1b. Sous-menu « Déplacer vers... » — flyout hover listant les autres panneaux
- C2. Raccourcis clavier —
Ctrl+Alt+\(split R),Ctrl+Alt+Shift+\(split D),Ctrl+Alt+W(close pane),Ctrl+Shift+Alt+W(close others),Ctrl+Alt+←/→/↑/↓(navigate) - C3. Boutons dans la barre d'onglets — ⊞→ et ⊞↓ visibles au survol
- C4. Fermeture panneau — retour single-pane si dernier, focus voisin, onglets perdus (pas déplacés)
D. Drag & Drop
- D1. Drag cross-pane —
text/plainJSON{paneId, tabId, index}, indicateurs visuels - D2. Drag depuis l'arborescence — format
tree:{vault,path}, drop sur panneau spécifique - D3. Drag-to-split — zone droite 28% → split right, zone basse 28% → split down, overlay bleu
E. Rendu et performance
- E1. Rendu indépendant —
window._activePaneContentAreaoverride pourrenderFile() - E2. Cache de contenu — chaque PaneTabManager a son propre
_tabCache, pas de refetch - E3. Rendu paresseux — contenu masqué via
display:nonesur panneaux inactifs - E4. Verrouillage éditeur — même fichier déjà ouvert ailleurs → focus le panneau existant
F. CSS & Design
- F1-F5. Grid layout, resize handles avec hover accent, barre onglets par panneau, variables CSS (dark/light), responsive <768px
G. Persistance et restauration
- G1. localStorage
obsigate-panes— layout, panes[{id, width, activeTab, tabs[]}] - G2. Restauration au chargement — reconstruction grille + onglets + activation
- G3. Reset dans la palette de commandes — « 🔄 Réinitialiser les panneaux »
H. Compatibilité
- H1. Palette de commandes — « Diviser à droite », « Diviser en bas », « Fermer le panneau », « Panneau suivant/précédent » (catégorie Panneaux)
- H2. Pop-out inchangé
- H3. Mermaid scoped au content-area
- H4. AI Editor en modale (inchangé)
- H5. Ctrl+S par panneau
I. Tests
- I1. 22 tests statiques (structure, CSS, brace balance, régression backend)
- I4. 307 tests de régression passent
- I2. Tests d'intégration frontend (JSDOM) —
tests/frontend/pane-manager.test.mjs(9 tests) - I3. Tests E2E Playwright (#58) — 2026-09 :
split-view.spec.js(16) +split-view-matrix.spec.js(21) = 37 tests verts en local + CI
Reste à faire
- C1b. Sous-menu « Déplacer vers... » dans le menu contextuel des onglets
- D2. Drag & drop depuis l'arborescence vers un panneau spécifique
- E3. Rendu paresseux (mémoire) — contenu masqué via
display:nonesur panneaux inactifs - E4. Verrouillage éditeur multi-panneau — même fichier ouvert dans 2 panneaux → focus le panneau existant
- G3. Bouton reset dans la palette de commandes (🔄 Réinitialiser les panneaux)
- I2. Tests d'intégration frontend (JSDOM) —
tests/frontend/pane-manager.test.mjs(9 tests, 100% verts) - I3. Tests E2E Playwright — matrice complète ouverture/fermeture couverte (voir split-view-matrix.spec.js)
Matrice de couverture ouverture/fermeture (validée 2026-09-08, 37/37 verts)
| Cas | Surface testée | Spec |
|---|---|---|
| Ouverture fichier → onglet | clic arbre, double-clic preview vs persistant | split-view |
| Split droit | raccourci Ctrl+Alt+\ · bouton ⊞→ · menu contextuel · palette · drag-to-split bord droit | les 5 |
| Split bas | raccourci Ctrl+Alt+Shift+\ · bouton ⊞↓ · menu contextuel · drag-to-split bord bas | les 4 |
| Déplacer onglet | drag cross-pane · flyout « Déplacer vers... » · drag depuis arbre vers panneau | les 3 |
| Navigation | Ctrl+Alt+←/→ (horizontal) · Ctrl+Alt+↑/↓ (vertical) · palette suivant/précédent | les 3 |
| Fermeture onglet | bouton X · double-clic · clic molette · Ctrl+W (single) | les 4 |
| Fermeture menu ctx | Fermer · Fermer les autres · Fermer à droite · Fermer tout → dashboard | les 4 |
| Fermeture panneau | Ctrl+Alt+W (clavier) · menu « Fermer le panneau » · Ctrl+Shift+Alt+W (autres) · auto-collapse panneau vidé (C4) · fermeture pane 0 → voisin survit · onglets du panneau fermé perdus (documenté) | les 5 |
| Persistance | layout restauré au reload · reset palette vide localStorage | les 2 |
| Edge | plafond 4 panneaux (PANE_MAX) · pas de doublon à la réouverture (E4) | les 2 |
Non couvert par E2E (hors périmètre ouverture/fermeture) : poignée de redimensionnement drag/dblclick-reset (A3) — logique vérifiée par les 22 tests statiques + JSDOM.