Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8694d6a67b | ||
|
|
4dc0f5df8e | ||
|
|
1c09d40851 | ||
|
|
c9598e1612 | ||
|
|
1c37c15fc2 | ||
|
|
e068428601 |
@@ -29,8 +29,8 @@ Zen is a firefox-based browser with the aim of pushing your productivity to a ne
|
||||
|
||||
### Firefox Versions
|
||||
|
||||
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `140.0.2`! 🚀
|
||||
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 140.0.2`!
|
||||
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `140.0.4`! 🚀
|
||||
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 140.0.4`!
|
||||
|
||||
### Contributing
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
d5e5ed08dac5a263dbc7784dff272198b17bbc4f
|
||||
48c1f420b7da724dd6072b6d83bb75b2e219b8cc
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/base/content/browser-commands.js b/browser/base/content/browser-commands.js
|
||||
index b0b2383453ef771af3eb9260618f1e2e3022eb4e..7c5844582d9adb55c55fb1627a9980cf0e5c110b 100644
|
||||
index b0b2383453ef771af3eb9260618f1e2e3022eb4e..d631cc8db95b4285e892ac8fcb5e72b7da489850 100644
|
||||
--- a/browser/base/content/browser-commands.js
|
||||
+++ b/browser/base/content/browser-commands.js
|
||||
@@ -318,6 +318,10 @@ var BrowserCommands = {
|
||||
@@ -13,21 +13,19 @@ index b0b2383453ef771af3eb9260618f1e2e3022eb4e..7c5844582d9adb55c55fb1627a9980cf
|
||||
// A notification intended to be useful for modular peformance tracking
|
||||
// starting as close as is reasonably possible to the time when the user
|
||||
// expressed the intent to open a new tab. Since there are a lot of
|
||||
@@ -402,6 +406,13 @@ var BrowserCommands = {
|
||||
@@ -402,6 +406,11 @@ var BrowserCommands = {
|
||||
return;
|
||||
}
|
||||
|
||||
+ if (gBrowser.selectedTab.hasAttribute("zen-empty-tab")) {
|
||||
+ if (gZenWorkspaces.shouldCloseWindow()) {
|
||||
+ closeWindow(true);
|
||||
+ }
|
||||
+ gZenWorkspaces.handleTabCloseWindow();
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
// Keyboard shortcuts that would close a tab that is pinned select the first
|
||||
// unpinned tab instead.
|
||||
if (
|
||||
@@ -409,8 +420,8 @@ var BrowserCommands = {
|
||||
@@ -409,8 +418,8 @@ var BrowserCommands = {
|
||||
(event.ctrlKey || event.metaKey || event.altKey) &&
|
||||
gBrowser.selectedTab.pinned
|
||||
) {
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
</defs>
|
||||
</svg>
|
||||
</box>
|
||||
<html:input type="range" min="0.3" max="0.8" value="0.4" step="0.001" id="PanelUI-zen-gradient-generator-opacity" />
|
||||
<html:input type="range" min="0.3" max="0.9" value="0.4" step="0.001" id="PanelUI-zen-gradient-generator-opacity" />
|
||||
</vbox>
|
||||
<vbox id="PanelUI-zen-gradient-generator-texture-wrapper">
|
||||
</vbox>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/tabbrowser/content/tab.js b/browser/components/tabbrowser/content/tab.js
|
||||
index 793ba822f087f4d198c9876ed208ff16d8a41e3b..e53ccd748de015997c355d5d37cb38cc73e90f3d 100644
|
||||
index 793ba822f087f4d198c9876ed208ff16d8a41e3b..f0c4bc58d7d48491e0c0ab9eb3e915b1bf4d762a 100644
|
||||
--- a/browser/components/tabbrowser/content/tab.js
|
||||
+++ b/browser/components/tabbrowser/content/tab.js
|
||||
@@ -21,6 +21,7 @@
|
||||
@@ -21,6 +21,18 @@ index 793ba822f087f4d198c9876ed208ff16d8a41e3b..e53ccd748de015997c355d5d37cb38cc
|
||||
</hbox>
|
||||
</stack>
|
||||
`;
|
||||
@@ -97,9 +100,9 @@
|
||||
"src=image,triggeringprincipal=iconloadingprincipal,requestcontextid,fadein,pinned,selected=visuallyselected,busy,crashed,sharing,pictureinpicture,pending,discarded",
|
||||
".tab-sharing-icon-overlay": "sharing,selected=visuallyselected,pinned",
|
||||
".tab-icon-overlay":
|
||||
- "sharing,pictureinpicture,crashed,busy,soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected,activemedia-blocked",
|
||||
+ "zen-essential,sharing,pictureinpicture,crashed,busy,soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected,activemedia-blocked",
|
||||
".tab-audio-button":
|
||||
- "crashed,soundplaying,soundplaying-scheduledremoval,pinned,muted,activemedia-blocked",
|
||||
+ "zen-essential,crashed,soundplaying,soundplaying-scheduledremoval,pinned,muted,activemedia-blocked",
|
||||
".tab-label-container":
|
||||
"pinned,selected=visuallyselected,labeldirection",
|
||||
".tab-label":
|
||||
@@ -180,7 +183,7 @@
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
|
||||
index 37570c54b06f9cebc46aa232e2d01ac5d330e17a..818b1df6778d9d299b86fefa46bbf1d689d29fdb 100644
|
||||
index 37570c54b06f9cebc46aa232e2d01ac5d330e17a..3a62769d327e9aa5d5c447e3931f235f984de42c 100644
|
||||
--- a/browser/components/tabbrowser/content/tabbrowser.js
|
||||
+++ b/browser/components/tabbrowser/content/tabbrowser.js
|
||||
@@ -413,11 +413,41 @@
|
||||
@@ -481,7 +481,15 @@ index 37570c54b06f9cebc46aa232e2d01ac5d330e17a..818b1df6778d9d299b86fefa46bbf1d6
|
||||
if (
|
||||
!this._beginRemoveTab(aTab, {
|
||||
closeWindowFastpath: true,
|
||||
@@ -4835,7 +4952,7 @@
|
||||
@@ -4828,14 +4945,14 @@
|
||||
var newTab = false;
|
||||
if (
|
||||
aTab.visible &&
|
||||
- this.visibleTabs.length == 1 &&
|
||||
+ this.visibleTabs.length == 0 &&
|
||||
!this.tabsInCollapsedTabGroups.length
|
||||
) {
|
||||
closeWindow =
|
||||
closeWindowWithLastTab != null
|
||||
? closeWindowWithLastTab
|
||||
: !window.toolbar.visible ||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/themes/shared/tabbrowser/tabs.css b/browser/themes/shared/tabbrowser/tabs.css
|
||||
index d7d9a40e8c473fa3b06f5bbc743e851a392ea8fa..c5b3f015caf666dad800432828a8c615e8353936 100644
|
||||
index d7d9a40e8c473fa3b06f5bbc743e851a392ea8fa..23a165fdd80abd754a53f941a5edf839143b2044 100644
|
||||
--- a/browser/themes/shared/tabbrowser/tabs.css
|
||||
+++ b/browser/themes/shared/tabbrowser/tabs.css
|
||||
@@ -19,7 +19,7 @@
|
||||
@@ -103,6 +103,24 @@ index d7d9a40e8c473fa3b06f5bbc743e851a392ea8fa..c5b3f015caf666dad800432828a8c615
|
||||
color-scheme: var(--tab-selected-color-scheme);
|
||||
border-radius: var(--border-radius-circle);
|
||||
|
||||
@@ -633,7 +625,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
- &[pinned]:is([soundplaying], [muted], [activemedia-blocked]),
|
||||
+ &[zen-essential]:is([soundplaying], [muted], [activemedia-blocked]),
|
||||
&[crashed] {
|
||||
display: revert;
|
||||
}
|
||||
@@ -737,7 +729,7 @@
|
||||
has not been added to root. There are certain scenarios when that attribute is temporarily
|
||||
removed from root such as when toggling the sidebar to expand with the toolbar button. */
|
||||
#tabbrowser-tabs[orient="horizontal"] &:not([pinned]):not([crashed]),
|
||||
- :root:not([sidebar-expand-on-hover]) #tabbrowser-tabs[orient="vertical"][expanded] &:not([pinned]):not([crashed]) {
|
||||
+ :root:not([sidebar-expand-on-hover]) #tabbrowser-tabs[orient="vertical"][expanded] &:not([zen-essential]):not([crashed]) {
|
||||
&:is([soundplaying], [muted], [activemedia-blocked]) {
|
||||
display: block;
|
||||
}
|
||||
@@ -1373,7 +1365,7 @@ tab-group {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,10 @@
|
||||
list-style-image: url('downloads.svg') !important;
|
||||
}
|
||||
|
||||
#downloads-indicator-icon {
|
||||
max-height: 16px;
|
||||
}
|
||||
|
||||
#appMenu-translate-button {
|
||||
list-style-image: url('translations.svg') !important;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
const { AppConstants } = ChromeUtils.importESModule('resource://gre/modules/AppConstants.sys.mjs');
|
||||
|
||||
class nsZenUIMigration {
|
||||
PREF_NAME = 'zen.ui.migration.version';
|
||||
MIGRATION_VERSION = 2;
|
||||
@@ -48,19 +50,24 @@ class nsZenUIMigration {
|
||||
const userContentFile = profileDir.clone();
|
||||
userContentFile.append('chrome');
|
||||
userContentFile.append('userContent.css');
|
||||
if (userChromeFile.exists() || userContentFile.exists()) {
|
||||
Services.prefs.setBoolPref('toolkit.legacyUserProfileCustomizations.stylesheets', true);
|
||||
}
|
||||
Services.prefs.setBoolPref(
|
||||
'zen.workspaces.separate-essentials',
|
||||
Services.prefs.getBoolPref('zen.workspaces.container-specific-essentials-enabled', false)
|
||||
);
|
||||
const theme = Services.prefs.getIntPref('layout.css.prefers-color-scheme.content-override', 0);
|
||||
Services.prefs.setIntPref('zen.view.window.scheme', theme);
|
||||
if (userChromeFile.exists() || userContentFile.exists()) {
|
||||
Services.prefs.setBoolPref('toolkit.legacyUserProfileCustomizations.stylesheets', true);
|
||||
console.log('ZenUIMigration: User stylesheets detected, enabling legacy stylesheets.');
|
||||
Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_migrateV2() {
|
||||
Services.prefs.setIntPref('zen.theme.gradient-legacy-version', 0);
|
||||
if (AppConstants.platform !== 'linux') {
|
||||
Services.prefs.setIntPref('zen.theme.gradient-legacy-version', 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -111,9 +111,7 @@
|
||||
}
|
||||
|
||||
@media (-moz-platform: macos) {
|
||||
#zen-main-app-wrapper,
|
||||
#zen-appcontent-wrapper,
|
||||
#zen-sidebar-splitter {
|
||||
#zen-main-app-wrapper {
|
||||
appearance: -moz-sidebar !important;
|
||||
}
|
||||
}
|
||||
@@ -286,3 +284,17 @@
|
||||
border-radius: 2px;
|
||||
margin: 10px 2px 0 0;
|
||||
}
|
||||
|
||||
#zen-sidebar-splitter {
|
||||
border-radius: 14px;
|
||||
transition:
|
||||
background 0.2s ease-in-out,
|
||||
opacity 0.2s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background: var(--zen-primary-color);
|
||||
transition: background 0.2s ease-in-out;
|
||||
transition-delay: 0.2s;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,13 +106,8 @@ body > #confetti {
|
||||
#zen-sidebar-foot-buttons & {
|
||||
--tab-border-radius: 6px;
|
||||
--toolbarbutton-border-radius: var(--tab-border-radius);
|
||||
--toolbarbutton-inner-padding: 7px;
|
||||
|
||||
&,
|
||||
& stack {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
--toolbarbutton-inner-padding: 5px;
|
||||
--toolbarbutton-outer-padding: 2px;
|
||||
}
|
||||
|
||||
transition:
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
--zen-button-padding: 0.6rem 1.2rem;
|
||||
|
||||
--zen-toolbar-element-bg: light-dark(
|
||||
color-mix(in oklch, var(--toolbox-textcolor) 9%, transparent),
|
||||
color-mix(in oklch, var(--toolbox-textcolor) 8%, transparent),
|
||||
color-mix(in oklch, var(--toolbox-textcolor) 15%, transparent)
|
||||
);
|
||||
|
||||
@@ -261,6 +261,11 @@
|
||||
color-scheme: dark;
|
||||
}
|
||||
}
|
||||
|
||||
:root[privatebrowsingmode='temporary'] &,
|
||||
&[privatebrowsingmode='temporary'] {
|
||||
color-scheme: dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,12 +34,8 @@
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
&[media-sharing] #zen-media-controls-hbox > toolbarbutton:not(:first-child) {
|
||||
&[media-sharing] :is(#zen-media-playback-buttons, #zen-media-mute-button) {
|
||||
display: none;
|
||||
|
||||
#media-device-buttons {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
&:not([can-pip]) {
|
||||
|
||||
@@ -940,7 +940,7 @@
|
||||
if (!this._dragIndicator) {
|
||||
this._dragIndicator = document.createElement('div');
|
||||
this._dragIndicator.id = 'zen-drag-indicator';
|
||||
document.body.appendChild(this._dragIndicator);
|
||||
gNavToolbox.appendChild(this._dragIndicator);
|
||||
}
|
||||
return this._dragIndicator;
|
||||
}
|
||||
|
||||
@@ -253,6 +253,8 @@
|
||||
overflow-x: clip; /* Clip horizontal overflow */
|
||||
overflow-clip-margin: var(--zen-toolbox-padding); /* Add margin to clipping area */
|
||||
|
||||
--focus-outline-color: transparent;
|
||||
|
||||
@media (-moz-platform: macos) {
|
||||
font-size: 1.1rem; /* Slightly larger font on macOS */
|
||||
}
|
||||
@@ -1489,6 +1491,7 @@
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
@@ -1513,3 +1516,16 @@
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#tabs-newtab-button:not([in-urlbar='true']) label,
|
||||
.zen-current-workspace-indicator-name {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.tab-throbber {
|
||||
display: none !important; /* Hide throbber always */
|
||||
}
|
||||
|
||||
.tab-icon-image {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
@@ -121,7 +121,6 @@
|
||||
const iconData = await getIconData(site[2]);
|
||||
await setCachedFaviconForURL(site[0], iconData);
|
||||
gBrowser.setIcon(tab, iconData);
|
||||
tab.removeAttribute('pending'); // Make it appear loaded
|
||||
_tabsToPin.push(tab);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,9 +40,11 @@
|
||||
return points;
|
||||
}
|
||||
|
||||
const MAX_OPACITY = 0.8;
|
||||
const MAX_OPACITY = 0.9;
|
||||
const MIN_OPACITY = 0.3;
|
||||
|
||||
const EXPLICIT_LIGHTNESS_TYPE = 'explicit-lightness';
|
||||
|
||||
class nsZenThemePicker extends ZenMultiWindowFeature {
|
||||
static MAX_DOTS = 3;
|
||||
|
||||
@@ -130,6 +132,9 @@
|
||||
}
|
||||
|
||||
get isDarkMode() {
|
||||
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
|
||||
return true;
|
||||
}
|
||||
switch (this.windowSchemeType) {
|
||||
case 0:
|
||||
return true;
|
||||
@@ -195,12 +200,14 @@
|
||||
ID: 0,
|
||||
position: { x, y },
|
||||
isPrimary: true,
|
||||
type: EXPLICIT_LIGHTNESS_TYPE,
|
||||
},
|
||||
];
|
||||
for (let i = 1; i < numDots; i++) {
|
||||
dots.push({
|
||||
ID: i,
|
||||
position: { x: 0, y: 0 },
|
||||
type: EXPLICIT_LIGHTNESS_TYPE,
|
||||
});
|
||||
}
|
||||
this.useAlgo = algo;
|
||||
@@ -434,13 +441,16 @@
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
getColorFromPosition(x, y) {
|
||||
getColorFromPosition(x, y, type = undefined) {
|
||||
// Return a color as hsl based on the position in the gradient
|
||||
const gradient = this.panel.querySelector('.zen-theme-picker-gradient');
|
||||
const rect = gradient.getBoundingClientRect();
|
||||
const padding = 20; // each side
|
||||
rect.width += padding * 2;
|
||||
rect.height += padding * 2;
|
||||
const dotHalfSize = 36 / 2; // half the size of the dot
|
||||
x += dotHalfSize;
|
||||
y += dotHalfSize;
|
||||
rect.width += padding * 2; // Adjust width and height for padding
|
||||
rect.height += padding * 2; // Adjust width and height for padding
|
||||
const centerX = rect.width / 2;
|
||||
const centerY = rect.height / 2;
|
||||
const radius = (rect.width - padding) / 2;
|
||||
@@ -453,6 +463,11 @@
|
||||
const normalizedDistance = 1 - Math.min(distance / radius, 1); // Normalize distance to [0, 1]
|
||||
const hue = (angle / 360) * 360; // Normalize angle to [0, 360)
|
||||
const saturation = normalizedDistance * 100; // Scale distance to [0, 100]
|
||||
if (type !== EXPLICIT_LIGHTNESS_TYPE) {
|
||||
// Set the current lightness to how far we are from the center of the circle
|
||||
// For example, moving the dot outside will have higher lightness, while moving it inside will have lower lightness
|
||||
this.#currentLightness = Math.round((1 - normalizedDistance) * 100);
|
||||
}
|
||||
const lightness = this.#currentLightness; // Fixed lightness for simplicity
|
||||
const [r, g, b] = this.hslToRgb(hue / 360, saturation / 100, lightness / 100);
|
||||
return [
|
||||
@@ -498,11 +513,14 @@
|
||||
|
||||
dot.style.setProperty('--zen-theme-picker-dot-color', `rgb(${r}, ${g}, ${b})`);
|
||||
dot.setAttribute('data-position', this.getJSONPos(x, y));
|
||||
dot.setAttribute('data-type', color.type);
|
||||
|
||||
this.dots.push({
|
||||
ID: id,
|
||||
element: dot,
|
||||
position: { x: null, y: null }, // at some point possition should instead be stored as percentege just so that the size of the color picker does not matter.
|
||||
type: color.type,
|
||||
lightness: color.lightness,
|
||||
});
|
||||
}
|
||||
if (!fromWorkspace) {
|
||||
@@ -566,14 +584,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
spawnDot(relativePosition, primary = false) {
|
||||
spawnDot(dotData, primary = false) {
|
||||
const dotPad = this.panel.querySelector('.zen-theme-picker-gradient');
|
||||
const relativePosition = {
|
||||
x: dotData.x,
|
||||
y: dotData.y,
|
||||
};
|
||||
|
||||
const dot = document.createElement('div');
|
||||
dot.classList.add('zen-theme-picker-dot');
|
||||
|
||||
dot.style.left = `${relativePosition.x}px`;
|
||||
dot.style.top = `${relativePosition.y}px`;
|
||||
dot.style.left = `${dotData.x}px`;
|
||||
dot.style.top = `${dotData.y}px`;
|
||||
|
||||
dotPad.appendChild(dot);
|
||||
|
||||
@@ -590,18 +612,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
const colorFromPos = this.getColorFromPosition(relativePosition.x, relativePosition.y);
|
||||
const colorFromPos = this.getColorFromPosition(
|
||||
relativePosition.x,
|
||||
relativePosition.y,
|
||||
dotData.type
|
||||
);
|
||||
dot.style.setProperty(
|
||||
'--zen-theme-picker-dot-color',
|
||||
`rgb(${colorFromPos[0]}, ${colorFromPos[1]}, ${colorFromPos[2]})`
|
||||
);
|
||||
dot.setAttribute('data-position', this.getJSONPos(relativePosition.x, relativePosition.y));
|
||||
dot.setAttribute('data-type', dotData.type);
|
||||
|
||||
this.dots.push({
|
||||
ID: id,
|
||||
element: dot,
|
||||
position: { x: relativePosition.x, y: relativePosition.y },
|
||||
lightness: this.#currentLightness,
|
||||
type: dotData.type,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -685,9 +713,14 @@
|
||||
let distance = getDistanceFromCenter(primaryDot.position, centerPosition);
|
||||
const radius = (rect.width - padding) / 2;
|
||||
if (distance > radius) distance = radius;
|
||||
|
||||
if (this.dots.length > 0) {
|
||||
updatedDots = [{ ID: 0, position: primaryDot.position }];
|
||||
updatedDots = [
|
||||
{
|
||||
ID: 0,
|
||||
position: primaryDot.position,
|
||||
type: primaryDot.type,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
harmonyAngles.angles.forEach((angleOffset, index) => {
|
||||
@@ -699,7 +732,11 @@
|
||||
y: centerPosition.y + distance * Math.sin(radian),
|
||||
};
|
||||
|
||||
updatedDots.push({ ID: index + 1, position: newPosition });
|
||||
updatedDots.push({
|
||||
ID: index + 1,
|
||||
position: newPosition,
|
||||
type: primaryDot.type,
|
||||
});
|
||||
});
|
||||
|
||||
return updatedDots;
|
||||
@@ -707,38 +744,24 @@
|
||||
|
||||
handleColorPositions(colorPositions, ignoreLegacy = false) {
|
||||
colorPositions.sort((a, b) => a.ID - b.ID);
|
||||
const existingPrimaryDot = this.dots.find((d) => d.ID === 0);
|
||||
|
||||
if (this.isLegacyVersion && !ignoreLegacy) {
|
||||
this.isLegacyVersion = false;
|
||||
Services.prefs.setIntPref('zen.theme.gradient-legacy-version', 1);
|
||||
}
|
||||
|
||||
if (existingPrimaryDot) {
|
||||
existingPrimaryDot.element.style.zIndex = 999;
|
||||
const colorFromPos = this.getColorFromPosition(
|
||||
existingPrimaryDot.position.x,
|
||||
existingPrimaryDot.position.y
|
||||
);
|
||||
existingPrimaryDot.element.style.setProperty(
|
||||
'--zen-theme-picker-dot-color',
|
||||
`rgb(${colorFromPos[0]}, ${colorFromPos[1]}, ${colorFromPos[2]})`
|
||||
);
|
||||
existingPrimaryDot.element.setAttribute(
|
||||
'data-position',
|
||||
this.getJSONPos(existingPrimaryDot.position.x, existingPrimaryDot.position.y)
|
||||
);
|
||||
}
|
||||
|
||||
colorPositions.forEach((dotPosition) => {
|
||||
const existingDot = this.dots.find((dot) => dot.ID === dotPosition.ID);
|
||||
|
||||
if (existingDot) {
|
||||
existingDot.type = dotPosition.type;
|
||||
existingDot.position = dotPosition.position;
|
||||
const colorFromPos = this.getColorFromPosition(
|
||||
dotPosition.position.x,
|
||||
dotPosition.position.y
|
||||
dotPosition.position.y,
|
||||
dotPosition.type
|
||||
);
|
||||
existingDot.lightness = this.#currentLightness;
|
||||
existingDot.element.style.setProperty(
|
||||
'--zen-theme-picker-dot-color',
|
||||
`rgb(${colorFromPos[0]}, ${colorFromPos[1]}, ${colorFromPos[2]})`
|
||||
@@ -747,6 +770,7 @@
|
||||
'data-position',
|
||||
this.getJSONPos(dotPosition.position.x, dotPosition.position.y)
|
||||
);
|
||||
existingDot.element.setAttribute('data-type', dotPosition.type);
|
||||
|
||||
if (!this.dragging) {
|
||||
gZenUIManager.motion.animate(
|
||||
@@ -766,7 +790,10 @@
|
||||
existingDot.element.style.top = `${dotPosition.position.y}px`;
|
||||
}
|
||||
} else {
|
||||
this.spawnDot(dotPosition.position);
|
||||
this.spawnDot({
|
||||
type: dotPosition.type,
|
||||
...dotPosition.position,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -849,7 +876,6 @@
|
||||
const relativeY = pixelY - rect.top;
|
||||
|
||||
if (!clickedDot && this.dots.length < 1) {
|
||||
this.#currentLightness = 50;
|
||||
this.spawnDot({ x: relativeX, y: relativeY }, this.dots.length === 0);
|
||||
|
||||
this.updateCurrentWorkspace(true);
|
||||
@@ -983,23 +1009,7 @@
|
||||
}
|
||||
|
||||
themedColors(colors) {
|
||||
const colorToBlend = this.isDarkMode ? [255, 255, 255] : [0, 0, 0]; // Default to white for dark mode, black otherwise
|
||||
const opacity = this.currentOpacity;
|
||||
// Convert opacity into a percentage where the lowest is 60% and the highest is 100%
|
||||
// The more transparent, the more white the color will be blended with. In order words,
|
||||
// make the transparency relative to these 2 ends.
|
||||
// e.g. 0% opacity becomes 60% blend, 100% opacity becomes 100% blend
|
||||
let blendPercentage = Math.max(30, 30 + opacity * 70);
|
||||
if (this.isLegacyVersion) {
|
||||
blendPercentage = 100; // Legacy version always blends to 100%
|
||||
}
|
||||
return colors.map((color) => ({
|
||||
c: color.isCustom ? color.c : this.blendColors(color.c, colorToBlend, blendPercentage),
|
||||
isCustom: color.isCustom,
|
||||
algorithm: color.algorithm,
|
||||
lightness: color.lightness,
|
||||
position: color.position,
|
||||
}));
|
||||
return [...colors];
|
||||
}
|
||||
|
||||
onOpacityChange(event) {
|
||||
@@ -1028,6 +1038,20 @@
|
||||
).matches;
|
||||
}
|
||||
|
||||
blendWithWhiteOverlay(baseColor, opacity) {
|
||||
const blendColor = [255, 255, 255];
|
||||
const blendAlpha = 0.2;
|
||||
const baseAlpha = baseColor[3] !== undefined ? baseColor[3] : 1;
|
||||
const blended = [];
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
blended[i] = Math.round(blendColor[i] * (1 - opacity) + baseColor[i] * opacity);
|
||||
}
|
||||
|
||||
const blendedAlpha = +(blendAlpha * (1 - opacity) + baseAlpha * opacity).toFixed(3);
|
||||
return `rgba(${blended[0]}, ${blended[1]}, ${blended[2]}, ${blendedAlpha})`;
|
||||
}
|
||||
|
||||
getSingleRGBColor(color, forToolbar = false) {
|
||||
if (color.isCustom) {
|
||||
return color.c;
|
||||
@@ -1043,7 +1067,7 @@
|
||||
} else {
|
||||
color = color.c;
|
||||
}
|
||||
return `rgba(${color[0]}, ${color[1]}, ${color[2]}, ${opacity})`;
|
||||
return this.blendWithWhiteOverlay(color, opacity);
|
||||
}
|
||||
|
||||
luminance([r, g, b]) {
|
||||
@@ -1067,31 +1091,10 @@
|
||||
];
|
||||
}
|
||||
|
||||
findOptimalBlend(dominantColor, blendTarget, minContrast = 4.5) {
|
||||
let low = 0;
|
||||
let high = 100;
|
||||
let bestMatch = null;
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const mid = (low + high) / 2;
|
||||
const blended = this.blendColors(dominantColor, blendTarget, mid);
|
||||
const contrast = this.contrastRatio(blended, blendTarget);
|
||||
|
||||
if (contrast >= minContrast) {
|
||||
bestMatch = blended;
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return bestMatch || this.blendColors(dominantColor, blendTarget, 10); // fallback
|
||||
}
|
||||
|
||||
getGradient(colors, forToolbar = false) {
|
||||
const themedColors = this.themedColors(colors);
|
||||
this.useAlgo = themedColors[0]?.algorithm ?? '';
|
||||
this.#currentLightness = themedColors[0]?.lightness ?? 70;
|
||||
this.#currentLightness = themedColors[0]?.lightness ?? 50;
|
||||
|
||||
const rotation = -45; // TODO: Detect rotation based on the accent color
|
||||
if (themedColors.length === 0) {
|
||||
@@ -1118,8 +1121,10 @@
|
||||
if (!forToolbar) {
|
||||
return [
|
||||
`linear-gradient(${rotation}deg, ${this.getSingleRGBColor(themedColors[1], forToolbar)} 0%, transparent 100%)`,
|
||||
`linear-gradient(${rotation + 180}deg, ${this.getSingleRGBColor(themedColors[0], forToolbar)} 0%, transparent 100%)`,
|
||||
].join(', ');
|
||||
`linear-gradient(${rotation + 180}deg, ${this.getSingleRGBColor(themedColors[0], forToolbar)} 0%, transparent 80%)`,
|
||||
]
|
||||
.reverse()
|
||||
.join(', ');
|
||||
}
|
||||
return `linear-gradient(${rotation}deg, ${this.getSingleRGBColor(themedColors[1], forToolbar)} 0%, ${this.getSingleRGBColor(themedColors[0], forToolbar)} 100%)`;
|
||||
} else if (themedColors.length === 3) {
|
||||
@@ -1140,9 +1145,7 @@
|
||||
}
|
||||
|
||||
shouldBeDarkMode(accentColor) {
|
||||
let minimalLum = 0.5;
|
||||
if (!this.canBeTransparent) {
|
||||
// Blend the color with the toolbar background
|
||||
const toolbarBg = this.getToolbarModifiedBaseRaw();
|
||||
accentColor = this.blendColors(
|
||||
toolbarBg.slice(0, 3),
|
||||
@@ -1150,9 +1153,23 @@
|
||||
(1 - this.currentOpacity) * 100
|
||||
);
|
||||
}
|
||||
const lum = this.luminance(accentColor);
|
||||
// Return true if background is dark enough that white text is preferred
|
||||
return lum < minimalLum;
|
||||
|
||||
const bg = accentColor;
|
||||
|
||||
// Get text colors (with alpha)
|
||||
let darkText = this.getToolbarColor(true); // e.g. [r, g, b, a]
|
||||
let lightText = this.getToolbarColor(false); // e.g. [r, g, b, a]
|
||||
|
||||
lightText[3] -= 0.4; // Reduce alpha for light text
|
||||
|
||||
// Composite text color over background
|
||||
darkText = this.blendColors(bg, darkText.slice(0, 3), (1 - darkText[3]) * 100);
|
||||
lightText = this.blendColors(bg, lightText.slice(0, 3), (1 - lightText[3]) * 100);
|
||||
|
||||
const darkContrast = this.contrastRatio(bg, darkText);
|
||||
const lightContrast = this.contrastRatio(bg, lightText);
|
||||
|
||||
return darkContrast > lightContrast;
|
||||
}
|
||||
|
||||
static getTheme(colors = [], opacity = 0.5, texture = 0) {
|
||||
@@ -1285,6 +1302,10 @@
|
||||
return color;
|
||||
}
|
||||
|
||||
getToolbarColor(isDarkMode = false) {
|
||||
return isDarkMode ? [255, 255, 255, 0.8] : [0, 0, 0, 0.8]; // Default toolbar
|
||||
}
|
||||
|
||||
async onWorkspaceChange(workspace, skipUpdate = false, theme = null) {
|
||||
const uuid = workspace.uuid;
|
||||
// Use theme from workspace object or passed theme
|
||||
@@ -1450,28 +1471,33 @@
|
||||
'--zen-main-browser-background',
|
||||
gradient
|
||||
);
|
||||
|
||||
const isDarkModeWindow = browser.gZenThemePicker.isDarkMode;
|
||||
if (dominantColor) {
|
||||
browser.document.documentElement.style.setProperty(
|
||||
'--zen-primary-color',
|
||||
this.pSBC(
|
||||
this.isDarkMode ? 0.2 : -0.5,
|
||||
isDarkModeWindow ? 0.2 : -0.5,
|
||||
`rgb(${dominantColor[0]}, ${dominantColor[1]}, ${dominantColor[2]})`
|
||||
)
|
||||
);
|
||||
browser.gZenThemePicker.isLegacyVersion = this.isLegacyVersion;
|
||||
let isDarkMode = this.isDarkMode;
|
||||
let isDarkMode = isDarkModeWindow;
|
||||
if (!isDefaultTheme && !this.isLegacyVersion) {
|
||||
// Check for the primary color
|
||||
isDarkMode = browser.gZenThemePicker.shouldBeDarkMode(dominantColor);
|
||||
browser.document.documentElement.setAttribute('zen-should-be-dark-mode', isDarkMode);
|
||||
browser.gZenThemePicker.panel.removeAttribute('invalidate-controls');
|
||||
} else {
|
||||
browser.document.documentElement.removeAttribute('zen-should-be-dark-mode');
|
||||
if (!this.isLegacyVersion) {
|
||||
browser.gZenThemePicker.panel.setAttribute('invalidate-controls', 'true');
|
||||
}
|
||||
}
|
||||
// Set `--toolbox-textcolor` to have a contrast with the primary color
|
||||
const textColor = this.getToolbarColor(isDarkMode);
|
||||
document.documentElement.style.setProperty(
|
||||
'--toolbox-textcolor',
|
||||
isDarkMode ? 'rgba(255, 255, 255, 0.8)' : 'rgba(0, 0, 0, 0.8)'
|
||||
`rgba(${textColor[0]}, ${textColor[1]}, ${textColor[2]}, ${textColor[3]})`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1549,6 +1575,7 @@
|
||||
const algorithm = this.useAlgo;
|
||||
const position =
|
||||
dot.getAttribute('data-position') && JSON.parse(dot.getAttribute('data-position'));
|
||||
const type = dot.getAttribute('data-type');
|
||||
return {
|
||||
c: isCustom ? color : color.match(/\d+/g).map(Number),
|
||||
isCustom,
|
||||
@@ -1556,6 +1583,7 @@
|
||||
isPrimary,
|
||||
lightness: this.#currentLightness,
|
||||
position,
|
||||
type,
|
||||
};
|
||||
});
|
||||
const gradient = nsZenThemePicker.getTheme(colors, this.currentOpacity, this.currentTexture);
|
||||
|
||||
@@ -2881,7 +2881,7 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||
parent.removeAttribute('icons-overflow');
|
||||
return;
|
||||
}
|
||||
const maxButtonSize = 30; // IMPORTANT: This should match the CSS size of the icons
|
||||
const maxButtonSize = 26; // IMPORTANT: This should match the CSS size of the icons
|
||||
const minButtonSize = 15;
|
||||
const separation = 3; // Space between icons
|
||||
|
||||
@@ -2944,4 +2944,10 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||
gBrowser.tabContainer.removeAttribute('overflow');
|
||||
}
|
||||
}
|
||||
|
||||
handleTabCloseWindow() {
|
||||
if (this.shouldCloseWindow()) {
|
||||
document.getElementById('cmd_closeWindow').doCommand();
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -261,6 +261,7 @@
|
||||
animation: zen-theme-picker-dot-animation 0.5s;
|
||||
transform: translate(-50%, -50%);
|
||||
pointer-events: none;
|
||||
transform-origin: center center;
|
||||
|
||||
&:first-of-type {
|
||||
width: 36px;
|
||||
@@ -269,10 +270,10 @@
|
||||
z-index: 2;
|
||||
pointer-events: all;
|
||||
transition: transform 0.2s;
|
||||
z-index: 999;
|
||||
&:hover {
|
||||
transform: scale(1.05) translate(-50%, -50%);
|
||||
}
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
&[dragging='true'] {
|
||||
@@ -435,7 +436,7 @@
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
:root:not([zen-should-be-dark-mode]) {
|
||||
#PanelUI-zen-gradient-generator[invalidate-controls='true'] {
|
||||
#PanelUI-zen-gradient-generator-opacity {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
|
||||
& toolbarbutton {
|
||||
margin: 0;
|
||||
max-width: 30px;
|
||||
height: 30px;
|
||||
max-width: 26px;
|
||||
height: 26px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 0 !important;
|
||||
@@ -205,6 +205,7 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
cursor: auto;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.zen-workspaces-actions {
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"binaryName": "zen",
|
||||
"version": {
|
||||
"product": "firefox",
|
||||
"version": "140.0.2",
|
||||
"candidate": "140.0.2"
|
||||
"version": "140.0.4",
|
||||
"candidate": "140.0.4"
|
||||
},
|
||||
"buildOptions": {
|
||||
"generateBranding": true
|
||||
@@ -19,7 +19,7 @@
|
||||
"brandShortName": "Zen",
|
||||
"brandFullName": "Zen Browser",
|
||||
"release": {
|
||||
"displayVersion": "1.14.2b",
|
||||
"displayVersion": "1.14.3b",
|
||||
"github": {
|
||||
"repo": "zen-browser/desktop"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user