diff --git a/src/browser/base/content/ZenUIManager.mjs b/src/browser/base/content/ZenUIManager.mjs index f669c4924..cdb6c75c0 100644 --- a/src/browser/base/content/ZenUIManager.mjs +++ b/src/browser/base/content/ZenUIManager.mjs @@ -18,6 +18,10 @@ var gZenUIManager = { return document.getElementById('zen-toast-container'); }); + ChromeUtils.defineLazyGetter(this, '_toastContainer', () => { + return document.getElementById('zen-toast-container'); + }); + new ResizeObserver(this.updateTabsToolbar.bind(this)).observe(document.getElementById('TabsToolbar')); new ResizeObserver( @@ -245,6 +249,38 @@ var gZenUIManager = { this._toastContainer.setAttribute('hidden', 'true'); } }, + + // Section: Notification messages + _createToastElement(messageId, options) { + const element = document.createXULElement('vbox'); + const label = document.createXULElement('label'); + document.l10n.setAttributes(label, messageId, options); + element.appendChild(label); + if (options.descriptionId) { + const description = document.createXULElement('label'); + description.classList.add('description'); + document.l10n.setAttributes(description, options.descriptionId, options); + element.appendChild(description); + } + element.classList.add('zen-toast'); + return element; + }, + + async showToast(messageId, options = {}) { + const toast = this._createToastElement(messageId, options); + this._toastContainer.removeAttribute('hidden'); + this._toastContainer.appendChild(toast); + await this.motion.animate(toast, { opacity: [0, 1], scale: [0.8, 1] }, { type: 'spring', duration: 0.3 }); + await new Promise((resolve) => setTimeout(resolve, 3000)); + await this.motion.animate(toast, { opacity: [1, 0], scale: [1, 0.9] }, { duration: 0.2, bounce: 0 }); + const toastHeight = toast.getBoundingClientRect().height; + // 5 for the separation between toasts + await this.motion.animate(toast, { marginBottom: [0, `-${toastHeight + 5}px`] }, { duration: 0.2 }); + toast.remove(); + if (!this._toastContainer.hasChildNodes()) { + this._toastContainer.setAttribute('hidden', 'true'); + } + }, }; var gZenVerticalTabsManager = { @@ -741,4 +777,85 @@ var gZenVerticalTabsManager = { this._tabEdited = null; }, + + renameTabKeydown(event) { + if (event.key === 'Enter') { + let label = this._tabEdited.querySelector('.tab-label-container-editing'); + let input = this._tabEdited.querySelector('#tab-label-input'); + let newName = input.value.trim(); + + // Check if name is blank, reset if so + // Always remove, so we can always rename and if it's empty, + // it will reset to the original name anyway + this._tabEdited.removeAttribute('zen-has-static-label'); + if (newName) { + gBrowser._setTabLabel(this._tabEdited, newName); + this._tabEdited.setAttribute('zen-has-static-label', 'true'); + } else { + gBrowser.setTabTitle(this._tabEdited); + } + + // Maybe add some confetti here?!? + gZenUIManager.motion.animate( + this._tabEdited, + { + scale: [1, 0.98, 1], + }, + { + duration: 0.25, + } + ); + + this._tabEdited.querySelector('.tab-editor-container').remove(); + label.classList.remove('tab-label-container-editing'); + + this._tabEdited = null; + } else if (event.key === 'Escape') { + event.target.blur(); + } + }, + + renameTabStart(event) { + if ( + this._tabEdited || + !Services.prefs.getBoolPref('zen.tabs.rename-tabs') || + Services.prefs.getBoolPref('browser.tabs.closeTabByDblclick') || + !gZenVerticalTabsManager._prefsSidebarExpanded + ) + return; + this._tabEdited = event.target.closest('.tabbrowser-tab'); + if (!this._tabEdited || !this._tabEdited.pinned || this._tabEdited.hasAttribute('zen-essential')) { + this._tabEdited = null; + return; + } + const label = this._tabEdited.querySelector('.tab-label-container'); + label.classList.add('tab-label-container-editing'); + + const container = window.MozXULElement.parseXULToFragment(` + + `); + label.after(container); + const containerHtml = this._tabEdited.querySelector('.tab-editor-container'); + const input = document.createElement('input'); + input.id = 'tab-label-input'; + input.value = this._tabEdited.label; + input.addEventListener('keydown', this.renameTabKeydown.bind(this)); + + containerHtml.appendChild(input); + input.focus(); + input.select(); + + input.addEventListener('blur', this._renameTabHalt); + }, + + renameTabHalt(event) { + if (document.activeElement === event.target || !this._tabEdited) { + return; + } + this._tabEdited.querySelector('.tab-editor-container').remove(); + const label = this._tabEdited.querySelector('.tab-label-container-editing'); + label.classList.remove('tab-label-container-editing'); + + this._tabEdited = null; + }, }; diff --git a/src/browser/base/content/zen-styles/zen-tabs/vertical-tabs.css b/src/browser/base/content/zen-styles/zen-tabs/vertical-tabs.css index e0e834675..8689e6a68 100644 --- a/src/browser/base/content/zen-styles/zen-tabs/vertical-tabs.css +++ b/src/browser/base/content/zen-styles/zen-tabs/vertical-tabs.css @@ -325,6 +325,9 @@ top: 0px; right: 0px; --tab-collapsed-width: 34px; + top: 0px; + right: 0px; + --tab-collapsed-width: 34px; --tab-min-height: 16px; width: var(--tab-collapsed-width) !important; z-index: 1; @@ -334,6 +337,11 @@ background: light-dark(rgb(249, 249, 249), rgb(63, 63, 63)) !important; border: 2px solid light-dark(rgba(0, 0, 0, 0.4), rgba(255, 255, 255, 0.4)); } + & .tab-background { + /* Solid colors because we don't want to show the background */ + background: light-dark(rgb(249, 249, 249), rgb(63, 63, 63)) !important; + border: 2px solid light-dark(rgba(0, 0, 0, 0.4), rgba(255, 255, 255, 0.4)); + } } } } @@ -955,6 +963,7 @@ padding: 0; } +#zen-essentials-container > .tabbrowser-tab { #zen-essentials-container > .tabbrowser-tab { --toolbarbutton-inner-padding: 0; max-width: unset; @@ -995,6 +1004,7 @@ } @media (-moz-bool-pref: 'zen.theme.essentials-favicon-bg') { + &[visuallyselected] > .tab-stack > .tab-background { &[visuallyselected] > .tab-stack > .tab-background { &::after { content: ""; diff --git a/src/browser/components/tabbrowser/content/tabbrowser-js.patch b/src/browser/components/tabbrowser/content/tabbrowser-js.patch index 34bfd4b41..3323b47e9 100644 --- a/src/browser/components/tabbrowser/content/tabbrowser-js.patch +++ b/src/browser/components/tabbrowser/content/tabbrowser-js.patch @@ -2,6 +2,7 @@ diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/compo index ff90a70bdad6c94ec4b90027ff102972d0eb28e5..c29a3620f85219074b2eeef8d75b4ca7232414e2 100644 --- a/browser/components/tabbrowser/content/tabbrowser.js +++ b/browser/components/tabbrowser/content/tabbrowser.js +@@ -406,11 +406,52 @@ @@ -406,11 +406,52 @@ return this.tabContainer.visibleTabs; } @@ -40,6 +41,7 @@ index ff90a70bdad6c94ec4b90027ff102972d0eb28e5..c29a3620f85219074b2eeef8d75b4ca7 + } + if (!tab.hidden) { + i += !tab.hasAttribute("zen-glance-tab"); ++ i += !tab.hasAttribute("zen-glance-tab"); + } + } + return i; @@ -53,10 +55,12 @@ index ff90a70bdad6c94ec4b90027ff102972d0eb28e5..c29a3620f85219074b2eeef8d75b4ca7 + if (!tab.pinned && !tab.hasAttribute("zen-glance-tab")) { break; } ++ i += !tab.hasAttribute("zen-glance-tab"); + i += !tab.hasAttribute("zen-glance-tab"); } return i; } +@@ -807,7 +848,7 @@ @@ -807,7 +848,7 @@ this.showTab(aTab); if (this.tabContainer.verticalMode) { @@ -66,6 +70,7 @@ index ff90a70bdad6c94ec4b90027ff102972d0eb28e5..c29a3620f85219074b2eeef8d75b4ca7 ); } else { this.moveTabTo(aTab, this.pinnedTabCount, { forceStandaloneTab: true }); +@@ -828,7 +869,7 @@ @@ -828,7 +869,7 @@ // the moving of a tab from the vertical pinned tabs container // and back into arrowscrollbox. @@ -75,6 +80,7 @@ index ff90a70bdad6c94ec4b90027ff102972d0eb28e5..c29a3620f85219074b2eeef8d75b4ca7 }); } else { this.moveTabTo(aTab, this.pinnedTabCount - 1, { +@@ -1055,6 +1096,8 @@ @@ -1055,6 +1096,8 @@ let LOCAL_PROTOCOLS = ["chrome:", "about:", "resource:", "data:"]; @@ -84,6 +90,7 @@ index ff90a70bdad6c94ec4b90027ff102972d0eb28e5..c29a3620f85219074b2eeef8d75b4ca7 if ( aIconURL && !aLoadingPrincipal && +@@ -1065,6 +1108,9 @@ @@ -1065,6 +1108,9 @@ ); return; @@ -94,6 +101,7 @@ index ff90a70bdad6c94ec4b90027ff102972d0eb28e5..c29a3620f85219074b2eeef8d75b4ca7 let browser = this.getBrowserForTab(aTab); browser.mIconURL = aIconURL; +@@ -1310,6 +1356,7 @@ @@ -1310,6 +1356,7 @@ if (!this._previewMode) { newTab.recordTimeFromUnloadToReload(); @@ -130,6 +138,7 @@ index ff90a70bdad6c94ec4b90027ff102972d0eb28e5..c29a3620f85219074b2eeef8d75b4ca7 aTab.linkedPanel = uniqueId; // Inject the into the DOM if necessary. +@@ -2446,8 +2496,8 @@ @@ -2446,8 +2496,8 @@ // If we transitioned from one browser to two browsers, we need to set // hasSiblings=false on both the existing browser and the new browser. @@ -141,6 +150,7 @@ index ff90a70bdad6c94ec4b90027ff102972d0eb28e5..c29a3620f85219074b2eeef8d75b4ca7 } else { aTab.linkedBrowser.browsingContext.hasSiblings = this.tabs.length > 1; } +@@ -2679,6 +2729,12 @@ @@ -2679,6 +2729,12 @@ ); } @@ -154,6 +164,7 @@ index ff90a70bdad6c94ec4b90027ff102972d0eb28e5..c29a3620f85219074b2eeef8d75b4ca7 if (!UserInteraction.running("browser.tabs.opening", window)) { UserInteraction.start("browser.tabs.opening", "initting", window); } +@@ -2742,6 +2798,12 @@ @@ -2742,6 +2798,12 @@ noInitialLabel, skipBackgroundNotify, @@ -167,6 +178,7 @@ index ff90a70bdad6c94ec4b90027ff102972d0eb28e5..c29a3620f85219074b2eeef8d75b4ca7 if (insertTab) { // insert the tab into the tab container in the correct position this._insertTabAtIndex(t, { +@@ -2885,6 +2947,9 @@ @@ -2885,6 +2947,9 @@ } }