From be244cfe5af16413997396a100c8fe4e6672dba1 Mon Sep 17 00:00:00 2001 From: Slowlife01 Date: Tue, 29 Apr 2025 14:13:01 +0700 Subject: [PATCH 01/11] fix: cache initial pinned tabs favicon, b=(no-bug), c=tabs, welcome --- src/zen/tabs/ZenPinnedTabManager.mjs | 19 +++++++++++++++++-- src/zen/welcome/ZenWelcome.mjs | 27 +++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/zen/tabs/ZenPinnedTabManager.mjs b/src/zen/tabs/ZenPinnedTabManager.mjs index f68fa1174..40a04a0ae 100644 --- a/src/zen/tabs/ZenPinnedTabManager.mjs +++ b/src/zen/tabs/ZenPinnedTabManager.mjs @@ -83,8 +83,23 @@ onTabIconChanged(tab, url = null) { const iconUrl = url ?? tab.iconImage.src; - if (tab.hasAttribute('zen-essential')) { - tab.querySelector('.tab-background').style.setProperty('--zen-tab-icon', `url(${iconUrl})`); + if (!iconUrl) { + try { + setTimeout(() => { + PlacesUtils.favicons.getFaviconURLForPage( + tab.linkedBrowser.currentURI, + (url) => { + if (url) gBrowser.setIcon(tab, url.spec); + }, + + 0 + ); + }); + } catch {} + } else { + if (tab.hasAttribute('zen-essential')) { + tab.querySelector('.tab-background').style.setProperty('--zen-tab-icon', `url(${iconUrl})`); + } } // TODO: work on this //if (tab.hasAttribute('zen-pinned-changed') || !this._pinsCache) { diff --git a/src/zen/welcome/ZenWelcome.mjs b/src/zen/welcome/ZenWelcome.mjs index 4e1eb8270..9527221a3 100644 --- a/src/zen/welcome/ZenWelcome.mjs +++ b/src/zen/welcome/ZenWelcome.mjs @@ -68,10 +68,9 @@ async function setCachedFaviconForURL(pageUrl, iconURL) { try { - // TODO: This always return "NS_ERROR_NOT_AVAILABLE" for some reason, figure out why await PlacesUtils.favicons.setFaviconForPage( Services.io.newURI(pageUrl), - Services.io.newURI('fake-favicon-uri:' + pageUrl), + Services.io.newURI(iconURL), Services.io.newURI(iconURL) ); } catch (ex) { @@ -84,6 +83,18 @@ ['https://reddit.com/r/zen_browser', 'Zen on Reddit', 'https://private-cdn.zen-browser.app/reddit.png'], ['https://x.com/zen_browser', 'Zen on Twitter', 'https://private-cdn.zen-browser.app/x.png'], ]; + + await PlacesUtils.history.insertMany( + tabs.map((site) => ({ + url: site[0], + visits: [ + { + transition: PlacesUtils.history.TRANSITIONS.TYPED, + }, + ], + })) + ); + for (const site of tabs) { const tab = window.gBrowser.addTrustedTab(site[0], { inBackground: true, @@ -443,6 +454,18 @@ const selectedTabs = document .getElementById('zen-welcome-initial-essentials-browser-sidebar-essentials') .querySelectorAll('.tabbrowser-tab[visuallyselected]'); + + await PlacesUtils.history.insertMany( + [...selectedTabs].map((tab) => ({ + url: tab.getAttribute('data-url'), + visits: [ + { + transition: PlacesUtils.history.TRANSITIONS.TYPED, + }, + ], + })) + ); + for (const tab of selectedTabs) { const url = tab.getAttribute('data-url'); const createdTab = window.gBrowser.addTrustedTab(url, { From 388e69cc38f42ad3d5c97819a1630e0ff88cbec7 Mon Sep 17 00:00:00 2001 From: "Mr. M" Date: Tue, 29 Apr 2025 10:08:03 +0200 Subject: [PATCH 02/11] fix: Fixed incorrect behavior when using ctrl+enter from new tab addressbar, b=(bug #7898), c=common --- .../urlbar/UrlbarInput-sys-mjs.patch | 4 +-- src/zen/common/ZenUIManager.mjs | 34 ++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/browser/components/urlbar/UrlbarInput-sys-mjs.patch b/src/browser/components/urlbar/UrlbarInput-sys-mjs.patch index b6894c048..b9773df1f 100644 --- a/src/browser/components/urlbar/UrlbarInput-sys-mjs.patch +++ b/src/browser/components/urlbar/UrlbarInput-sys-mjs.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/urlbar/UrlbarInput.sys.mjs b/browser/components/urlbar/UrlbarInput.sys.mjs -index 4b69136aa31bfef3a1d3b57ad0c75fe07fa26be0..a469d122622fcf361eea8faa4a8d3a13a5a9e4f1 100644 +index 4b69136aa31bfef3a1d3b57ad0c75fe07fa26be0..a864dd8854611d78e3ace9db301cf7c4f1357a32 100644 --- a/browser/components/urlbar/UrlbarInput.sys.mjs +++ b/browser/components/urlbar/UrlbarInput.sys.mjs @@ -68,6 +68,13 @@ XPCOMUtils.defineLazyPreferenceGetter( @@ -58,7 +58,7 @@ index 4b69136aa31bfef3a1d3b57ad0c75fe07fa26be0..a469d122622fcf361eea8faa4a8d3a13 if (!this.#providesSearchMode(result)) { - this.view.close({ elementPicked: true }); + if (this._zenHandleUrlbarClose) { -+ this._zenHandleUrlbarClose(true); ++ this._zenHandleUrlbarClose(true, true); + } else { + this.view.close({ elementPicked: true }); + } diff --git a/src/zen/common/ZenUIManager.mjs b/src/zen/common/ZenUIManager.mjs index 0afb0ca06..4d3c8b0fd 100644 --- a/src/zen/common/ZenUIManager.mjs +++ b/src/zen/common/ZenUIManager.mjs @@ -323,7 +323,7 @@ var gZenUIManager = { this._lastSearch = ''; }, - handleUrlbarClose(onSwitch) { + handleUrlbarClose(onSwitch = false, onElementPicked = false) { // Validate browser state first if (!this._validateBrowserState()) { console.warn('Browser state invalid for URL bar close operation'); @@ -350,27 +350,29 @@ var gZenUIManager = { } // Handle search data - if (onSwitch) { - this.clearUrlbarData(); - } else { - this._lastSearch = gURLBar._untrimmedValue || ''; + if (!onElementPicked) { + if (onSwitch) { + this.clearUrlbarData(); + } else { + this._lastSearch = gURLBar._untrimmedValue || ''; - if (this._clearTimeout) { - clearTimeout(this._clearTimeout); + if (this._clearTimeout) { + clearTimeout(this._clearTimeout); + } + + this._clearTimeout = setTimeout(() => { + this.clearUrlbarData(); + }, this.urlbarWaitToClear); } - this._clearTimeout = setTimeout(() => { - this.clearUrlbarData(); - }, this.urlbarWaitToClear); - } + // Safely restore URL bar state with proper validation + if (this._prevUrlbarLabel) { + gURLBar.setURI(this._prevUrlbarLabel, onSwitch, false, false, !onSwitch); + } - // Safely restore URL bar state with proper validation - if (this._prevUrlbarLabel) { - gURLBar.setURI(this._prevUrlbarLabel, onSwitch, false, false, !onSwitch); + gURLBar.handleRevert(); } - gURLBar.handleRevert(); - if (gURLBar.focused) { gURLBar.view.close({ elementPicked: onSwitch }); gURLBar.updateTextOverflow(); From c5515fc3aeeab1e2c54726fcb82d96f481574af9 Mon Sep 17 00:00:00 2001 From: "Mr. M" Date: Tue, 29 Apr 2025 10:44:26 +0200 Subject: [PATCH 03/11] fix: Revert fix for linux addons not loading, b=(no-bug), c=common --- src/zen/common/styles/zen-panel-ui.css | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/zen/common/styles/zen-panel-ui.css b/src/zen/common/styles/zen-panel-ui.css index dcb790190..bcefa1ea9 100644 --- a/src/zen/common/styles/zen-panel-ui.css +++ b/src/zen/common/styles/zen-panel-ui.css @@ -20,20 +20,12 @@ panel[type='arrow'][animate='open'] { } } } - @media (-moz-platform: windows) and (not (-moz-windows-mica-popups)) { + @media (-moz-platform: linux) or ((-moz-platform: windows) and (not (-moz-windows-mica-popups))) { /* Mica popups have a weird background while the animation is running */ &::part(content) { animation: zen-jello-animation 0.35s ease; } } - - @media (-moz-platform: linux) { - /* Check https://github.com/zen-browser/desktop/issues/7633 as in - * to why we dont animate addons */ - &:not(#customizationui-widget-panel)::part(content) { - animation: zen-jello-animation 0.35s ease; - } - } } panel[type='arrow'][animate]:not([animate='open']) { From a35ef0e735e44a5e4a08116bb7ac184440e10900 Mon Sep 17 00:00:00 2001 From: "Mr. M" Date: Tue, 29 Apr 2025 12:52:05 +0200 Subject: [PATCH 04/11] chore: Made an URL revamp! Fixed lots of things in different layouts and made it's UI a bit cleaner, b=(no-bug), c=common --- src/browser/app/profile/zen-browser.js | 2 +- .../urlbar/UrlbarInput-sys-mjs.patch | 15 ++++++-- .../themes/shared/urlbar-searchbar-css.patch | 6 ++-- src/zen/common/styles/zen-urlbar.css | 35 +++++++++++++------ 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/browser/app/profile/zen-browser.js b/src/browser/app/profile/zen-browser.js index c960c3916..834815676 100644 --- a/src/browser/app/profile/zen-browser.js +++ b/src/browser/app/profile/zen-browser.js @@ -387,7 +387,7 @@ pref('zen.widget.linux.transparency', false); #endif // Urlbar and autocomplete -pref("browser.urlbar.maxRichResults", 6); +pref("browser.urlbar.maxRichResults", 8); pref("browser.urlbar.trimHttps", true); pref("browser.search.separatePrivateDefault.ui.enabled", true); pref("browser.urlbar.update2.engineAliasRefresh", true); diff --git a/src/browser/components/urlbar/UrlbarInput-sys-mjs.patch b/src/browser/components/urlbar/UrlbarInput-sys-mjs.patch index b9773df1f..2303e8d50 100644 --- a/src/browser/components/urlbar/UrlbarInput-sys-mjs.patch +++ b/src/browser/components/urlbar/UrlbarInput-sys-mjs.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/urlbar/UrlbarInput.sys.mjs b/browser/components/urlbar/UrlbarInput.sys.mjs -index 4b69136aa31bfef3a1d3b57ad0c75fe07fa26be0..a864dd8854611d78e3ace9db301cf7c4f1357a32 100644 +index 4b69136aa31bfef3a1d3b57ad0c75fe07fa26be0..2de9f51784a92442da84ead54312e879c1da127b 100644 --- a/browser/components/urlbar/UrlbarInput.sys.mjs +++ b/browser/components/urlbar/UrlbarInput.sys.mjs @@ -68,6 +68,13 @@ XPCOMUtils.defineLazyPreferenceGetter( @@ -108,6 +108,15 @@ index 4b69136aa31bfef3a1d3b57ad0c75fe07fa26be0..a864dd8854611d78e3ace9db301cf7c4 this.removeAttribute("breakout-extend"); this.#updateTextboxPosition(); } +@@ -2485,7 +2529,7 @@ export class UrlbarInput { + + this.textbox.parentNode.style.setProperty( + "--urlbar-container-height", +- px(getBoundsWithoutFlushing(this.textbox.parentNode).height) ++ px(getBoundsWithoutFlushing(this.textbox.parentNode).height + 8) + ); + this.textbox.style.setProperty( + "--urlbar-height", @@ -2998,7 +3042,7 @@ export class UrlbarInput { */ _trimValue(val) { @@ -158,7 +167,7 @@ index 4b69136aa31bfef3a1d3b57ad0c75fe07fa26be0..a864dd8854611d78e3ace9db301cf7c4 } _on_click(event) { -+ if (lazy.ZEN_URLBAR_BEHAVIOR === 'float' && event.target == this.inputField) { ++ if (event.target == this.inputField) { + event.zenOriginalTarget = this.textbox; + this._on_mousedown(event); + } @@ -183,7 +192,7 @@ index 4b69136aa31bfef3a1d3b57ad0c75fe07fa26be0..a864dd8854611d78e3ace9db301cf7c4 + switch (event.zenOriginalTarget || event.currentTarget) { case this.textbox: { this._mousedownOnUrlbarDescendant = true; -+ if (event.type != "click" && lazy.ZEN_URLBAR_BEHAVIOR === 'float') { ++ if (event.type != "click") { + return true; + } diff --git a/src/browser/themes/shared/urlbar-searchbar-css.patch b/src/browser/themes/shared/urlbar-searchbar-css.patch index 259fe7eaf..3d2c912e2 100644 --- a/src/browser/themes/shared/urlbar-searchbar-css.patch +++ b/src/browser/themes/shared/urlbar-searchbar-css.patch @@ -1,5 +1,5 @@ diff --git a/browser/themes/shared/urlbar-searchbar.css b/browser/themes/shared/urlbar-searchbar.css -index 574f83af7fa49ddcdff6711ca8b1d3bed1a35e0c..c2e8cb8b37438176db07a47e1e975ae1aea42252 100644 +index e237ee9edea85c1d2ef22f988df6b22755e343e6..b06fc06686a7a969e924ad0df662dec937b3c70d 100644 --- a/browser/themes/shared/urlbar-searchbar.css +++ b/browser/themes/shared/urlbar-searchbar.css @@ -5,7 +5,7 @@ @@ -7,11 +7,11 @@ index 574f83af7fa49ddcdff6711ca8b1d3bed1a35e0c..c2e8cb8b37438176db07a47e1e975ae1 :root { - --urlbar-container-padding: 1px; -+ --urlbar-container-padding: 4px; ++ --urlbar-container-padding: 2px; --urlbar-margin-inline: 5px; --urlbar-padding-block: 4px; } -@@ -291,7 +291,9 @@ +@@ -292,7 +292,9 @@ } #urlbar[breakout][breakout-extend] { diff --git a/src/zen/common/styles/zen-urlbar.css b/src/zen/common/styles/zen-urlbar.css index 7413868a6..d690f68cb 100644 --- a/src/zen/common/styles/zen-urlbar.css +++ b/src/zen/common/styles/zen-urlbar.css @@ -9,19 +9,30 @@ padding-block: 0 !important; } +:root[zen-single-toolbar='true'] { + --urlbar-container-padding: 4px; + & #urlbar:not([breakout-extend='true']) { + padding: 1px; + --toolbarbutton-border-radius: 6px; + } +} + #urlbar { - --toolbarbutton-border-radius: 8px; --urlbarView-separator-color: light-dark(hsl(0, 0%, 90%), hsl(0, 0%, 20%)); --urlbarView-hover-background: var(--toolbarbutton-hover-background); --urlbarView-highlight-background: var(--toolbarbutton-hover-background); - border-radius: var(--toolbarbutton-border-radius); - padding: 1px; + border-radius: calc(var(--toolbarbutton-border-radius) - 2px); + --urlbarView-results-padding: 10px !important; :root:not([zen-single-toolbar='true']) &[zen-floating-urlbar='true'] { --urlbar-container-padding: 2px !important; } } +:root:not([zen-single-toolbar='true']) #urlbar:not([zen-floating-urlbar='true']) { + --urlbarView-results-padding: 6px !important; +} + .urlbar-input::placeholder { text-overflow: ellipsis; } @@ -84,8 +95,11 @@ position: relative; } -#urlbar:not([breakout-extend='true']) #identity-box { +:root[zen-single-toolbar='true'] #urlbar:not([breakout-extend='true']) #identity-box { margin-inline-end: 0 !important; + &.chromeUI:not([pageproxystate='invalid']) #identity-icon-box { + border-radius: 10px !important; + } } .urlbar-page-action, @@ -177,7 +191,7 @@ transform: none !important; display: flex; #urlbar:not(:hover) & { - transition: 0; + transition: none; } } @@ -325,11 +339,6 @@ button.popup-notification-dropmarker { border-radius: var(--urlbar-icon-border-radius) !important; } -/* Extensions or similar */ -#urlbar:not([breakout-extend='true']) #identity-box.chromeUI:not([pageproxystate='invalid']) #identity-icon-box { - border-radius: 10px !important; -} - /* Notification Stack */ .notificationbox-stack { @@ -407,7 +416,7 @@ button.popup-notification-dropmarker { #urlbar[open] { z-index: 2; - --urlbar-margin-inline: 5px !important; + --urlbar-margin-inline: 5px; & #identity-box { margin-right: var(--urlbar-margin-inline); @@ -538,4 +547,8 @@ button.popup-notification-dropmarker { color: color-mix(in srgb, var(--zen-colors-primary) 30%, lightgray) !important; } } + + &[selected] { + background-color: color-mix(in srgb, var(--zen-primary-color) 50%, transparent 50%) !important; + } } From 0dac5522fe4b77d95fa571042f0319f4e5582d34 Mon Sep 17 00:00:00 2001 From: "Mr. M" Date: Tue, 29 Apr 2025 14:26:21 +0200 Subject: [PATCH 05/11] chore: Refactored vertical tabs css and improved essentials layout, b=(no-bug), c=tabs, workspaces --- .prettierignore | 2 +- .../base/content/zen-assets.jar.inc.mn | 4 +- src/zen/tabs/zen-tabs.css | 97 ++ src/zen/tabs/zen-tabs/vertical-tabs.css | 896 +++++++++++------- src/zen/workspaces/ZenWorkspaces.mjs | 12 + 5 files changed, 650 insertions(+), 361 deletions(-) diff --git a/.prettierignore b/.prettierignore index 82e333acc..9ecc5ffd9 100644 --- a/.prettierignore +++ b/.prettierignore @@ -22,7 +22,7 @@ docs/issue-metrics/*.md # Some CSS files are preprocessed and prettier doesn't handle them well # We also dont want to format the CSS files that are generated by the build -src/zen/tabs/zen-tabs/vertical-tabs.css +src/zen/tabs/zen-tabs.css src/zen/compact-mode/zen-compact-mode.css src/zen/common/ZenEmojies.mjs diff --git a/src/browser/base/content/zen-assets.jar.inc.mn b/src/browser/base/content/zen-assets.jar.inc.mn index 8e3de8d36..bd4e8aab3 100644 --- a/src/browser/base/content/zen-assets.jar.inc.mn +++ b/src/browser/base/content/zen-assets.jar.inc.mn @@ -51,8 +51,8 @@ content/browser/zen-components/ZenTabUnloader.mjs (../../zen/tabs/ZenTabUnloader.mjs) content/browser/zen-components/ZenPinnedTabsStorage.mjs (../../zen/tabs/ZenPinnedTabsStorage.mjs) content/browser/zen-components/ZenPinnedTabManager.mjs (../../zen/tabs/ZenPinnedTabManager.mjs) - content/browser/zen-styles/zen-tabs.css (../../zen/tabs/zen-tabs.css) -* content/browser/zen-styles/zen-tabs/vertical-tabs.css (../../zen/tabs/zen-tabs/vertical-tabs.css) +* content/browser/zen-styles/zen-tabs.css (../../zen/tabs/zen-tabs.css) + content/browser/zen-styles/zen-tabs/vertical-tabs.css (../../zen/tabs/zen-tabs/vertical-tabs.css) content/browser/zen-components/ZenGlanceManager.mjs (../../zen/glance/ZenGlanceManager.mjs) content/browser/zen-styles/zen-glance.css (../../zen/glance/zen-glance.css) diff --git a/src/zen/tabs/zen-tabs.css b/src/zen/tabs/zen-tabs.css index 5ddb9c656..e8f15ccd7 100644 --- a/src/zen/tabs/zen-tabs.css +++ b/src/zen/tabs/zen-tabs.css @@ -16,3 +16,100 @@ display: none !important; } } + +/* ========================================================================== + Single Toolbar Mode - Top Bar Handling (Includes External CSS) + ========================================================================== */ +:root[zen-single-toolbar='true']:not([customizing]) { + #zen-appcontent-navbar-container { + display: flex; + -moz-window-dragging: drag; /* Allow dragging the window via this bar */ + min-height: var(--zen-element-separation); + height: var(--zen-element-separation); + + /* Ensure Personal Toolbar takes available width */ + & #PersonalToolbar { + width: -moz-available; + } + + /* Include styles for the top bar under certain conditions: + * - Bookmarks toolbar is visible OR + * - The container is explicitly marked to hide controls (e.g., on Linux with reversed controls) + */ + &:has(#PersonalToolbar[collapsed='false']) { +%include zen-tabs/vertical-tabs-topbar.inc.css + } + &[should-hide='true'] { +%include zen-tabs/vertical-tabs-topbar.inc.css + } + + /* Hide the top bar completely in fullscreen mode */ + :root[inDOMFullscreen='true'] & { + max-height: 0 !important; + min-height: unset !important; + opacity: 0 !important; + pointer-events: none !important; + } + } +} + + +/* ========================================================================== + Very Special Occasions - Complex Layout Fixes + ========================================================================== */ + +/* Exclude these complex fixes if in compact mode */ +:root:not([zen-compact-mode='true']) { + + /* --- Fix: Right Sidebar + Collapsed + Standard Window Buttons --- */ + &[zen-right-side='true']:not([zen-sidebar-expanded='true']):not([zen-window-buttons-reversed='true']) { + /* Push toolbox down below the top toolbar */ + & #navigator-toolbox { + margin-top: var(--zen-toolbar-height) !important; + } + /* Pull window buttons container leftwards over the collapsed sidebar */ + & .titlebar-buttonbox-container { + margin-right: calc(-1 * var(--zen-toolbox-max-width)) !important; + } + /* Allow overflow for the button box */ + & #zen-appcontent-wrapper { + overflow-x: visible; + } + /* Reset padding for top buttons */ + & #zen-sidebar-top-buttons-customization-target { + padding-top: 0; + } + /* Add padding to the left of the nav container */ + & #zen-appcontent-navbar-container { + padding-left: var(--zen-element-separation); + } + /* Include common fixes for this top-button scenario */ +%include zen-tabs/vertical-tabs-topbuttons-fix.css + } + + /* --- Fix: Left Sidebar + Collapsed + Reversed Window Buttons --- */ + &:not([zen-right-side='true']):not([zen-sidebar-expanded='true'])[zen-window-buttons-reversed='true'] { + /* Push toolbox down below the top toolbar */ + & #navigator-toolbox { + margin-top: var(--zen-toolbar-height) !important; + } + /* Pull window buttons container rightwards over the collapsed sidebar */ + & .titlebar-buttonbox-container { + margin-left: calc(-1 * var(--zen-toolbox-max-width) + var(--zen-toolbox-padding) / 2) !important; + } + /* Allow overflow for the button box */ + & #zen-appcontent-wrapper { + overflow-x: visible; + } + /* Reset padding for top buttons */ + & #zen-sidebar-top-buttons-customization-target { + padding-top: 0; + } + /* Add padding to the right of the nav container */ + & #zen-appcontent-navbar-container { + padding-right: var(--zen-element-separation); + } + /* Include common fixes for this top-button scenario */ +%include zen-tabs/vertical-tabs-topbuttons-fix.css + } +} \ No newline at end of file diff --git a/src/zen/tabs/zen-tabs/vertical-tabs.css b/src/zen/tabs/zen-tabs/vertical-tabs.css index 5e1edd0e1..3d115ea73 100644 --- a/src/zen/tabs/zen-tabs/vertical-tabs.css +++ b/src/zen/tabs/zen-tabs/vertical-tabs.css @@ -4,306 +4,342 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* ========================================================================== + Initial Setup & Layout Changes for Vertical Tabs + ========================================================================== */ + +/* Ensure tabs, toolbar, and titlebar stack vertically */ #tabbrowser-tabs, #TabsToolbar, #titlebar, #TabsToolbar-customization-target { flex-direction: column; - height: 100%; + height: 100%; /* Make sure they take up full height */ } +/* ========================================================================== + Single Toolbar Mode Specific Styles (`zen-single-toolbar='true'`) + ========================================================================== */ :root[zen-single-toolbar='true'] { + /* Define and apply a smaller toolbar height for single toolbar mode */ & #zen-appcontent-navbar-container, & #zen-sidebar-top-buttons { --zen-toolbar-height: 32px; height: var(--zen-toolbar-height); } + /* Specific styling for macOS when the three-dot menu is hidden */ @media (-moz-platform: macos) and (not -moz-pref('zen.view.mac.show-three-dot-menu')) { + /* Hide the PanelUI (hamburger) button when not customizing or open */ &:not([customizing]) #PanelUI-button:not([open]):not([panelopen]) { - position: absolute; + position: absolute; /* Remove from layout flow */ opacity: 0; - pointer-events: none; + pointer-events: none; /* Make it unclickable */ } } - & #zen-sidebar-top-buttons .toolbarbutton-1 { - & > .toolbarbutton-icon { - padding: 4px; - } + /* Adjust padding for top sidebar buttons */ + & #zen-sidebar-top-buttons .toolbarbutton-1 > .toolbarbutton-icon { + padding: 4px; } + /* Make the separator take full width */ & #zen-sidebar-top-buttons-separator { width: 100%; } } +/* ========================================================================== + Vertical Tabs Mode Specific Styles (`zen.tabs.vertical` pref) + ========================================================================== */ @media -moz-pref('zen.tabs.vertical') { :root:not([zen-window-buttons-reversed='true']) { + /* Align window controls to the right by default */ & .titlebar-buttonbox-container { margin-left: auto; width: fit-content; } + /* Specific adjustments for window controls when sidebar is on the right */ &:root[zen-right-side='true'] #zen-sidebar-top-buttons .titlebar-buttonbox-container { - /* Must have the #zen-sidebar-top-buttons so we target it only when it's on the sidebar */ - margin-right: calc(-1 * var(--zen-toolbox-padding)); - margin-top: -10px /*Make sure this stays synced with the top buttons' margin!*/; - height: calc(4px + var(--zen-toolbar-height)) !important; + /* Selector ensures this only applies when buttons are in the sidebar */ + margin-right: calc(-1 * var(--zen-toolbox-padding)); /* Pull slightly outside */ + margin-top: -10px /* Align vertically with top buttons */; + height: calc(4px + var(--zen-toolbar-height)) !important; /* Adjust height */ & .titlebar-button { - align-items: end; + align-items: end; /* Align button content to the bottom */ } } } + /* Ensure arrow scrollbox takes minimum necessary height */ #tabbrowser-arrowscrollbox { min-height: fit-content !important; } } +/* Alignreversed window controls to the left */ :root[zen-window-buttons-reversed='true'] .titlebar-buttonbox-container { margin-right: auto; width: fit-content; } +/* Center items within the TabsToolbar */ #TabsToolbar > * { justify-content: center; } +/* ========================================================================== + Toolbox Padding & Variables + ========================================================================== */ #browser { - --zen-min-toolbox-padding: .4rem; + /* Define base padding with platform-specific overrides */ + --zen-min-toolbox-padding: 0.4rem; @media (-moz-platform: macos) { - --zen-min-toolbox-padding: .52rem; + --zen-min-toolbox-padding: 0.52rem; } @media (-moz-platform: linux) { - --zen-min-toolbox-padding: .35rem; + --zen-min-toolbox-padding: 0.35rem; } + /* Actual padding used, ensuring it's at least min padding or based on element separation */ --zen-toolbox-padding: max(var(--zen-min-toolbox-padding), calc(var(--zen-element-separation) / 1.5)); } +/* ========================================================================== + Single Toolbar Mode - Further Layout Adjustments + ========================================================================== */ :root[zen-single-toolbar='true'] { + /* Make URL bar container take available width */ #urlbar-container { width: -moz-available !important; } + /* Center identity icons vertically */ #identity-icon-box, #identity-permission-box { margin-top: auto; margin-bottom: auto; - padding: 6px !important; + padding: 6px !important; /* Add padding */ } + /* Adjust height for floating URL bar */ & #urlbar-container[breakout='true']:has([zen-floating-urlbar='true']) { --urlbar-container-height: 36px !important; --urlbar-height: 38px !important; } & #nav-bar { + /* Add bottom margin */ margin-bottom: var(--zen-toolbox-padding); + /* Hide flexible spaces */ & toolbarspring { display: none; } } + /* Add vertical margins to the top sidebar buttons area */ & #zen-sidebar-top-buttons { margin: var(--zen-toolbox-padding) 0 calc(var(--zen-toolbox-padding) / 2) 0; } + /* Remove padding from PanelUI button */ & #PanelUI-menu-button { padding: 0 !important; } } +/* ========================================================================== + Pinned Tabs Separator + ========================================================================== */ .vertical-pinned-tabs-container-separator { background: light-dark(rgba(1, 1, 1, 0.075), rgba(255, 255, 255, 0.1)); - margin: 8px auto; + margin: 8px auto; /* Center horizontally */ border: none; height: 1px; max-height: 1px; - width: 98%; - transition: margin 0.2s ease-in-out, background 0.2s ease-in-out, max-height 0.2s ease-in-out; + width: 98%; /* Slightly less than full width */ + transition: + margin 0.2s ease-in-out, + background 0.2s ease-in-out, + max-height 0.2s ease-in-out; + /* Hide separator when specified by parent container attribute */ #vertical-pinned-tabs-container .zen-workspace-tabs-section[hide-separator] & { max-height: 0; - margin: 0 auto; + margin: 0 auto; /* Collapse margins */ } } +/* ========================================================================== + Navigator Toolbox (Main Sidebar Container) Base Styles + ========================================================================== */ #navigator-toolbox { + /* Define theme variables, including platform specifics for native look */ --border-radius-medium: 10px; --tab-border-radius: 6px; - --zen-toolbox-min-width: 1px; + --zen-toolbox-min-width: 1px; /* Default minimum width (used when collapsed) */ @media (-moz-platform: windows) { - /* More native look */ --border-radius-medium: 8px; --tab-border-radius: 6px; } @media (-moz-platform: macos) { - /* More native look */ --border-radius-medium: 12px; --tab-border-radius: 10px; } + /* Define tab hover background color */ --tab-hover-background-color: color-mix(in srgb, var(--toolbarbutton-hover-background) 50%, transparent 50%); min-width: var(--zen-toolbox-min-width); - margin-top: 0 !important; /* Fix full screen mode */ - - border: none; - order: 0 !important; - - display: flex; + margin-top: 0 !important; /* Fix potential issues in full screen mode */ + border: none; /* Remove default borders */ + order: 0 !important; /* Default order (can be changed for right-side) */ + display: flex; /* Use flex layout */ } +/* Hide default titlebar spacers */ .titlebar-spacer[type='pre-tabs'], .titlebar-spacer[type='post-tabs'] { display: none; } -:root[zen-single-toolbar='true']:not([customizing]) { - #zen-appcontent-navbar-container { - display: flex; - -moz-window-dragging: drag; - min-height: var(--zen-element-separation); - height: var(--zen-element-separation); - - & #PersonalToolbar { - width: -moz-available; - } - - /* We enable this trick IF we follow any of theses conditions: - * - We are supposed to hide the window controls (e.g. left sidebar, windows like layouts) - * - This also involves linux's reverse GTK window controls, we'll need to handle that a bit differently - * - If we are not in any of the above, we can still enable it if the user has bookmarks toolbar enabled - */ - &:has(#PersonalToolbar[collapsed='false']) { -%include vertical-tabs-topbar.inc.css - } - - &[should-hide='true'] { -%include vertical-tabs-topbar.inc.css - } - - :root[inDOMFullscreen='true'] & { - max-height: 0 !important; - min-height: unset !important; - opacity: 0 !important; - pointer-events: none !important; - } - } -} - +/* ========================================================================== + Tabs Toolbar Customization Target + ========================================================================== */ #TabsToolbar-customization-target { - position: relative; + position: relative; /* For pseudo-element positioning */ max-width: 100%; - gap: 0; + gap: 0; /* Remove default gap */ + + /* Add a separator line at the bottom */ &::after { content: ''; display: block; height: 1px; - margin: 0 auto; width: 80%; left: 50%; transform: translateX(-50%); position: absolute; - bottom: calc(-1 * var(--zen-toolbox-padding)); + bottom: calc(-1 * var(--zen-toolbox-padding)); /* Position below the target */ } + /* Remove top borders from direct children */ & > * { border-top-width: 0 !important; } } +/* Style the new tab button specifically */ #vertical-tabs-newtab-button { + /* Transparent background unless active */ &:hover, &:not(:is(:hover, :active)) .toolbarbutton-icon { background: transparent !important; } } +/* ========================================================================== + Tab Container (#tabbrowser-tabs) Base Styles + ========================================================================== */ #tabbrowser-tabs { margin-inline-start: 0 !important; padding-inline-start: 0 !important; - overflow-y: unset !important; /* DO NOT CHANGE THIS: Firefox renders badly workspace changes */ - overflow-x: clip; - overflow-clip-margin: var(--zen-toolbox-padding); + overflow-y: unset !important; /* Critical: Prevents rendering issues on workspace changes */ + overflow-x: clip; /* Clip horizontal overflow */ + overflow-clip-margin: var(--zen-toolbox-padding); /* Add margin to clipping area */ @media (-moz-platform: macos) { - font-size: 1.1rem; + font-size: 1.1rem; /* Slightly larger font on macOS */ } - --tab-inner-inline-margin: 0; + --tab-inner-inline-margin: 0; /* Reset default inner margin */ position: relative; - border-bottom: 0px solid transparent !important; + border-bottom: 0px solid transparent !important; /* Remove default bottom border */ + /* Define tab variables */ --tab-block-margin: 2px; --tab-selected-bgcolor: light-dark(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.12)); --tab-selected-shadow: 0 1px 1px 1px light-dark(rgba(0, 0, 0, 0.09), rgba(0, 0, 0, 0.1)) !important; - grid-gap: 0 !important; + grid-gap: 0 !important; /* Reset grid gap */ + /* Hide default overflow indicators and the provided separator */ &[overflow]::after, - #vertical-tabs-newtab-button, - #vertical-pinned-tabs-container-separator { /* notice #vertical-pinned-tabs-container-separator is an ID */ - /* Hide separator they give us, eww */ + #vertical-tabs-newtab-button, /* Assuming this is a button *within* #tabbrowser-tabs, but it looks like it's outside */ + #vertical-pinned-tabs-container-separator { + /* Selector targets the specific separator ID */ display: none !important; } + /* ======================================================================== + Individual Tab Styles (.tabbrowser-tab within #tabbrowser-tabs) + ======================================================================== */ & .tabbrowser-tab { + /* Add smooth scaling transition */ &, & .tab-content > image { transition: scale 0.07s ease; } + /* Hide specific empty tabs (likely placeholders) */ &[zen-empty-tab] { display: none; } + /* Scale down tab slightly on active press (but not when dragging or clicking images) */ #tabbrowser-tabs:not([movingtab]) &:active:not(:has(.tab-content > image:active)) { - scale: var(--zen-active-tab-scale); + scale: var(--zen-active-tab-scale); /* Requires --zen-active-tab-scale to be defined elsewhere */ } + /* Scale down icon/image specifically on active press */ #tabbrowser-tabs:not([movingtab]) & .tab-content > image:active { scale: 0.92; } + /* Fallback icon for broken/missing favicons */ & .tab-icon-image { &:not([src]), &:-moz-broken { + /* Use an empty SVG as placeholder */ content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100'%3E%3C/svg%3E") !important; + /* Semi-transparent background based on primary color */ background: color-mix(in srgb, var(--zen-primary-color) 30%, transparent 70%); } } - max-width: unset; - padding: 0 !important; - - position: relative; + max-width: unset; /* Allow tabs to take full width */ + padding: 0 !important; /* Remove default padding */ + position: relative; /* For absolute positioning of children */ + /* Tab Background Styles */ & .tab-background { - overflow: hidden; + overflow: hidden; /* Hide overflowing content/pseudo-elements */ + /* Context line (usually for container tabs) styling */ & .tab-context-line { - margin: 0 0px !important; - width: 3px !important; + margin: 0 0px !important; /* Reset margin */ + width: 3px !important; /* Set specific width */ } } + /* Dim pending tabs if preference is enabled */ @media -moz-pref('zen.tabs.dim-pending') { &[pending='true'] .tab-icon-image { opacity: 0.5; } } - /* We have a tab inside a tab, this means, it's a glance tab */ + /* --- Glance Tab Styles (Nested .tabbrowser-tab) --- */ + /* Styles for a tab nested within another tab (representing a "glance"?) */ & .tabbrowser-tab { - pointer-events: none; - margin: 0 0 0 4px; + pointer-events: none; /* Disable interaction */ + margin: 0 0 0 4px; /* Add left margin */ + /* Reset/override variables for smaller size */ --toolbarbutton-inner-padding: 0; --border-radius-medium: 8px; width: 24px; @@ -311,22 +347,25 @@ --tab-min-height: 24px; --tab-min-width: 24px; + /* Style glance tab background */ & .tab-background { background: var(--zen-toolbar-element-bg) !important; margin-block: 0 !important; margin-inline: 0 !important; box-shadow: none !important; } + /* Adjust padding for content */ & .tab-content { padding: 0 5px; } - & label { display: none !important; } + /* Hide label and buttons */ + & label, & .tab-close-button, & .tab-reset-button, & .tab-reset-pin-button { display: none !important; } - + /* Style glance tab icon */ & .tab-icon-image { --toolbarbutton-inner-padding: 0 !important; width: 14px; @@ -334,18 +373,21 @@ } } - /* On essentials, glance tabs are floating */ + /* --- Essentials Glance Tab Specifics (Floating) --- */ + /* Additional styles for glance tabs in "essential" mode */ &[zen-essential='true'] .tabbrowser-tab { - position: absolute; + position: absolute; /* Position absolutely relative to parent tab */ top: 0px; right: 0px; + /* Define variables for size */ --tab-collapsed-width: 34px; --tab-min-height: 16px; width: var(--tab-collapsed-width) !important; - z-index: 1; - pointer-events: none; + z-index: 1; /* Ensure it's above parent tab content */ + pointer-events: none; /* Still non-interactive */ + + /* Specific background and border for floating effect */ & .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)); } @@ -353,110 +395,144 @@ } } +/* ========================================================================== + Sidebar Bottom Buttons Area + ========================================================================== */ #zen-sidebar-bottom-buttons { background: transparent; - gap: 5px; - align-items: center; - - padding-top: var(--zen-element-separation); - --toolbarbutton-inner-padding: 5px; + gap: 5px; /* Spacing between buttons */ + align-items: center; /* Center vertically */ + padding-top: var(--zen-element-separation); /* Add padding above */ + --toolbarbutton-inner-padding: 5px; /* Define inner padding for buttons */ + /* Remove padding from direct children (except workspaces button) */ & > toolbarbutton:not(#zen-workspaces-button) { padding: 0 !important; } } +/* Hide the default new tab button container */ #newtab-button-container { display: none !important; } +/* ========================================================================== + Tab Arrow Scrollbox Adjustments + ========================================================================== */ #tabbrowser-arrowscrollbox { + /* Remove gap within the scrollbox part */ &::part(scrollbox) { gap: 0px !important; } + /* Hide default overflow indicators */ &::part(overflow-start-indicator), &::part(overflow-end-indicator) { display: none !important; } } +/* ========================================================================== + Custom Tab Wrapper & Container Styles + ========================================================================== */ + +/* Wrapper for vertical tabs, enabling scrolling */ #zen-tabs-wrapper { min-height: fit-content; - overflow-y: auto; - height: 100%; - scrollbar-color: color-mix(in srgb, currentColor 26%, transparent) transparent; + overflow-y: auto; /* Allow vertical scrolling */ + height: 100%; /* Take full available height */ + scrollbar-color: color-mix(in srgb, currentColor 26%, transparent) transparent; /* Custom scrollbar */ - /* Only do this hack if we have workspaces enabled */ + /* Negative margin hack for workspace transitions (only if workspaces are enabled) */ :root[zen-workspace-id] & { margin-left: calc(-1 * var(--zen-toolbox-padding)); width: calc(100% + var(--zen-toolbox-padding) * 2); } } +/* Container for browser tabs within the sidebar */ #zen-browser-tabs-container { - overflow-x: clip !important; /* might break custom css with new design, so let's force it */ - position: relative; + overflow-x: clip !important; /* Force horizontal clipping */ + position: relative; /* Positioning context */ } +/* ========================================================================== + Pinned Tabs Container Specific Styles + ========================================================================== */ #vertical-pinned-tabs-container { - padding-inline-end: 0 !important; - display: flex !important; - flex-direction: column; + padding-inline-end: 0 !important; /* Remove end padding */ + display: flex !important; /* Use flex layout */ + flex-direction: column; /* Stack pinned tabs vertically */ min-height: fit-content !important; - overflow-x: clip; - overflow-y: visible; - max-height: unset !important; + overflow-x: clip; /* Clip horizontal overflow */ + overflow-y: visible; /* Allow vertical overflow (for menus etc.) */ + max-height: unset !important; /* Allow it to grow */ + /* Make non-selected, non-hovered pinned tab backgrounds transparent */ & .tabbrowser-tab:not(:hover) .tab-background:not([selected]):not([multiselected]) { background: transparent; } + /* Center content within pinned tabs */ & .tabbrowser-tab .tab-content { display: flex; align-items: center; justify-content: center; } + /* Ensure glance tabs within pinned container fit their content */ .tabbrowser-tab[zen-glance-tab='true'] { width: fit-content !important; } } +/* Styling for the label shown when hovering the reset-pin button */ .tab-reset-pin-label { - pointer-events: none; - transition: opacity 0.1s ease-in-out, margin 0.1s ease-in-out, max-height 0.1s ease-in-out; - max-height: 0px; + pointer-events: none; /* Non-interactive */ + transition: + opacity 0.1s ease-in-out, + margin 0.1s ease-in-out, + max-height 0.1s ease-in-out; + max-height: 0px; /* Hidden by default */ opacity: 0; - transform: translateY(-5px); + transform: translateY(-5px); /* Slight offset */ font-size: x-small; margin: 0; } -/* Mark: toolbox as expanded */ +/* ========================================================================== + Mark: EXPANDED Sidebar Styles (`zen-sidebar-expanded='true'`) + ========================================================================== */ #navigator-toolbox[zen-sidebar-expanded='true'] { + /* Set width to fit content when expanded */ --zen-toolbox-min-width: fit-content; - --tab-icon-end-margin: 8.5px; + /* Define margin for tab icons */ + --tab-icon-end-margin: 8.5px; /* Used later? Not directly applied here */ padding: var(--zen-toolbox-padding); - padding-left: 0; - padding-top: 0; + padding-left: 0; /* Reset left padding (adjusted later based on side) */ + padding-top: 0; /* Reset top padding */ + /* Ensure Personal Toolbar has no left padding when expanded */ #PersonalToolbar:not([collapsed='true']) { padding-left: 0 !important; } + /* Set a minimum width for the titlebar area */ & #titlebar { min-width: 150px; } + /* Add margin to the new tab button area */ & #tabbrowser-arrowscrollbox-periphery { margin-inline: var(--tab-block-margin); } + /* Adjust nav-bar padding */ & #nav-bar { - padding-right: 0; + padding-right: 0; /* Reset right padding */ + /* Specific padding for URL bar input in single toolbar mode */ :root[zen-single-toolbar='true'] & { & #urlbar:not([breakout-extend='true']):not([pageproxystate='invalid']) .urlbar-input-container { padding-left: 8px; @@ -465,155 +541,170 @@ } } + /* Remove top margin from nav-bar */ & #nav-bar { margin-top: 0; } + /* Hide workspace indicator icon if it has no specific icon set */ & .zen-current-workspace-indicator-icon[no-icon='true'] { display: none; } + /* Hide workspace button icon if it has no specific icon set */ & #zen-workspaces-button { & .zen-workspace-sidebar-icon[no-icon='true'] { display: none; } } + /* Style pinned tabs container when it has visible tabs */ & #vertical-pinned-tabs-container:has(tab:not([hidden])) { position: relative; + /* Make pinned tabs take full width */ & .tabbrowser-tab { width: 100%; } } + /* Style bottom buttons area when expanded */ & #zen-sidebar-bottom-buttons { display: flex; - /* Make sure the icons take most of the space, smartly */ - flex-direction: row; - justify-content: space-between; - + flex-direction: row; /* Arrange buttons horizontally */ + justify-content: space-between; /* Distribute space */ width: 100%; position: relative; } + /* Set min height for tabs in the essentials wrapper */ & #zen-essentials-wrapper { --tab-min-height: 44px; } - /* Mark: Fix separator paddings */ + /* Adjust padding based on sidebar side */ &[zen-right-side='true'] { - padding-left: 0; + padding-left: 0; /* No padding on the inside edge (left) */ } - &:not([zen-right-side='true']) { - padding-right: 0; - padding-left: var(--zen-toolbox-padding); + padding-right: 0; /* No padding on the inside edge (right) */ + padding-left: var(--zen-toolbox-padding); /* Add padding on the outside edge (left) */ } + /* Style the customization target and its contents when expanded */ & #TabsToolbar-customization-target { + /* Make separator full width */ &::after { width: 100%; bottom: calc(-0.5 * var(--zen-toolbox-padding)); } + /* Style toolbar items (buttons, etc.) */ & > :is(toolbaritem, toolbarbutton):not(#search-container):not(#zen-workspaces-button), & #tabbrowser-arrowscrollbox-periphery > toolbarbutton { - width: 100% !important; - border-radius: var(--border-radius-medium) !important; - - padding-left: var(--toolbarbutton-inner-padding) !important; + /* Target new tab button too */ + width: 100% !important; /* Full width */ + border-radius: var(--border-radius-medium) !important; /* Apply border radius */ + padding-left: var(--toolbarbutton-inner-padding) !important; /* Apply padding */ padding-right: var(--toolbarbutton-inner-padding) !important; + /* Ensure label takes full width */ & label { display: flex; width: 100%; } + /* Standardize icon size */ & image { height: 16px; width: 16px; padding: 0 !important; } + /* Style for active/checked state */ &:is([open], [checked]) { background: var(--toolbarbutton-active-background) !important; - & image, label { background: transparent !important; - } + } /* Ensure children are transparent */ } + /* Style for hover state */ &:hover { background: var(--toolbarbutton-hover-background); - & image, label { background: transparent !important; - } + } /* Ensure children are transparent */ } } } + /* Style tabs container when expanded */ & #tabbrowser-tabs { - --tab-inline-padding: 8px; - & .tabbrowser-tab { + --tab-inline-padding: 8px; /* Define padding for tab content */ + & .tabbrowser-tab { + /* Show tab label */ & .tab-label-container { display: flex; } + /* Adjust tab background margin and width */ & .tab-background { margin-inline: var(--tab-block-margin); - width: -moz-available; + width: -moz-available; /* Take available width */ } + /* --- Pinned Tab Icon Repositioning & Reset Button --- */ + /* Reposition icon stack absolutely when tab is pinned (and not essential) */ &[zen-pinned-changed='true']:not([zen-essential]) > .tab-stack > .tab-content > .tab-icon-stack { position: absolute; top: 50%; transform: translateY(-50%); - /* 16px divided by 2, it's the icon size */ - left: 8px; + left: 8px; /* Position near the start */ margin: 0 !important; - pointer-events: none; + pointer-events: none; /* Icon stack itself is not interactive */ + /* Allow interaction with elements inside the stack (e.g., overlays) */ & > *:not(.tab-icon-image) { pointer-events: all; } } + /* Hide the reset-pin image by default */ &[zen-pinned-changed='true']:not([zen-essential]) .tab-reset-pin-button image { opacity: 0; } + /* Show reset-pin interactions on hover */ &[zen-pinned-changed='true']:not([zen-essential]) .tab-reset-pin-button:hover { + /* Show the helper label */ & ~ .tab-label-container .tab-reset-pin-label { max-height: 10px; opacity: 0.6; } - - & ~ .tab-label-container .tab-reset-pin-label { - max-height: 10px; - opacity: 0.6; - } - - + /* Fade out the original tab icon */ & ~ .tab-icon-stack .tab-icon-image { opacity: 0; } - + /* Show the reset-pin button image */ & image { opacity: 1; } } + /* --- End Pinned Tab --- */ + /* Show close button on hover or when selected */ &:is(:hover, [visuallyselected]) .tab-close-button { display: block; - --tab-inline-padding: 0; /* Avoid weird padding */ + /* Reset padding for close button positioning */ + --tab-inline-padding: 0; margin-inline-end: 0; } + /* Adjust margins for various tab icon states/overlays */ .tab-throbber, .tab-icon-pending, .tab-icon-image, @@ -626,118 +717,166 @@ } } +/* ========================================================================== + Mark: COLLAPSED Sidebar Styles (`:not([zen-sidebar-expanded='true'])`) + ========================================================================== */ + +/* Define fixed width and padding for collapsed state */ :root:not([zen-sidebar-expanded='true']) { --tab-min-width: 36px !important; --zen-toolbox-padding: 6px !important; --zen-toolbox-max-width: calc(var(--tab-min-width) + var(--zen-toolbox-padding) * 2); } -/* Mark: collapsed sidebar */ #navigator-toolbox:not([zen-sidebar-expanded='true']) { + /* Force fixed width */ max-width: var(--zen-toolbox-max-width) !important; min-width: var(--zen-toolbox-max-width) !important; - padding-bottom: var(--zen-toolbox-padding); + padding-bottom: var(--zen-toolbox-padding); /* Apply bottom padding */ + + /* Hide text labels */ & .zen-current-workspace-indicator-name, & .toolbarbutton-text { display: none !important; } + + /* Center and dim workspace indicator */ & .zen-current-workspace-indicator { padding-left: 0; padding-right: 0; display: flex; align-items: center; justify-content: center; - opacity: .4; - align-items: center; + opacity: 0.4; } + + /* Center items in essentials container */ & .zen-essentials-container { justify-content: center; } + + /* Style new tab button when collapsed */ & #vertical-tabs-newtab-button { padding: 0 !important; background: transparent !important; } + + /* Ensure bottom buttons container fits content during customization */ :root[customizing] & #zen-sidebar-bottom-buttons { min-width: unset !important; } + + /* Center top buttons container */ & #zen-sidebar-top-buttons { justify-content: center; - max-height: unset !important; + max-height: unset !important; /* Allow natural height */ height: fit-content !important; } + + /* Adjust titlebar layout for collapsed state */ & #titlebar { display: grid; - grid-template-rows: auto 1fr; + grid-template-rows: auto 1fr; /* Allow content below button box */ } + + /* Style top buttons customization target */ & #zen-sidebar-top-buttons-customization-target { - flex-direction: column; + flex-direction: column; /* Stack items vertically */ padding-top: var(--zen-element-separation); } + + /* Style bottom buttons area when collapsed */ & #zen-sidebar-bottom-buttons { display: flex; - flex-direction: column; + flex-direction: column; /* Stack vertically */ padding-top: var(--zen-element-separation); - align-items: center; + align-items: center; /* Center horizontally */ } + + /* Style new tab button area */ & #tabbrowser-arrowscrollbox-periphery { & > toolbarbutton { - margin: 0 auto !important; - padding: 0 !important; + margin: 0 auto !important; /* Center the button */ + padding: 0 !important; /* Remove padding */ } + /* Adjust separator */ &::before { width: 90% !important; } } - & #EssentialsToolbar { - display: none !important; - } + + /* Hide optional elements */ + & #EssentialsToolbar, & #essentials-accordion-header { display: none !important; } + + /* Style pinned tabs container */ & #vertical-pinned-tabs-container:has(tab:not([hidden])) { position: relative; + /* Constrain pinned tab width */ & .tabbrowser-tab { max-width: var(--tab-min-width); } } + + /* Adjust customization target padding and separator */ & #TabsToolbar-customization-target { padding-bottom: var(--zen-toolbox-padding); &::after { - bottom: -1px !important; + bottom: -1px !important; /* Position separator correctly */ } } + + /* Style tabs container when collapsed */ & #tabbrowser-tabs { - margin-top: -2px; + margin-top: -2px; /* Minor visual adjustment */ + & .tabbrowser-tab { - margin: 0 auto; + margin: 0 auto; /* Center tabs horizontally */ + + /* Center background */ & .tab-background { margin-inline: auto !important; } + + /* Hide reset buttons */ & .tab-reset-button, & .tab-reset-pin-button { display: none !important; } + + /* Center tab content and hide label */ & .tab-content { display: flex; align-content: center; justify-content: center; - padding: 0 !important; + padding: 0 !important; /* Remove padding */ + & .tab-label-container { - display: none !important; + display: none !important; /* Hide label */ } + + /* Reset icon end margin */ & .tab-icon-image, & .tab-icon-pending { margin-inline-end: 0 !important; } - /* Hide glances */ + + /* Hide nested glance tabs completely */ & .tabbrowser-tab { display: none !important; } } } + + /* Optionally hide mute button overlay on non-selected tabs when collapsed */ @media -moz-pref('zen.view.sidebar-collapsed.hide-mute-button') { & .tab-icon-overlay:is([soundplaying], [muted]):not([selected]) { display: none !important; + + /* Complex selectors to ensure indicators still show correctly in specific density/hover states */ + /* This part seems overly complex and might need review/simplification if possible */ :is( :root[uidensity='compact'], #tabbrowser-tabs[secondarytext-unsupported], @@ -749,10 +888,12 @@ #tabbrowser-tabs:not([secondarytext-unsupported]) .tabbrowser-tab:not(:hover) &[indicator-replaces-favicon] { - opacity: 1 !important; + opacity: 1 !important; /* Ensure full opacity */ } } } + + /* Reset end margins for all icon types when collapsed */ & .tab-throbber, & .tab-icon-pending, & .tab-icon-image, @@ -761,46 +902,59 @@ margin-inline-end: 0 !important; } } + + /* Stack workspace button content vertically */ & #zen-workspaces-button { flex-direction: column; } } +/* Hide splitter when sidebar is collapsed */ :root:not([zen-sidebar-expanded='true']) #zen-sidebar-splitter { display: none !important; } -/* Mark: Separator styling */ +/* ========================================================================== + Mark: Sidebar Splitter Styling + ========================================================================== */ #zen-sidebar-splitter { - opacity: 0; - max-width: var(--zen-toolbox-padding) !important; + opacity: 0; /* Hidden by default, maybe shown on hover/drag? */ + max-width: var(--zen-toolbox-padding) !important; /* Width based on padding */ min-width: var(--zen-toolbox-padding) !important; height: 100%; transition: opacity 0.2s ease-in-out; - background: var(--zen-colors-border); - appearance: none; - position: relative !important; - order: 0; + background: var(--zen-colors-border); /* Use theme border color */ + appearance: none; /* Remove default styling */ + position: relative !important; /* Ensure positioning context */ + order: 0; /* Default order */ } -/* Mark: Move sidebar to the right */ +/* ========================================================================== + Mark: Move Sidebar to the Right (`zen-right-side='true'`) + ========================================================================== */ :root[zen-right-side='true'] { + /* Move the main toolbox (sidebar) to the right */ & #navigator-toolbox { - order: 10 !important; + order: 10 !important; /* High order value */ } + /* Move the splitter just before the toolbox */ & #zen-sidebar-splitter { order: 9 !important; } } -/* Mark: Override the default tab close button */ +/* ========================================================================== + Mark: Override Default Tab Close/Reset Button Behavior + ========================================================================== */ #tabbrowser-tabs { & .tabbrowser-tab { + /* Hide standard close button on pinned tabs (except pending) */ &[pinned]:not([pending='true']) .tab-close-button { display: none !important; } + /* Show custom reset (unpin) button on hover/selection for non-essential pinned tabs */ &[pinned]:not([pending='true']):not([zen-essential]) { &:hover .tab-reset-button, &[visuallyselected] .tab-reset-button { @@ -808,70 +962,80 @@ } } + /* Hide the reset-pin button if tab isn't marked as changed */ &:not([zen-pinned-changed='true']) .tab-reset-pin-button { display: none; } + /* Never show reset buttons on essential tabs */ &[zen-essential] .tab-reset-button, &[zen-essential] .tab-reset-pin-button { display: none; } + /* Hide reset button unless pinned and selected/hovered */ &:not([pinned][visuallyselected]) .tab-reset-button { display: none; } + /* Ensure selected tab background border is transparent */ &[selected] .tab-background { border-color: transparent; } } } -.tab-reset-button, +/* ========================================================================== + Custom Reset/Unpin Button Styles + ========================================================================== */ +.tab-reset-button, /* Standard unpin button */ .tab-reset-pin-button { - display: none; - -moz-context-properties: fill, fill-opacity; + /* Button shown when pinning state changes */ + display: none; /* Hidden by default, shown conditionally above */ + -moz-context-properties: fill, fill-opacity; /* Inherit fill properties */ border-radius: var(--tab-border-radius); color: inherit; fill: currentColor; - padding: var(--tab-close-button-padding); - width: 24px; + padding: var(--tab-close-button-padding); /* Use standard close button padding */ + width: 24px; /* Fixed size */ height: 24px; - outline: var(--toolbarbutton-outline); + outline: var(--toolbarbutton-outline); /* Use standard outline */ + /* Hover/active outline styles */ &:hover { outline-color: var(--toolbarbutton-hover-outline-color); } - &:hover:active { outline-color: var(--toolbarbutton-active-outline-color); } } +/* Specific styling for the alternative reset-pin button */ .tab-reset-pin-button { - display: flex; - position: relative; - height: calc(100% - var(--tab-block-margin) * 2); - margin-left: calc(-1 * var(--tab-inline-padding) + var(--tab-block-margin)); + display: flex; /* Use flex for alignment */ + position: relative; /* For pseudo-element positioning */ + height: calc(100% - var(--tab-block-margin) * 2); /* Adjust height based on margins */ + margin-left: calc(-1 * var(--tab-inline-padding) + var(--tab-block-margin)); /* Overlap slightly */ margin-right: 8px; - padding: 0 calc(var(--toolbarbutton-inner-padding) - 2px) 0 calc(var(--toolbarbutton-inner-padding) / 4 + var(--tab-inline-padding) - 2px); - border-radius: 0; - border-top-left-radius: var(--border-radius-medium); - width: unset; + padding: 0 calc(var(--toolbarbutton-inner-padding) - 2px) 0 + calc(var(--toolbarbutton-inner-padding) / 4 + var(--tab-inline-padding) - 2px); /* Custom padding */ + border-radius: 0; /* Remove general radius */ + border-top-left-radius: var(--border-radius-medium); /* Apply radius only to left corners */ + width: unset; /* Auto width */ border-bottom-left-radius: var(--border-radius-medium); align-items: center; justify-content: center; + /* Style the image inside (uses original tab icon) */ & > image { - list-style-image: var(--zen-original-tab-icon); - width: 100%; - height: 100%; - pointer-events: none; - width: 16px; + list-style-image: var(--zen-original-tab-icon); /* Expects variable set elsewhere */ + width: 16px; /* Fixed size */ height: 16px; - border-radius: 4px; + pointer-events: none; + border-radius: 4px; /* Slightly rounded */ } + /* Add a decorative vertical line */ &::after { content: ''; display: block; @@ -882,32 +1046,36 @@ right: 0; top: 50%; border-radius: 2px; - transform: rotate(15deg) translateY(-50%); + transform: rotate(15deg) translateY(-50%); /* Tilted line */ } + /* Hide the line on hover (reveals icon change) */ &:hover::after { opacity: 0; } } -.reset-icon, +/* Remove default appearance for custom buttons */ +.reset-icon, /* Assuming this is used within .tab-reset-button */ .tab-reset-pin-button { appearance: none; } +/* Background color changes on hover/active (for non-forced-colors mode) */ @media not (forced-colors) { .tab-reset-button:hover, .tab-reset-pin-button:hover { - background-color: color-mix(in srgb, currentColor 10%, transparent); + background-color: color-mix(in srgb, currentColor 10%, transparent); /* Slight tint */ } .tab-reset-button:hover:active, .tab-reset-pin-button:hover:active { - background-color: color-mix(in srgb, currentColor 20%, transparent); + background-color: color-mix(in srgb, currentColor 20%, transparent); /* Darker tint */ } } -.tab-reset-button> .button-icon, +/* Ensure icons within reset buttons have no margin */ +.tab-reset-button > .button-icon, .tab-reset-button > .button-box > .button-icon, .tab-reset-button > .toolbarbutton-icon, .tab-reset-pin-button > .button-icon, @@ -916,6 +1084,7 @@ margin: 0; } +/* Hide text labels within reset buttons */ .tab-reset-button > .button-box > .button-text, .tab-reset-button > .toolbarbutton-text, .tab-reset-pin-button > .button-box > .button-text, @@ -923,134 +1092,158 @@ display: none; } - -/* Customization mode */ - +/* ========================================================================== + Customization Mode Adjustments + ========================================================================== */ :root[customizing] #TabsToolbar > *, :root[customizing] #TabsToolbar-customization-target { - min-width: unset !important; + min-width: unset !important; /* Allow shrinking during customization */ } -/* Mark: Sidebar top buttons */ +/* ========================================================================== + Mark: Sidebar Top Buttons Area Styles + ========================================================================== */ #zen-sidebar-top-buttons { - order: -1; - - min-width: unset !important; + order: -1; /* Ensure it appears at the top */ + min-width: unset !important; /* Allow shrinking */ + /* Adjust inner padding based on sidebar state */ :root[zen-sidebar-expanded='true'] & { - --toolbarbutton-inner-padding: var(--zen-toolbar-button-inner-padding) !important; + --toolbarbutton-inner-padding: var(--zen-toolbar-button-inner-padding) !important; /* Use theme variable */ } - :root[zen-single-toolbar='true'] & { - --toolbarbutton-inner-padding: calc(var(--zen-toolbar-button-inner-padding) - 2px) !important; + --toolbarbutton-inner-padding: calc( + var(--zen-toolbar-button-inner-padding) - 2px + ) !important; /* Slightly less in single toolbar */ + /* Reorder buttons in single toolbar mode */ & #PanelUI-button { - order: -2; + order: -2; /* Hamburger first */ } - & #unified-extensions-button { - order: -1; + order: -1; /* Extensions next */ } } + /* Style the customization target within the top buttons area */ & #zen-sidebar-top-buttons-customization-target { - height: 100%; - align-items: center; + height: 100%; /* Full height */ + align-items: center; /* Center items vertically */ + /* Adjust start padding based on state and side */ :root:not([zen-sidebar-expanded='true']):not([zen-right-side='true']) { padding-inline-start: var(--zen-toolbox-padding); } - #nav-bar & { + /* If nested in nav-bar, use outer padding */ padding-inline-start: var(--toolbarbutton-outer-padding); } - :root[zen-right-side='true']:not([zen-window-buttons-reversed='true']) { - padding-inline-end: var(--zen-toolbox-padding); + padding-inline-end: var(--zen-toolbox-padding); /* Add end padding for right sidebar */ } + /* Standardize height and padding for toolbar buttons (excluding titlebar buttons) */ & toolbarbutton:not(.titlebar-button) { - height: calc(2 * var(--toolbarbutton-inner-padding) + 16px); - padding: 0 var(--toolbarbutton-outer-padding) !important; + height: calc(2 * var(--toolbarbutton-inner-padding) + 16px); /* Calculate height based on padding + icon */ + padding: 0 var(--toolbarbutton-outer-padding) !important; /* Apply outer padding */ } + /* Hide flexible space when collapsed */ :root:not([zen-sidebar-expanded='true']) & toolbarspring { display: none; } } + /* Style specific action buttons (likely icon-only) */ & .zen-sidebar-action-button { - padding: 0 !important; - + padding: 0 !important; /* Remove padding */ & label { - display: none !important; + display: none !important; /* Hide label */ } } } +/* ========================================================================== + Vertical New Tab Button (Optional Feature) + ========================================================================== */ + +/* Hide the button wrapper by default */ #tabs-newtab-button { display: none; - opacity: 0.5; - -moz-user-focus: ignore !important; + opacity: 0.5; /* Dimmed by default */ + -moz-user-focus: ignore !important; /* Prevent focus */ } +/* Show and style the button if preference `zen.tabs.show-newtab-vertical` is enabled */ @media -moz-pref('zen.tabs.show-newtab-vertical') { #tabs-newtab-button { - display: flex !important; - transition: scale 0.1s ease; + display: flex !important; /* Show the button */ + transition: scale 0.1s ease; /* Add scale transition */ + + /* Style text within the button */ & .toolbarbutton-text { align-items: center; padding-top: 0; } + /* Scale down slightly on press */ &:active, &[open] { scale: 0.98; } + /* Style when placed "in urlbar" (likely a state/attribute) */ &[in-urlbar] { background: var(--tab-selected-bgcolor) !important; - opacity: 1 !important; - box-shadow: var(--tab-selected-shadow); + opacity: 1 !important; /* Full opacity */ + box-shadow: var(--tab-selected-shadow); /* Apply selected tab shadow */ } } + /* Style the container ("periphery") holding the new tab button */ #tabbrowser-arrowscrollbox-periphery { + /* Conditional border color for light mode */ @media not (prefers-color-scheme: dark) { - --zen-colors-border: var(--zen-colors-tertiary); + --zen-colors-border: var(--zen-colors-tertiary); /* Use tertiary color */ } + /* Move button to the top if preference is set */ @media -moz-pref('zen.view.show-newtab-button-top') { order: -1; } + /* Add a separator line above the button if preferences are set and there are tabs */ @media -moz-pref('zen.view.show-newtab-button-border-top') and (not -moz-pref('zen.view.show-newtab-button-top')) { - #tabbrowser-arrowscrollbox:has(tab:not([hidden])) & { - margin-top: 15px; - position: relative; - &::before { - content: ''; - display: block; - height: 1px; - background: light-dark(rgba(1, 1, 1, 0.075), rgba(255, 255, 255, 0.1)); - width: 98%; - position: absolute; - top: -8px; - left: 50%; - transform: translateX(-50%); + #tabbrowser-arrowscrollbox:has(tab:not([hidden])) & { + /* Only if tabs exist */ + margin-top: 15px; /* Space above */ + position: relative; /* For pseudo-element */ + &::before { + content: ''; + display: block; + height: 1px; + background: light-dark(rgba(1, 1, 1, 0.075), rgba(255, 255, 255, 0.1)); /* Separator color */ + width: 98%; /* Near full width */ + position: absolute; + top: -8px; /* Position above the button */ + left: 50%; + transform: translateX(-50%); /* Center horizontally */ + } } } } - } } +/* ========================================================================== + Mark: Essentials Toolbar / Section Styles + ========================================================================== */ -/* Mark: Essentials Toolbar */ #zen-essentials-wrapper { margin-left: calc(-1 * var(--zen-toolbox-padding)); min-width: calc(100% + var(--zen-toolbox-padding) * 2); } +/* Container for essential items (often pinned/favorite tabs) */ .zen-essentials-container { padding-bottom: var(--zen-toolbox-padding); overflow: hidden; @@ -1058,30 +1251,39 @@ transition: max-height 0.3s ease-out; opacity: 1; grid-template-columns: repeat(auto-fit, minmax(49px, auto)); - overflow: hidden; + &[data-hack-type] { + &[data-hack-type='3'] { + --zen-hack-type: 3; + } + &[data-hack-type='4'] { + --zen-hack-type: 4; + } + grid-template-columns: repeat(auto-fit, minmax(calc(100% / var(--zen-hack-type) - 1%), auto)); + } scrollbar-width: thin; min-width: calc(100% + var(--zen-toolbox-padding) * 2); padding: 0 var(--zen-toolbox-padding); - display: grid; } +/* Style tabs within the Essentials container (and a related welcome sidebar) */ .zen-essentials-container > .tabbrowser-tab, #zen-welcome-initial-essentials-browser-sidebar-essentials .tabbrowser-tab { - --toolbarbutton-inner-padding: 0; - max-width: unset; - width: 100% !important; + --toolbarbutton-inner-padding: 0; /* Reset padding */ + max-width: unset; /* Allow stretching */ + width: 100% !important; /* Force full width of grid cell */ + /* Style background */ & .tab-background { - border-radius: var(--border-radius-medium) !important; - transition: background 0.1s ease-in-out; + border-radius: var(--border-radius-medium) !important; /* Use medium radius */ + transition: background 0.1s ease-in-out; /* Smooth background transition */ } --tab-selected-bgcolor: light-dark(rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.2)); - &:not([visuallyselected], [multiselected="true"]) .tab-background { - background: var(--zen-toolbar-element-bg); - border: none; + &:not([visuallyselected], [multiselected='true']) .tab-background { + background: var(--zen-toolbar-element-bg); /* Use generic element background */ + border: none; /* No border */ } & .tab-content { @@ -1089,10 +1291,7 @@ justify-content: center; } - & .tab-label-container { - display: none !important; - } - + & .tab-label-container, & .tab-close-button { display: none !important; } @@ -1106,123 +1305,88 @@ background: var(--tab-selected-bgcolor); } + /* Optional blurred favicon background effect (if pref `zen.theme.essentials-favicon-bg` is enabled) */ @media -moz-pref('zen.theme.essentials-favicon-bg') { &[visuallyselected] > .tab-stack > .tab-background { + /* Create a blurred background pseudo-element using the tab icon */ &::after { - content: ""; - inset: -50%; - filter: blur(20px); + content: ''; + inset: -50%; /* Extend beyond bounds */ + filter: blur(20px); /* Apply blur */ position: absolute; background-size: contain; background-clip: padding-box; - background-image: var(--zen-tab-icon); - z-index: -1; + background-image: var(--zen-tab-icon); /* Use tab icon variable */ + z-index: -1; /* Place behind content */ background-position: center; } - background: transparent; - overflow: hidden; - position: relative; - --zen-essential-bg-margin: 2px; + background: transparent; /* Make main background transparent */ + overflow: hidden; /* Clip pseudo-elements */ + position: relative; /* Positioning context */ + --zen-essential-bg-margin: 2px; /* Margin for inner layer */ + /* Create an inner background layer for contrast */ &::before { background: light-dark(rgba(255, 255, 255, 0.85), rgba(68, 64, 64, 0.85)); - margin: var(--zen-essential-bg-margin); - border-radius: calc(var(--border-radius-medium) - var(--zen-essential-bg-margin)); + margin: var(--zen-essential-bg-margin); /* Apply margin */ + border-radius: calc(var(--border-radius-medium) - var(--zen-essential-bg-margin)); /* Adjust radius */ position: absolute; inset: 0; - z-index: 0; - content: ""; - transition: background 0.1s ease-in-out; + z-index: 0; /* Position above ::after, below content */ + content: ''; + transition: background 0.1s ease-in-out; /* Smooth transition */ } } + /* Slightly fade inner background on hover */ &[visuallyselected]:hover .tab-background::before { - background: light-dark(rgba(255, 255, 255, 0.80), rgba(68, 64, 64, 0.75)); + background: light-dark(rgba(255, 255, 255, 0.8), rgba(68, 64, 64, 0.75)); } } } - -/* Very special occasions */ - -/* Mark: Right side windows controls with collapsed sidebar */ -:root:not([zen-compact-mode='true']) { - &[zen-right-side='true']:not([zen-sidebar-expanded='true']):not([zen-window-buttons-reversed='true']) { - & #navigator-toolbox { - margin-top: var(--zen-toolbar-height) !important; - } - - & .titlebar-buttonbox-container { - margin-right: calc(-1 * var(--zen-toolbox-max-width)) !important; - } - - & #zen-appcontent-wrapper { - overflow-x: visible; - } - - & #zen-sidebar-top-buttons-customization-target { - padding-top: 0; - } - - & #zen-appcontent-navbar-container { - padding-left: var(--zen-element-separation); - } - -%include vertical-tabs-topbuttons-fix.css - } - - &:not([zen-right-side='true']):not([zen-sidebar-expanded='true'])[zen-window-buttons-reversed='true'] { - & #navigator-toolbox { - margin-top: var(--zen-toolbar-height) !important; - } - - & .titlebar-buttonbox-container { - margin-left: calc(-1 * var(--zen-toolbox-max-width) + var(--zen-toolbox-padding) / 2) !important; - } - - & #zen-appcontent-wrapper { - overflow-x: visible; - } - - & #zen-sidebar-top-buttons-customization-target { - padding-top: 0; - } - - & #zen-appcontent-navbar-container { - padding-right: var(--zen-element-separation); - } - -%include vertical-tabs-topbuttons-fix.css - } -} - -/* Vertical tabs reordering indicators */ +/* ========================================================================== + Vertical Tabs Reordering Drag Indicator + ========================================================================== */ #zen-drag-indicator { + /* Define indicator variables */ --zen-drag-indicator-height: 2px; - --zen-drag-indicator-bg: color-mix(in srgb, var(--zen-primary-color) 50%, light-dark(rgba(0, 0, 0, .85), rgba(255, 255, 255, .95)) 50%); - position: fixed; - z-index: 1000; - background: var(--zen-drag-indicator-bg); - pointer-events: none; - border-radius: 5px; + --zen-drag-indicator-bg: color-mix( + in srgb, + var(--zen-primary-color) 50%, + light-dark(rgba(0, 0, 0, 0.85), rgba(255, 255, 255, 0.95)) 50% + ); + position: fixed; /* Position relative to viewport */ + z-index: 1000; /* Ensure it's on top */ + background: var(--zen-drag-indicator-bg); + pointer-events: none; /* Non-interactive */ + border-radius: 5px; /* Rounded ends */ + + /* Add a circle at the start of the indicator */ &::before { - content: ""; + content: ''; position: absolute; - height: calc(2 * var(--zen-drag-indicator-height)); + height: calc(2 * var(--zen-drag-indicator-height)); /* Circle diameter */ width: calc(2 * var(--zen-drag-indicator-height)); - border: var(--zen-drag-indicator-height) solid var(--zen-drag-indicator-bg); - border-radius: 50%; - background: transparent; + border: var(--zen-drag-indicator-height) solid var(--zen-drag-indicator-bg); /* Thick border */ + border-radius: 50%; /* Make it a circle */ + background: transparent; /* Hollow circle */ } + /* Styles for horizontal drag indicator (e.g., between workspaces?) */ &[orientation='horizontal'] { + /* Position and size based on external CSS variables */ left: calc(var(--indicator-left) + 2 * var(--zen-drag-indicator-height) + 4px); width: calc(var(--indicator-width) - 2 * var(--zen-drag-indicator-height) - 4px); height: var(--zen-drag-indicator-height); - transition: top 0.1s ease-out, left 0.1s ease-out, width 0.1s ease-out; + transition: + top 0.1s ease-out, + left 0.1s ease-out, + width 0.1s ease-out; + /* Position the circle at the left end */ &::before { left: calc(-2 * var(--zen-drag-indicator-height)); top: 50%; @@ -1230,12 +1394,18 @@ } } + /* Styles for vertical drag indicator (between tabs) */ &[orientation='vertical'] { + /* Position and size based on external CSS variables */ top: calc(var(--indicator-top) + 2 * var(--zen-drag-indicator-height) + 4px); height: calc(var(--indicator-height) - 2 * var(--zen-drag-indicator-height) - 4px); width: var(--zen-drag-indicator-height); - transition: top 0.1s ease-out, left 0.1s ease-out, height 0.1s ease-out; + transition: + top 0.1s ease-out, + left 0.1s ease-out, + height 0.1s ease-out; + /* Position the circle at the top end */ &::before { top: calc(-2 * var(--zen-drag-indicator-height)); left: 50%; @@ -1244,7 +1414,10 @@ } } -/* Renaming tabs */ +/* ========================================================================== + Renaming Tabs Input Styles + ========================================================================== */ + .tab-label-container-editing { display: none !important; } @@ -1258,20 +1431,27 @@ padding: 0; } -/* Section: tab workspaces stylings */ -.zen-workspace-tabs-section { - position: absolute; - transform: translateX(-100%); +/* ========================================================================== + Section: Tab Workspaces Stylings + ========================================================================== */ +/* Style for individual workspace tab sections */ +.zen-workspace-tabs-section { + position: absolute; /* Position absolutely for transitions */ + transform: translateX(-100%); /* Initially off-screen to the left */ + + /* Apply flex layout unless it's the essentials container */ &:not(.zen-essentials-container) { display: flex; - min-width: calc(100% - var(--zen-toolbox-padding) * 2); + min-width: calc(100% - var(--zen-toolbox-padding) * 2); /* Set width based on padding */ } + /* Apply horizontal margins unless it's the indicator or essentials */ &:not(.zen-current-workspace-indicator):not(.zen-essentials-container) { margin: 0 var(--zen-toolbox-padding); } + /* Hide section visually and disable interaction when hidden attribute is present */ &[hidden='true'] { visibility: hidden; pointer-events: none; diff --git a/src/zen/workspaces/ZenWorkspaces.mjs b/src/zen/workspaces/ZenWorkspaces.mjs index 676fd4b58..72bf7e2a4 100644 --- a/src/zen/workspaces/ZenWorkspaces.mjs +++ b/src/zen/workspaces/ZenWorkspaces.mjs @@ -2386,6 +2386,18 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature { ); const workspaceObject = this.getWorkspaceFromId(workspaceId); const essentialContainer = this.getEssentialsSection(workspaceObject.containerTabId); + const essentialNumChildren = essentialContainer.children.length; + let essentialHackType = 0; + if (essentialNumChildren % 3 === 0) { + essentialHackType = 3; + } else if (essentialNumChildren % 4 === 0 || essentialNumChildren % 4 === 3) { + essentialHackType = 4; + } + if (essentialHackType > 0) { + essentialContainer.setAttribute('data-hack-type', essentialHackType); + } else { + essentialContainer.removeAttribute('data-hack-type'); + } this._updateMarginTopPinnedTabs(arrowScrollbox, pinnedContainer, essentialContainer, workspaceIndicator, forAnimation); this.updateShouldHideSeparator(arrowScrollbox, pinnedContainer); } From 4f49ff3290931e413c4e69416d9b2fc457118c9c Mon Sep 17 00:00:00 2001 From: "Mr. M" Date: Tue, 29 Apr 2025 18:18:48 +0200 Subject: [PATCH 06/11] fix: Fixed PGO builds and test runs, b=(no-bug), c=no-component --- src/testing/profiles/mochitest/user-js.patch | 5 +++-- src/testing/profiles/profileserver/user-js.patch | 5 +++-- src/toolkit/modules/ShortcutUtils-sys-mjs.patch | 12 ++++++++++-- surfer.json | 2 +- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/testing/profiles/mochitest/user-js.patch b/src/testing/profiles/mochitest/user-js.patch index f3aaea0e8..ad2b941d4 100644 --- a/src/testing/profiles/mochitest/user-js.patch +++ b/src/testing/profiles/mochitest/user-js.patch @@ -1,8 +1,8 @@ diff --git a/testing/profiles/mochitest/user.js b/testing/profiles/mochitest/user.js -index a4068ac3f61161d014c49d54ae7a3bf886868f1b..b9861cfaae19a4a71b75ccc73095dc602df22b12 100644 +index a4068ac3f61161d014c49d54ae7a3bf886868f1b..6af5907abb46b6d3b871c159c73eec8373ee8ef5 100644 --- a/testing/profiles/mochitest/user.js +++ b/testing/profiles/mochitest/user.js -@@ -41,3 +41,9 @@ user_pref("places.history.floodingPrevention.enabled", false); +@@ -41,3 +41,10 @@ user_pref("places.history.floodingPrevention.enabled", false); // permission, and we can open it and wait for the user to give permission, then // don't do that. user_pref("geo.prompt.open_system_prefs", false); @@ -12,3 +12,4 @@ index a4068ac3f61161d014c49d54ae7a3bf886868f1b..b9861cfaae19a4a71b75ccc73095dc60 +user_pref("zen.watermark.enabled", false); +user_pref("zen.urlbar.replace-newtab", false); +user_pref("zen.testing.enabled", true); ++user_pref("dom.security.https_only_mode", false); // Dont ask why diff --git a/src/testing/profiles/profileserver/user-js.patch b/src/testing/profiles/profileserver/user-js.patch index 6b48c861e..ccfcc06ae 100644 --- a/src/testing/profiles/profileserver/user-js.patch +++ b/src/testing/profiles/profileserver/user-js.patch @@ -1,8 +1,8 @@ diff --git a/testing/profiles/profileserver/user.js b/testing/profiles/profileserver/user.js -index 19ff7d474f6d22d2d386764e2e6942ce6a324470..a68a1f692e050c2a2a7e5e1390dec9556e71d7ed 100644 +index 19ff7d474f6d22d2d386764e2e6942ce6a324470..b8a915b921e624c416d2ec379a2b54aedfcf9c36 100644 --- a/testing/profiles/profileserver/user.js +++ b/testing/profiles/profileserver/user.js -@@ -8,3 +8,11 @@ +@@ -8,3 +8,12 @@ user_pref("dom.timeout.enable_budget_timer_throttling", false); // Turn off update user_pref("app.update.disabledForTesting", true); @@ -14,3 +14,4 @@ index 19ff7d474f6d22d2d386764e2e6942ce6a324470..a68a1f692e050c2a2a7e5e1390dec955 +user_pref("zen.watermark.enabled", false); +user_pref("zen.urlbar.replace-newtab", false); +user_pref("zen.testing.enabled", true); ++user_pref("dom.security.https_only_mode", false); // Dont ask why diff --git a/src/toolkit/modules/ShortcutUtils-sys-mjs.patch b/src/toolkit/modules/ShortcutUtils-sys-mjs.patch index fe61b602a..11dd0b994 100644 --- a/src/toolkit/modules/ShortcutUtils-sys-mjs.patch +++ b/src/toolkit/modules/ShortcutUtils-sys-mjs.patch @@ -1,8 +1,16 @@ diff --git a/toolkit/modules/ShortcutUtils.sys.mjs b/toolkit/modules/ShortcutUtils.sys.mjs -index 360a7dbeeae3899af01945e35d5fe3aa0cb3c562..895d39fe5887ffae9cdbce9576df8b00d4cc8442 100644 +index 360a7dbeeae3899af01945e35d5fe3aa0cb3c562..354c0c9e65e443682a2b12113bc618af9e07910f 100644 --- a/toolkit/modules/ShortcutUtils.sys.mjs +++ b/toolkit/modules/ShortcutUtils.sys.mjs -@@ -382,12 +382,12 @@ export var ShortcutUtils = { +@@ -140,6 +140,7 @@ export var ShortcutUtils = { + key = keyCode.replace(/^VK_/, ""); + } + } else { ++ if (!keyAttribute) return ""; + key = keyAttribute.toUpperCase(); + } + +@@ -382,12 +383,12 @@ export var ShortcutUtils = { return ShortcutUtils.MOVE_TAB_FORWARD; } break; diff --git a/surfer.json b/surfer.json index 6074c44e6..65e0eef17 100644 --- a/surfer.json +++ b/surfer.json @@ -4,7 +4,7 @@ "appId": "zen", "binaryName": "zen", "version": { - "product": "firefox-beta", + "product": "firefox", "version": "137.0.2", "candidate": "138.0" }, From 79e731e89cf97d33294a42e6bd58205ba9068a8a Mon Sep 17 00:00:00 2001 From: "Mr. M" Date: Tue, 29 Apr 2025 18:27:00 +0200 Subject: [PATCH 07/11] test: Enable workspaces when doing tests, b=(no-bug), c=tests, workspaces --- src/zen/tests/browser.toml | 2 +- src/zen/tests/browser_zen_workspaces.js | 8 -------- .../tests/workspaces/browser_basic_workspaces.js | 13 +++++++++++++ src/zen/workspaces/ZenWorkspaces.mjs | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-) delete mode 100644 src/zen/tests/browser_zen_workspaces.js create mode 100644 src/zen/tests/workspaces/browser_basic_workspaces.js diff --git a/src/zen/tests/browser.toml b/src/zen/tests/browser.toml index 4f13eca6f..3a2658416 100644 --- a/src/zen/tests/browser.toml +++ b/src/zen/tests/browser.toml @@ -1,2 +1,2 @@ -["browser_zen_workspaces.js"] +["workspaces/browser_basic_workspaces.js"] diff --git a/src/zen/tests/browser_zen_workspaces.js b/src/zen/tests/browser_zen_workspaces.js deleted file mode 100644 index 04fa358c3..000000000 --- a/src/zen/tests/browser_zen_workspaces.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - https://creativecommons.org/publicdomain/zero/1.0/ */ - -'use strict'; - -add_task(async function test_TODO() { - ok(true, 'TODO: implement the test'); -}); diff --git a/src/zen/tests/workspaces/browser_basic_workspaces.js b/src/zen/tests/workspaces/browser_basic_workspaces.js new file mode 100644 index 000000000..73d38021e --- /dev/null +++ b/src/zen/tests/workspaces/browser_basic_workspaces.js @@ -0,0 +1,13 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +'use strict'; + +add_setup(async function () { + await ZenWorkspaces.createAndSaveWorkspace('Test Workspace 2'); +}); + +add_task(async function test_Check_Creation() { + const workspaces = await ZenWorkspaces._workspaces(); + ok(workspaces.workspaces.length, 2); +}); diff --git a/src/zen/workspaces/ZenWorkspaces.mjs b/src/zen/workspaces/ZenWorkspaces.mjs index 72bf7e2a4..fff326c49 100644 --- a/src/zen/workspaces/ZenWorkspaces.mjs +++ b/src/zen/workspaces/ZenWorkspaces.mjs @@ -678,7 +678,7 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature { get workspaceEnabled() { if (typeof this._workspaceEnabled === 'undefined') { - this._workspaceEnabled = !gZenUIManager.testingEnabled && this.shouldHaveWorkspaces; + this._workspaceEnabled = this.shouldHaveWorkspaces; } return this._workspaceEnabled && !window.closed; } From 8eec660d03c6a3be36a229d6d8df289c2b8b0f86 Mon Sep 17 00:00:00 2001 From: "Mr. M" Date: Tue, 29 Apr 2025 19:58:47 +0200 Subject: [PATCH 08/11] fix: Improved the way essentials are rendered, b=(no-bug), c=tabs, workspaces --- src/zen/tabs/zen-tabs/vertical-tabs.css | 12 +++--------- src/zen/workspaces/ZenWorkspaces.mjs | 4 +--- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/zen/tabs/zen-tabs/vertical-tabs.css b/src/zen/tabs/zen-tabs/vertical-tabs.css index 3d115ea73..c0217d85f 100644 --- a/src/zen/tabs/zen-tabs/vertical-tabs.css +++ b/src/zen/tabs/zen-tabs/vertical-tabs.css @@ -1250,15 +1250,9 @@ gap: calc(var(--zen-toolbox-padding) - 2px); transition: max-height 0.3s ease-out; opacity: 1; - grid-template-columns: repeat(auto-fit, minmax(49px, auto)); - &[data-hack-type] { - &[data-hack-type='3'] { - --zen-hack-type: 3; - } - &[data-hack-type='4'] { - --zen-hack-type: 4; - } - grid-template-columns: repeat(auto-fit, minmax(calc(100% / var(--zen-hack-type) - 1%), auto)); + grid-template-columns: repeat(auto-fit, minmax(48px, 1fr) minmax(48px, 1fr)); + &[data-hack-type='3'] { + grid-template-columns: repeat(auto-fit, minmax(calc(100% / 3 - 1%), auto)); } scrollbar-width: thin; min-width: calc(100% + var(--zen-toolbox-padding) * 2); diff --git a/src/zen/workspaces/ZenWorkspaces.mjs b/src/zen/workspaces/ZenWorkspaces.mjs index fff326c49..d90a8cae9 100644 --- a/src/zen/workspaces/ZenWorkspaces.mjs +++ b/src/zen/workspaces/ZenWorkspaces.mjs @@ -370,7 +370,7 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature { } let essentialsContainer = document.querySelector(`.zen-essentials-container[container="${container}"]:not([cloned])`); if (!essentialsContainer) { - essentialsContainer = document.createXULElement('vbox'); + essentialsContainer = document.createXULElement('hbox'); essentialsContainer.className = 'zen-essentials-container zen-workspace-tabs-section'; essentialsContainer.setAttribute('flex', '1'); essentialsContainer.setAttribute('container', container); @@ -2390,8 +2390,6 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature { let essentialHackType = 0; if (essentialNumChildren % 3 === 0) { essentialHackType = 3; - } else if (essentialNumChildren % 4 === 0 || essentialNumChildren % 4 === 3) { - essentialHackType = 4; } if (essentialHackType > 0) { essentialContainer.setAttribute('data-hack-type', essentialHackType); From f38bea67ab6e54e0858f04c183ca13b4fe4c94f6 Mon Sep 17 00:00:00 2001 From: "Mr. M" Date: Tue, 29 Apr 2025 20:09:08 +0200 Subject: [PATCH 09/11] chore: Added an icon for 'report broken site', b=(no-bug), c=no-component --- src/browser/themes/shared/zen-icons/icons.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/browser/themes/shared/zen-icons/icons.css b/src/browser/themes/shared/zen-icons/icons.css index 8de72d45a..21f954682 100644 --- a/src/browser/themes/shared/zen-icons/icons.css +++ b/src/browser/themes/shared/zen-icons/icons.css @@ -324,7 +324,8 @@ } /* security */ -.identity-popup-security-connection { +.identity-popup-security-connection, +#appMenu-report-broken-site-button { list-style-image: url('security-broken.svg') !important; } From 053bc28e6812a4721fa7cbd66ede49e9673d256b Mon Sep 17 00:00:00 2001 From: "Mr. M" Date: Tue, 29 Apr 2025 20:23:31 +0200 Subject: [PATCH 10/11] chore: Invoke less connections at startup by locally bundling icons, b=(bug #7000), c=common, images, welcome --- .../base/content/zen-assets.jar.inc.mn | 12 ++++++++++ src/zen/common/ZenCustomizableUI.sys.mjs | 2 +- src/zen/images/favicons/calendar.ico | Bin 0 -> 4414 bytes src/zen/images/favicons/discord.ico | Bin 0 -> 3774 bytes src/zen/images/favicons/figma.ico | Bin 0 -> 34494 bytes src/zen/images/favicons/github.ico | Bin 0 -> 41662 bytes src/zen/images/favicons/notion.ico | Bin 0 -> 32038 bytes src/zen/images/favicons/obsidian.ico | Bin 0 -> 31332 bytes src/zen/images/favicons/reddit.ico | Bin 0 -> 2238 bytes src/zen/images/favicons/slack.ico | Bin 0 -> 4286 bytes src/zen/images/favicons/trello.ico | Bin 0 -> 108167 bytes src/zen/images/favicons/x.ico | Bin 0 -> 2238 bytes src/zen/welcome/ZenWelcome.mjs | 22 +++++++++--------- 13 files changed, 24 insertions(+), 12 deletions(-) create mode 100644 src/zen/images/favicons/calendar.ico create mode 100644 src/zen/images/favicons/discord.ico create mode 100644 src/zen/images/favicons/figma.ico create mode 100644 src/zen/images/favicons/github.ico create mode 100644 src/zen/images/favicons/notion.ico create mode 100644 src/zen/images/favicons/obsidian.ico create mode 100644 src/zen/images/favicons/reddit.ico create mode 100644 src/zen/images/favicons/slack.ico create mode 100644 src/zen/images/favicons/trello.ico create mode 100644 src/zen/images/favicons/x.ico diff --git a/src/browser/base/content/zen-assets.jar.inc.mn b/src/browser/base/content/zen-assets.jar.inc.mn index bd4e8aab3..04f14da29 100644 --- a/src/browser/base/content/zen-assets.jar.inc.mn +++ b/src/browser/base/content/zen-assets.jar.inc.mn @@ -92,3 +92,15 @@ # JS Vendor content/browser/zen-vendor/tsparticles.confetti.bundle.min.js (../../zen/vendor/tsparticles.confetti.bundle.min.js) content/browser/zen-vendor/motion.min.mjs (../../zen/vendor/motion.min.mjs) + + # FavIcons for startup + content/browser/zen-images/favicons/calendar.ico (../../zen/images/favicons/calendar.ico) + content/browser/zen-images/favicons/discord.ico (../../zen/images/favicons/discord.ico) + content/browser/zen-images/favicons/figma.ico (../../zen/images/favicons/figma.ico) + content/browser/zen-images/favicons/github.ico (../../zen/images/favicons/github.ico) + content/browser/zen-images/favicons/notion.ico (../../zen/images/favicons/notion.ico) + content/browser/zen-images/favicons/obsidian.ico (../../zen/images/favicons/obsidian.ico) + content/browser/zen-images/favicons/slack.ico (../../zen/images/favicons/slack.ico) + content/browser/zen-images/favicons/reddit.ico (../../zen/images/favicons/reddit.ico) + content/browser/zen-images/favicons/x.ico (../../zen/images/favicons/x.ico) + content/browser/zen-images/favicons/trello.ico (../../zen/images/favicons/trello.ico) \ No newline at end of file diff --git a/src/zen/common/ZenCustomizableUI.sys.mjs b/src/zen/common/ZenCustomizableUI.sys.mjs index db25a7a39..7c4520cfa 100644 --- a/src/zen/common/ZenCustomizableUI.sys.mjs +++ b/src/zen/common/ZenCustomizableUI.sys.mjs @@ -77,7 +77,7 @@ export var ZenCustomizableUI = new (class { }); // remove all styles except for the width, since we are xulstoring the complet style list - const width = toolbox.style.width || '180px'; + const width = toolbox.style.width || '228px'; toolbox.removeAttribute('style'); toolbox.style.width = width; diff --git a/src/zen/images/favicons/calendar.ico b/src/zen/images/favicons/calendar.ico new file mode 100644 index 0000000000000000000000000000000000000000..7b1720e2c8c670d2f06a54a4a154eba65d5aea68 GIT binary patch literal 4414 zcmZQzU}RuqP*4ET3Je;83=Con3=A3!3=9ek3=9qo5OD@55awoJ0AVPX!L&itz@kCo zzD0w?e`FlI!sI_Sv6<7$2AG}5w0VR0dt`fIY--vKGRxHY)qiYmfZ2ymgY-}ngX{-k zbT^>e3*%GMZjf0ZyI~mF4KVxAX^JKar~laS ze<}l(J-`2B!`SQwiBZ{ltagLk1F{PnCS?E5H;?{*xp@?f|9t&ONI6yQf3~vj|D|+E z6bur>=MIoxv0-d}2Z`bG(BlR9aC;w2OZX4sUoBJzi-Fj<^kK6bBnGkz8^&f1D7-=b zzFMIE9~AyDH6ZqlDl@PfKx$y($TY|^XF4&oPcPUdSn`# z-5@cLUDzFUbEO8YTv#Uu^CHyNw?9U#~Jl34c(!yVdLhw*U2>SuiJ|&>+8J z!`S=|5<}4p<-q(13ImWEK=A>>AT~%0lmbvl}FaVE|MBWDm$bkX<16ygRn?KZu4(5!NLGrK7gq~r?J@$5(C+V4WsKv=7Yi> z=7zhy!6l-EFc z5?7gvtPf-tHjK?~kQlOFYOt}{4H5&{g$+}~PGmDcc45QV>;{P;>!k)8o82HWkX`h^ zpfUp+ria}iJFwXe5(CN61B2|shUsB9$PR3FgT%hHI^74!(;9>9!h-jIZ*z$M-0Jjx T0PNp?K0^XDM1b5KA8~8|@7UM+ literal 0 HcmV?d00001 diff --git a/src/zen/images/favicons/discord.ico b/src/zen/images/favicons/discord.ico new file mode 100644 index 0000000000000000000000000000000000000000..deb85436d83f636982720cdd6007cd491660257b GIT binary patch literal 3774 zcmZQzU}RuqFfaho91JV?7#PGD7#K7d7#Iu~7#I>5AmR)lzzHItm=P?&;8Wnv@F_K% z;Zte^7=KJbuwh~_`v3p`44>iy89qjMGJKymo#AUo9mCI^TNr*{ILq+w%NK?}5AQR4 zE>4G9FiMSvz-R~zxe#FCU}ffH;^JcBWM<`HA>@2^PA(L{$&N<{3oD9RD2El7CG1cI z7!+1J7}+q?!3Eerg&nHHIN*|4862pp8F0DFGRCow_<2$674 z;|UpLGuWVhCc^O$Z4fW8KsXSRhnEM!fRJcha7-g50v=vIVSXeHJp96Z$Of>2Tm&(R zi;IhgS3roHTZk9LG_k;=7OEbu5`_U*&jAY^ znE5Em;2gMmR%Vbbpb&wXFD$|(08uBvB?9vbTsx#8+T zB>~t59)5_FATJjegbj)~UP$BE1i9q8Vq84re57cTQK7J@mke?44{DN@vnPC3q;(~erVj?OD@(RRwPFQ#%9E7SA z!~-WmhT#KtgZ~E>93S9xjf9 z0V%H-7)UG+8AvT}8IU6xhg-O~5al^aB;ZmHb37A)2 o46_$T<8mj=AL#yr`5P7vuyFYg@&qWnVBrP}M_9PR!WkOw0LS33IRF3v literal 0 HcmV?d00001 diff --git a/src/zen/images/favicons/figma.ico b/src/zen/images/favicons/figma.ico new file mode 100644 index 0000000000000000000000000000000000000000..108a33de2656fdbbd34b9411880271cad13e5fa1 GIT binary patch literal 34494 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 literal 0 HcmV?d00001 diff --git a/src/zen/images/favicons/github.ico b/src/zen/images/favicons/github.ico new file mode 100644 index 0000000000000000000000000000000000000000..497be7368a436033cf9f18baddf2ce529e1ef0ee GIT binary patch literal 41662 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 YOh};s<%3-W%0)0fI{lvklITF<0R3h=k^lez literal 0 HcmV?d00001 diff --git a/src/zen/images/favicons/notion.ico b/src/zen/images/favicons/notion.ico new file mode 100644 index 0000000000000000000000000000000000000000..b179b1fcf185d0230199835cd9fd5d7c9b71ffa3 GIT binary patch literal 32038 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 literal 0 HcmV?d00001 diff --git a/src/zen/images/favicons/obsidian.ico b/src/zen/images/favicons/obsidian.ico new file mode 100644 index 0000000000000000000000000000000000000000..8aad7e4619e74ee78fee5b73a622a978f8b6a3c3 GIT binary patch literal 31332 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 literal 0 HcmV?d00001 diff --git a/src/zen/images/favicons/slack.ico b/src/zen/images/favicons/slack.ico new file mode 100644 index 0000000000000000000000000000000000000000..3279160cf85efa6acb54ba5a61873d0a81c968fe GIT binary patch literal 4286 zcmZQzU}RuqP*4ET3Jfa*7#PGD7#K7d7#I{77#JKFAmR)lAOIpr$I!7tdEj^ z@F_~}!G&n~hv89j4;f)5>2H3^q`&!Hj^3s>H}y8Xd8@bi%^dwLZ{%U}l+aOf51FFm z9^8$Rd+;9#|BaD8F$?WIv_mgY?HKJ!Fbecn}&b|1dvB@u?h042Frd-+1$XHvP@-BJ?-E z>BNh-ylv6n^4`;A`zLVu5v%x6GfM8kEu{4IBU=7pIw|%WZT={wx9QCd9O)387trMX z>1}>{Tz~63=_vV!Ymw{*=kI8_hyP*}AE|=eK*;~bn?Et>Z+?3j&3tTjVi9}W1}#&; z_M*DuVGPLrXt{@dsN#rnFjegtyWy5MV&vKV=D+^tH>aZH9$dm|zWjqUu>JB6L$S)s zJ-h^xH`(!l9hBe5bHm$}(ee+YqvRg^!>|Kt|EkdcOwn==&Y;PEiIIPx53(PG4Ys_C z(%barCy8$OWw7h#u)hrHc@g9pQ6|SwI5`DlHx0#Xt{^0qvRg^jh26SD@yT^ z5l9>v8*F*!r@!g#Q)1kpzxmA#lbs)xjJCZ6=K+{GF-lLk<5eE+IaJSM&oTCc<|!wpSeJ4(eam44s4%Jn2UcnVJ?9Se>r9;{_T_<3%Xty zzxjYUTf=rEJ{TWHH|#LvsoQBF0m8Mr48$6?nKQ%WJ{~n={B+DL>cdg9Zy%1D{U?M! z9yR;;>9~a_Oh1V3-eb*Jw?jXpZoA%(+HHFO>bB{xYu#_g4Uz-l+U)ZEE;y|Gk!c~o=(V4Eb`w!oiMipnGM2q+w`+*x9R$aiU50U>{ zw_V@s!!fh#Sj;CJ4#&)Ig3NB-Y06oxw|2YU z_PTBQpr$&*w^MeEpHEm=emrWC_3@}h4o-Z`JnQ3eOL(~lGPhxyAwmCx)PZorHgnP1 z?fPMLJM>Y^0LhVyiHU!5%|_Pu@u<1g$7AM&ACH+;!|%qy_j4HEl#!k(>eyPh;OO@qrEWOm&Sg9zj}B!~U!xLGL3 zE-V<_{%F{4z)`zR?>n-+Q1;)(?M5o(*omy?<8ced4@b=|q1pfY^Jztx>Eki8nIDds-T8RTZ0E=0=I&pPS;E@^bvq0g>v!l!*KN}~ zRJUF4THSX2_WJGm62#d3zp?TEe?|~y`2U{)h8h3=XJG#SpW*-ic7_9t%nS_-Aj`m* zk%57cv4MfH`2fSi=MUHqus?5RU~X(+U<6@?1_lPOVvvRd4eSh$!G;`Q`2W8FW;VnB M|BN8q_#b390K-H#i~s-t literal 0 HcmV?d00001 diff --git a/src/zen/images/favicons/trello.ico b/src/zen/images/favicons/trello.ico new file mode 100644 index 0000000000000000000000000000000000000000..c8bb9d9be36a44b7c4cbc39c8c818cc13870eaed GIT binary patch literal 108167 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 literal 0 HcmV?d00001 diff --git a/src/zen/images/favicons/x.ico b/src/zen/images/favicons/x.ico new file mode 100644 index 0000000000000000000000000000000000000000..67f3740155b019bf6d4a22dfac1ac7e6e05cf0c7 GIT binary patch literal 2238 zcmZQzU}RuqP*4ET91JTs7#PGD7#K7d7#I{77#JKFAmR)lzyczmm=P=i=KTNvpW*)f z`wRjC0t^ZY3JmYxzh@{YC}41KaA0U?XkggCe?P@FE&B(?EGK3vOAWJ~m z%v_ADVAGkfm=03I!U_rouoWOK1_t{IYz2lCNB|sWEFddDJWLD@Gft2PFy$DaVaCRY z8kY!_yo}ro47{vd{1`zCR>RB%@){Q_3o{p18+bsXJRrR+;0Oe3LJ;6E1IIi{WWyA| zq6Lx&cp1?{kOvfS2$!*e+zQjnz`(!`vR42p(!p^FSHR4~%E7_Gikzf)kb{96l$;q+ NBb^JC3pZ<|F#tm$AL{@B literal 0 HcmV?d00001 diff --git a/src/zen/welcome/ZenWelcome.mjs b/src/zen/welcome/ZenWelcome.mjs index 9527221a3..b982844cf 100644 --- a/src/zen/welcome/ZenWelcome.mjs +++ b/src/zen/welcome/ZenWelcome.mjs @@ -80,8 +80,8 @@ async function openInitialPinTab() { const tabs = [ - ['https://reddit.com/r/zen_browser', 'Zen on Reddit', 'https://private-cdn.zen-browser.app/reddit.png'], - ['https://x.com/zen_browser', 'Zen on Twitter', 'https://private-cdn.zen-browser.app/x.png'], + ['https://reddit.com/r/zen_browser', 'Zen on Reddit', 'chrome://browser/content/zen-images/favicons/reddit.ico'], + ['https://x.com/zen_browser', 'Zen on Twitter', 'chrome://browser/content/zen-images/favicons/x.ico'], ]; await PlacesUtils.history.insertMany( @@ -387,47 +387,47 @@ - + - + - + - + - + - + - + - + - + From be54733b13105af8aaf3f64ee74d6f473a6a4326 Mon Sep 17 00:00:00 2001 From: "Mr. M" Date: Tue, 29 Apr 2025 22:59:06 +0200 Subject: [PATCH 11/11] chore: Updated to firefox 138, b=(no-bug), c=common, tabs --- README.md | 2 +- build/firefox-cache/l10n-last-commit-hash | 2 +- src/zen/common/ZenCommonUtils.mjs | 1 + src/zen/tabs/ZenPinnedTabManager.mjs | 4 ++-- surfer.json | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7bedcb977..e60570472 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ ## 🖥️ Compatibility -Zen is currently built using Firefox version `137.0.2`! 🚀 +Zen is currently built using Firefox version `138.0`! 🚀 - [`Zen Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 138.0`! - Check out the latest [release notes](https://zen-browser.app/release-notes)! diff --git a/build/firefox-cache/l10n-last-commit-hash b/build/firefox-cache/l10n-last-commit-hash index 30a227e75..21cd03a56 100644 --- a/build/firefox-cache/l10n-last-commit-hash +++ b/build/firefox-cache/l10n-last-commit-hash @@ -1 +1 @@ -7113caf804fda45f011f1900c25de638398d586e \ No newline at end of file +8113a66aeeec42dca9739c7b742a3408cb5b7cf7 \ No newline at end of file diff --git a/src/zen/common/ZenCommonUtils.mjs b/src/zen/common/ZenCommonUtils.mjs index 83a75a1c8..054a22196 100644 --- a/src/zen/common/ZenCommonUtils.mjs +++ b/src/zen/common/ZenCommonUtils.mjs @@ -36,6 +36,7 @@ class ZenMultiWindowFeature { } for (const browser of ZenMultiWindowFeature.browsers) { try { + if (browser.closed) continue; await callback(browser); } catch (e) { console.error(e); diff --git a/src/zen/tabs/ZenPinnedTabManager.mjs b/src/zen/tabs/ZenPinnedTabManager.mjs index 40a04a0ae..114835927 100644 --- a/src/zen/tabs/ZenPinnedTabManager.mjs +++ b/src/zen/tabs/ZenPinnedTabManager.mjs @@ -585,9 +585,9 @@ const state = JSON.parse(tabState); const foundEntryIndex = state.entries?.findIndex((entry) => entry.url === pin.url); - if (!foundEntryIndex || foundEntryIndex === -1) { + if (foundEntryIndex === -1) { state.entries = [ - { + [state.entries[0]] ?? { url: pin.url, title: pin.title, triggeringPrincipal_base64: lazy.E10SUtils.SERIALIZED_SYSTEMPRINCIPAL, diff --git a/surfer.json b/surfer.json index 65e0eef17..d65dd994e 100644 --- a/surfer.json +++ b/surfer.json @@ -5,7 +5,7 @@ "binaryName": "zen", "version": { "product": "firefox", - "version": "137.0.2", + "version": "138.0", "candidate": "138.0" }, "buildOptions": {