0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-03 23:00:14 -05:00

Improved color picker

refs https://github.com/TryGhost/Team/issues/2830

Only update the order of the colors on mouseleave (+ after the animation). This also includes some minor changes to the CSS files to remove glitches in the animation. I temporarily removed the border of the colors because they keep taking up space when the colors are hidden. Ideally we want to move those borders to :before or :after, that will also be better for the animation.
This commit is contained in:
Simon Backx 2023-03-29 16:59:58 +02:00
parent fbd46e7688
commit 73d823ad6a
3 changed files with 104 additions and 13 deletions

View file

@ -1,17 +1,16 @@
<div class="gh-email-design-color-picker"> <div class="gh-email-design-color-picker">
<div class="gh-btn-group"> <div class="gh-btn-group" {{on "mouseenter" this.onMouseEnter}} {{on "mouseleave" this.onMouseLeave}}>
<p>{{this.currentColorObject.name}}</p> <p>{{this.currentColorObject.name}}</p>
<label type="button" class="gh-btn gh-email-design-color custom" {{on "click" this.onOpenColorPicker}}> <label type="button" style={{html-safe this.customColorStyle}} class="gh-btn gh-email-design-color custom {{if this.customColorSelected "gh-btn-group-selected"}}" {{on "click" this.onOpenColorPicker}}>
<input <input
type="color" type="color"
value={{this.colorInputValue}} value={{this.colorInputValue}}
{{on "input" this.updateColorInputValue}} {{on "input" this.updateColorInputValue}}
{{on "change" this.updateColorInputValue}} {{on "change" this.updateColorInputValue}}
> />
</label> </label>
{{#each this.availablePresetColors as |color|}} {{#each this.dynamicOrderedPresetColors as |color|}}
<button type="button" class="gh-btn gh-email-design-color {{color.class}}" {{on "click" (fn this.setCurrentColor color.value) }}></button> <button type="button" style={{html-safe color.style}} class="gh-btn gh-email-design-color {{color.class}} {{if (eq this.currentColorObject.value color.value) "gh-btn-group-selected"}}" {{on "click" (fn this.setCurrentColor color.value) }}></button>
{{/each}} {{/each}}
<button type="button" class="gh-btn gh-email-design-color {{this.currentColorObject.class}} gh-btn-group-selected" style={{html-safe this.currentColorObject.style}}></button>
</div> </div>
</div> </div>

View file

@ -1,7 +1,17 @@
import Component from '@glimmer/component'; import Component from '@glimmer/component';
import {action} from '@ember/object'; import {action} from '@ember/object';
import {tracked} from '@glimmer/tracking';
export default class ColorPicker extends Component { export default class ColorPicker extends Component {
@tracked
orderedPresetColors = [];
@tracked
mouseOver = false;
@tracked
lastSelectedCustomColor = null;
timer;
get presetColors() { get presetColors() {
return this.args.presetColors ?? []; return this.args.presetColors ?? [];
} }
@ -19,8 +29,81 @@ export default class ColorPicker extends Component {
this.currentColor = value; this.currentColor = value;
} }
get availablePresetColors() { @action
return this.presetColors.filter(preset => preset.value !== this.currentColor); onMouseEnter() {
this.mouseOver = true;
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
}
@action
onMouseLeave() {
this.mouseOver = false;
if (this.timer) {
clearTimeout(this.timer);
}
// Wait 200ms after the animation to update
// we need to do this on mouse leave, because on mouse enter it breaks the animations
this.timer = setTimeout(() => {
if (!this.mouseOver) {
this.updateOrderedPresetColors();
}
this.timer = null;
}, 500);
}
@action
updateOrderedPresetColors() {
const customColorSelected = !this.presetColors.find(c => c.value === this.currentColor);
const orderedPresetColors = this.presetColors.filter(c => c.value !== this.currentColor);
if (!customColorSelected) {
// Never append custom colors here
orderedPresetColors.push(this.currentColorObject);
} else {
// Append custom
//orderedPresetColors.push({
}
this.orderedPresetColors = orderedPresetColors;
}
get dynamicOrderedPresetColors() {
// Createa deep clone so we don't update anything
const arr = [...this.orderedPresetColors.map((c) => {
return {...c};
})];
// Make sure all preset colors are presents
for (const preset of this.presetColors) {
if (!arr.find(c => c.value === preset.value)) {
arr.push({...preset});
}
}
return arr;
}
get customColorSelected() {
if (!this.dynamicOrderedPresetColors.find(c => c.value === this.currentColor)) {
return true;
}
return false;
}
get customColorStyle() {
// Make sure the current color is present
if (!this.dynamicOrderedPresetColors.find(c => c.value === this.currentColor)) {
return 'background: ' + this.currentColor + ' !important;';
} else {
if (this.lastSelectedCustomColor) {
return 'background: ' + this.lastSelectedCustomColor + ' !important;';
}
}
return '';
} }
get currentColorObject() { get currentColorObject() {
@ -33,11 +116,14 @@ export default class ColorPicker extends Component {
value: this.currentColor, value: this.currentColor,
name: this.currentColor, name: this.currentColor,
class: 'custom-value', class: 'custom-value',
style: 'background-color: ' + this.currentColor + ' !important;' style: 'background: ' + this.currentColor + ' !important;'
}; };
} }
get colorInputValue() { get colorInputValue() {
if (this.lastSelectedCustomColor) {
return this.lastSelectedCustomColor;
}
if (!this.currentColorObject.value || !this.currentColorObject.value.startsWith('#')) { if (!this.currentColorObject.value || !this.currentColorObject.value.startsWith('#')) {
return '#000000'; return '#000000';
} }
@ -65,6 +151,7 @@ export default class ColorPicker extends Component {
} }
if (newColor.match(/#[0-9A-Fa-f]{6}$/)) { if (newColor.match(/#[0-9A-Fa-f]{6}$/)) {
this.lastSelectedCustomColor = newColor.toUpperCase();
this.setCurrentColor(newColor.toUpperCase()); this.setCurrentColor(newColor.toUpperCase());
} }
} }

View file

@ -1738,6 +1738,11 @@ p.gh-members-import-errordetail:first-of-type {
.gh-email-design-color-picker .gh-btn-group { .gh-email-design-color-picker .gh-btn-group {
vertical-align: middle; vertical-align: middle;
/* Required to remove glitches in mouseover during animations */
overflow: hidden;
padding: 4px;
margin-right: -4px;
} }
.gh-email-design-color-picker .gh-btn-group p { .gh-email-design-color-picker .gh-btn-group p {
@ -1775,7 +1780,7 @@ p.gh-members-import-errordetail:first-of-type {
width: 22px; width: 22px;
height: 22px; height: 22px;
margin: 0 0 0 5px; margin: 0 0 0 5px;
border: 1px solid transparent; /*border: 1px solid transparent;*/
transition: all .15s ease-in-out; transition: all .15s ease-in-out;
transition-delay: .05s; transition-delay: .05s;
} }
@ -1785,7 +1790,7 @@ p.gh-members-import-errordetail:first-of-type {
width: 22px; width: 22px;
height: 22px; height: 22px;
margin: 0 0 0 5px; margin: 0 0 0 5px;
border: 1px solid transparent; /*border: 1px solid transparent;*/
} }
.gh-email-design-color.gh-btn-group-selected::before { .gh-email-design-color.gh-btn-group-selected::before {
@ -1810,7 +1815,7 @@ p.gh-members-import-errordetail:first-of-type {
.gh-btn-group .gh-email-design-color.transparent { .gh-btn-group .gh-email-design-color.transparent {
background: transparent; background: transparent;
border: 1px solid var(--lightgrey); /*border: 1px solid var(--lightgrey);*/
} }
.gh-email-design-color.transparent::after { .gh-email-design-color.transparent::after {
@ -1828,7 +1833,7 @@ p.gh-members-import-errordetail:first-of-type {
.gh-btn-group .gh-email-design-color.white { .gh-btn-group .gh-email-design-color.white {
background: var(--white) !important; background: var(--white) !important;
border: 1px solid var(--lightgrey-l1); /*border: 1px solid var(--lightgrey-l1);*/
} }
.gh-btn-group .gh-email-design-color.black { .gh-btn-group .gh-email-design-color.black {