mirror of
https://github.com/zen-browser/components.git
synced 2025-07-08 16:19:58 +02:00
feat(workspaces): Implement gradient theme with customization options
This commit introduces a new gradient theme for workspaces, offering a more visually appealing and customizable interface.
This commit is contained in:
parent
3c095d47d8
commit
a9ec46885c
1 changed files with 155 additions and 82 deletions
|
@ -348,7 +348,7 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||||
currentContainer.appendChild(currentWorkspace);
|
currentContainer.appendChild(currentWorkspace);
|
||||||
|
|
||||||
if (activeWorkspace.themeColor) {
|
if (activeWorkspace.themeColor) {
|
||||||
this.generateZenColorsComplementary(activeWorkspace.themeColor);
|
this.generateZenGradientTheme(activeWorkspace.themeColor);
|
||||||
} else {
|
} else {
|
||||||
// If no themeColor is set, reset to default colors
|
// If no themeColor is set, reset to default colors
|
||||||
this.resetZenColors();
|
this.resetZenColors();
|
||||||
|
@ -933,117 +933,190 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||||
|
|
||||||
shiftHue = (h, shift) => (h + shift + 360) % 360; // Ensuring positive hue values
|
shiftHue = (h, shift) => (h + shift + 360) % 360; // Ensuring positive hue values
|
||||||
|
|
||||||
generateZenColorsComplementary(baseHex) {
|
generateZenGradientTheme(baseHex) {
|
||||||
const isDarkTheme = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
const isDarkTheme = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
|
||||||
// Get HSL from base hex color
|
// Get HSL from base hex color
|
||||||
let [h, s, l] = this.hexToHsl(baseHex);
|
let [h, s, l] = this.hexToHsl(baseHex);
|
||||||
|
|
||||||
// Apply desaturation and adjust lightness for pastel effect
|
// Adjust saturation based on user preference
|
||||||
s = Math.min(s, 40); // Cap saturation at 40%
|
const desaturate = Services.prefs.getBoolPref('zen.workspaces.gradient.desaturate', false);
|
||||||
|
s = desaturate ? Math.min(s, 55) : Math.min(s, 80);
|
||||||
|
|
||||||
if (!isDarkTheme) {
|
// Control lightness/intensity based on theme
|
||||||
l = Math.max(l, 70); // Ensure lightness is at least 70% in light mode
|
let lightness, accentLightness;
|
||||||
|
if (isDarkTheme) {
|
||||||
|
lightness = 12; // Default lightness for dark theme
|
||||||
|
accentLightness = 40;
|
||||||
} else {
|
} else {
|
||||||
l = 30; // Set base lightness to 30% in dark mode
|
lightness = 80; // Default lightness for light theme
|
||||||
|
accentLightness = 58;
|
||||||
}
|
}
|
||||||
baseHex = this.hslToHex(h, s, l);
|
|
||||||
|
|
||||||
let colors = {};
|
// Set CSS variables for saturation and lightness
|
||||||
|
document.documentElement.style.setProperty('--saturation', `${s}%`);
|
||||||
|
document.documentElement.style.setProperty('--lightness', `${lightness}%`);
|
||||||
|
document.documentElement.style.setProperty('--accent-color-lightness', `${accentLightness}%`);
|
||||||
|
|
||||||
if (s < 15) {
|
// Determine the target hue based on the base hue category
|
||||||
// Neutral color selected (e.g., grey shade)
|
function getColorCategory(hue) {
|
||||||
// Generate a primary color that pops
|
if ((hue >= 0 && hue < 30) || (hue >= 330 && hue <= 360)) {
|
||||||
const popHues = [0, 30, 60, 120, 180, 240, 300]; // Array of hues for vibrant colors
|
return 'red';
|
||||||
const popHue = popHues[Math.floor(Math.random() * popHues.length)]; // Randomly select a hue
|
} else if (hue >= 30 && hue < 60) {
|
||||||
const popSaturation = 80; // High saturation for popping color
|
return 'orange';
|
||||||
const popLightness = isDarkTheme ? 40 : 50; // Adjusted lightness based on theme
|
} else if (hue >= 60 && hue < 90) {
|
||||||
|
return 'yellow';
|
||||||
const l_tertiary = isDarkTheme ? 15 : l; // Much darker in dark mode
|
} else if (hue >= 90 && hue < 150) {
|
||||||
|
return 'green';
|
||||||
colors = {
|
} else if (hue >= 150 && hue < 210) {
|
||||||
"--zen-colors-primary": this.hslToHex(popHue, popSaturation, popLightness), // Vibrant color
|
return 'cyan';
|
||||||
"--zen-colors-secondary": this.hslToHex(h, s, Math.min(l_tertiary + 10, 100)), // Slightly lighter neutral
|
} else if (hue >= 210 && hue < 270) {
|
||||||
"--zen-colors-tertiary": this.hslToHex(h, s, l_tertiary), // Darker neutral color (background)
|
return 'blue';
|
||||||
"--zen-colors-border": this.hslToHex(h, s, Math.max(l_tertiary - 5, 0)), // Even darker neutral
|
} else if (hue >= 270 && hue < 330) {
|
||||||
"--zen-dialog-background": this.hslToHex(h, s, Math.min(l_tertiary + 5, 100)), // Slightly lighter neutral
|
return 'purple';
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
// Non-neutral color selected
|
return 'unknown';
|
||||||
const primaryH = this.shiftHue(h, isDarkTheme ? 0 : -10); // No hue shift in dark mode
|
|
||||||
const secondaryH = this.shiftHue(h, isDarkTheme ? 0 : 10);
|
|
||||||
|
|
||||||
if (!isDarkTheme) {
|
|
||||||
// Light mode
|
|
||||||
colors = {
|
|
||||||
"--zen-colors-primary": this.hslToHex(primaryH, s, Math.max(l - 10, 0)), // Slightly darker shade with shifted hue
|
|
||||||
"--zen-colors-secondary": this.hslToHex(secondaryH, s, Math.min(l + 10, 100)), // Slightly lighter shade with shifted hue
|
|
||||||
"--zen-colors-tertiary": baseHex, // Base color (background)
|
|
||||||
"--zen-colors-border": this.hslToHex(h, s, Math.max(l - 20, 0)), // Darker version for border
|
|
||||||
"--zen-dialog-background": this.hslToHex(h, s, Math.min(l + 5, 100)), // Slightly lighter
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// Dark mode
|
|
||||||
const l_tertiary = 15; // Much darker for tertiary color
|
|
||||||
const l_primary = 40; // Lightness adjusted for white text
|
|
||||||
|
|
||||||
colors = {
|
|
||||||
"--zen-colors-primary": this.hslToHex(h, s, l_primary), // Similar to baseHex but dark enough for white text
|
|
||||||
"--zen-colors-secondary": this.hslToHex(h, s, Math.max(l_primary - 10, 0)), // Slightly darker than primary
|
|
||||||
"--zen-colors-tertiary": this.hslToHex(h, s, l_tertiary), // Much darker base color (background)
|
|
||||||
"--zen-colors-border": this.hslToHex(h, s, Math.max(l_tertiary - 5, 0)), // Even darker for border
|
|
||||||
"--zen-dialog-background": this.hslToHex(h, s, Math.min(l_tertiary + 5, 100)), // Slightly lighter
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the colors to the document's root style
|
function getTargetHue(category) {
|
||||||
Object.keys(colors).forEach(key => {
|
switch (category) {
|
||||||
document.documentElement.style.setProperty(key, colors[key]);
|
case 'red':
|
||||||
|
// Last color should be yellowish (60-90)
|
||||||
|
return 75; // Midpoint of yellow range
|
||||||
|
case 'orange':
|
||||||
|
// Last color should be blueish (210-270)
|
||||||
|
return 240; // Midpoint of blue range
|
||||||
|
case 'yellow':
|
||||||
|
// Last color should be purplish (270-330)
|
||||||
|
return 300; // Midpoint of purple range
|
||||||
|
case 'green':
|
||||||
|
// Last color should be reddish (0-30 or 330-360)
|
||||||
|
return 0; // Red hue
|
||||||
|
case 'cyan':
|
||||||
|
// Last color should be orangeish (30-60)
|
||||||
|
return 45; // Midpoint of orange range
|
||||||
|
case 'blue':
|
||||||
|
// Last color should be greenish (90-150)
|
||||||
|
return 120; // Midpoint of green range
|
||||||
|
case 'purple':
|
||||||
|
// Last color should be cyan (150-210)
|
||||||
|
return 180; // Midpoint of cyan range
|
||||||
|
default:
|
||||||
|
// If unknown, pick a complementary hue
|
||||||
|
return (h + 180) % 360;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hueDifference(h1, h2) {
|
||||||
|
let diff = h2 - h1;
|
||||||
|
if (diff > 180) {
|
||||||
|
diff -= 360;
|
||||||
|
} else if (diff < -180) {
|
||||||
|
diff += 360;
|
||||||
|
}
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
function interpolateHue(h1, h2, t) {
|
||||||
|
let diff = hueDifference(h1, h2);
|
||||||
|
return (h1 + diff * t + 360) % 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseCategory = getColorCategory(h);
|
||||||
|
const targetHue = getTargetHue(baseCategory);
|
||||||
|
|
||||||
|
const numberOfColors = 4; // Number of gradient colors
|
||||||
|
const gradientColors = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < numberOfColors; i++) {
|
||||||
|
let t = i / (numberOfColors - 1); // Normalized position (0 to 1)
|
||||||
|
let newHue = interpolateHue(h, targetHue, t);
|
||||||
|
let colorVar = `--gradient-color${i + 1}`;
|
||||||
|
let colorValue = `hsl(${newHue}, var(--saturation), var(--lightness))`;
|
||||||
|
document.documentElement.style.setProperty(colorVar, colorValue);
|
||||||
|
gradientColors.push(colorValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set custom accent color using base hue
|
||||||
|
let accentColor = `hsla(${h}, 50%, var(--accent-color-lightness), 0.7)`;
|
||||||
|
document.documentElement.style.setProperty('--custom-accent-color', accentColor);
|
||||||
|
|
||||||
|
// Optionally switch colors if preference is set
|
||||||
|
const switchColors = Services.prefs.getBoolPref('zen.workspaces.gradient.switch-colors', true);
|
||||||
|
if (switchColors) {
|
||||||
|
gradientColors.forEach((color, index) => {
|
||||||
|
let switchedColorVar = `--switched-color${index + 1}`;
|
||||||
|
document.documentElement.style.setProperty(switchedColorVar, color);
|
||||||
});
|
});
|
||||||
|
// Update accent color if needed
|
||||||
return colors;
|
document.documentElement.style.setProperty('--custom-accent-color', accentColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.documentElement.setAttribute('zen-gradient-theme', 'true');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
resetZenColors() {
|
resetZenColors() {
|
||||||
// Remove custom properties
|
// Remove custom properties
|
||||||
const properties = [
|
const properties = [
|
||||||
"--zen-colors-primary",
|
'--saturation',
|
||||||
"--zen-colors-secondary",
|
'--lightness',
|
||||||
"--zen-colors-tertiary",
|
'--accent-color-lightness',
|
||||||
"--zen-colors-border",
|
'--gradient-color1',
|
||||||
"--zen-dialog-background"
|
'--gradient-color2',
|
||||||
|
'--gradient-color3',
|
||||||
|
'--gradient-color4',
|
||||||
|
'--switched-color1',
|
||||||
|
'--switched-color2',
|
||||||
|
'--switched-color3',
|
||||||
|
'--switched-color4',
|
||||||
|
'--custom-accent-color',
|
||||||
|
'--gradient-start',
|
||||||
|
'--zen-main-browser-background',
|
||||||
|
'--zen-themed-toolbar-bg',
|
||||||
|
'--toolbarbutton-hover-background',
|
||||||
|
'--toolbarbutton-active-background',
|
||||||
|
'--panel-item-hover-bgcolor',
|
||||||
|
'--zen-workspaces-strip-background-color',
|
||||||
|
'--zen-webview-border-radius',
|
||||||
|
'--zen-border-radius',
|
||||||
];
|
];
|
||||||
properties.forEach(prop => {
|
properties.forEach(prop => {
|
||||||
document.documentElement.style.removeProperty(prop);
|
document.documentElement.style.removeProperty(prop);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.documentElement.removeAttribute('zen-gradient-theme');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
zenColorOptions = [
|
zenColorOptions = [
|
||||||
null,
|
null,
|
||||||
"#FFD1DC", // Pastel Pink
|
"#FF5733", // Vibrant Orange
|
||||||
"#FFB347", // Pastel Orange
|
"#FFC300", // Vibrant Yellow
|
||||||
"#FFFF99", // Pastel Yellow
|
"#DAF7A6", // Light Green
|
||||||
"#77DD77", // Pastel Green
|
"#33FF57", // Vibrant Green
|
||||||
"#AEC6CF", // Pastel Blue
|
"#33FFF6", // Aqua
|
||||||
"#D8BFD8", // Pastel Lilac
|
"#3357FF", // Vibrant Blue
|
||||||
"#98FF98", // Pastel Mint
|
"#9D33FF", // Vibrant Purple
|
||||||
"#FFDAB9", // Pastel Peach
|
"#FF33A8", // Vibrant Pink
|
||||||
"#E6E6FA", // Pastel Lavender
|
"#FF3333", // Vibrant Red
|
||||||
"#F5F5DC", // Pastel Beige
|
"#FF8C33", // Vibrant Coral
|
||||||
"#F0E68C", // Khaki
|
"#FFD133", // Vibrant Gold
|
||||||
"#E0FFFF", // Light Cyan
|
"#8CFF33", // Lime Green
|
||||||
"#FFB6C1", // Light Pink
|
"#33FF8C", // Mint Green
|
||||||
"#ADD8E6", // Light Blue
|
"#33FFD1", // Turquoise
|
||||||
"#CD5C5C", // Darker Red
|
"#338CFF", // Sky Blue
|
||||||
"#F08080", // Light Coral
|
"#8C33FF", // Deep Purple
|
||||||
"#AFEEEE", // Pale Turquoise
|
"#D133FF", // Magenta
|
||||||
"#20B2AA", // Light Sea Green
|
"#FF33D1", // Hot Pink
|
||||||
"#8470FF", // Light Slate Blue
|
"#FF338C", // Rose
|
||||||
"#FFA07A", // Light Salmon
|
"#333333", // Dark Gray
|
||||||
"#000000" // Black
|
"#FFFFFF" // White
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
// Function to initialize the color picker
|
// Function to initialize the color picker
|
||||||
initializeZenColorPicker(containerId, onColorSelected, initialColor = null) {
|
initializeZenColorPicker(containerId, onColorSelected, initialColor = null) {
|
||||||
const container = document.getElementById(containerId);
|
const container = document.getElementById(containerId);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue