mirror of
https://github.com/zen-browser/components.git
synced 2025-07-07 21:29:59 +02:00
Added a working workspaces gradient chooser!
This commit is contained in:
parent
5ce7d24842
commit
649b22bbe3
1 changed files with 140 additions and 43 deletions
|
@ -2,13 +2,19 @@
|
||||||
{
|
{
|
||||||
class ZenThemePicker extends ZenDOMOperatedFeature {
|
class ZenThemePicker extends ZenDOMOperatedFeature {
|
||||||
static GRADIENT_IMAGE_URL = 'chrome://browser/content/zen-images/gradient.png';
|
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;
|
static MAX_DOTS = 5;
|
||||||
|
|
||||||
|
currentOpacity = 0.5;
|
||||||
|
currentRotation = 45;
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
ChromeUtils.defineLazyGetter(this, 'panel', () => document.getElementById('PanelUI-zen-gradient-generator'));
|
ChromeUtils.defineLazyGetter(this, 'panel', () => document.getElementById('PanelUI-zen-gradient-generator'));
|
||||||
ChromeUtils.defineLazyGetter(this, 'toolbox', () => document.getElementById('navigator-toolbox'));
|
ChromeUtils.defineLazyGetter(this, 'toolbox', () => document.getElementById('navigator-toolbox'));
|
||||||
|
|
||||||
|
this.initRotation();
|
||||||
this.initCanvas();
|
this.initCanvas();
|
||||||
|
|
||||||
ZenWorkspaces.addChangeListeners(this.onWorkspaceChange.bind(this));
|
ZenWorkspaces.addChangeListeners(this.onWorkspaceChange.bind(this));
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').addListener(this.onDarkModeChange.bind(this));
|
window.matchMedia('(prefers-color-scheme: dark)').addListener(this.onDarkModeChange.bind(this));
|
||||||
}
|
}
|
||||||
|
@ -17,9 +23,9 @@
|
||||||
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
async onDarkModeChange(event) {
|
async onDarkModeChange(event, skipUpdate = false) {
|
||||||
const currentWorkspace = await ZenWorkspaces.getActiveWorkspace();
|
const currentWorkspace = await ZenWorkspaces.getActiveWorkspace();
|
||||||
this.onWorkspaceChange(currentWorkspace);
|
this.onWorkspaceChange(currentWorkspace, skipUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
initContextMenu() {
|
initContextMenu() {
|
||||||
|
@ -67,9 +73,77 @@
|
||||||
this.initThemePicker();
|
this.initThemePicker();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = 1;
|
||||||
|
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 = 0;
|
||||||
|
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() {
|
initThemePicker() {
|
||||||
const themePicker = this.panel.querySelector('.zen-theme-picker-gradient');
|
const themePicker = this.panel.querySelector('.zen-theme-picker-gradient');
|
||||||
themePicker.style.setProperty('--zen-theme-picker-gradient-image', `url(${ZenThemePicker.GRADIENT_IMAGE_URL})`);
|
themePicker.style.setProperty('--zen-theme-picker-gradient-image', `url(${ZenThemePicker.GRADIENT_DISPLAY_URL})`);
|
||||||
themePicker.addEventListener('mousemove', this.onDotMouseMove.bind(this));
|
themePicker.addEventListener('mousemove', this.onDotMouseMove.bind(this));
|
||||||
themePicker.addEventListener('mouseup', this.onDotMouseUp.bind(this));
|
themePicker.addEventListener('mouseup', this.onDotMouseUp.bind(this));
|
||||||
}
|
}
|
||||||
|
@ -112,17 +186,13 @@
|
||||||
dot.addEventListener('mousedown', this.onDotMouseDown.bind(this));
|
dot.addEventListener('mousedown', this.onDotMouseDown.bind(this));
|
||||||
this.panel.querySelector('.zen-theme-picker-gradient').appendChild(dot);
|
this.panel.querySelector('.zen-theme-picker-gradient').appendChild(dot);
|
||||||
if (!fromWorkspace) {
|
if (!fromWorkspace) {
|
||||||
this.onDarkModeChange();
|
this.onDarkModeChange(null, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDotMouseDown(event) {
|
onDotMouseDown(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (event.button === 2) {
|
if (event.button === 2) {
|
||||||
if (this.numberOfDots <= 2 || !event.target.classList.contains('zen-theme-picker-dot')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
event.target.remove();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.dragging = true;
|
this.dragging = true;
|
||||||
|
@ -135,33 +205,42 @@
|
||||||
if (this.dragging) {
|
if (this.dragging) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const rect = this.panel.querySelector('.zen-theme-picker-gradient').getBoundingClientRect();
|
const rect = this.panel.querySelector('.zen-theme-picker-gradient').getBoundingClientRect();
|
||||||
let x = (event.clientX - rect.left) / rect.width;
|
const padding = 90; // each side
|
||||||
let y = (event.clientY - rect.top) / rect.height;
|
// do NOT let the ball be draged outside of an imaginary circle. You can drag it anywhere inside the circle
|
||||||
// percentage to pixel
|
// if the distance between the center of the circle and the dragged ball is bigger than the radius, then the ball
|
||||||
const dotSize = 16;
|
// should be placed on the edge of the circle. If it's inside the circle, then the ball just follows the mouse
|
||||||
const maxX = rect.width - dotSize;
|
const centerX = rect.left + rect.width / 2;
|
||||||
const maxY = rect.height - dotSize;
|
const centerY = rect.top + rect.height / 2;
|
||||||
if (x < 0) {
|
const radius = (rect.width - padding) / 2;
|
||||||
x = 0.01;
|
let pixelX = event.clientX;
|
||||||
} else if (x > 1) {
|
let pixelY = event.clientY;
|
||||||
x = 0.99;
|
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;
|
||||||
}
|
}
|
||||||
if (y < 0) {
|
// set the location of the dot in pixels
|
||||||
y = 0.01;
|
const relativeX = pixelX - rect.left;
|
||||||
} else if (y > 1) {
|
const relativeY = pixelY - rect.top;
|
||||||
y = 0.99;
|
this.draggedDot.style.left = `${relativeX}px`;
|
||||||
}
|
this.draggedDot.style.top = `${relativeY}px`;
|
||||||
const pixelX = x * rect.width - dotSize;
|
const color = this.getColorFromPosition(relativeX, relativeY);
|
||||||
const pixelY = y * rect.height - dotSize;
|
|
||||||
this.draggedDot.style.left = `${Math.min(maxX, Math.max(0, pixelX))}px`;
|
|
||||||
this.draggedDot.style.top = `${Math.min(maxY, Math.max(0, pixelY))}px`;
|
|
||||||
const color = this.getColorFromPosition(pixelX, pixelY);
|
|
||||||
this.draggedDot.style.setProperty('--zen-theme-picker-dot-color', `rgb(${color[0]}, ${color[1]}, ${color[2]})`);
|
this.draggedDot.style.setProperty('--zen-theme-picker-dot-color', `rgb(${color[0]}, ${color[1]}, ${color[2]})`);
|
||||||
this.updateCurrentWorkspace();
|
this.updateCurrentWorkspace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDotMouseUp(event) {
|
onDotMouseUp(event) {
|
||||||
|
if (event.button === 2) {
|
||||||
|
if (this.numberOfDots <= 2 || !event.target.classList.contains('zen-theme-picker-dot')
|
||||||
|
|| this.numberOfDots === 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
event.target.remove();
|
||||||
|
this.updateCurrentWorkspace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this.dragging) {
|
if (this.dragging) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.dragging = false;
|
this.dragging = false;
|
||||||
|
@ -178,27 +257,39 @@
|
||||||
|
|
||||||
themedColors(colors) {
|
themedColors(colors) {
|
||||||
const isDarkMode = this.isDarkMode;
|
const isDarkMode = this.isDarkMode;
|
||||||
const factor = isDarkMode ? 0.1 : 1.9;
|
const factor = isDarkMode ? 0.5 : 1.1;
|
||||||
return colors.map(color => {
|
return colors.map(color => {
|
||||||
// make the color really light or really dark depending on the theme
|
|
||||||
const [r, g, b] = color;
|
|
||||||
return [
|
return [
|
||||||
Math.floor(Math.min(255, Math.max(0, r * factor))),
|
Math.min(255, color[0] * factor),
|
||||||
Math.floor(Math.min(255, Math.max(0, g * factor))),
|
Math.min(255, color[1] * factor),
|
||||||
Math.floor(Math.min(255, Math.max(0, b * factor))),
|
Math.min(255, color[2] * factor),
|
||||||
];
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onOpacityChange(event) {
|
||||||
|
this.currentOpacity = event.target.value;
|
||||||
|
this.updateCurrentWorkspace();
|
||||||
|
}
|
||||||
|
|
||||||
|
getSingleRGBColor(color) {
|
||||||
|
return `color-mix(in srgb, rgb(${color[0]}, ${color[1]}, ${color[2]}) ${this.currentOpacity * 100}%, var(--zen-themed-toolbar-bg) ${(1 - this.currentOpacity) * 100}%)`;
|
||||||
|
}
|
||||||
|
|
||||||
getGradient(colors) {
|
getGradient(colors) {
|
||||||
const themedColors = this.themedColors(colors);
|
const themedColors = this.themedColors(colors);
|
||||||
return `linear-gradient(to right, ${themedColors.map(color => `rgb(${color[0]}, ${color[1]}, ${color[2]})`).join(', ')})`;
|
if (themedColors.length === 1) {
|
||||||
|
return this.getSingleRGBColor(themedColors[0]);
|
||||||
|
}
|
||||||
|
return `linear-gradient(${this.currentRotation}deg, ${themedColors.map(color => this.getSingleRGBColor(color)).join(', ')})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTheme(colors) {
|
getTheme(colors, opacity = 0.5, rotation = 45) {
|
||||||
return {
|
return {
|
||||||
type: 'gradient',
|
type: 'gradient',
|
||||||
gradientColors: colors,
|
gradientColors: colors,
|
||||||
|
opacity,
|
||||||
|
rotation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,16 +297,22 @@
|
||||||
const uuid = workspace.uuid;
|
const uuid = workspace.uuid;
|
||||||
const theme = await ZenWorkspacesStorage.getWorkspaceTheme(uuid);
|
const theme = await ZenWorkspacesStorage.getWorkspaceTheme(uuid);
|
||||||
const appWrapepr = document.getElementById('zen-main-app-wrapper');
|
const appWrapepr = document.getElementById('zen-main-app-wrapper');
|
||||||
appWrapepr.removeAttribute('animating');
|
if (!skipUpdate) {
|
||||||
appWrapepr.setAttribute('animating', 'true');
|
|
||||||
document.body.style.setProperty('--zen-main-browser-background-old', document.body.style.getPropertyValue('--zen-main-browser-background'));
|
|
||||||
setTimeout(() => {
|
|
||||||
appWrapepr.removeAttribute('animating');
|
appWrapepr.removeAttribute('animating');
|
||||||
}, 1000);
|
appWrapepr.setAttribute('animating', 'true');
|
||||||
|
document.body.style.setProperty('--zen-main-browser-background-old', document.body.style.getPropertyValue('--zen-main-browser-background'));
|
||||||
|
setTimeout(() => {
|
||||||
|
appWrapepr.removeAttribute('animating');
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
if (!theme || theme.type !== 'gradient') {
|
if (!theme || theme.type !== 'gradient') {
|
||||||
document.body.style.removeProperty('--zen-main-browser-background');
|
document.body.style.removeProperty('--zen-main-browser-background');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.currentOpacity = theme.opacity || 0.5;
|
||||||
|
this.currentRotation = theme.rotation || 45;
|
||||||
|
document.getElementById('PanelUI-zen-gradient-generator-opacity').value = this.currentOpacity;
|
||||||
|
this.setRotationInput(this.currentRotation);
|
||||||
const gradient = this.getGradient(theme.gradientColors);
|
const gradient = this.getGradient(theme.gradientColors);
|
||||||
document.body.style.setProperty('--zen-main-browser-background', gradient);
|
document.body.style.setProperty('--zen-main-browser-background', gradient);
|
||||||
if (!skipUpdate) {
|
if (!skipUpdate) {
|
||||||
|
@ -239,7 +336,7 @@
|
||||||
const color = dot.style.getPropertyValue('--zen-theme-picker-dot-color');
|
const color = dot.style.getPropertyValue('--zen-theme-picker-dot-color');
|
||||||
return color.match(/\d+/g).map(Number);
|
return color.match(/\d+/g).map(Number);
|
||||||
});
|
});
|
||||||
const gradient = this.getTheme(colors);
|
const gradient = this.getTheme(colors, this.currentOpacity, this.currentRotation);
|
||||||
const currentWorkspace = await ZenWorkspaces.getActiveWorkspace();
|
const currentWorkspace = await ZenWorkspaces.getActiveWorkspace();
|
||||||
await ZenWorkspacesStorage.saveWorkspaceTheme(currentWorkspace.uuid, gradient);
|
await ZenWorkspacesStorage.saveWorkspaceTheme(currentWorkspace.uuid, gradient);
|
||||||
this.onWorkspaceChange(currentWorkspace, true);
|
this.onWorkspaceChange(currentWorkspace, true);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue