diff --git a/frontend/js/pane-manager.js b/frontend/js/pane-manager.js index f6600f7..968d62c 100644 --- a/frontend/js/pane-manager.js +++ b/frontend/js/pane-manager.js @@ -69,11 +69,11 @@ function createPaneTabManager(paneId) { `; btns.querySelector('[data-action="split-right"]').addEventListener('click', (e) => { e.stopPropagation(); - if (window.PaneManager) window.PaneManager.splitRight(); + if (window.PaneManager && window.PaneManager._hasAnyTab()) window.PaneManager.splitRight(); }); btns.querySelector('[data-action="split-down"]').addEventListener('click', (e) => { e.stopPropagation(); - if (window.PaneManager) window.PaneManager.splitDown(); + if (window.PaneManager && window.PaneManager._hasAnyTab()) window.PaneManager.splitDown(); }); this._tabBar.appendChild(btns); if (typeof safeCreateIcons === 'function') safeCreateIcons(); @@ -539,8 +539,23 @@ function createPaneTabManager(paneId) { menu.addEventListener('click', (e) => { const action = e.target.closest('.context-menu-item')?.dataset.action; if (action === 'moveTo') return; // handled by hover - if (action === 'splitRight') { if (pm) { pm.splitRight(); menu.remove(); return; } } - else if (action === 'splitDown') { if (pm) { pm.splitDown(); menu.remove(); return; } } + if (action === 'splitRight') { + if (pm && pm._hasAnyTab()) { + pm.splitRight(); + // Transfer this specific tab to the new pane + const newPaneId = pm.panes.length - 1; + pm.transferTab(this.paneId, tabId, newPaneId); + menu.remove(); return; + } + } + else if (action === 'splitDown') { + if (pm && pm._hasAnyTab()) { + pm.splitDown(); + const newPaneId = pm.panes.length - 1; + pm.transferTab(this.paneId, tabId, newPaneId); + menu.remove(); return; + } + } else if (action === 'closePane') { if (pm) { pm.closeActivePane(); menu.remove(); return; } } else if (action === 'close') this.close(tabId); else if (action === 'closeOthers') this.closeOthers(tabId); @@ -660,20 +675,60 @@ const PaneManager = { // ------------------------------------------------------------------ splitRight() { if (this.panes.length >= PANE_MAX) return; + // Don't split if no tab is open anywhere + if (!this._hasAnyTab()) return; this.layout = 'horizontal'; - if (this.panes.length === 0) this._buildGrid(2); - else this._addPane(); + if (this.panes.length === 0) { + this._buildGrid(2); + // Copy active tab to the new pane + this._copyActiveTabToNewPane(); + } else { + this._addPane(); + } this._persist(); }, splitDown() { if (this.panes.length >= PANE_MAX) return; + if (!this._hasAnyTab()) return; this.layout = 'vertical'; - if (this.panes.length === 0) this._buildGrid(2); - else this._addPane(); + if (this.panes.length === 0) { + this._buildGrid(2); + this._copyActiveTabToNewPane(); + } else { + this._addPane(); + } this._persist(); }, + /** Check if any pane has at least one tab */ + _hasAnyTab() { + if (!this.isSplit()) { + // Check singleton in single-pane mode + if (window._singletonTabManager && window._singletonTabManager._tabs.length > 0) + return true; + return false; + } + for (const tm of Object.values(this.tabManagers)) { + if (tm._tabs && tm._tabs.length > 0) return true; + } + return false; + }, + + /** Copy the active tab to the newly created last pane */ + _copyActiveTabToNewPane() { + const newPaneId = this.panes.length - 1; + const srcTm = this.tabManagers[this.activePaneId]; + const dstTm = this.tabManagers[newPaneId]; + if (!srcTm || !dstTm || !srcTm._activeTabId) return; + const cache = srcTm._tabCache[srcTm._activeTabId]; + if (cache) { + setTimeout(() => { + dstTm.open(cache.vault, cache.path); + }, 150); + } + }, + // ------------------------------------------------------------------ // Close pane // ------------------------------------------------------------------ @@ -1268,11 +1323,23 @@ if (typeof window !== 'undefined') { document.addEventListener('keydown', (e) => { if (e.ctrlKey && e.altKey && !e.shiftKey && e.key === '\\') { e.preventDefault(); - PaneManager.splitRight(); + if (PaneManager._hasAnyTab()) { + PaneManager.splitRight(); + // Transfer active tab to new pane + const tm = PaneManager.getActiveTabManager(); + if (tm && tm._activeTabId) { + setTimeout(() => { + const newPaneId = PaneManager.panes.length - 1; + PaneManager.transferTab(PaneManager.activePaneId === newPaneId ? 0 : PaneManager.activePaneId, tm._activeTabId, newPaneId); + }, 200); + } + } } if (e.ctrlKey && e.altKey && e.shiftKey && e.key === '\\') { e.preventDefault(); - PaneManager.splitDown(); + if (PaneManager._hasAnyTab()) { + PaneManager.splitDown(); + } } // Close active pane if (e.ctrlKey && e.altKey && !e.shiftKey && (e.key === 'w' || e.key === 'W') && PaneManager.isSplit()) { diff --git a/frontend/js/ui.js b/frontend/js/ui.js index 077efaf..36c0c5d 100644 --- a/frontend/js/ui.js +++ b/frontend/js/ui.js @@ -2351,8 +2351,22 @@ export const TabManager = { menu.addEventListener("click", (e) => { const action = e.target.closest(".context-menu-item")?.dataset.action; - if (action === "splitRight") { if (window.PaneManager) { window.PaneManager.splitRight(); menu.remove(); return; } } - else if (action === "splitDown") { if (window.PaneManager) { window.PaneManager.splitDown(); menu.remove(); return; } } + if (action === "splitRight") { + if (window.PaneManager && window.PaneManager._hasAnyTab && window.PaneManager._hasAnyTab()) { + window.PaneManager.splitRight(); + const newPaneId = window.PaneManager.panes.length - 1; + window.PaneManager.transferTab(0, tabId, newPaneId); + menu.remove(); return; + } + } + else if (action === "splitDown") { + if (window.PaneManager && window.PaneManager._hasAnyTab && window.PaneManager._hasAnyTab()) { + window.PaneManager.splitDown(); + const newPaneId = window.PaneManager.panes.length - 1; + window.PaneManager.transferTab(0, tabId, newPaneId); + menu.remove(); return; + } + } else if (action === "closePane") { if (window.PaneManager) { window.PaneManager.closeActivePane(); menu.remove(); return; } } else if (action === "close") this.close(tabId); else if (action === "closeOthers") this.closeOthers(tabId);