feat: split view multi-panneaux (#75) — PaneManager intégré avec split right/down, menu contextuel, raccourcis clavier, CSS responsive et tests
CI / lint (push) Failing after 35s
CI / test (push) Has been skipped
CI / build (push) Has been skipped
CI / e2e (push) Has been skipped
CI / security (push) Successful in 15s
Desktop Build / build-windows (push) Has been cancelled
Desktop Build / build-linux (push) Has been cancelled

- PaneManager: splitRight/splitDown avec 1-4 panneaux, persistance localStorage, resize
- Viewer/TabManager pane-aware: fonctions getContentArea/getTabBar/getTabList
- Menu contextuel onglets: actions Diviser à droite / Diviser en bas / Fermer le panneau
- Raccourcis clavier: Ctrl+Alt+\ (split right), Ctrl+Alt+Shift+\ (split down), Ctrl+Alt+W (fermer panneau)
- CSS pane-grid: grille, poignées resize, bordure active pane, responsive (désactivé <768px)
- Tests: 22 nouveaux tests unitaires + régression (307 total, 100% green)
- Déployé sur Docker test (localhost:2021)
This commit is contained in:
2026-07-27 21:06:47 -04:00
parent 0cea78b3b1
commit b27b38d32b
5 changed files with 555 additions and 57 deletions
+87
View File
@@ -1247,6 +1247,93 @@ select {
overflow: hidden;
}
/* --- Multi-Pane Grid (Split View #75) --- */
.pane-grid {
flex: 1;
display: grid;
overflow: hidden;
min-width: 0;
min-height: 0;
}
.pane-container {
display: flex;
flex-direction: column;
overflow: hidden;
min-width: 0;
min-height: 0;
border: 2px solid transparent;
transition: border-color 150ms ease;
}
.pane-container.pane-active {
border-color: var(--accent);
}
.pane-container .tab-bar.pane-tab-bar {
flex-shrink: 0;
}
.pane-container .content-area.pane-content {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: clamp(12px, 2vw, 24px) clamp(12px, 3vw, 24px) 40px;
}
.pane-resize-handle {
width: 4px;
background: var(--border);
transition: background 150ms ease;
position: relative;
z-index: 2;
flex-shrink: 0;
}
.pane-resize-handle:hover {
background: var(--accent);
}
.pane-resize-handle::after {
content: '';
position: absolute;
top: 10%;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
width: 2px;
background: var(--accent);
opacity: 0;
transition: opacity 150ms ease;
}
.pane-resize-handle:hover::after {
opacity: 1;
}
/* Pane active state */
.pane-container.pane-active {
outline: none;
border: 2px solid var(--accent);
}
/* Responsive: disable split view below 768px */
@media (max-width: 768px) {
.pane-grid {
display: flex !important;
flex-direction: column !important;
}
.pane-grid .pane-container:not(:first-child) {
display: none;
}
.pane-grid .pane-resize-handle {
display: none;
}
.pane-container.pane-active {
border-color: transparent;
}
}
/* --- Content Area --- */
.content-area {
flex: 1;