mirror of
https://github.com/zen-browser/components.git
synced 2025-07-07 22:49:58 +02:00
584 lines
22 KiB
TypeScript
584 lines
22 KiB
TypeScript
|
|
{
|
|
class ZenThemePicker extends ZenMultiWindowFeature {
|
|
static GRADIENT_IMAGE_URL = 'chrome://browser/content/zen-images/gradient.png';
|
|
static GRADIENT_DISPLAY_URL = 'chrome://browser/content/zen-images/gradient-display.png';
|
|
static MAX_DOTS = 5;
|
|
|
|
currentOpacity = 0.5;
|
|
currentRotation = 45;
|
|
|
|
numberOfDots = 0;
|
|
|
|
constructor() {
|
|
super();
|
|
if (!Services.prefs.getBoolPref('zen.theme.gradient', true) || !ZenWorkspaces.shouldHaveWorkspaces) {
|
|
return;
|
|
}
|
|
|
|
ChromeUtils.defineLazyGetter(this, 'panel', () => document.getElementById('PanelUI-zen-gradient-generator'));
|
|
ChromeUtils.defineLazyGetter(this, 'toolbox', () => document.getElementById('TabsToolbar'));
|
|
ChromeUtils.defineLazyGetter(this, 'customColorInput', () => document.getElementById('PanelUI-zen-gradient-generator-custom-input'));
|
|
ChromeUtils.defineLazyGetter(this, 'customColorList', () => document.getElementById('PanelUI-zen-gradient-generator-custom-list'));
|
|
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
'allowWorkspaceColors',
|
|
'zen.theme.color-prefs.use-workspace-colors',
|
|
true,
|
|
this.onDarkModeChange.bind(this)
|
|
)
|
|
|
|
this.initRotation();
|
|
this.initCanvas();
|
|
|
|
ZenWorkspaces.addChangeListeners(this.onWorkspaceChange.bind(this));
|
|
window.matchMedia('(prefers-color-scheme: dark)').addListener(this.onDarkModeChange.bind(this));
|
|
}
|
|
|
|
get isDarkMode() {
|
|
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
}
|
|
|
|
async onDarkModeChange(event, skipUpdate = false) {
|
|
const currentWorkspace = await ZenWorkspaces.getActiveWorkspace();
|
|
this.onWorkspaceChange(currentWorkspace, skipUpdate);
|
|
}
|
|
|
|
initContextMenu() {
|
|
const menu = window.MozXULElement.parseXULToFragment(`
|
|
<menuitem id="zenToolbarThemePicker"
|
|
data-lazy-l10n-id="zen-workspaces-change-gradient"
|
|
oncommand="gZenThemePicker.openThemePicker(event);"/>
|
|
`);
|
|
document.getElementById('toolbar-context-customize').before(menu);
|
|
}
|
|
|
|
openThemePicker(event) {
|
|
PanelMultiView.openPopup(this.panel, this.toolbox, {
|
|
position: 'topright topleft',
|
|
triggerEvent: event,
|
|
});
|
|
}
|
|
|
|
initCanvas() {
|
|
this.image = new Image();
|
|
this.image.src = ZenThemePicker.GRADIENT_IMAGE_URL;
|
|
|
|
this.canvas = document.createElement('canvas');
|
|
this.panel.appendChild(this.canvas);
|
|
this.canvasCtx = this.canvas.getContext('2d');
|
|
|
|
// wait for the image to load
|
|
this.image.onload = this.onImageLoad.bind(this);
|
|
}
|
|
|
|
onImageLoad() {
|
|
// resize the image to fit the panel
|
|
const imageSize = 300 - 20; // 20 is the padding (10px)
|
|
const scale = imageSize / Math.max(this.image.width, this.image.height);
|
|
this.image.width *= scale;
|
|
this.image.height *= scale;
|
|
|
|
this.canvas.width = this.image.width;
|
|
this.canvas.height = this.image.height;
|
|
this.canvasCtx.drawImage(this.image, 0, 0);
|
|
|
|
this.canvas.setAttribute('hidden', 'true');
|
|
|
|
// Call the rest of the initialization
|
|
this.initContextMenu();
|
|
this.initThemePicker();
|
|
|
|
this._hasInitialized = true;
|
|
this.onDarkModeChange(null);
|
|
}
|
|
|
|
initRotation() {
|
|
this.rotationInput = document.getElementById('PanelUI-zen-gradient-degrees');
|
|
this.rotationInputDot = this.rotationInput.querySelector('.dot');
|
|
this.rotationInputText = this.rotationInput.querySelector('.text');
|
|
this.rotationInputDot.addEventListener('mousedown', this.onRotationMouseDown.bind(this));
|
|
this.rotationInput.addEventListener('wheel', this.onRotationWheel.bind(this));
|
|
}
|
|
|
|
onRotationWheel(event) {
|
|
event.preventDefault();
|
|
const delta = event.deltaY;
|
|
const degrees = this.currentRotation + (delta > 0 ? 10 : -10);
|
|
this.setRotationInput(degrees);
|
|
this.updateCurrentWorkspace();
|
|
}
|
|
|
|
onRotationMouseDown(event) {
|
|
event.preventDefault();
|
|
this.rotationDragging = true;
|
|
this.rotationInputDot.style.zIndex = 2;
|
|
this.rotationInputDot.classList.add('dragging');
|
|
document.addEventListener('mousemove', this.onRotationMouseMove.bind(this));
|
|
document.addEventListener('mouseup', this.onRotationMouseUp.bind(this));
|
|
}
|
|
|
|
onRotationMouseUp(event) {
|
|
this.rotationDragging = false;
|
|
this.rotationInputDot.style.zIndex = 1;
|
|
this.rotationInputDot.classList.remove('dragging');
|
|
document.removeEventListener('mousemove', this.onRotationMouseMove.bind(this));
|
|
document.removeEventListener('mouseup', this.onRotationMouseUp.bind(this));
|
|
}
|
|
|
|
onRotationMouseMove(event) {
|
|
if (this.rotationDragging) {
|
|
event.preventDefault();
|
|
const rect = this.rotationInput.getBoundingClientRect();
|
|
// Make the dot follow the mouse in a circle, it can't go outside or inside the circle
|
|
const centerX = rect.left + rect.width / 2;
|
|
const centerY = rect.top + rect.height / 2;
|
|
const angle = Math.atan2(event.clientY - centerY, event.clientX - centerX);
|
|
const distance = Math.sqrt((event.clientX - centerX) ** 2 + (event.clientY - centerY) ** 2);
|
|
const radius = rect.width / 2;
|
|
let x = centerX + Math.cos(angle) * radius;
|
|
let y = centerY + Math.sin(angle) * radius;
|
|
if (distance > radius) {
|
|
x = event.clientX;
|
|
y = event.clientY;
|
|
}
|
|
const degrees = Math.round(Math.atan2(y - centerY, x - centerX) * 180 / Math.PI);
|
|
this.setRotationInput(degrees);
|
|
this.updateCurrentWorkspace();
|
|
}
|
|
}
|
|
|
|
setRotationInput(degrees) {
|
|
let fixedRotation = degrees;
|
|
while (fixedRotation < 0) {
|
|
fixedRotation += 360;
|
|
}
|
|
while (fixedRotation >= 360) {
|
|
fixedRotation -= 360;
|
|
}
|
|
this.currentRotation = degrees;
|
|
this.rotationInputDot.style.transform = `rotate(${degrees - 20}deg)`;
|
|
this.rotationInputText.textContent = `${fixedRotation}°`;
|
|
}
|
|
|
|
initThemePicker() {
|
|
const themePicker = this.panel.querySelector('.zen-theme-picker-gradient');
|
|
themePicker.style.setProperty('--zen-theme-picker-gradient-image', `url(${ZenThemePicker.GRADIENT_DISPLAY_URL})`);
|
|
themePicker.addEventListener('mousemove', this.onDotMouseMove.bind(this));
|
|
themePicker.addEventListener('mouseup', this.onDotMouseUp.bind(this));
|
|
}
|
|
|
|
calculateInitialPosition(color) {
|
|
const [r, g, b] = color.c;
|
|
const imageData = this.canvasCtx.getImageData(0, 0, this.canvas.width, this.canvas.height);
|
|
// Find all pixels that are at least 90% similar to the color
|
|
const similarPixels = [];
|
|
for (let i = 0; i < imageData.data.length; i += 4) {
|
|
const pixelR = imageData.data[i];
|
|
const pixelG = imageData.data[i + 1];
|
|
const pixelB = imageData.data[i + 2];
|
|
if (Math.abs(r - pixelR) < 25 && Math.abs(g - pixelG) < 25 && Math.abs(b - pixelB) < 25) {
|
|
similarPixels.push(i);
|
|
}
|
|
}
|
|
// Check if there's an exact match
|
|
for (const pixel of similarPixels) {
|
|
const x = (pixel / 4) % this.canvas.width;
|
|
const y = Math.floor((pixel / 4) / this.canvas.width);
|
|
const pixelColor = this.getColorFromPosition(x, y);
|
|
if (pixelColor[0] === r && pixelColor[1] === g && pixelColor[2] === b) {
|
|
return {x: x / this.canvas.width, y: y / this.canvas.height};
|
|
}
|
|
}
|
|
// If there's no exact match, return the first similar pixel
|
|
const pixel = similarPixels[0];
|
|
const x = (pixel / 4) % this.canvas.width;
|
|
const y = Math.floor((pixel / 4) / this.canvas.width);
|
|
return {x: x / this.canvas.width, y: y / this.canvas.height};
|
|
}
|
|
|
|
getColorFromPosition(x, y) {
|
|
// get the color from the x and y from the image
|
|
const imageData = this.canvasCtx.getImageData(x, y, 1, 1);
|
|
return imageData.data;
|
|
}
|
|
|
|
createDot(color, fromWorkspace = false) {
|
|
if (color.isCustom) {
|
|
this.addColorToCustomList(color.c);
|
|
}
|
|
const [r, g, b] = color.c;
|
|
const dot = document.createElement('div');
|
|
dot.classList.add('zen-theme-picker-dot');
|
|
if (color.isCustom) {
|
|
if (!color.c) {
|
|
return;
|
|
}
|
|
dot.classList.add('custom');
|
|
dot.style.opacity = 0;
|
|
dot.style.setProperty('--zen-theme-picker-dot-color', color.c);
|
|
} else {
|
|
dot.style.setProperty('--zen-theme-picker-dot-color', `rgb(${r}, ${g}, ${b})`);
|
|
const { x, y } = this.calculateInitialPosition(color);
|
|
dot.style.left = `${x * 100}%`;
|
|
dot.style.top = `${y * 100}%`;
|
|
dot.addEventListener('mousedown', this.onDotMouseDown.bind(this));
|
|
}
|
|
this.panel.querySelector('.zen-theme-picker-gradient').appendChild(dot);
|
|
if (!fromWorkspace) {
|
|
this.updateCurrentWorkspace(true);
|
|
}
|
|
}
|
|
|
|
onDotMouseDown(event) {
|
|
event.preventDefault();
|
|
if (event.button === 2) {
|
|
return;
|
|
}
|
|
this.dragging = true;
|
|
this.draggedDot = event.target;
|
|
this.draggedDot.style.zIndex = 1;
|
|
this.draggedDot.classList.add('dragging');
|
|
}
|
|
|
|
onDotMouseMove(event) {
|
|
if (this.dragging) {
|
|
event.preventDefault();
|
|
const rect = this.panel.querySelector('.zen-theme-picker-gradient').getBoundingClientRect();
|
|
const padding = 90; // each side
|
|
// do NOT let the ball be draged outside of an imaginary circle. You can drag it anywhere inside the circle
|
|
// if the distance between the center of the circle and the dragged ball is bigger than the radius, then the ball
|
|
// should be placed on the edge of the circle. If it's inside the circle, then the ball just follows the mouse
|
|
const centerX = rect.left + rect.width / 2;
|
|
const centerY = rect.top + rect.height / 2;
|
|
const radius = (rect.width - padding) / 2;
|
|
let pixelX = event.clientX;
|
|
let pixelY = event.clientY;
|
|
const distance = Math.sqrt((pixelX - centerX) ** 2 + (pixelY - centerY) ** 2);
|
|
if (distance > radius) {
|
|
const angle = Math.atan2(pixelY - centerY, pixelX - centerX);
|
|
pixelX = centerX + Math.cos(angle) * radius;
|
|
pixelY = centerY + Math.sin(angle) * radius;
|
|
}
|
|
// set the location of the dot in pixels
|
|
const relativeX = pixelX - rect.left;
|
|
const relativeY = pixelY - rect.top;
|
|
this.draggedDot.style.left = `${relativeX}px`;
|
|
this.draggedDot.style.top = `${relativeY}px`;
|
|
const color = this.getColorFromPosition(relativeX, relativeY);
|
|
this.draggedDot.style.setProperty('--zen-theme-picker-dot-color', `rgb(${color[0]}, ${color[1]}, ${color[2]})`);
|
|
this.updateCurrentWorkspace();
|
|
}
|
|
}
|
|
|
|
addColorToCustomList(color) {
|
|
const listItems = window.MozXULElement.parseXULToFragment(`
|
|
<hbox class="zen-theme-picker-custom-list-item">
|
|
<html:div class="zen-theme-picker-dot-custom"></html:div>
|
|
<label class="zen-theme-picker-custom-list-item-label"></label>
|
|
<toolbarbutton class="zen-theme-picker-custom-list-item-remove toolbarbutton-1" oncommand="gZenThemePicker.removeCustomColor(event);"></toolbarbutton>
|
|
</hbox>
|
|
`);
|
|
listItems.querySelector('.zen-theme-picker-custom-list-item').setAttribute('data-color', color);
|
|
listItems.querySelector('.zen-theme-picker-dot-custom').style.setProperty('--zen-theme-picker-dot-color', color);
|
|
listItems.querySelector('.zen-theme-picker-custom-list-item-label').textContent = color;
|
|
this.customColorList.appendChild(listItems);
|
|
}
|
|
|
|
async addCustomColor() {
|
|
const color = this.customColorInput.value;
|
|
if (!color) {
|
|
return;
|
|
}
|
|
// can be any color format, we just add it to the list as a dot, but hidden
|
|
const dot = document.createElement('div');
|
|
dot.classList.add('zen-theme-picker-dot', 'hidden', 'custom');
|
|
dot.style.opacity = 0;
|
|
dot.style.setProperty('--zen-theme-picker-dot-color', color);
|
|
this.panel.querySelector('.zen-theme-picker-gradient').appendChild(dot);
|
|
this.customColorInput.value = '';
|
|
await this.updateCurrentWorkspace();
|
|
}
|
|
|
|
onDotMouseUp(event) {
|
|
if (event.button === 2) {
|
|
if (!event.target.classList.contains('zen-theme-picker-dot')) {
|
|
return;
|
|
}
|
|
event.target.remove();
|
|
this.updateCurrentWorkspace();
|
|
this.numberOfDots--;
|
|
return;
|
|
}
|
|
if (this.dragging) {
|
|
event.preventDefault();
|
|
this.dragging = false;
|
|
this.draggedDot.style.zIndex = 1;
|
|
this.draggedDot.classList.remove('dragging');
|
|
this.draggedDot = null;
|
|
return;
|
|
}
|
|
this.numberOfDots = this.panel.querySelectorAll('.zen-theme-picker-dot').length;
|
|
if (this.numberOfDots < ZenThemePicker.MAX_DOTS) {
|
|
this.createDot({c:[255, 255, 255]}); // right in the center!
|
|
}
|
|
}
|
|
|
|
themedColors(colors) {
|
|
const isDarkMode = this.isDarkMode;
|
|
const factor = isDarkMode ? 0.5 : 1.1;
|
|
return colors.map(color => {
|
|
return {
|
|
c: color.isCustom ? color.c : [
|
|
Math.min(255, color.c[0] * factor),
|
|
Math.min(255, color.c[1] * factor),
|
|
Math.min(255, color.c[2] * factor),
|
|
],
|
|
isCustom: color.isCustom,
|
|
}
|
|
});
|
|
}
|
|
|
|
onOpacityChange(event) {
|
|
this.currentOpacity = event.target.value;
|
|
this.updateCurrentWorkspace();
|
|
}
|
|
|
|
onTextureChange(event) {
|
|
this.currentTexture = event.target.value;
|
|
this.updateCurrentWorkspace();
|
|
}
|
|
|
|
getSingleRGBColor(color) {
|
|
if (color.isCustom) {
|
|
return color.c;
|
|
}
|
|
return `color-mix(in srgb, rgb(${color.c[0]}, ${color.c[1]}, ${color.c[2]}) ${this.currentOpacity * 100}%, var(--zen-themed-toolbar-bg) ${(1 - this.currentOpacity) * 100}%)`;
|
|
}
|
|
|
|
|
|
getGradient(colors) {
|
|
const themedColors = this.themedColors(colors);
|
|
if (themedColors.length === 0) {
|
|
return "var(--zen-themed-toolbar-bg)";
|
|
} else if (themedColors.length === 1) {
|
|
return this.getSingleRGBColor(themedColors[0]);
|
|
}
|
|
return `linear-gradient(${this.currentRotation}deg, ${themedColors.map(color => this.getSingleRGBColor(color)).join(', ')})`;
|
|
}
|
|
|
|
getTheme(colors, opacity = 0.5, rotation = 45, texture = 0) {
|
|
return {
|
|
type: 'gradient',
|
|
gradientColors: colors.filter(color => color), // remove undefined
|
|
opacity,
|
|
rotation,
|
|
texture,
|
|
};
|
|
}
|
|
|
|
updateNoise(texture) {
|
|
const wrapper = document.getElementById('zen-main-app-wrapper');
|
|
wrapper.style.setProperty('--zen-grainy-background-opacity', texture);
|
|
}
|
|
|
|
hexToRgb(hex) {
|
|
if (hex.startsWith('#')) {
|
|
hex = hex.substring(1);
|
|
}
|
|
if (hex.length === 3) {
|
|
hex = hex.split('').map(char => char + char).join('');
|
|
}
|
|
return [
|
|
parseInt(hex.substring(0, 2), 16),
|
|
parseInt(hex.substring(2, 4), 16),
|
|
parseInt(hex.substring(4, 6), 16),
|
|
];
|
|
}
|
|
|
|
pSBC=(p,c0,c1,l)=>{
|
|
let r,g,b,P,f,t,h,i=parseInt,m=Math.round,a=typeof(c1)=="string";
|
|
if(typeof(p)!="number"||p<-1||p>1||typeof(c0)!="string"||(c0[0]!='r'&&c0[0]!='#')||(c1&&!a))return null;
|
|
if(!this.pSBCr)this.pSBCr=(d)=>{
|
|
let n=d.length,x={};
|
|
if(n>9){
|
|
[r,g,b,a]=d=d.split(","),n=d.length;
|
|
if(n<3||n>4)return null;
|
|
x.r=i(r[3]=="a"?r.slice(5):r.slice(4)),x.g=i(g),x.b=i(b),x.a=a?parseFloat(a):-1
|
|
}else{
|
|
if(n==8||n==6||n<4)return null;
|
|
if(n<6)d="#"+d[1]+d[1]+d[2]+d[2]+d[3]+d[3]+(n>4?d[4]+d[4]:"");
|
|
d=i(d.slice(1),16);
|
|
if(n==9||n==5)x.r=d>>24&255,x.g=d>>16&255,x.b=d>>8&255,x.a=m((d&255)/0.255)/1000;
|
|
else x.r=d>>16,x.g=d>>8&255,x.b=d&255,x.a=-1
|
|
}return x};
|
|
h=c0.length>9,h=a?c1.length>9?true:c1=="c"?!h:false:h,f=this.pSBCr(c0),P=p<0,t=c1&&c1!="c"?this.pSBCr(c1):P?{r:0,g:0,b:0,a:-1}:{r:255,g:255,b:255,a:-1},p=P?p*-1:p,P=1-p;
|
|
if(!f||!t)return null;
|
|
if(l)r=m(P*f.r+p*t.r),g=m(P*f.g+p*t.g),b=m(P*f.b+p*t.b);
|
|
else r=m((P*f.r**2+p*t.r**2)**0.5),g=m((P*f.g**2+p*t.g**2)**0.5),b=m((P*f.b**2+p*t.b**2)**0.5);
|
|
a=f.a,t=t.a,f=a>=0||t>=0,a=f?a<0?t:t<0?a:a*P+t*p:0;
|
|
if(h)return"rgb"+(f?"a(":"(")+r+","+g+","+b+(f?","+m(a*1000)/1000:"")+")";
|
|
else return"#"+(4294967296+r*16777216+g*65536+b*256+(f?m(a*255):0)).toString(16).slice(1,f?undefined:-2)
|
|
}
|
|
|
|
getMostDominantColor(allColors) {
|
|
const colors = this.themedColors(allColors);
|
|
const themedColors = colors.filter(color => !color.isCustom);
|
|
if (themedColors.length === 0 || !this.allowWorkspaceColors) {
|
|
return null;
|
|
}
|
|
// get the most dominant color in the gradient
|
|
let dominantColor = themedColors[0].c;
|
|
let dominantColorCount = 0;
|
|
for (const color of themedColors) {
|
|
const count = themedColors.filter(c => c.c[0] === color.c[0] && c.c[1] === color.c[1] && c.c[2] === color.c[2]).length;
|
|
if (count > dominantColorCount) {
|
|
dominantColorCount = count;
|
|
dominantColor = color.c;
|
|
}
|
|
}
|
|
const result = this.pSBC(
|
|
this.isDarkMode ? 0.7 : -0.7,
|
|
`rgb(${dominantColor[0]}, ${dominantColor[1]}, ${dominantColor[2]})`);
|
|
return result?.match(/\d+/g).map(Number);
|
|
}
|
|
|
|
async onWorkspaceChange(workspace, skipUpdate = false, theme = null) {
|
|
const uuid = workspace.uuid;
|
|
// Use theme from workspace object or passed theme
|
|
let workspaceTheme = theme || workspace.theme;
|
|
|
|
await this.foreachWindowAsActive(async (browser) => {
|
|
if (!browser.gZenThemePicker._hasInitialized) {
|
|
return;
|
|
}
|
|
// Do not rebuild if the workspace is not the same as the current one
|
|
const windowWorkspace = await browser.ZenWorkspaces.getActiveWorkspace();
|
|
if (windowWorkspace.uuid !== uuid && theme !== null) {
|
|
return;
|
|
}
|
|
|
|
// get the theme from the window
|
|
workspaceTheme = theme || windowWorkspace.theme;
|
|
|
|
const appWrapper = browser.document.getElementById('zen-main-app-wrapper');
|
|
if (!skipUpdate) {
|
|
appWrapper.removeAttribute('animating');
|
|
appWrapper.setAttribute('animating', 'true');
|
|
browser.document.body.style.setProperty('--zen-main-browser-background-old',
|
|
browser.document.body.style.getPropertyValue('--zen-main-browser-background')
|
|
);
|
|
browser.window.requestAnimationFrame(() => {
|
|
setTimeout(() => {
|
|
appWrapper.removeAttribute('animating');
|
|
}, 500);
|
|
});
|
|
}
|
|
|
|
browser.gZenThemePicker.resetCustomColorList();
|
|
if (!workspaceTheme || workspaceTheme.type !== 'gradient') {
|
|
browser.document.body.style.removeProperty('--zen-main-browser-background');
|
|
browser.gZenThemePicker.updateNoise(0);
|
|
if (!skipUpdate) {
|
|
for (const dot of browser.gZenThemePicker.panel.querySelectorAll('.zen-theme-picker-dot')) {
|
|
dot.remove();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
browser.gZenThemePicker.currentOpacity = workspaceTheme.opacity ?? 0.5;
|
|
browser.gZenThemePicker.currentRotation = workspaceTheme.rotation ?? 45;
|
|
browser.gZenThemePicker.currentTexture = workspaceTheme.texture ?? 0;
|
|
|
|
browser.gZenThemePicker.numberOfDots = workspaceTheme.gradientColors.length;
|
|
|
|
browser.document.getElementById('PanelUI-zen-gradient-generator-opacity').value = browser.gZenThemePicker.currentOpacity;
|
|
browser.document.getElementById('PanelUI-zen-gradient-generator-texture').value = browser.gZenThemePicker.currentTexture;
|
|
browser.gZenThemePicker.setRotationInput(browser.gZenThemePicker.currentRotation);
|
|
|
|
const gradient = browser.gZenThemePicker.getGradient(workspaceTheme.gradientColors);
|
|
browser.gZenThemePicker.updateNoise(workspaceTheme.texture);
|
|
|
|
for (const dot of workspaceTheme.gradientColors) {
|
|
if (dot.isCustom) {
|
|
browser.gZenThemePicker.addColorToCustomList(dot.c);
|
|
}
|
|
}
|
|
|
|
browser.document.documentElement.style.setProperty('--zen-main-browser-background', gradient);
|
|
|
|
const dominantColor = this.getMostDominantColor(workspaceTheme.gradientColors);
|
|
if (dominantColor) {
|
|
browser.document.documentElement.style.setProperty('--zen-primary-color', `rgb(${dominantColor[0]}, ${dominantColor[1]}, ${dominantColor[2]})`);
|
|
}
|
|
|
|
if (!skipUpdate) {
|
|
browser.gZenThemePicker.recalculateDots(workspaceTheme.gradientColors);
|
|
}
|
|
});
|
|
}
|
|
|
|
resetCustomColorList() {
|
|
this.customColorList.innerHTML = '';
|
|
}
|
|
|
|
removeCustomColor(event) {
|
|
const target = event.target.closest('.zen-theme-picker-custom-list-item');
|
|
const color = target.getAttribute('data-color');
|
|
const dots = this.panel.querySelectorAll('.zen-theme-picker-dot');
|
|
for (const dot of dots) {
|
|
if (dot.style.getPropertyValue('--zen-theme-picker-dot-color') === color) {
|
|
dot.remove();
|
|
break;
|
|
}
|
|
}
|
|
target.remove();
|
|
this.updateCurrentWorkspace();
|
|
}
|
|
|
|
recalculateDots(colors) {
|
|
const dots = this.panel.querySelectorAll('.zen-theme-picker-dot');
|
|
for (let i = 0; i < colors.length; i++) {
|
|
dots[i]?.remove();
|
|
}
|
|
for (const color of colors) {
|
|
this.createDot(color, true);
|
|
}
|
|
}
|
|
|
|
async updateCurrentWorkspace(skipSave = true) {
|
|
this.updated = skipSave;
|
|
const dots = this.panel.querySelectorAll('.zen-theme-picker-dot');
|
|
const colors = Array.from(dots).map(dot => {
|
|
const color = dot.style.getPropertyValue('--zen-theme-picker-dot-color');
|
|
if (color === 'undefined') {
|
|
return;
|
|
}
|
|
const isCustom = dot.classList.contains('custom');
|
|
return {c: isCustom ? color : color.match(/\d+/g).map(Number), isCustom};
|
|
});
|
|
const gradient = this.getTheme(colors, this.currentOpacity, this.currentRotation, this.currentTexture);
|
|
let currentWorkspace = await ZenWorkspaces.getActiveWorkspace();
|
|
|
|
if(!skipSave) {
|
|
await ZenWorkspacesStorage.saveWorkspaceTheme(currentWorkspace.uuid, gradient);
|
|
await ZenWorkspaces._propagateWorkspaceData();
|
|
ConfirmationHint.show(document.getElementById("PanelUI-menu-button"), "zen-panel-ui-gradient-generator-saved-message");
|
|
currentWorkspace = await ZenWorkspaces.getActiveWorkspace();
|
|
}
|
|
|
|
await this.onWorkspaceChange(currentWorkspace, true, skipSave ? gradient : null);
|
|
}
|
|
|
|
async handlePanelClose() {
|
|
if(this.updated) {
|
|
await this.updateCurrentWorkspace(false);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
window.ZenThemePicker = ZenThemePicker;
|
|
}
|