mirror of
https://github.com/zen-browser/desktop.git
synced 2026-01-25 22:26:11 +00:00
Merge pull request #5440 from zen-browser/new-color-picker
This commit is contained in:
2
l10n
2
l10n
Submodule l10n updated: 3df11464be...ead5aeaac4
@@ -83,6 +83,7 @@ pref('zen.tabs.rename-tabs', true);
|
||||
pref('zen.theme.accent-color', "#ffb787");
|
||||
pref('zen.theme.content-element-separation', 6); // In pixels
|
||||
pref('zen.theme.gradient', true);
|
||||
pref('zen.theme.gradient.show-custom-colors', false);
|
||||
pref('zen.theme.essentials-favicon-bg', true);
|
||||
|
||||
pref('zen.tabs.show-newtab-vertical', true);
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
|
||||
# Images
|
||||
content/browser/zen-images/gradient.png (content/zen-images/gradient.png)
|
||||
content/browser/zen-images/gradient-display.png (content/zen-images/gradient-display.png)
|
||||
content/browser/zen-images/brand-header.svg (content/zen-images/brand-header.svg)
|
||||
content/browser/zen-images/layouts/collapsed.png (content/zen-images/layouts/collapsed.png)
|
||||
content/browser/zen-images/layouts/multiple-toolbar.png (content/zen-images/layouts/multiple-toolbar.png)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 422 KiB |
@@ -82,28 +82,45 @@
|
||||
</panel>
|
||||
</html:template>
|
||||
|
||||
<panel flip="side" type="arrow" orient="vertical" id="PanelUI-zen-gradient-generator" position="bottomright topright" mainview="true" side="left" onpopuphidden="gZenThemePicker.handlePanelClose();">
|
||||
<panel flip="side" type="arrow" orient="vertical" id="PanelUI-zen-gradient-generator" position="bottomright topright" mainview="true" side="left" onpopuphidden="gZenThemePicker.handlePanelClose();" onpopupshowing="gZenThemePicker.handlePanelOpen();">
|
||||
<panelmultiview id="PanelUI-zen-gradient-generator-multiview" mainViewId="PanelUI-zen-gradient-generator-view">
|
||||
<panelview id="PanelUI-zen-gradient-generator-view" class="PanelUI-subView zen-theme-picker" role="document" mainview-with-header="true" has-custom-header="true">
|
||||
<hbox>
|
||||
<hbox id="PanelUI-zen-gradient-generator-predefined">
|
||||
<box data-algo="analogous" data-num-dots="3" data-position="219,99" style="background: linear-gradient(135deg, rgb(117, 255, 136), rgb(60, 66, 58));"></box>
|
||||
<box data-algo="analogous" data-num-dots="3" data-position="167,201" style="background: linear-gradient(135deg, #a03fe0, #382b5c);"></box>
|
||||
<box data-algo="analogous" data-num-dots="3" data-position="90,170" style="background: linear-gradient(135deg, #c57aa3, #af824f);"></box>
|
||||
<box data-algo="splitComplementary" data-num-dots="3" data-position="83,103" style="background: linear-gradient(135deg, #1e90ff, #968a4a);"></box>
|
||||
<box data-algo="analogous" data-num-dots="3" data-position="219,99" style="background: linear-gradient(135deg, #a07a48, #ab80e4);"></box>
|
||||
<box data-algo="float" data-num-dots="1" data-position="196,176" style="background: #7bcbda;"></box>
|
||||
<box data-algo="float" data-num-dots="1" data-position="116,167" style="background: #be9ac9;"></box>
|
||||
<box data-algo="float" data-num-dots="1" data-position="122,110" style="background: #cdcea1;"></box>
|
||||
<box data-algo="float" data-num-dots="1" data-position="181,83" style="background: #6ac593;"></box>
|
||||
<box data-algo="complementary" data-num-dots="3" data-position="82,112" style="background: linear-gradient(135deg, #1e90ff, #cfb179);"></box>
|
||||
</hbox>
|
||||
</hbox>
|
||||
<hbox class="zen-theme-picker-gradient">
|
||||
<div id="PanelUI-zen-gradient-generator-color-actions">
|
||||
<button id="PanelUI-zen-gradient-generator-color-add" class="subviewbutton">
|
||||
</button>
|
||||
<button id="PanelUI-zen-gradient-generator-color-remove" class="subviewbutton">
|
||||
</button>
|
||||
<html:div class="separator"></html:div>
|
||||
<button id="PanelUI-zen-gradient-generator-color-toggle-algo" class="subviewbutton">
|
||||
</button>
|
||||
</div>
|
||||
<label data-l10n-id="zen-panel-ui-gradient-click-to-add" id="PanelUI-zen-gradient-generator-color-click-to-add"></label>
|
||||
</hbox>
|
||||
<hbox id="PanelUI-zen-gradient-generator-controls">
|
||||
<vbox id="PanelUI-zen-gradient-generator-options">
|
||||
<hbox id="PanelUI-zen-gradient-degrees">
|
||||
<box class="dot"></box>
|
||||
<box class="text"></box>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<vbox id="PanelUI-zen-gradient-colors-wrapper">
|
||||
<hbox id="PanelUI-zen-gradient-colors-wrapper">
|
||||
<vbox>
|
||||
<label data-l10n-id="zen-panel-ui-gradient-generator-opacity-text"></label>
|
||||
<html:input type="range" min="0" max="1" value="0.5" step="0.05" oninput="gZenThemePicker.onOpacityChange(event);" id="PanelUI-zen-gradient-generator-opacity" />
|
||||
</vbox>
|
||||
<vbox>
|
||||
<label data-l10n-id="zen-panel-ui-gradient-generator-texture-text"></label>
|
||||
<html:input type="range" min="0" max="1" value="0.5" step="0.05" oninput="gZenThemePicker.onTextureChange(event);" id="PanelUI-zen-gradient-generator-texture" />
|
||||
</vbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</hbox>
|
||||
<vbox id="PanelUI-zen-gradient-generator-custom-colors">
|
||||
<vbox id="zen-theme-picker-color">
|
||||
|
||||
@@ -17,60 +17,10 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#PanelUI-zen-gradient-degrees {
|
||||
position: relative;
|
||||
border-radius: 999px;
|
||||
min-height: 50px;
|
||||
min-width: 50px;
|
||||
max-height: 50px;
|
||||
max-width: 50px;
|
||||
border: 3px solid var(--zen-primary-color);
|
||||
display: flex;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
z-index: 1;
|
||||
|
||||
& .dot {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
/* +3 because of the border */
|
||||
width: 53px;
|
||||
height: 53px;
|
||||
top: -3px;
|
||||
left: -3px;
|
||||
|
||||
&::after {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background: var(--zen-colors-tertiary);
|
||||
box-shadow: 0 0 0 2px var(--zen-themed-toolbar-bg);
|
||||
cursor: grab;
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
right: 0;
|
||||
border: 2px solid var(--zen-colors-border);
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
&[dragging='true']::after {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
& .text {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
#PanelUI-zen-gradient-generator-controls {
|
||||
padding-right: var(--panel-padding);
|
||||
align-items: center;
|
||||
gap: var(--panel-padding);
|
||||
border-bottom: 1px solid color-mix(in srgb, var(--zen-colors-border) 50%, transparent 50%);
|
||||
padding-bottom: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#zen-theme-picker-color {
|
||||
@@ -97,8 +47,8 @@
|
||||
|
||||
#PanelUI-zen-gradient-generator-color-custom-add {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -112,11 +62,30 @@
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
#PanelUI-zen-gradient-generator-options {
|
||||
#PanelUI-zen-gradient-generator-predefined {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
margin: auto;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
margin: 5px 5px 10px 0;
|
||||
|
||||
& > box {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
outline: 2px solid var(--zen-toolbar-element-bg);
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#PanelUI-zen-gradient-generator-custom-list {
|
||||
@@ -178,80 +147,118 @@
|
||||
&::-moz-range-track {
|
||||
background: var(--zen-colors-border);
|
||||
border-radius: 999px;
|
||||
height: 4px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
&::-moz-range-progress {
|
||||
background: var(--zen-primary-color);
|
||||
border-radius: 999px;
|
||||
height: 4px;
|
||||
height: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.zen-theme-picker-gradient {
|
||||
position: relative;
|
||||
border-radius: calc(var(--zen-border-radius) + 5px);
|
||||
border-radius: calc(var(--zen-border-radius) - 2px);
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--zen-colors-border);
|
||||
border-radius: var(--zen-border-radius);
|
||||
|
||||
min-height: calc(var(--panel-width) - var(--panel-padding) * 2);
|
||||
min-width: calc(var(--panel-width) - var(--panel-padding) * 2);
|
||||
margin-bottom: 20px;
|
||||
|
||||
margin-bottom: 15px;
|
||||
|
||||
background: var(--zen-theme-picker-gradient-image) center center / cover no-repeat;
|
||||
|
||||
&::before {
|
||||
background: light-dark(
|
||||
color-mix(in srgb, var(--zen-themed-toolbar-bg) 60%, transparent 40%),
|
||||
color-mix(in srgb, var(--zen-themed-toolbar-bg) 80%, transparent 20%)
|
||||
);
|
||||
backdrop-filter: blur(5px);
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
margin: var(--panel-padding);
|
||||
box-shadow: 0 0 0 1px 1px var(--zen-colors-border);
|
||||
width: calc(100% - var(--panel-padding) * 2);
|
||||
height: calc(100% - var(--panel-padding) * 2);
|
||||
border-radius: var(--zen-border-radius);
|
||||
}
|
||||
|
||||
&::after {
|
||||
z-index: 0;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: linear-gradient(to right, var(--zen-primary-color) 1px, transparent 1px),
|
||||
linear-gradient(to bottom, var(--zen-primary-color) 1px, transparent 1px);
|
||||
background-size: 24px 24px;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: var(--panel-padding);
|
||||
width: calc(100% - var(--panel-padding) * 2);
|
||||
height: calc(100% - var(--panel-padding) * 2);
|
||||
opacity: 0.1;
|
||||
}
|
||||
background: var(--zen-toolbar-element-bg);
|
||||
background-image: radial-gradient(light-dark(rgba(0, 0, 0, 0.05), rgba(0,0,0,.225)) 1px, transparent 0);
|
||||
background-position: -19px -19px;
|
||||
background-size: 10px 10px;
|
||||
|
||||
& .zen-theme-picker-dot {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
width: 20px;
|
||||
width: 22px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: var(--zen-theme-picker-dot-color);
|
||||
box-shadow: 0 0 0 2px var(--zen-themed-toolbar-bg);
|
||||
@media (-prefers-color-scheme: dark) {
|
||||
box-shadow: 0 0 0 2px rgba(0,0,0,.1);
|
||||
}
|
||||
cursor: pointer;
|
||||
border: 2px solid #fff;
|
||||
border: 2px solid #ffffff;
|
||||
animation: zen-theme-picker-dot-animation 0.5s;
|
||||
transition: transform 0.2s;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
&.primary {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
&[dragging='true'] {
|
||||
transform: scale(1.2) translate(-50%, -50%) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#PanelUI-zen-gradient-generator-color-click-to-add {
|
||||
position: absolute;
|
||||
font-weight: 600;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
|
||||
&[hidden] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#PanelUI-zen-gradient-generator-color-actions {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
left: 50%;
|
||||
z-index: 1;
|
||||
transform: translateX(-50%);
|
||||
& .separator,
|
||||
& button {
|
||||
background: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1));
|
||||
}
|
||||
|
||||
& button {
|
||||
border: none !important;
|
||||
padding: 0.4rem !important;
|
||||
min-width: fit-content !important;
|
||||
transition: background 0.2s;
|
||||
appearance: none;
|
||||
|
||||
& .button-box {
|
||||
gap: 0.1rem;
|
||||
}
|
||||
|
||||
&:not(#PanelUI-zen-gradient-generator-color-toggle-algo) .button-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: light-dark(#cfcfcf, #313131);
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
& .separator {
|
||||
width: 1px;
|
||||
margin: 0 0.5rem;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
@media not (-moz-bool-pref: 'zen.theme.gradient.show-custom-colors') {
|
||||
#PanelUI-zen-gradient-generator-custom-colors {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
#zen-welcome-workspace-colors-anchor {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: 10% auto auto 30%;
|
||||
margin: 20% auto auto 28%;
|
||||
}
|
||||
|
||||
#zen-welcome-initial-essentials-browser {
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
{
|
||||
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;
|
||||
static MAX_DOTS = 3;
|
||||
|
||||
currentOpacity = 0.5;
|
||||
currentRotation = 45;
|
||||
|
||||
numberOfDots = 0;
|
||||
|
||||
dots = [];
|
||||
useAlgo = '';
|
||||
constructor() {
|
||||
super();
|
||||
if (!Services.prefs.getBoolPref('zen.theme.gradient', true) || !ZenWorkspaces.shouldHaveWorkspaces) {
|
||||
@@ -33,7 +31,6 @@
|
||||
this.onDarkModeChange.bind(this)
|
||||
);
|
||||
|
||||
this.initRotation();
|
||||
this.initCanvas();
|
||||
this.initCustomColorInput();
|
||||
|
||||
@@ -79,7 +76,7 @@
|
||||
|
||||
onImageLoad() {
|
||||
// resize the image to fit the panel
|
||||
const imageSize = 300 - 20; // 20 is the padding (10px)
|
||||
const imageSize = 350 - 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;
|
||||
@@ -92,78 +89,52 @@
|
||||
|
||||
// Call the rest of the initialization
|
||||
this.initContextMenu();
|
||||
this.initThemePicker();
|
||||
this.initPredefinedColors();
|
||||
|
||||
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;
|
||||
initPredefinedColors() {
|
||||
document.getElementById('PanelUI-zen-gradient-generator-predefined').addEventListener('click', async (event) => {
|
||||
const target = event.target;
|
||||
const rawPosition = target.getAttribute('data-position');
|
||||
if (!rawPosition) {
|
||||
return;
|
||||
}
|
||||
const degrees = Math.round((Math.atan2(y - centerY, x - centerX) * 180) / Math.PI);
|
||||
this.setRotationInput(degrees);
|
||||
const algo = target.getAttribute('data-algo');
|
||||
const numDots = parseInt(target.getAttribute('data-num-dots'));
|
||||
if (algo == 'float') {
|
||||
for (const dot of this.dots) {
|
||||
dot.element.remove();
|
||||
}
|
||||
this.dots = [];
|
||||
}
|
||||
// Generate new gradient from the single color given
|
||||
const [x, y] = rawPosition.split(',').map((pos) => parseInt(pos));
|
||||
let dots = [
|
||||
{
|
||||
ID: 0,
|
||||
position: { x, y },
|
||||
},
|
||||
];
|
||||
for (let i = 1; i < numDots; i++) {
|
||||
dots.push({
|
||||
ID: i,
|
||||
position: { x: 0, y: 0 },
|
||||
});
|
||||
}
|
||||
this.useAlgo = algo;
|
||||
dots = this.calculateCompliments(dots, 'update', this.useAlgo);
|
||||
if (algo == 'float') {
|
||||
for (const dot of dots) {
|
||||
this.spawnDot(dot.position);
|
||||
}
|
||||
this.dots[0].element.classList.add('primary');
|
||||
}
|
||||
this.handleColorPositions(dots);
|
||||
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}°`;
|
||||
});
|
||||
}
|
||||
|
||||
initCustomColorInput() {
|
||||
@@ -171,7 +142,7 @@
|
||||
}
|
||||
|
||||
onCustomColorKeydown(event) {
|
||||
//checks for enter key for custom colors
|
||||
// Check for Enter key to add custom colors
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
this.addCustomColor();
|
||||
@@ -180,10 +151,26 @@
|
||||
|
||||
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));
|
||||
themePicker.addEventListener('click', this.onThemePickerClick.bind(this));
|
||||
this._onDotMouseMove = this.onDotMouseMove.bind(this);
|
||||
this._onDotMouseUp = this.onDotMouseUp.bind(this);
|
||||
this._onDotMouseDown = this.onDotMouseDown.bind(this);
|
||||
this._onThemePickerClick = this.onThemePickerClick.bind(this);
|
||||
document.addEventListener('mousemove', this._onDotMouseMove);
|
||||
document.addEventListener('mouseup', this._onDotMouseUp);
|
||||
themePicker.addEventListener('mousedown', this._onDotMouseDown);
|
||||
themePicker.addEventListener('click', this._onThemePickerClick);
|
||||
}
|
||||
|
||||
uninitThemePicker() {
|
||||
const themePicker = this.panel.querySelector('.zen-theme-picker-gradient');
|
||||
document.removeEventListener('mousemove', this._onDotMouseMove);
|
||||
document.removeEventListener('mouseup', this._onDotMouseUp);
|
||||
themePicker.removeEventListener('mousedown', this._onDotMouseDown);
|
||||
themePicker.removeEventListener('click', this._onThemePickerClick);
|
||||
this._onDotMouseMove = null;
|
||||
this._onDotMouseUp = null;
|
||||
this._onDotMouseDown = null;
|
||||
this._onThemePickerClick = null;
|
||||
}
|
||||
|
||||
calculateInitialPosition(color) {
|
||||
@@ -224,7 +211,9 @@
|
||||
createDot(color, fromWorkspace = false) {
|
||||
const [r, g, b] = color.c;
|
||||
const dot = document.createElement('div');
|
||||
dot.classList.add('zen-theme-picker-dot');
|
||||
if (color.isPrimary) {
|
||||
dot.classList.add('primary');
|
||||
}
|
||||
if (color.isCustom) {
|
||||
if (!color.c) {
|
||||
return;
|
||||
@@ -233,64 +222,31 @@
|
||||
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);
|
||||
const dotPad = this.panel.querySelector('.zen-theme-picker-gradient');
|
||||
|
||||
dot.classList.add('zen-theme-picker-dot');
|
||||
|
||||
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');
|
||||
|
||||
// Store the starting position of the drag
|
||||
this.dragStartPosition = {
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
if (this.dots.length < 1) {
|
||||
dot.classList.add('primary');
|
||||
}
|
||||
|
||||
// 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();
|
||||
dotPad.appendChild(dot);
|
||||
let id = this.dots.length;
|
||||
|
||||
dot.style.setProperty('--zen-theme-picker-dot-color', `rgb(${r}, ${g}, ${b})`);
|
||||
|
||||
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.
|
||||
});
|
||||
}
|
||||
if (!fromWorkspace) {
|
||||
this.updateCurrentWorkspace(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,14 +287,275 @@
|
||||
await this.updateCurrentWorkspace();
|
||||
}
|
||||
|
||||
spawnDot(relativePosition, primary = false) {
|
||||
const dotPad = this.panel.querySelector('.zen-theme-picker-gradient');
|
||||
|
||||
const dot = document.createElement('div');
|
||||
dot.classList.add('zen-theme-picker-dot');
|
||||
|
||||
dot.style.left = `${relativePosition.x}px`;
|
||||
dot.style.top = `${relativePosition.y}px`;
|
||||
|
||||
dotPad.appendChild(dot);
|
||||
|
||||
let id = this.dots.length;
|
||||
|
||||
if (primary) {
|
||||
id = 0;
|
||||
dot.classList.add('primary');
|
||||
|
||||
const existingPrimaryDot = this.dots.find((d) => d.ID === 0);
|
||||
if (existingPrimaryDot) {
|
||||
existingPrimaryDot.ID = this.dots.length;
|
||||
existingPrimaryDot.element.classList.remove('primary');
|
||||
}
|
||||
dot.classList.add('primary');
|
||||
}
|
||||
|
||||
const colorFromPos = this.getColorFromPosition(relativePosition.x, relativePosition.y);
|
||||
dot.style.setProperty('--zen-theme-picker-dot-color', `rgb(${colorFromPos[0]}, ${colorFromPos[1]}, ${colorFromPos[2]})`);
|
||||
|
||||
this.dots.push({
|
||||
ID: id,
|
||||
element: dot,
|
||||
position: { x: relativePosition.x, y: relativePosition.y },
|
||||
});
|
||||
}
|
||||
|
||||
calculateCompliments(dots, action = 'update', useHarmony = '') {
|
||||
const colorHarmonies = [
|
||||
{ type: 'complementary', angles: [180] },
|
||||
{ type: 'splitComplementary', angles: [150, 210] },
|
||||
{ type: 'analogous', angles: [30, 330] },
|
||||
{ type: 'triadic', angles: [120, 240] },
|
||||
{ type: 'floating', angles: [] },
|
||||
];
|
||||
|
||||
if (dots.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
function getColorHarmonyType(numDots, dots) {
|
||||
if (useHarmony !== '') {
|
||||
const selectedHarmony = colorHarmonies.find((harmony) => harmony.type === useHarmony);
|
||||
|
||||
if (selectedHarmony) {
|
||||
if (action === 'remove') {
|
||||
if (dots.length !== 0) {
|
||||
return colorHarmonies.find((harmony) => harmony.angles.length === selectedHarmony.angles.length - 1);
|
||||
} else {
|
||||
return { type: 'floating', angles: [] };
|
||||
}
|
||||
}
|
||||
if (action === 'add') {
|
||||
return colorHarmonies.find((harmony) => harmony.angles.length === selectedHarmony.angles.length + 1);
|
||||
}
|
||||
if (action === 'update') {
|
||||
return selectedHarmony;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (action === 'remove') {
|
||||
return colorHarmonies.find((harmony) => harmony.angles.length === numDots);
|
||||
}
|
||||
if (action === 'add') {
|
||||
return colorHarmonies.find((harmony) => harmony.angles.length + 1 === numDots);
|
||||
}
|
||||
if (action === 'update') {
|
||||
return colorHarmonies.find((harmony) => harmony.angles.length + 1 === numDots);
|
||||
}
|
||||
}
|
||||
|
||||
function getAngleFromPosition(position, centerPosition) {
|
||||
let deltaX = position.x - centerPosition.x;
|
||||
let deltaY = position.y - centerPosition.y;
|
||||
let angle = Math.atan2(deltaY, deltaX) * (180 / Math.PI);
|
||||
return (angle + 360) % 360;
|
||||
}
|
||||
|
||||
function getDistanceFromCenter(position, centerPosition) {
|
||||
const deltaX = position.x - centerPosition.x;
|
||||
const deltaY = position.y - centerPosition.y;
|
||||
return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
}
|
||||
|
||||
const dotPad = this.panel.querySelector('.zen-theme-picker-gradient');
|
||||
const rect = dotPad.getBoundingClientRect();
|
||||
const padding = 90;
|
||||
|
||||
let updatedDots = [...dots];
|
||||
const centerPosition = { x: rect.width / 2, y: rect.height / 2 };
|
||||
|
||||
const harmonyAngles = getColorHarmonyType(dots.length + (action === 'add' ? 1 : action === 'remove' ? -1 : 0), this.dots);
|
||||
|
||||
this.useAlgo = harmonyAngles.type;
|
||||
|
||||
if (!harmonyAngles || harmonyAngles.angles.length === 0) return dots;
|
||||
|
||||
let primaryDot = dots.find((dot) => dot.ID === 0);
|
||||
if (!primaryDot) return [];
|
||||
|
||||
if (action === 'add' && this.dots.length) {
|
||||
updatedDots.push({ ID: this.dots.length, position: centerPosition });
|
||||
}
|
||||
const baseAngle = getAngleFromPosition(primaryDot.position, centerPosition);
|
||||
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 }];
|
||||
}
|
||||
|
||||
harmonyAngles.angles.forEach((angleOffset, index) => {
|
||||
let newAngle = (baseAngle + angleOffset) % 360;
|
||||
let radian = (newAngle * Math.PI) / 180;
|
||||
|
||||
let newPosition = {
|
||||
x: centerPosition.x + distance * Math.cos(radian),
|
||||
y: centerPosition.y + distance * Math.sin(radian),
|
||||
};
|
||||
|
||||
updatedDots.push({ ID: index + 1, position: newPosition });
|
||||
});
|
||||
|
||||
return updatedDots;
|
||||
}
|
||||
|
||||
handleColorPositions(colorPositions) {
|
||||
colorPositions.sort((a, b) => a.ID - b.ID);
|
||||
if (this.useAlgo === 'floating') {
|
||||
const dotPad = this.panel.querySelector('.zen-theme-picker-gradient');
|
||||
const rect = dotPad.getBoundingClientRect();
|
||||
this.dots.forEach((dot) => {
|
||||
dot.element.style.zIndex = 999;
|
||||
|
||||
let pixelX, pixelY;
|
||||
if (dot.position.x === null) {
|
||||
const leftPercentage = parseFloat(dot.element.style.left) / 100;
|
||||
const topPercentage = parseFloat(dot.element.style.top) / 100;
|
||||
|
||||
pixelX = leftPercentage * rect.width;
|
||||
pixelY = topPercentage * rect.height;
|
||||
} else {
|
||||
pixelX = dot.position.x;
|
||||
pixelY = dot.position.y;
|
||||
}
|
||||
|
||||
const colorFromPos = this.getColorFromPosition(pixelX, pixelY);
|
||||
|
||||
dot.element.style.setProperty(
|
||||
'--zen-theme-picker-dot-color',
|
||||
`rgb(${colorFromPos[0]}, ${colorFromPos[1]}, ${colorFromPos[2]})`
|
||||
);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
const existingPrimaryDot = this.dots.find((d) => d.ID === 0);
|
||||
|
||||
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]})`
|
||||
);
|
||||
}
|
||||
|
||||
colorPositions.forEach((dotPosition) => {
|
||||
const existingDot = this.dots.find((dot) => dot.ID === dotPosition.ID);
|
||||
|
||||
if (existingDot) {
|
||||
existingDot.position = dotPosition.position;
|
||||
existingDot.element.style.left = `${dotPosition.position.x}px`;
|
||||
existingDot.element.style.top = `${dotPosition.position.y}px`;
|
||||
const colorFromPos = this.getColorFromPosition(dotPosition.position.x, dotPosition.position.y);
|
||||
existingDot.element.style.setProperty(
|
||||
'--zen-theme-picker-dot-color',
|
||||
`rgb(${colorFromPos[0]}, ${colorFromPos[1]}, ${colorFromPos[2]})`
|
||||
);
|
||||
|
||||
if (!this.dragging) {
|
||||
gZenUIManager.motion.animate(
|
||||
existingDot.element,
|
||||
{
|
||||
left: `${dotPosition.position.x}px`,
|
||||
top: `${dotPosition.position.y}px`,
|
||||
},
|
||||
{
|
||||
duration: 0.4,
|
||||
type: 'spring',
|
||||
bounce: 0.3,
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.spawnDot(dotPosition.position);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onThemePickerClick(event) {
|
||||
event.preventDefault();
|
||||
const target = event.target;
|
||||
if (target.id === 'PanelUI-zen-gradient-generator-color-add') {
|
||||
if (this.dots.length >= ZenThemePicker.MAX_DOTS) return;
|
||||
let colorPositions = this.calculateCompliments(this.dots, 'add', this.useAlgo);
|
||||
|
||||
if (event.button !== 0 || this.dragging) return;
|
||||
this.handleColorPositions(colorPositions);
|
||||
this.updateCurrentWorkspace();
|
||||
return;
|
||||
} else if (target.id === 'PanelUI-zen-gradient-generator-color-remove') {
|
||||
this.dots.sort((a, b) => a.ID - b.ID);
|
||||
if (this.dots.length === 0) return;
|
||||
|
||||
const lastDot = this.dots.pop();
|
||||
lastDot.element.remove();
|
||||
|
||||
this.dots.forEach((dot, index) => {
|
||||
dot.ID = index;
|
||||
if (index === 0) {
|
||||
dot.element.classList.add('primary');
|
||||
} else {
|
||||
dot.element.classList.remove('primary');
|
||||
}
|
||||
});
|
||||
|
||||
let colorPositions = this.calculateCompliments(this.dots, 'remove', this.useAlgo);
|
||||
this.handleColorPositions(colorPositions);
|
||||
this.updateCurrentWorkspace();
|
||||
return;
|
||||
} else if (target.id === 'PanelUI-zen-gradient-generator-color-toggle-algo') {
|
||||
const colorHarmonies = [
|
||||
{ type: 'complementary', angles: [180] },
|
||||
{ type: 'splitComplementary', angles: [150, 210] },
|
||||
{ type: 'analogous', angles: [30, 330] },
|
||||
{ type: 'triadic', angles: [120, 240] },
|
||||
{ type: 'floating', angles: [] },
|
||||
];
|
||||
|
||||
const applicableHarmonies = colorHarmonies.filter(
|
||||
(harmony) => harmony.angles.length + 1 === this.dots.length || harmony.type === 'floating'
|
||||
);
|
||||
|
||||
let currentIndex = applicableHarmonies.findIndex((harmony) => harmony.type === this.useAlgo);
|
||||
|
||||
let nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % applicableHarmonies.length;
|
||||
this.useAlgo = applicableHarmonies[nextIndex].type;
|
||||
|
||||
let colorPositions = this.calculateCompliments(this.dots, 'update', this.useAlgo);
|
||||
this.handleColorPositions(colorPositions);
|
||||
this.updateCurrentWorkspace();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.button !== 0 || this.dragging || this.recentlyDragged) return;
|
||||
|
||||
const gradient = this.panel.querySelector('.zen-theme-picker-gradient');
|
||||
const rect = gradient.getBoundingClientRect();
|
||||
const padding = 90; // each side
|
||||
const padding = 90;
|
||||
|
||||
const centerX = rect.left + rect.width / 2;
|
||||
const centerY = rect.top + rect.height / 2;
|
||||
@@ -346,44 +563,79 @@
|
||||
let pixelX = event.clientX;
|
||||
let pixelY = event.clientY;
|
||||
|
||||
// Check if the click is within the circle
|
||||
const distance = Math.sqrt((pixelX - centerX) ** 2 + (pixelY - centerY) ** 2);
|
||||
if (distance > radius) {
|
||||
const clickedElement = event.target;
|
||||
let clickedDot = null;
|
||||
const existingPrimaryDot = this.dots.find((d) => d.ID === 0);
|
||||
|
||||
clickedDot = this.dots.find((dot) => dot.element === clickedElement);
|
||||
|
||||
if (clickedDot) {
|
||||
// TODO: this doesnt work and needs to be fixed
|
||||
existingPrimaryDot.ID = clickedDot.ID;
|
||||
clickedDot.ID = 0;
|
||||
clickedDot.element.style.zIndex = 999;
|
||||
|
||||
let colorPositions = this.calculateCompliments(this.dots, 'update', this.useAlgo);
|
||||
this.handleColorPositions(colorPositions);
|
||||
return;
|
||||
}
|
||||
|
||||
const clickedElement = event.target;
|
||||
const isExistingDot = clickedElement.classList.contains('zen-theme-picker-dot');
|
||||
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 (!isExistingDot && this.numberOfDots < ZenThemePicker.MAX_DOTS) {
|
||||
const relativeX = event.clientX - rect.left;
|
||||
const relativeY = event.clientY - rect.top;
|
||||
const relativeX = pixelX - rect.left;
|
||||
const relativeY = pixelY - rect.top;
|
||||
|
||||
const color = this.getColorFromPosition(relativeX, relativeY);
|
||||
|
||||
const dot = document.createElement('div');
|
||||
dot.classList.add('zen-theme-picker-dot');
|
||||
dot.addEventListener('mousedown', this.onDotMouseDown.bind(this));
|
||||
|
||||
dot.style.left = `${relativeX}px`;
|
||||
dot.style.top = `${relativeY}px`;
|
||||
dot.style.setProperty('--zen-theme-picker-dot-color', `rgb(${color[0]}, ${color[1]}, ${color[2]})`);
|
||||
|
||||
gradient.appendChild(dot);
|
||||
if (!clickedDot && this.dots.length < 1) {
|
||||
if (this.dots.length === 0) {
|
||||
this.spawnDot({ x: relativeX, y: relativeY }, true);
|
||||
} else {
|
||||
this.spawnDot({ x: relativeX, y: relativeY });
|
||||
}
|
||||
|
||||
this.updateCurrentWorkspace(true);
|
||||
} else if (!clickedDot && existingPrimaryDot) {
|
||||
existingPrimaryDot.element.style.left = `${relativeX}px`;
|
||||
existingPrimaryDot.element.style.top = `${relativeY}px`;
|
||||
existingPrimaryDot.position = {
|
||||
x: relativeX,
|
||||
y: relativeY,
|
||||
};
|
||||
|
||||
let colorPositions = this.calculateCompliments(this.dots, 'update', this.useAlgo);
|
||||
this.handleColorPositions(colorPositions);
|
||||
this.updateCurrentWorkspace(true);
|
||||
|
||||
gZenUIManager.motion.animate(
|
||||
existingPrimaryDot.element,
|
||||
{
|
||||
left: `${existingPrimaryDot.position.x}px`,
|
||||
top: `${existingPrimaryDot.position.y}px`,
|
||||
},
|
||||
{
|
||||
duration: 0.4,
|
||||
type: 'spring',
|
||||
bounce: 0.3,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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');
|
||||
const draggedDot = this.dots.find((dot) => dot.element === event.target);
|
||||
if (draggedDot) {
|
||||
event.preventDefault();
|
||||
this.dragging = true;
|
||||
this.draggedDot = event.target;
|
||||
this.draggedDot.classList.add('dragging');
|
||||
}
|
||||
|
||||
// Store the starting position of the drag
|
||||
this.dragStartPosition = {
|
||||
@@ -397,9 +649,25 @@
|
||||
if (!event.target.classList.contains('zen-theme-picker-dot')) {
|
||||
return;
|
||||
}
|
||||
this.dots = this.dots.filter((dot) => dot.element !== event.target);
|
||||
event.target.remove();
|
||||
|
||||
this.dots.sort((a, b) => a.ID - b.ID);
|
||||
|
||||
// Reassign the IDs after sorting
|
||||
this.dots.forEach((dot, index) => {
|
||||
dot.ID = index;
|
||||
if (index === 0) {
|
||||
dot.element.classList.add('primary');
|
||||
} else {
|
||||
dot.element.classList.remove('primary');
|
||||
}
|
||||
});
|
||||
|
||||
let colorPositions = this.calculateCompliments(this.dots, 'remove', this.useAlgo);
|
||||
this.handleColorPositions(colorPositions);
|
||||
|
||||
this.updateCurrentWorkspace();
|
||||
this.numberOfDots--;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -407,27 +675,68 @@
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.dragging = false;
|
||||
this.draggedDot.style.zIndex = 1;
|
||||
this.draggedDot.classList.remove('dragging');
|
||||
this.draggedDot = null;
|
||||
this.dragStartPosition = null; // Reset the drag start position
|
||||
|
||||
this.recentlyDragged = true;
|
||||
setTimeout(() => {
|
||||
this.recentlyDragged = false;
|
||||
}, 100);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.numberOfDots = this.panel.querySelectorAll('.zen-theme-picker-dot').length;
|
||||
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;
|
||||
|
||||
const draggedDot = this.dots.find((dot) => dot.element === this.draggedDot);
|
||||
draggedDot.element.style.left = `${relativeX}px`;
|
||||
draggedDot.element.style.top = `${relativeY}px`;
|
||||
draggedDot.position = {
|
||||
x: relativeX,
|
||||
y: relativeY,
|
||||
};
|
||||
let colorPositions = this.calculateCompliments(this.dots, 'update', this.useAlgo);
|
||||
this.handleColorPositions(colorPositions);
|
||||
|
||||
this.updateCurrentWorkspace();
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
});
|
||||
|
||||
return colors.map((color) => ({
|
||||
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,
|
||||
algorithm: color.algorithm,
|
||||
}));
|
||||
}
|
||||
|
||||
onOpacityChange(event) {
|
||||
@@ -456,6 +765,8 @@
|
||||
|
||||
getGradient(colors, forToolbar = false) {
|
||||
const themedColors = this.themedColors(colors);
|
||||
this.useAlgo = themedColors[0]?.algorithm ?? '';
|
||||
|
||||
if (themedColors.length === 0) {
|
||||
return forToolbar ? 'var(--zen-themed-toolbar-bg)' : 'var(--zen-themed-toolbar-bg-transparent)';
|
||||
} else if (themedColors.length === 1) {
|
||||
@@ -546,23 +857,7 @@
|
||||
};
|
||||
|
||||
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 dominantColor = this.getPrimaryColor(allColors);
|
||||
const result = this.pSBC(
|
||||
this.isDarkMode ? 0.2 : -0.5,
|
||||
`rgb(${dominantColor[0]}, ${dominantColor[1]}, ${dominantColor[2]})`
|
||||
@@ -586,7 +881,7 @@
|
||||
}
|
||||
|
||||
// get the theme from the window
|
||||
workspaceTheme = theme || windowWorkspace.theme;
|
||||
workspaceTheme = this.fixTheme(theme || windowWorkspace.theme);
|
||||
|
||||
if (!skipUpdate) {
|
||||
for (const dot of browser.gZenThemePicker.panel.querySelectorAll('.zen-theme-picker-dot')) {
|
||||
@@ -617,6 +912,9 @@
|
||||
});
|
||||
}
|
||||
|
||||
const button = browser.document.getElementById('PanelUI-zen-gradient-generator-color-toggle-algo');
|
||||
document.l10n.setAttributes(button, `zen-panel-ui-gradient-generator-algo-${browser.gZenThemePicker.useAlgo}`);
|
||||
|
||||
browser.gZenThemePicker.resetCustomColorList();
|
||||
if (!workspaceTheme || workspaceTheme.type !== 'gradient') {
|
||||
const gradient = browser.gZenThemePicker.getGradient([]);
|
||||
@@ -632,13 +930,22 @@
|
||||
browser.gZenThemePicker.currentRotation = workspaceTheme.rotation ?? 45;
|
||||
browser.gZenThemePicker.currentTexture = workspaceTheme.texture ?? 0;
|
||||
|
||||
browser.gZenThemePicker.numberOfDots = workspaceTheme.gradientColors.length;
|
||||
for (const button of browser.document.querySelectorAll('#PanelUI-zen-gradient-generator-color-actions button')) {
|
||||
// disable if there are no buttons
|
||||
button.disabled =
|
||||
workspaceTheme.gradientColors.length === 0 ||
|
||||
(button.id === 'PanelUI-zen-gradient-generator-color-add'
|
||||
? workspaceTheme.gradientColors.length >= ZenThemePicker.MAX_DOTS
|
||||
: false);
|
||||
}
|
||||
document
|
||||
.getElementById('PanelUI-zen-gradient-generator-color-click-to-add')
|
||||
.toggleAttribute('hidden', workspaceTheme.gradientColors.length > 0);
|
||||
|
||||
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);
|
||||
const gradientToolbar = browser.gZenThemePicker.getGradient(workspaceTheme.gradientColors, true);
|
||||
@@ -662,11 +969,20 @@
|
||||
}
|
||||
|
||||
if (!skipUpdate) {
|
||||
this.dots = [];
|
||||
browser.gZenThemePicker.recalculateDots(workspaceTheme.gradientColors);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fixTheme(theme) {
|
||||
// add a primary color if there isn't one
|
||||
if (!theme.gradientColors.find((color) => color.isPrimary) && theme.gradientColors.length > 0) {
|
||||
theme.gradientColors[(theme.gradientColors.length / 2) | 0].isPrimary = true;
|
||||
}
|
||||
return theme;
|
||||
}
|
||||
|
||||
get riceManager() {
|
||||
if (!this._riceManager) {
|
||||
this._riceManager = new window.ZenRiceManager();
|
||||
@@ -701,8 +1017,19 @@
|
||||
this.updateCurrentWorkspace();
|
||||
}
|
||||
|
||||
getPrimaryColor(colors) {
|
||||
const primaryColor = colors.find((color) => color.isPrimary);
|
||||
if (primaryColor) {
|
||||
return primaryColor.c;
|
||||
}
|
||||
if (colors.length === 0) {
|
||||
return this.hexToRgb(this.getNativeAccentColor());
|
||||
}
|
||||
// Get the middle color
|
||||
return colors[Math.floor(colors.length / 2)].c;
|
||||
}
|
||||
|
||||
recalculateDots(colors) {
|
||||
//THIS IS PART OF THE ISSUE
|
||||
for (const color of colors) {
|
||||
this.createDot(color, true);
|
||||
}
|
||||
@@ -711,14 +1038,19 @@
|
||||
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 colors = Array.from(dots)
|
||||
.sort((a, b) => a.getAttribute('data-index') - b.getAttribute('data-index'))
|
||||
.map((dot) => {
|
||||
const color = dot.style.getPropertyValue('--zen-theme-picker-dot-color');
|
||||
const isPrimary = dot.classList.contains('primary');
|
||||
|
||||
if (color === 'undefined') {
|
||||
return;
|
||||
}
|
||||
const isCustom = dot.classList.contains('custom');
|
||||
const algorithm = this.useAlgo;
|
||||
return { c: isCustom ? color : color.match(/\d+/g).map(Number), isCustom, algorithm, isPrimary };
|
||||
});
|
||||
const gradient = ZenThemePicker.getTheme(colors, this.currentOpacity, this.currentRotation, this.currentTexture);
|
||||
let currentWorkspace = await ZenWorkspaces.getActiveWorkspace();
|
||||
|
||||
@@ -736,6 +1068,11 @@
|
||||
if (this.updated) {
|
||||
await this.updateCurrentWorkspace(false);
|
||||
}
|
||||
this.uninitThemePicker();
|
||||
}
|
||||
|
||||
handlePanelOpen() {
|
||||
this.initThemePicker();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
document.getElementById('zen-welcome-pages').style.display = 'flex';
|
||||
document.getElementById('zen-welcome-start').remove();
|
||||
window.maximize();
|
||||
animate('#zen-welcome-pages', { opacity: [0, 1] }, { delay: 0.1 });
|
||||
animate('#zen-welcome-pages', { opacity: [0, 1] }, { delay: 0.2, duration: 0.2 });
|
||||
}
|
||||
|
||||
async fadeInTitles(page) {
|
||||
|
||||
@@ -45,7 +45,12 @@
|
||||
list-style-image: url('reload.svg') !important;
|
||||
}
|
||||
|
||||
.tab-reset-button {
|
||||
#PanelUI-zen-gradient-generator-color-toggle-algo {
|
||||
list-style-image: url('palette.svg');
|
||||
}
|
||||
|
||||
.tab-reset-button,
|
||||
#PanelUI-zen-gradient-generator-color-remove {
|
||||
list-style-image: url('unpin.svg') !important;
|
||||
}
|
||||
|
||||
@@ -87,7 +92,8 @@
|
||||
list-style-image: url('translations.svg') !important;
|
||||
}
|
||||
|
||||
#appMenu-zoom-controls {
|
||||
#appMenu-zoom-controls,
|
||||
#PanelUI-zen-gradient-generator-color-add {
|
||||
list-style-image: url('plus.svg') !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1 @@
|
||||
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.726 18.0187C5.52867 17.6186 2.27067 13.9976 2.45167 9.65528C2.62612 5.47095 6.17401 2.01584 10.3614 1.9455C14.8739 1.86961 18.5556 5.50484 18.5556 9.99984C18.5556 11.6874 17.1876 13.0554 15.5 13.0554H12.2078C11.0593 13.0554 10.3269 14.2816 10.8714 15.2928L11.1352 15.7827C11.4238 16.3186 11.3643 16.9752 10.984 17.4505C10.68 17.8305 10.2104 18.0648 9.726 18.0187Z" stroke="#482615" style="stroke:#482615;stroke:color(display-p3 0.2824 0.1490 0.0824);stroke-opacity:1;" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M10.5 6.66656C11.1136 6.66656 11.6111 6.1691 11.6111 5.55545C11.6111 4.9418 11.1136 4.44434 10.5 4.44434C9.88635 4.44434 9.38889 4.9418 9.38889 5.55545C9.38889 6.1691 9.88635 6.66656 10.5 6.66656Z" fill="currentColor" stroke="none" fill-opacity="context-fill-opacity"/>
|
||||
<path d="M7.35733 7.96856C7.97098 7.96856 8.46845 7.4711 8.46845 6.85745C8.46845 6.2438 7.97098 5.74634 7.35733 5.74634C6.74368 5.74634 6.24622 6.2438 6.24622 6.85745C6.24622 7.4711 6.74368 7.96856 7.35733 7.96856Z" fill="currentColor" stroke="none" fill-opacity="context-fill-opacity"/>
|
||||
<path d="M13.6427 7.96856C14.2563 7.96856 14.7538 7.4711 14.7538 6.85745C14.7538 6.2438 14.2563 5.74634 13.6427 5.74634C13.029 5.74634 12.5316 6.2438 12.5316 6.85745C12.5316 7.4711 13.029 7.96856 13.6427 7.96856Z" fill="currentColor" stroke="none" fill-opacity="context-fill-opacity"/>
|
||||
<path d="M6.05555 11.1111C6.6692 11.1111 7.16666 10.6137 7.16666 10C7.16666 9.38638 6.6692 8.88892 6.05555 8.88892C5.4419 8.88892 4.94444 9.38638 4.94444 10C4.94444 10.6137 5.4419 11.1111 6.05555 11.1111Z" fill="currentColor" stroke="none" fill-opacity="context-fill-opacity"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 18 18"><g stroke-linecap="round" stroke-width="1.5" fill="none" stroke="currentColor" stroke-linejoin="round" class="nc-icon-wrapper"><path d="M7.25,4.25v-.5c0-.552-.448-1-1-1H3.75c-.552,0-1,.448-1,1V13" data-color="color-2"></path><path d="M12.932,8.25l.2-.2c.391-.391,.391-1.024,0-1.414l-1.768-1.768c-.391-.391-1.024-.391-1.414,0L3.409,11.409" data-color="color-2"></path><circle cx="5" cy="13" r=".75" fill="currentColor" data-stroke="none" stroke="none"></circle><path d="M9,6.75h0c1.242,0,2.25,1.008,2.25,2.25v9.25c0,.552-.448,1-1,1h-2.5c-.552,0-1-.448-1-1V9c0-1.242,1.008-2.25,2.25-2.25Z" transform="translate(-4 22) rotate(-90)"></path><line x1="8.25" y1="10.75" x2="8.25" y2="15.25"></line><line x1="11.75" y1="10.75" x2="11.75" y2="15.25"></line></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 841 B |
Reference in New Issue
Block a user