mirror of
https://github.com/zen-browser/components.git
synced 2025-07-07 23:39:59 +02:00
Added per workspace support for gradients and animations
This commit is contained in:
parent
23e6294c9a
commit
5ce7d24842
3 changed files with 148 additions and 8 deletions
|
@ -9,6 +9,17 @@
|
||||||
ChromeUtils.defineLazyGetter(this, 'toolbox', () => document.getElementById('navigator-toolbox'));
|
ChromeUtils.defineLazyGetter(this, 'toolbox', () => document.getElementById('navigator-toolbox'));
|
||||||
|
|
||||||
this.initCanvas();
|
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) {
|
||||||
|
const currentWorkspace = await ZenWorkspaces.getActiveWorkspace();
|
||||||
|
this.onWorkspaceChange(currentWorkspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
initContextMenu() {
|
initContextMenu() {
|
||||||
|
@ -65,10 +76,23 @@
|
||||||
|
|
||||||
calculateInitialPosition(color) {
|
calculateInitialPosition(color) {
|
||||||
const [r, g, b] = color;
|
const [r, g, b] = color;
|
||||||
// get the x and y position of the color
|
const imageData = this.canvasCtx.getImageData(0, 0, this.canvas.width, this.canvas.height);
|
||||||
const x = r / 255;
|
const pixels = imageData.data;
|
||||||
const y = g / 255;
|
let x = 0;
|
||||||
return { x, y };
|
let y = 0;
|
||||||
|
let minDistance = Infinity;
|
||||||
|
for (let i = 0; i < pixels.length; i += 4) {
|
||||||
|
const r2 = pixels[i];
|
||||||
|
const g2 = pixels[i + 1];
|
||||||
|
const b2 = pixels[i + 2];
|
||||||
|
const distance = Math.sqrt((r - r2) ** 2 + (g - g2) ** 2 + (b - b2) ** 2);
|
||||||
|
if (distance < minDistance) {
|
||||||
|
minDistance = distance;
|
||||||
|
x = (i / 4) % this.canvas.width;
|
||||||
|
y = Math.floor((i / 4) / this.canvas.width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { x: x / this.canvas.width, y: y / this.canvas.height };
|
||||||
}
|
}
|
||||||
|
|
||||||
getColorFromPosition(x, y) {
|
getColorFromPosition(x, y) {
|
||||||
|
@ -77,7 +101,7 @@
|
||||||
return imageData.data;
|
return imageData.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
createDot(color) {
|
createDot(color, fromWorkspace = false) {
|
||||||
const [r, g, b] = color;
|
const [r, g, b] = color;
|
||||||
const dot = document.createElement('div');
|
const dot = document.createElement('div');
|
||||||
dot.classList.add('zen-theme-picker-dot');
|
dot.classList.add('zen-theme-picker-dot');
|
||||||
|
@ -87,12 +111,18 @@
|
||||||
dot.style.top = `${y * 100}%`;
|
dot.style.top = `${y * 100}%`;
|
||||||
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) {
|
||||||
|
this.onDarkModeChange();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDotMouseDown(event) {
|
onDotMouseDown(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (event.button === 2) {
|
if (event.button === 2) {
|
||||||
this.draggedDot.remove();
|
if (this.numberOfDots <= 2 || !event.target.classList.contains('zen-theme-picker-dot')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
event.target.remove();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.dragging = true;
|
this.dragging = true;
|
||||||
|
@ -121,12 +151,13 @@
|
||||||
} else if (y > 1) {
|
} else if (y > 1) {
|
||||||
y = 0.99;
|
y = 0.99;
|
||||||
}
|
}
|
||||||
const pixelX = x * rect.width - dotSize*2;
|
const pixelX = x * rect.width - dotSize;
|
||||||
const pixelY = y * rect.height - dotSize*2;
|
const pixelY = y * rect.height - dotSize;
|
||||||
this.draggedDot.style.left = `${Math.min(maxX, Math.max(0, pixelX))}px`;
|
this.draggedDot.style.left = `${Math.min(maxX, Math.max(0, pixelX))}px`;
|
||||||
this.draggedDot.style.top = `${Math.min(maxY, Math.max(0, pixelY))}px`;
|
this.draggedDot.style.top = `${Math.min(maxY, Math.max(0, pixelY))}px`;
|
||||||
const color = this.getColorFromPosition(pixelX, pixelY);
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +175,75 @@
|
||||||
this.createDot([Math.random() * 255, Math.random() * 255, Math.random() * 255]);
|
this.createDot([Math.random() * 255, Math.random() * 255, Math.random() * 255]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
themedColors(colors) {
|
||||||
|
const isDarkMode = this.isDarkMode;
|
||||||
|
const factor = isDarkMode ? 0.1 : 1.9;
|
||||||
|
return colors.map(color => {
|
||||||
|
// make the color really light or really dark depending on the theme
|
||||||
|
const [r, g, b] = color;
|
||||||
|
return [
|
||||||
|
Math.floor(Math.min(255, Math.max(0, r * factor))),
|
||||||
|
Math.floor(Math.min(255, Math.max(0, g * factor))),
|
||||||
|
Math.floor(Math.min(255, Math.max(0, b * factor))),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getGradient(colors) {
|
||||||
|
const themedColors = this.themedColors(colors);
|
||||||
|
return `linear-gradient(to right, ${themedColors.map(color => `rgb(${color[0]}, ${color[1]}, ${color[2]})`).join(', ')})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTheme(colors) {
|
||||||
|
return {
|
||||||
|
type: 'gradient',
|
||||||
|
gradientColors: colors,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async onWorkspaceChange(workspace, skipUpdate = false) {
|
||||||
|
const uuid = workspace.uuid;
|
||||||
|
const theme = await ZenWorkspacesStorage.getWorkspaceTheme(uuid);
|
||||||
|
const appWrapepr = document.getElementById('zen-main-app-wrapper');
|
||||||
|
appWrapepr.removeAttribute('animating');
|
||||||
|
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') {
|
||||||
|
document.body.style.removeProperty('--zen-main-browser-background');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const gradient = this.getGradient(theme.gradientColors);
|
||||||
|
document.body.style.setProperty('--zen-main-browser-background', gradient);
|
||||||
|
if (!skipUpdate) {
|
||||||
|
this.recalculateDots(theme.gradientColors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
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');
|
||||||
|
return color.match(/\d+/g).map(Number);
|
||||||
|
});
|
||||||
|
const gradient = this.getTheme(colors);
|
||||||
|
const currentWorkspace = await ZenWorkspaces.getActiveWorkspace();
|
||||||
|
await ZenWorkspacesStorage.saveWorkspaceTheme(currentWorkspace.uuid, gradient);
|
||||||
|
this.onWorkspaceChange(currentWorkspace, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.gZenThemePicker = new ZenThemePicker();
|
window.gZenThemePicker = new ZenThemePicker();
|
||||||
|
|
|
@ -862,6 +862,13 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||||
return Services.prefs.getBoolPref('zen.workspaces.individual-pinned-tabs');
|
return Services.prefs.getBoolPref('zen.workspaces.individual-pinned-tabs');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addChangeListeners(func) {
|
||||||
|
if (!this._changeListeners) {
|
||||||
|
this._changeListeners = [];
|
||||||
|
}
|
||||||
|
this._changeListeners.push(func);
|
||||||
|
}
|
||||||
|
|
||||||
async changeWorkspace(window, onInit = false) {
|
async changeWorkspace(window, onInit = false) {
|
||||||
if (!this.workspaceEnabled || this._inChangingWorkspace) {
|
if (!this.workspaceEnabled || this._inChangingWorkspace) {
|
||||||
return;
|
return;
|
||||||
|
@ -911,6 +918,10 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||||
|
|
||||||
await this._propagateWorkspaceData();
|
await this._propagateWorkspaceData();
|
||||||
this._inChangingWorkspace = false;
|
this._inChangingWorkspace = false;
|
||||||
|
|
||||||
|
for (let listener of this._changeListeners ?? []) {
|
||||||
|
listener(window);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _updateWorkspacesChangeContextMenu() {
|
async _updateWorkspacesChangeContextMenu() {
|
||||||
|
|
|
@ -38,6 +38,14 @@ var ZenWorkspacesStorage = {
|
||||||
await db.execute(`
|
await db.execute(`
|
||||||
CREATE INDEX IF NOT EXISTS idx_zen_workspaces_changes_uuid ON zen_workspaces_changes(uuid)
|
CREATE INDEX IF NOT EXISTS idx_zen_workspaces_changes_uuid ON zen_workspaces_changes(uuid)
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
// Create a workspace theme table if it doesn't exist, theme can be null
|
||||||
|
await db.execute(`
|
||||||
|
CREATE TABLE IF NOT EXISTS zen_workspace_themes (
|
||||||
|
uuid TEXT PRIMARY KEY,
|
||||||
|
json TEXT
|
||||||
|
)
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -171,6 +179,10 @@ var ZenWorkspacesStorage = {
|
||||||
timestamp: Math.floor(now / 1000)
|
timestamp: Math.floor(now / 1000)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await db.execute(`
|
||||||
|
DELETE FROM zen_workspace_themes WHERE uuid = :uuid
|
||||||
|
`, { uuid });
|
||||||
|
|
||||||
await this.updateLastChangeTimestamp(db);
|
await this.updateLastChangeTimestamp(db);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -239,6 +251,23 @@ var ZenWorkspacesStorage = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async saveWorkspaceTheme(uuid, theme) {
|
||||||
|
await PlacesUtils.withConnectionWrapper('ZenWorkspacesStorage.saveWorkspaceTheme', async (db) => {
|
||||||
|
await db.execute(`
|
||||||
|
INSERT OR REPLACE INTO zen_workspace_themes (uuid, json)
|
||||||
|
VALUES (:uuid, :json)
|
||||||
|
`, { uuid, json: JSON.stringify(theme) });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async getWorkspaceTheme(uuid) {
|
||||||
|
const db = await PlacesUtils.promiseDBConnection();
|
||||||
|
const result = await db.executeCached(`
|
||||||
|
SELECT json FROM zen_workspace_themes WHERE uuid = :uuid
|
||||||
|
`, { uuid });
|
||||||
|
return result.length ? JSON.parse(result[0].getResultByName('json')) : null;
|
||||||
|
},
|
||||||
|
|
||||||
async getChangedIDs() {
|
async getChangedIDs() {
|
||||||
const db = await PlacesUtils.promiseDBConnection();
|
const db = await PlacesUtils.promiseDBConnection();
|
||||||
const rows = await db.execute(`
|
const rows = await db.execute(`
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue