From 60b47d622e4d8ed3644e82891138d60fb244db98 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Mon, 9 Mar 2020 10:07:03 +0100 Subject: [PATCH] UX: adds support for a color setting type (#9016) --- .../admin/components/color-input.js.es6 | 44 +++++++++++------ .../components/site-settings/color.js.es6 | 49 +++++++++++++++++++ .../admin/mixins/setting-component.js.es6 | 3 +- .../components/site-settings/color.hbs | 9 ++++ .../templates/components/color-input.hbs | 8 ++- .../stylesheets/common/admin/settings.scss | 9 ++++ config/site_settings.yml | 6 ++- lib/site_settings/type_supervisor.rb | 1 + .../site_settings/type_supervisor_spec.rb | 6 +++ 9 files changed, 117 insertions(+), 18 deletions(-) create mode 100644 app/assets/javascripts/admin/components/site-settings/color.js.es6 create mode 100644 app/assets/javascripts/admin/templates/components/site-settings/color.hbs diff --git a/app/assets/javascripts/admin/components/color-input.js.es6 b/app/assets/javascripts/admin/components/color-input.js.es6 index 8648506bf98..44fe738b43d 100644 --- a/app/assets/javascripts/admin/components/color-input.js.es6 +++ b/app/assets/javascripts/admin/components/color-input.js.es6 @@ -1,5 +1,6 @@ import { schedule } from "@ember/runloop"; import Component from "@ember/component"; +import { computed, action } from "@ember/object"; import loadScript, { loadCSS } from "discourse/lib/load-script"; import { observes } from "discourse-common/utils/decorators"; @@ -13,28 +14,45 @@ import { observes } from "discourse-common/utils/decorators"; export default Component.extend({ classNames: ["color-picker"], + onlyHex: true, + + styleSelection: true, + + maxlength: computed("onlyHex", function() { + return this.onlyHex ? 6 : null; + }), + + @action + onHexInput(color) { + this.attrs.onChangeColor && + this.attrs.onChangeColor((color || "").replace(/^#/, "")); + }, + @observes("hexValue", "brightnessValue", "valid") hexValueChanged: function() { - var hex = this.hexValue; + const hex = this.hexValue; let text = this.element.querySelector("input.hex-input"); + this.attrs.onChangeColor && this.attrs.onChangeColor(hex); + if (this.valid) { - text.setAttribute( - "style", - "color: " + - (this.brightnessValue > 125 ? "black" : "white") + - "; background-color: #" + - hex + - ";" - ); + this.styleSelection && + text.setAttribute( + "style", + "color: " + + (this.brightnessValue > 125 ? "black" : "white") + + "; background-color: #" + + hex + + ";" + ); if (this.pickerLoaded) { $(this.element.querySelector(".picker")).spectrum({ - color: "#" + this.hexValue + color: "#" + hex }); } } else { - text.setAttribute("style", ""); + this.styleSelection && text.setAttribute("style", ""); } }, @@ -51,8 +69,6 @@ export default Component.extend({ }); }); }); - schedule("afterRender", () => { - this.hexValueChanged(); - }); + schedule("afterRender", () => this.hexValueChanged()); } }); diff --git a/app/assets/javascripts/admin/components/site-settings/color.js.es6 b/app/assets/javascripts/admin/components/site-settings/color.js.es6 new file mode 100644 index 00000000000..5b7e40e34c4 --- /dev/null +++ b/app/assets/javascripts/admin/components/site-settings/color.js.es6 @@ -0,0 +1,49 @@ +import Component from "@ember/component"; +import { computed, action } from "@ember/object"; + +function RGBToHex(rgb) { + // Choose correct separator + let sep = rgb.indexOf(",") > -1 ? "," : " "; + // Turn "rgb(r,g,b)" into [r,g,b] + rgb = rgb + .substr(4) + .split(")")[0] + .split(sep); + + let r = (+rgb[0]).toString(16), + g = (+rgb[1]).toString(16), + b = (+rgb[2]).toString(16); + + if (r.length === 1) r = "0" + r; + if (g.length === 1) g = "0" + g; + if (b.length === 1) b = "0" + b; + + return "#" + r + g + b; +} + +export default Component.extend({ + valid: computed("value", function() { + let value = this.value.toLowerCase(); + + let testColor = new Option().style; + testColor.color = value; + + if (!testColor.color && !value.startsWith("#")) { + value = `#${value}`; + testColor = new Option().style; + testColor.color = value; + } + + let hexifiedColor = RGBToHex(testColor.color); + if (hexifiedColor.includes("NaN")) { + hexifiedColor = testColor.color; + } + + return testColor.color && hexifiedColor === value; + }), + + @action + onChangeColor(color) { + this.set("value", color); + } +}); diff --git a/app/assets/javascripts/admin/mixins/setting-component.js.es6 b/app/assets/javascripts/admin/mixins/setting-component.js.es6 index 70384c1a277..200ec00c1f8 100644 --- a/app/assets/javascripts/admin/mixins/setting-component.js.es6 +++ b/app/assets/javascripts/admin/mixins/setting-component.js.es6 @@ -22,7 +22,8 @@ const CUSTOM_TYPES = [ "secret_list", "upload", "group_list", - "tag_list" + "tag_list", + "color" ]; const AUTO_REFRESH_ON_SAVE = ["logo", "logo_small", "large_icon"]; diff --git a/app/assets/javascripts/admin/templates/components/site-settings/color.hbs b/app/assets/javascripts/admin/templates/components/site-settings/color.hbs new file mode 100644 index 00000000000..33c66076a24 --- /dev/null +++ b/app/assets/javascripts/admin/templates/components/site-settings/color.hbs @@ -0,0 +1,9 @@ +{{color-input + hexValue=(readonly value) + valid=valid + onlyHex=false + styleSelection=false + onChangeColor=(action "onChangeColor") +}} +{{setting-validation-message message=validationMessage}} +
{{{unbound setting.description}}}
diff --git a/app/assets/javascripts/discourse/templates/components/color-input.hbs b/app/assets/javascripts/discourse/templates/components/color-input.hbs index 3b8d76fbb86..f8d8503a38d 100644 --- a/app/assets/javascripts/discourse/templates/components/color-input.hbs +++ b/app/assets/javascripts/discourse/templates/components/color-input.hbs @@ -1 +1,7 @@ -{{text-field class="hex-input" value=hexValue maxlength="6"}} +{{text-field + class="hex-input" + value=hexValue + maxlength=maxlength + input=(action "onHexInput" value="target.value") +}} + diff --git a/app/assets/stylesheets/common/admin/settings.scss b/app/assets/stylesheets/common/admin/settings.scss index 1c0f902e04b..0eb49fecb92 100644 --- a/app/assets/stylesheets/common/admin/settings.scss +++ b/app/assets/stylesheets/common/admin/settings.scss @@ -96,6 +96,15 @@ font-size: $font-0; font-weight: normal; } + + &.color { + .color-picker { + display: flex; + .picker + .sp-replacer { + border-left: none; + } + } + } } .setting.overridden { h3 { diff --git a/config/site_settings.yml b/config/site_settings.yml index a2320348a11..a1c1f93aba8 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -942,7 +942,9 @@ email: default: false client: true apply_custom_styles_to_digest: true - email_accent_bg_color: "#2F70AC" + email_accent_bg_color: + type: color + default: "#2F70AC" email_accent_fg_color: "#FFFFFF" email_link_color: "#006699" show_topic_featured_link_in_digest: false @@ -1480,7 +1482,7 @@ spam: auto_silence_fast_typers_max_trust_level: 0 auto_silence_first_post_regex: "" high_trust_flaggers_auto_hide_posts: true - cooldown_hours_until_reflag: + cooldown_hours_until_reflag: default: 24 min: 0 diff --git a/lib/site_settings/type_supervisor.rb b/lib/site_settings/type_supervisor.rb index 420c64f60be..26cc20b84e5 100644 --- a/lib/site_settings/type_supervisor.rb +++ b/lib/site_settings/type_supervisor.rb @@ -34,6 +34,7 @@ class SiteSettings::TypeSupervisor group: 19, group_list: 20, tag_list: 21, + color: 22 ) end diff --git a/spec/components/site_settings/type_supervisor_spec.rb b/spec/components/site_settings/type_supervisor_spec.rb index c46cde843ab..caea601178d 100644 --- a/spec/components/site_settings/type_supervisor_spec.rb +++ b/spec/components/site_settings/type_supervisor_spec.rb @@ -82,6 +82,12 @@ describe SiteSettings::TypeSupervisor do it "'group_list' should be at the right position" do expect(SiteSettings::TypeSupervisor.types[:group_list]).to eq(20) end + it "'tag_list' should be at the right position" do + expect(SiteSettings::TypeSupervisor.types[:tag_list]).to eq(21) + end + it "'color' should be at the right position" do + expect(SiteSettings::TypeSupervisor.types[:color]).to eq(22) + end end end