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-btn-group">
<div class="gh-btn-group" {{on "mouseenter" this.onMouseEnter}} {{on "mouseleave" this.onMouseLeave}}>
<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
type="color"
value={{this.colorInputValue}}
{{on "input" this.updateColorInputValue}}
{{on "change" this.updateColorInputValue}}
>
/>
</label>
{{#each this.availablePresetColors as |color|}}
<button type="button" class="gh-btn gh-email-design-color {{color.class}}" {{on "click" (fn this.setCurrentColor color.value) }}></button>
{{#each this.dynamicOrderedPresetColors as |color|}}
<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}}
<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>

View File

@ -1,7 +1,17 @@
import Component from '@glimmer/component';
import {action} from '@ember/object';
import {tracked} from '@glimmer/tracking';
export default class ColorPicker extends Component {
@tracked
orderedPresetColors = [];
@tracked
mouseOver = false;
@tracked
lastSelectedCustomColor = null;
timer;
get presetColors() {
return this.args.presetColors ?? [];
}
@ -19,8 +29,81 @@ export default class ColorPicker extends Component {
this.currentColor = value;
}
get availablePresetColors() {
return this.presetColors.filter(preset => preset.value !== this.currentColor);
@action
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() {
@ -33,11 +116,14 @@ export default class ColorPicker extends Component {
value: this.currentColor,
name: this.currentColor,
class: 'custom-value',
style: 'background-color: ' + this.currentColor + ' !important;'
style: 'background: ' + this.currentColor + ' !important;'
};
}
get colorInputValue() {
if (this.lastSelectedCustomColor) {
return this.lastSelectedCustomColor;
}
if (!this.currentColorObject.value || !this.currentColorObject.value.startsWith('#')) {
return '#000000';
}
@ -65,6 +151,7 @@ export default class ColorPicker extends Component {
}
if (newColor.match(/#[0-9A-Fa-f]{6}$/)) {
this.lastSelectedCustomColor = 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 {
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 {
@ -1775,7 +1780,7 @@ p.gh-members-import-errordetail:first-of-type {
width: 22px;
height: 22px;
margin: 0 0 0 5px;
border: 1px solid transparent;
/*border: 1px solid transparent;*/
transition: all .15s ease-in-out;
transition-delay: .05s;
}
@ -1785,7 +1790,7 @@ p.gh-members-import-errordetail:first-of-type {
width: 22px;
height: 22px;
margin: 0 0 0 5px;
border: 1px solid transparent;
/*border: 1px solid transparent;*/
}
.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 {
background: transparent;
border: 1px solid var(--lightgrey);
/*border: 1px solid var(--lightgrey);*/
}
.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 {
background: var(--white) !important;
border: 1px solid var(--lightgrey-l1);
/*border: 1px solid var(--lightgrey-l1);*/
}
.gh-btn-group .gh-email-design-color.black {