feat: finalisation split view #75 — boutons, nav clavier, palette, ROADMAP
CI / lint (push) Failing after 12s
CI / test (push) Has been skipped
CI / build (push) Has been skipped
CI / e2e (push) Has been skipped
CI / security (push) Successful in 13s
Desktop Build / build-windows (push) Has been cancelled
Desktop Build / build-linux (push) Has been cancelled

Ajouts:
- C3: Boutons Split ⊞→ ⊞↓ dans la barre d'onglets (visibles au survol)
- C2: Ctrl+Alt+←/→/↑/↓ navigation entre panneaux
- C2: Ctrl+Shift+Alt+W fermer tous les autres panneaux
- H1: 5 commandes palette (Split R/D, Close Pane, Focus Next/Prev)
- ROADMAP.md: section 75 mise à jour avec statut 80% complété

CSS: .tab-split-buttons, .tab-split-btn avec opacity hover
This commit is contained in:
2026-07-28 10:08:11 -04:00
parent ed5cf597f9
commit 804e6313b3
4 changed files with 160 additions and 118 deletions
+57
View File
@@ -46,6 +46,37 @@ function createPaneTabManager(paneId) {
this._tabList = document.getElementById('tab-list-' + paneId);
if (!this._contentArea)
this._contentArea = document.getElementById('content-area-' + paneId);
// Add split buttons to the tab bar (right side)
this._ensureSplitButtons();
},
_ensureSplitButtons() {
if (!this._tabBar) return;
// Remove existing split buttons if any
const existing = this._tabBar.querySelector('.tab-split-buttons');
if (existing) existing.remove();
const btns = document.createElement('div');
btns.className = 'tab-split-buttons';
btns.innerHTML = `
<button class="tab-split-btn" title="Diviser à droite (Ctrl+Alt+\\)" data-action="split-right">
<i data-lucide="panel-right" style="width:13px;height:13px"></i>
</button>
<button class="tab-split-btn" title="Diviser en bas (Ctrl+Alt+Shift+\\)" data-action="split-down">
<i data-lucide="panel-bottom" style="width:13px;height:13px"></i>
</button>
`;
btns.querySelector('[data-action="split-right"]').addEventListener('click', (e) => {
e.stopPropagation();
if (window.PaneManager) window.PaneManager.splitRight();
});
btns.querySelector('[data-action="split-down"]').addEventListener('click', (e) => {
e.stopPropagation();
if (window.PaneManager) window.PaneManager.splitDown();
});
this._tabBar.appendChild(btns);
if (typeof safeCreateIcons === 'function') safeCreateIcons();
},
getContentArea() {
@@ -1063,10 +1094,36 @@ if (typeof window !== 'undefined') {
e.preventDefault();
PaneManager.splitDown();
}
// Close active pane
if (e.ctrlKey && e.altKey && !e.shiftKey && (e.key === 'w' || e.key === 'W') && PaneManager.isSplit()) {
e.preventDefault();
PaneManager.closeActivePane();
}
// Close all other panes
if (e.ctrlKey && e.shiftKey && e.altKey && (e.key === 'w' || e.key === 'W') && PaneManager.isSplit()) {
e.preventDefault();
PaneManager.closeOtherPanes();
}
// Navigate between panes
if (e.ctrlKey && e.altKey && PaneManager.isSplit()) {
if (e.key === 'ArrowRight') {
e.preventDefault();
const next = (PaneManager.activePaneId + 1) % PaneManager.panes.length;
PaneManager.setActivePane(next);
} else if (e.key === 'ArrowLeft') {
e.preventDefault();
const prev = (PaneManager.activePaneId - 1 + PaneManager.panes.length) % PaneManager.panes.length;
PaneManager.setActivePane(prev);
} else if (e.key === 'ArrowDown' && PaneManager.layout === 'vertical') {
e.preventDefault();
const next = (PaneManager.activePaneId + 1) % PaneManager.panes.length;
PaneManager.setActivePane(next);
} else if (e.key === 'ArrowUp' && PaneManager.layout === 'vertical') {
e.preventDefault();
const prev = (PaneManager.activePaneId - 1 + PaneManager.panes.length) % PaneManager.panes.length;
PaneManager.setActivePane(prev);
}
}
});
// Init — wait for DOM + singleton TabManager to be ready
setTimeout(() => {