diff --git a/src/browser/base/content/ZenUIManager.mjs b/src/browser/base/content/ZenUIManager.mjs index cfde08211..46dff2042 100644 --- a/src/browser/base/content/ZenUIManager.mjs +++ b/src/browser/base/content/ZenUIManager.mjs @@ -149,11 +149,7 @@ var gZenUIManager = { }, get newtabButton() { - if (this._newtabButton) { - return this._newtabButton; - } - this._newtabButton = document.getElementById('tabs-newtab-button'); - return this._newtabButton; + return ZenWorkspaces.activeWorkspaceStrip.querySelector('#tabs-newtab-button'); }, _prevUrlbarLabel: null, diff --git a/src/browser/base/zen-components/ZenWorkspaces.mjs b/src/browser/base/zen-components/ZenWorkspaces.mjs index c37cd4921..4a603d441 100644 --- a/src/browser/base/zen-components/ZenWorkspaces.mjs +++ b/src/browser/base/zen-components/ZenWorkspaces.mjs @@ -97,6 +97,47 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature { ); } + get activeWorkspaceStrip() { + const activeWorkspace = this.activeWorkspace; + return document.querySelector(`.zen-workspace-tabs-section[zen-workspace-id="${activeWorkspace}"]`); + } + + get tabboxChildren() { + if (!this.workspaceEnabled || !this._hasInitializedTabsStrip) { + return gBrowser.tabContainer.arrowScrollbox.children; + } + return this.activeWorkspaceStrip.children + } + + async initializeTabsStripSections() { + const tabs = this.tabboxChildren; + const perifery = document.getElementById('tabbrowser-arrowscrollbox-periphery'); + for (const workspace of (await this._workspaces()).workspaces) { + this._createWorkspaceTabsSection(workspace, tabs, perifery); + } + perifery.remove(); + this._hasInitializedTabsStrip = true; + } + + async _createWorkspaceTabsSection(workspace, tabs, perifery) { + const container = gBrowser.tabContainer.arrowScrollbox; + const section = document.createXULElement('vbox'); + section.className = 'zen-workspace-tabs-section'; + section.setAttribute('flex', '1'); + section.setAttribute('zen-workspace-id', workspace.uuid); + container.appendChild(section); + this._organizeTabsToWorkspaceSections(workspace, section, tabs); + section.appendChild(perifery.cloneNode(true)); + } + + _organizeTabsToWorkspaceSections(workspace, section, tabs) { + const workspaceTabs = Array.from(tabs).filter((tab) => tab.getAttribute('zen-workspace-id') === workspace.uuid); + for (const tab of workspaceTabs) { + section.appendChild(tab); + } + this.tabContainer._invalidateCachedTabs(); + } + initializeWorkspaceNavigation() { this._setupAppCommandHandlers(); this._setupSidebarHandlers(); @@ -411,6 +452,7 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature { this.activeWorkspace = activeWorkspace?.uuid; } } + await this.initializeTabsStripSections(); try { if (activeWorkspace) { window.gZenThemePicker = new ZenThemePicker(); @@ -1319,19 +1361,8 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature { // Refresh tab cache this.tabContainer._invalidateCachedTabs(); - let animationDirection; if (previousWorkspace && !onInit && !this._animatingChange) { - animationDirection = - explicitAnimationDirection ?? - (workspaces.workspaces.findIndex((w) => w.uuid === previousWorkspace.uuid) < - workspaces.workspaces.findIndex((w) => w.uuid === window.uuid) - ? 'right' - : 'left'); - } - if (animationDirection) { - // Animate tabs out of view before changing workspace, therefor we - // need to animate in the opposite direction - await this._animateTabs(animationDirection === 'left' ? 'right' : 'left', true); + await this._animateTabs(previousWorkspace, window); } // First pass: Handle tab visibility and workspace ID assignment @@ -1343,9 +1374,6 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature { // Update UI and state await this._updateWorkspaceState(window, onInit); - if (animationDirection) { - await this._animateTabs(animationDirection); - } } get _animateTabsElements() { @@ -1354,35 +1382,31 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature { return [...this.tabContainer.querySelectorAll(selector), ...this.tabContainer.querySelectorAll(extraSelector)]; } - async _animateTabs(direction, out = false) { - this.tabContainer.removeAttribute('dont-animate-tabs'); - const tabsWidth = this.tabContainer.getBoundingClientRect().width; - // order by actual position in the children list to animate - const elements = this._animateTabsElements; - if (out) { - const existingTransform = elements[0].style.transform; - const newTransform = `translateX(${direction === 'left' ? '-' : ''}${tabsWidth}px)`; - return gZenUIManager.motion.animate( - elements, - { - transform: existingTransform ? [existingTransform, newTransform] : newTransform, - }, - { - type: 'spring', - bounce: 0, - duration: 0.12, - } - ); - } - return gZenUIManager.motion.animate( - elements, + async _animateTabs(previousWorkspace, newWorkspace) { + const newWorkspaceContainer = this.tabContainer; + const previousWorkspaceContainer = document.querySelector(`[zen-workspace-id="${previousWorkspace.uuid}"]`); + + const newWorkspaceLeft = newWorkspaceContainer.getBoundingClientRect().left; + gZenUIManager.motion.animate( + newWorkspaceContainer, { - transform: [`translateX(${direction === 'left' ? '-' : ''}${tabsWidth}px)`, 'translateX(0px)'], + transform: [`translateX(${newWorkspaceLeft}px)`, 'translateX(0)'], }, { - duration: 0.15, type: 'spring', bounce: 0, + duration: 0.12, + } + ); + gZenUIManager.motion.animate( + previousWorkspaceContainer, + { + transform: ['translateX(0)', `translateX(-${newWorkspaceLeft}px)`], + }, + { + type: 'spring', + bounce: 0, + duration: 0.12, } ); } diff --git a/src/browser/components/tabbrowser/content/tabs-js.patch b/src/browser/components/tabbrowser/content/tabs-js.patch index 756161868..b0a668a3c 100644 --- a/src/browser/components/tabbrowser/content/tabs-js.patch +++ b/src/browser/components/tabbrowser/content/tabs-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js -index 8aeb244ffca9f48661805f5b7d860b5896055562..bffa5e0be62e73f380adf558c5df3441bde7b604 100644 +index 8aeb244ffca9f48661805f5b7d860b5896055562..ef532d6b5d311cab5bc573c2d0aae6ceab5c1dcf 100644 --- a/browser/components/tabbrowser/content/tabs.js +++ b/browser/components/tabbrowser/content/tabs.js @@ -94,7 +94,7 @@ @@ -101,7 +101,16 @@ index 8aeb244ffca9f48661805f5b7d860b5896055562..bffa5e0be62e73f380adf558c5df3441 ) { delete draggedTab._dragData; return; -@@ -1512,9 +1525,19 @@ +@@ -1498,7 +1511,7 @@ + if (this.#allTabs) { + return this.#allTabs; + } +- let children = Array.from(this.arrowScrollbox.children); ++ let children = Array.from(ZenWorkspaces.tabboxChildren); + // remove arrowScrollbox periphery element + children.pop(); + +@@ -1512,14 +1525,24 @@ } this.#allTabs = [ @@ -122,6 +131,21 @@ index 8aeb244ffca9f48661805f5b7d860b5896055562..bffa5e0be62e73f380adf558c5df3441 return this.#allTabs; } + get allGroups() { +- let children = Array.from(this.arrowScrollbox.children); ++ let children = Array.from(ZenWorkspaces.tabboxChildren); + return children.filter(node => node.tagName == "tab-group"); + } + +@@ -1577,7 +1600,7 @@ + let verticalPinnedTabsContainer = document.getElementById( + "vertical-pinned-tabs-container" + ); +- let children = Array.from(this.arrowScrollbox.children); ++ let children = Array.from(ZenWorkspaces.tabboxChildren); + + let focusableItems = []; + for (let child of children) { @@ -1593,6 +1616,7 @@ } diff --git a/src/toolkit/content/widgets/arrowscrollbox-js.patch b/src/toolkit/content/widgets/arrowscrollbox-js.patch index ebfbd2dec..28739a036 100644 --- a/src/toolkit/content/widgets/arrowscrollbox-js.patch +++ b/src/toolkit/content/widgets/arrowscrollbox-js.patch @@ -1,7 +1,25 @@ diff --git a/toolkit/content/widgets/arrowscrollbox.js b/toolkit/content/widgets/arrowscrollbox.js -index 328c770d275ebbaada8a44438eaf738b1a62d985..95460108c6356408170b8a4a40d55a8f0621756b 100644 +index 328c770d275ebbaada8a44438eaf738b1a62d985..070439e26bfe6a2299aa4b82ee4c434e143e1a20 100644 --- a/toolkit/content/widgets/arrowscrollbox.js +++ b/toolkit/content/widgets/arrowscrollbox.js +@@ -15,7 +15,7 @@ + static get inheritedAttributes() { + return { + "#scrollbutton-up": "disabled=scrolledtostart", +- scrollbox: "orient,align,pack,dir,smoothscroll", ++ scrollbox: "align,pack,dir,smoothscroll", + "#scrollbutton-down": "disabled=scrolledtoend", + }; + } +@@ -26,7 +26,7 @@ + + + +- ++ + + + @@ -98,6 +98,7 @@ let slot = this.shadowRoot.querySelector("slot");