diff --git a/frappe/public/images/color-circle.png b/frappe/public/images/color-circle.png new file mode 100644 index 0000000000..1dce698365 Binary files /dev/null and b/frappe/public/images/color-circle.png differ diff --git a/frappe/public/js/frappe/color_picker/color_picker.js b/frappe/public/js/frappe/color_picker/color_picker.js index 6844d6cd37..e1e63758aa 100644 --- a/frappe/public/js/frappe/color_picker/color_picker.js +++ b/frappe/public/js/frappe/color_picker/color_picker.js @@ -10,13 +10,20 @@ class Picker { this.setup_picker(); } + refresh() { + this.set_selector_position(true); + this.update_color_map(); + } + setup_picker() { let color_picker_template = document.createElement('template'); color_picker_template.innerHTML = `
- RECENT
-
- COLOR PICKER
+
+ ${__('SWATCHES')}
+
+
+ ${__('COLOR PICKER')}
@@ -32,10 +39,9 @@ class Picker { this.hue_map = this.color_picker_wrapper.getElementsByClassName('hue-map')[0]; this.swatches_wrapper = this.color_picker_wrapper.getElementsByClassName('swatches')[0]; this.hue_selector_circle = this.hue_map.getElementsByClassName('hue-selector')[0]; - this.set_selector_position(); + this.refresh(); this.setup_events(); this.setup_swatches(); - this.update_color_map(); } setup_events() { @@ -58,15 +64,15 @@ class Picker { }); } - set_selector_position() { + set_selector_position(silent) { this.hue = utils.get_hue(this.color); this.color_selector_position = this.get_pointer_coords(); this.hue_selector_position = { x: this.hue * this.hue_map.offsetWidth / 360, y: this.hue_map.offsetHeight / 2 }; - this.update_color_selector(); - this.update_hue_selector(); + this.update_color_selector(silent); + this.update_hue_selector(silent); } setup_color_event() { @@ -91,14 +97,14 @@ class Picker { ); } - update_color_selector() { + update_color_selector(silent) { let x = this.color_selector_position.x; let y = this.color_selector_position.y; // set color selector position and background this.color_selector_circle.style.top = (y - this.color_selector_circle.offsetHeight / 2) + 'px'; this.color_selector_circle.style.left = (x - this.color_selector_circle.offsetWidth / 2) + 'px'; this.color_map.style.color = this.color; - this.on_change && this.on_change(this.color); + !silent && this.on_change && this.on_change(this.color); } setup_hue_event() { @@ -136,7 +142,7 @@ class Picker { let width = this.color_map.offsetWidth; let height = this.color_map.offsetHeight; let x = utils.clamp(0, s * width / 100, width); - let y = utils.clamp(0, (1 - v * height) / 100, height); + let y = utils.clamp(0, (1 - (v / 100)) * height, height); return {x, y}; } diff --git a/frappe/public/js/frappe/form/controls/color.js b/frappe/public/js/frappe/form/controls/color.js index 61f15c224f..f96137d0a0 100644 --- a/frappe/public/js/frappe/form/controls/color.js +++ b/frappe/public/js/frappe/form/controls/color.js @@ -3,34 +3,31 @@ import Picker from '../../color_picker/color_picker'; frappe.ui.form.ControlColor = frappe.ui.form.ControlData.extend({ make_input: function () { this._super(); - this.colors = [ - "#ffc4c4", "#ff8989", "#ff4d4d", "#a83333", - "#ffe8cd", "#ffd19c", "#ffb868", "#a87945", - "#ffd2c2", "#ffa685", "#ff7846", "#a85b5b", - "#ffd7d7", "#ffb1b1", "#ff8989", "#a84f2e", - "#fffacd", "#fff168", "#fff69c", "#a89f45", - "#ebf8cc", "#d9f399", "#c5ec63", "#7b933d", - "#cef6d1", "#9deca2", "#6be273", "#428b46", - "#d2f8ed", "#a4f3dd", "#77ecca", "#49937e", - "#d2f1ff", "#a6e4ff", "#78d6ff", "#4f8ea8", - "#d2d2ff", "#a3a3ff", "#7575ff", "#4d4da8", - "#dac7ff", "#b592ff", "#8e58ff", "#5e3aa8", - "#f8d4f8", "#f3aaf0", "#ec7dea", "#934f92" - ]; this.make_color_input(); }, make_color_input: function () { let picker_wrapper = $('
'); this.picker = new Picker({ parent: picker_wrapper[0], - color: "#ffc4c4", + color: this.get_color() || '#F4F5F5', swatches: [ - "#ffc4c4", "#d9f399", "#78d6ff", "#fff69c", "#d2f8ed" + '#449CF0', + '#ECAD4B', + '#29CD42', + '#761ACB', + '#CB2929', + '#ED6396', + '#29CD42', + '#4463F0', + '#EC864B', + '#4F9DD9', + '#39E4A5', + '#B4CD29', ] }); this.$wrapper.popover({ - trigger: 'click', + trigger: 'manual', offset: `${-this.$wrapper.width() / 4}, 5`, placement: 'bottom', template: ` @@ -41,56 +38,66 @@ frappe.ui.form.ControlColor = frappe.ui.form.ControlData.extend({ `, content: () => picker_wrapper, html: true + }).on('show.bs.popover', () => { + setTimeout(() => { + this.picker.refresh(); + }, 10); + }).on('hidden.bs.popover', () => { + $('body').off('click.color-popover'); + $(window).off('hashchange.color-popover'); + }); + + this.$input.on('click', (e) => { + this.$wrapper.popover('show'); + if (!this.get_color()) { + this.$input.val(''); + } + e.stopPropagation(); + $('body').on('click.color-popover', (ev) => { + if (!$(ev.target).parents().is('.popover')) { + this.$wrapper.popover('hide'); + } + }); + $(window).on('hashchange.color-popover', () => { + this.$wrapper.popover('hide'); + }); }); this.picker.on_change = (color) => { this.set_value(color); }; + + if (!this.selected_color) { + this.selected_color = $(`
`); + this.selected_color.insertAfter(this.$input); + } + }, + refresh() { + this._super(); + this.picker.refresh(); }, set_formatted_input: function(value) { this._super(value); - if (!value) value = '#F4F5F5'; - const contrast = frappe.ui.color.get_contrast_color(value); - - this.$input.css({ - "background-color": value, "color": contrast + this.$input.val(value || __('Choose a color')); + this.selected_color.css({ + "background-color": value || 'transparent', }); + this.selected_color.toggleClass('no-value', !value); + if (this.picker.color !== value) { + this.picker.color = value; + this.picker.refresh(); + } }, - bind_events: function () { - // var mousedown_happened = false; - // this.$wrapper.on("click", ".color-box", (e) => { - // mousedown_happened = false; - - // var color_val = $(e.target).data("color"); - // this.set_value(color_val); - // // set focus so that we can blur it later - // this.set_focus(); - // }); - - // this.$wrapper.find(".color-box").mousedown(() => { - // mousedown_happened = true; - // }); - - // this.$input.on("focus", () => { - // this.$color_pallete.show(); - // }); - // this.$input.on("blur", () => { - // if (mousedown_happened) { - // // cancel the blur event - // mousedown_happened = false; - // } else { - // // blur event is okay - // $(this.$color_pallete).hide(); - // } - // }); + get_color() { + return this.validate(this.get_value()); }, validate: function (value) { - if(value === '') { + if (value === '') { return ''; } var is_valid = /^#[0-9A-F]{6}$/i.test(value); - if(is_valid) { + if (is_valid) { return value; } return null; diff --git a/frappe/public/scss/color_picker.scss b/frappe/public/scss/color_picker.scss index 5b80a97702..f9fa1c13b2 100644 --- a/frappe/public/scss/color_picker.scss +++ b/frappe/public/scss/color_picker.scss @@ -1,9 +1,11 @@ .color-picker { font-size: var(--text-xs); color: var(--text-muted); + --color-picker-width: 210px; + width: var(--color-picker-width); .swatches { margin-top: 10px; - margin-bottom: 15px; + margin-bottom: 10px; display: flex; flex-wrap: wrap; } @@ -34,8 +36,8 @@ } &::before { - width: calc(100%); - height: calc(100%); + width: 100%; + height: 100%; background-color: currentColor; border: 2px solid white; } @@ -58,7 +60,7 @@ margin-top: 10px; color: transparent; position: relative; - width: 210px; + width: auto; height: 140px; /* background: linear-gradient(0deg, black, transparent), linear-gradient(90deg, white, transparent), red; */ border-radius: 6px; @@ -67,7 +69,7 @@ .hue-map { color: transparent; - width: 210px; + width: auto; height: 14px; position: relative; background: linear-gradient( @@ -86,48 +88,25 @@ } .picker-arrow { - left: 0 !important; + left: 15px !important; } -// .color-picker-wrapper { -// position: relative; -// z-index: 999; -// } - -// .color-picker { -// border-radius: 4px; -// box-shadow: 0 4px 12px rgba(0,0,0,.15); -// background: #fff; -// border: 1px solid var(--border-color); -// width: 290px; -// height: 106px; -// padding-top: 10px; -// padding-left: 5px; -// position: absolute; -// top: 0; -// left: 0; - -// &:after, -// &:before { -// border: solid transparent; -// content: " "; -// height: 0; -// width: 0; -// pointer-events: none; -// position: absolute; -// bottom: 100%; -// left: 30px; -// } -// &:after { -// border-color: rgba(255, 255, 255, 0); -// border-bottom-color: #fff; -// border-width: 8px; -// margin-left: -8px; -// } -// &:before { -// border-color: rgba(221, 221, 221, 0); -// border-bottom-color: var(--border-color); -// border-width: 9px; -// margin-left: -9px; -// } -// } \ No newline at end of file +.frappe-control[data-fieldtype='Color'] { + input { + padding-left: 40px; + } + .selected-color { + width: 22px; + height: 22px; + border-radius: 5px; + background-color: red; + position: absolute; + top: calc(50% + 1px); + left: 5px; + content: ' '; + &.no-value { + background: url('/assets/frappe/images/color-circle.png'); + background-size: contain; + } + } +} \ No newline at end of file