FEATURE: User selectable color schemes (#10544)

FEATURE: User selectable color schemes (#10544)

diff --git a/app/assets/javascripts/admin/controllers/admin-customize-colors-show.js b/app/assets/javascripts/admin/controllers/admin-customize-colors-show.js
index 9ca23f1..68d7f65 100644
--- a/app/assets/javascripts/admin/controllers/admin-customize-colors-show.js
+++ b/app/assets/javascripts/admin/controllers/admin-customize-colors-show.js
@@ -72,6 +72,10 @@ export default Controller.extend({
       this.model.save();
     },
 
+    applyUserSelectable() {
+      this.model.updateUserSelectable(this.get("model.user_selectable"));
+    },
+
     destroy: function() {
       const model = this.model;
       return bootbox.confirm(
diff --git a/app/assets/javascripts/admin/models/color-scheme.js b/app/assets/javascripts/admin/models/color-scheme.js
index 5fe6337..28457d9 100644
--- a/app/assets/javascripts/admin/models/color-scheme.js
+++ b/app/assets/javascripts/admin/models/color-scheme.js
@@ -107,6 +107,17 @@ const ColorScheme = EmberObject.extend({
     });
   },
 
+  updateUserSelectable(value) {
+    if (!this.id) return;
+
+    return ajax(`/admin/color_schemes/${this.id}.json`, {
+      data: JSON.stringify({ color_scheme: { user_selectable: value } }),
+      type: "PUT",
+      dataType: "json",
+      contentType: "application/json"
+    });
+  },
+
   destroy() {
     if (this.id) {
       return ajax(`/admin/color_schemes/${this.id}`, { type: "DELETE" });
@@ -129,6 +140,7 @@ ColorScheme.reopenClass({
             theme_id: colorScheme.theme_id,
             theme_name: colorScheme.theme_name,
             base_scheme_id: colorScheme.base_scheme_id,
+            user_selectable: colorScheme.user_selectable,
             colors: colorScheme.colors.map(c => {
               return ColorSchemeColor.create({
                 name: c.name,
diff --git a/app/assets/javascripts/admin/templates/customize-colors-show.hbs b/app/assets/javascripts/admin/templates/customize-colors-show.hbs
index b360a1c..86f5c59 100644
--- a/app/assets/javascripts/admin/templates/customize-colors-show.hbs
+++ b/app/assets/javascripts/admin/templates/customize-colors-show.hbs
@@ -22,9 +22,12 @@
         icon="far-clipboard"
         label="admin.customize.copy_to_clipboard"
       }}
+      <span class="saving {{unless model.savingStatus "hidden"}}">{{model.savingStatus}}</span>
       {{#if model.theme_id}}
-        {{i18n "admin.customize.theme_owner"}}
-        {{#link-to "adminCustomizeThemes.show" model.theme_id}}{{model.theme_name}}{{/link-to}}
+        <span class="not-editable">
+          {{i18n "admin.customize.theme_owner"}}
+          {{#link-to "adminCustomizeThemes.show" model.theme_id}}{{model.theme_name}}{{/link-to}}
+        </span>
       {{else}}
         {{d-button
           action=(action "destroy")
@@ -33,27 +36,29 @@
           label="admin.customize.delete"
         }}
       {{/if}}
-      <span class="saving {{unless model.savingStatus "hidden"}}">{{model.savingStatus}}</span>
     </div>
 
     <br>
 
     <div class="admin-controls">
-      <div class="search controls">
-        <label>
-          {{input type="checkbox" checked=onlyOverridden}}
-          {{i18n "admin.settings.show_overriden"}}
-        </label>
-      </div>
+      {{inline-edit-checkbox action=(action "applyUserSelectable") labelKey="admin.customize.theme.color_scheme_user_selectable" checked=model.user_selectable}}
     </div>
 
     {{#if colors.length}}
       <table class="table colors">
         <thead>
           <tr>
-            <th></th>
+            <th>
+            </th>
             <th class="hex">{{i18n "admin.customize.color"}}</th>
-            <th></th>
+            <th class="overriden">
+              {{#unless model.theme_id}}
+                <label>
+                  {{input type="checkbox" checked=onlyOverridden}}
+                  {{i18n "admin.settings.show_overriden"}}
+                </label>
+              {{/unless}}
+            </th>
           </tr>
         </thead>
         <tbody>
diff --git a/app/assets/javascripts/discourse/app/controllers/preferences/interface.js b/app/assets/javascripts/discourse/app/controllers/preferences/interface.js
index dd80b40..1ec0dd6 100644
--- a/app/assets/javascripts/discourse/app/controllers/preferences/interface.js
+++ b/app/assets/javascripts/discourse/app/controllers/preferences/interface.js
@@ -4,6 +4,11 @@ import Controller from "@ember/controller";
 import { setDefaultHomepage } from "discourse/lib/utilities";
 import discourseComputed from "discourse-common/utils/decorators";
 import { listThemes, setLocalTheme } from "discourse/lib/theme-selector";
+import {
+  listColorSchemes,
+  loadColorSchemeStylesheet,
+  updateColorSchemeCookie
+} from "discourse/lib/color-scheme-picker";
 import { popupAjaxError } from "discourse/lib/ajax-error";
 import { reload } from "discourse/helpers/page-reloader";
 import {
@@ -12,6 +17,7 @@ import {
   iOSWithVisualViewport
 } from "discourse/lib/utilities";
 import { computed } from "@ember/object";
+import { reads } from "@ember/object/computed";
 
 const USER_HOMES = {
   1: "latest",
@@ -26,14 +32,25 @@ const TITLE_COUNT_MODES = ["notifications", "contextual"];
 
 export default Controller.extend({
   currentThemeId: -1,
+  previewingColorScheme: false,
+  selectedColorSchemeId: null,
+  selectedDarkColorSchemeId: null,
   preferencesController: inject("preferences"),
 
-  @discourseComputed("makeThemeDefault")
-  saveAttrNames(makeDefault) {
+  init() {
+    this._super(...arguments);
+
+    this.setProperties({
+      selectedColorSchemeId: this.session.userColorSchemeId,
+      selectedDarkColorSchemeId: this.session.userDarkSchemeId
+    });
+  },
+
+  @discourseComputed("makeThemeDefault", "makeColorSchemeDefault")
+  saveAttrNames(makeThemeDefault, makeColorSchemeDefault) {
     let attrs = [
       "locale",
       "external_links_in_new_tab",
-      "dark_scheme_id",
       "dynamic_favicon",
       "enable_quoting",
       "enable_defer",
@@ -47,10 +64,14 @@ export default Controller.extend({
       "skip_new_user_tips"
     ];
 
-    if (makeDefault) {
+    if (makeThemeDefault) {
       attrs.push("theme_ids");
     }
 
+    if (makeColorSchemeDefault) {
+      attrs.push("color_scheme_id");
+      attrs.push("dark_scheme_id");
+    }
     return attrs;
   },
 
@@ -72,6 +93,11 @@ export default Controller.extend({
   },
 
   @discourseComputed
+  defaultDarkSchemeId() {
+    return this.siteSettings.default_dark_mode_color_scheme_id;
+  },
+
+  @discourseComputed
   textSizes() {
     return TEXT_SIZES.map(value => {
       return { name: I18n.t(`user.text_size.${value}`), value };
@@ -116,6 +142,16 @@ export default Controller.extend({
     }
   },
 
+  @discourseComputed
+  userSelectableColorSchemes() {
+    return listColorSchemes(this.site);
+  },
+
+  showColorSchemeSelector: reads("userSelectableColorSchemes.length"),
+  selectedColorSchemeNoneLabel: I18n.t(
+    "user.color_schemes.default_description"
+  ),
+
   @discourseComputed("model.user_option.theme_ids", "themeId")
   showThemeSetDefault(userOptionThemes, selectedTheme) {
     return !userOptionThemes || userOptionThemes[0] !== selectedTheme;
@@ -153,7 +189,23 @@ export default Controller.extend({
 
   @discourseComputed
   showDarkModeToggle() {
-    return this.siteSettings.default_dark_mode_color_scheme_id > 0;
+    return this.defaultDarkSchemeId > 0 && !this.showDarkColorSchemeSelector;
+  },
+
+  @discourseComputed
+  userSelectableDarkColorSchemes() {
+    return listColorSchemes(this.site, {
+      darkOnly: true
+    });
+  },
+
+  @discourseComputed("userSelectableDarkColorSchemes")
+  showDarkColorSchemeSelector(darkSchemes) {
+    // when a default dark scheme is set
+    // dropdown has two items (disable / use site default)
+    // but we show a checkbox in that case
+    const minToShow = this.defaultDarkSchemeId > 0 ? 2 : 1;
+    return darkSchemes && darkSchemes.length > minToShow;
   },
 
   enableDarkMode: computed({

[... diff too long, it was truncated ...]

GitHub sha: b7cfc9e8

This commit appears in #10544 which was merged by pmusaraj.