diff --git a/app/assets/javascripts/select-kit/addon/components/color-palettes/color-palettes-row.js b/app/assets/javascripts/select-kit/addon/components/color-palettes/color-palettes-row.js
index 4819db65d06..df52f73cb17 100644
--- a/app/assets/javascripts/select-kit/addon/components/color-palettes/color-palettes-row.js
+++ b/app/assets/javascripts/select-kit/addon/components/color-palettes/color-palettes-row.js
@@ -1,6 +1,5 @@
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
import { computed } from "@ember/object";
-import { escapeExpression } from "discourse/lib/utilities";
import layout from "select-kit/templates/components/color-palettes/color-palettes-row";
export default SelectKitRowComponent.extend({
@@ -10,7 +9,7 @@ export default SelectKitRowComponent.extend({
palettes: computed("item.colors.[]", function () {
return (this.item.colors || [])
.filter((color) => color.name !== "secondary")
- .map((color) => `#${escapeExpression(color.hex)}`)
+ .map((color) => `#${escape(color.hex)}`)
.map(
(hex) => ``
)
@@ -22,7 +21,7 @@ export default SelectKitRowComponent.extend({
const secondary = (this.item.colors || []).findBy("name", "secondary");
if (secondary && secondary.hex) {
- return `background-color:#${escapeExpression(secondary.hex)}`.htmlSafe();
+ return `background-color:#${escape(secondary.hex)}`.htmlSafe();
} else {
return "";
}
diff --git a/app/assets/javascripts/wizard/components/homepage-preview.js b/app/assets/javascripts/wizard/components/homepage-preview.js
index 0e61f60f3aa..b0800076ab9 100644
--- a/app/assets/javascripts/wizard/components/homepage-preview.js
+++ b/app/assets/javascripts/wizard/components/homepage-preview.js
@@ -3,14 +3,14 @@ import {
createPreviewComponent,
darkLightDiff,
} from "wizard/lib/preview";
-import { observes } from "discourse-common/utils/decorators";
export default createPreviewComponent(659, 320, {
logo: null,
avatar: null,
- @observes("step.fieldsById.homepage_style.value")
- styleChanged() {
+ didUpdateAttrs() {
+ this._super(...arguments);
+
this.triggerRepaint();
},
@@ -22,7 +22,9 @@ export default createPreviewComponent(659, 320, {
},
paint({ ctx, colors, font, width, height }) {
- this.drawFullHeader(colors, font, this.logo);
+ if (this.logo) {
+ this.drawFullHeader(colors, font, this.logo);
+ }
if (this.get("step.fieldsById.homepage_style.value") === "latest") {
this.drawPills(colors, font, height * 0.15);
diff --git a/app/assets/javascripts/wizard/components/font-preview.js b/app/assets/javascripts/wizard/components/styling-preview.js
similarity index 65%
rename from app/assets/javascripts/wizard/components/font-preview.js
rename to app/assets/javascripts/wizard/components/styling-preview.js
index ef2f73f216b..a45d1ef168e 100644
--- a/app/assets/javascripts/wizard/components/font-preview.js
+++ b/app/assets/javascripts/wizard/components/styling-preview.js
@@ -15,13 +15,66 @@ metus. Fusce in consequat augue, vel facilisis felis.`;
export default createPreviewComponent(659, 320, {
logo: null,
avatar: null,
+ previewTopic: true,
+ draggingActive: false,
+ startX: 0,
+ scrollLeft: 0,
+
+ mouseDown(e) {
+ const slider = this.element.querySelector(".previews");
+ this.setProperties({
+ draggingActive: true,
+ startX: e.pageX - slider.offsetLeft,
+ scrollLeft: slider.scrollLeft,
+ });
+ },
+
+ mouseLeave() {
+ this.set("draggingActive", false);
+ },
+
+ mouseUp() {
+ this.set("draggingActive", false);
+ },
+
+ mouseMove(e) {
+ if (!this.draggingActive) {
+ return;
+ }
+ e.preventDefault();
+
+ const slider = this.element.querySelector(".previews"),
+ x = e.pageX - slider.offsetLeft,
+ walk = (x - this.startX) * 1.5;
+
+ slider.scrollLeft = this.scrollLeft - walk;
+
+ if (slider.scrollLeft < 50) {
+ this.set("previewTopic", true);
+ }
+ if (slider.scrollLeft > slider.offsetWidth) {
+ this.set("previewTopic", false);
+ }
+ },
+
+ didUpdateAttrs() {
+ this._super(...arguments);
- @observes(
- "step.fieldsById.body_font.value",
- "step.fieldsById.heading_font.value"
- )
- fontChanged() {
this.triggerRepaint();
+
+ if (this.stylingDropdown?.id === "homepage_style") {
+ this.set("previewTopic", false);
+ }
+ },
+
+ @observes("previewTopic")
+ scrollPreviewArea() {
+ const el = this.element.querySelector(".previews");
+ el.scrollTo({
+ top: 0,
+ left: this.previewTopic ? 0 : el.scrollWidth - el.offsetWidth,
+ behavior: "smooth",
+ });
},
images() {
@@ -39,14 +92,14 @@ export default createPreviewComponent(659, 320, {
}
const margin = 20;
- const avatarSize = height * 0.2;
- const lineHeight = height / 11;
+ const avatarSize = height * 0.15;
+ const lineHeight = height / 14;
// Draw a fake topic
this.scaleImage(
this.avatar,
margin,
- headerHeight + height * 0.11,
+ headerHeight + height * 0.09,
avatarSize,
avatarSize
);
@@ -80,7 +133,7 @@ export default createPreviewComponent(659, 320, {
ctx.fillText(
I18n.t("wizard.previews.share_button"),
margin + 10,
- line + lineHeight * 1.7
+ line + lineHeight * 1.9
);
// Reply Button
@@ -100,7 +153,7 @@ export default createPreviewComponent(659, 320, {
ctx.fillText(
I18n.t("wizard.previews.reply_button"),
shareButtonWidth + margin + 20,
- line + lineHeight * 1.7
+ line + lineHeight * 1.9
);
// Draw Timeline
@@ -124,4 +177,14 @@ export default createPreviewComponent(659, 320, {
ctx.fillStyle = colors.primary;
ctx.fillText("1 / 20", timelineX + margin, height * 0.3 + margin * 1.5);
},
+
+ actions: {
+ setPreviewHomepage() {
+ this.set("previewTopic", false);
+ },
+
+ setPreviewTopic() {
+ this.set("previewTopic", true);
+ },
+ },
});
diff --git a/app/assets/javascripts/wizard/components/theme-previews.js b/app/assets/javascripts/wizard/components/theme-previews.js
deleted file mode 100644
index 65c8d2f4c7a..00000000000
--- a/app/assets/javascripts/wizard/components/theme-previews.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import Component from "@ember/component";
-export default Component.extend({
- actions: {
- changed(value) {
- this.set("field.value", value);
- },
- },
-});
diff --git a/app/assets/javascripts/wizard/components/wizard-field-dropdown.js b/app/assets/javascripts/wizard/components/wizard-field-dropdown.js
index 3e49cb3561f..f0c510ba34a 100644
--- a/app/assets/javascripts/wizard/components/wizard-field-dropdown.js
+++ b/app/assets/javascripts/wizard/components/wizard-field-dropdown.js
@@ -1,7 +1,36 @@
import Component from "@ember/component";
+import discourseComputed from "discourse-common/utils/decorators";
+import { set } from "@ember/object";
export default Component.extend({
+ init(...args) {
+ this._super(...args);
+
+ if (this.field.id === "color_scheme") {
+ for (let choice of this.field.choices) {
+ if (choice?.data?.colors) {
+ set(choice, "colors", choice.data.colors);
+ }
+ }
+ }
+ },
+
+ @discourseComputed("field.id")
+ componentName(id) {
+ if (id === "color_scheme") {
+ return "color-palettes";
+ }
+ return "combo-box";
+ },
+
keyPress(e) {
e.stopPropagation();
},
+
+ actions: {
+ onChangeValue(value) {
+ this.set("field.value", value);
+ this.stylingDropdownChanged(this.field.id, value);
+ },
+ },
});
diff --git a/app/assets/javascripts/wizard/components/wizard-field.js b/app/assets/javascripts/wizard/components/wizard-field.js
index 3a39cb46d5d..443b589f6e7 100644
--- a/app/assets/javascripts/wizard/components/wizard-field.js
+++ b/app/assets/javascripts/wizard/components/wizard-field.js
@@ -3,10 +3,11 @@ import { dasherize } from "@ember/string";
import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({
- classNameBindings: [":wizard-field", "typeClass", "field.invalid"],
+ classNameBindings: [":wizard-field", "typeClasses", "field.invalid"],
- @discourseComputed("field.type")
- typeClass: (type) => `${dasherize(type)}-field`,
+ @discourseComputed("field.type", "field.id")
+ typeClasses: (type, id) =>
+ `${dasherize(type)}-field ${dasherize(type)}-${dasherize(id)}`,
@discourseComputed("field.id")
fieldClass: (id) => `field-${dasherize(id)} wizard-focusable`,
diff --git a/app/assets/javascripts/wizard/components/wizard-step.js b/app/assets/javascripts/wizard/components/wizard-step.js
index 80b41ec1307..1d66e86cca9 100644
--- a/app/assets/javascripts/wizard/components/wizard-step.js
+++ b/app/assets/javascripts/wizard/components/wizard-step.js
@@ -27,6 +27,11 @@ export default Component.extend({
classNames: ["wizard-step"],
saving: null,
+ init() {
+ this._super(...arguments);
+ this.set("stylingDropdown", {});
+ },
+
didInsertElement() {
this._super(...arguments);
this.autoFocus();
@@ -96,6 +101,11 @@ export default Component.extend({
return htmlSafe(`width: ${ratio * 200}px`);
},
+ @discourseComputed("step.fields")
+ includeSidebar(fields) {
+ return !!fields.findBy("show_in_sidebar");
+ },
+
autoFocus() {
schedule("afterRender", () => {
const $invalid = $(
@@ -130,6 +140,10 @@ export default Component.extend({
document.location = getUrl("/");
},
+ stylingDropdownChanged(id, value) {
+ this.set("stylingDropdown", { id, value });
+ },
+
exitEarly() {
const step = this.step;
step.validate();
diff --git a/app/assets/javascripts/wizard/controllers/application.js b/app/assets/javascripts/wizard/controllers/application.js
index a9f67bbe49e..d0c86664b39 100644
--- a/app/assets/javascripts/wizard/controllers/application.js
+++ b/app/assets/javascripts/wizard/controllers/application.js
@@ -12,7 +12,7 @@ export default Controller.extend({
@discourseComputed("model")
fontClasses(model) {
- const fontsStep = model.steps.findBy("id", "fonts");
+ const fontsStep = model.steps.findBy("id", "styling");
if (!fontsStep) {
return [];
}
diff --git a/app/assets/javascripts/wizard/lib/preview.js b/app/assets/javascripts/wizard/lib/preview.js
index db9553d0354..3ed162ccad3 100644
--- a/app/assets/javascripts/wizard/lib/preview.js
+++ b/app/assets/javascripts/wizard/lib/preview.js
@@ -2,6 +2,7 @@ import Component from "@ember/component";
import { Promise } from "rsvp";
/*eslint no-bitwise:0 */
import getUrl from "discourse-common/lib/get-url";
+import { htmlSafe } from "@ember/template";
import { scheduleOnce } from "@ember/runloop";
export const LOREM = `
@@ -41,7 +42,7 @@ export function createPreviewComponent(width, height, obj) {
height,
elementWidth: width * scale,
elementHeight: height * scale,
- canvasStyle: `width:${width}px;height:${height}px`,
+ canvasStyle: htmlSafe(`width:${width}px;height:${height}px`),
ctx: null,
loaded: false,
@@ -87,11 +88,17 @@ export function createPreviewComponent(width, height, obj) {
return false;
}
- const colors = this.wizard.getCurrentColors(this.colorsId);
- if (!colors) {
+ const colorsArray = this.wizard.getCurrentColors(this.colorsId);
+ if (!colorsArray) {
return;
}
+ let colors = {};
+ colorsArray.forEach(function (c) {
+ const name = c.name;
+ colors[name] = `#${c.hex}`;
+ });
+
const font = this.wizard.getCurrentFont(this.fontId);
const headingFont = this.wizard.getCurrentFont(
this.fontId,
@@ -115,12 +122,6 @@ export function createPreviewComponent(width, height, obj) {
height: this.height,
};
this.paint(options);
-
- // draw border
- ctx.beginPath();
- ctx.strokeStyle = "rgba(0, 0, 0, 0.2)";
- ctx.rect(0, 0, width, height);
- ctx.stroke();
},
categories() {
diff --git a/app/assets/javascripts/wizard/models/wizard.js b/app/assets/javascripts/wizard/models/wizard.js
index b0bb132c399..f6b83ede7bd 100644
--- a/app/assets/javascripts/wizard/models/wizard.js
+++ b/app/assets/javascripts/wizard/models/wizard.js
@@ -26,12 +26,12 @@ const Wizard = EmberObject.extend({
// A bit clunky, but get the current colors from the appropriate step
getCurrentColors(schemeId) {
- const colorStep = this.steps.findBy("id", "colors");
+ const colorStep = this.steps.findBy("id", "styling");
if (!colorStep) {
return this.current_color_scheme;
}
- const themeChoice = colorStep.get("fieldsById.theme_previews");
+ const themeChoice = colorStep.get("fieldsById.color_scheme");
if (!themeChoice) {
return;
}
@@ -55,7 +55,7 @@ const Wizard = EmberObject.extend({
},
getCurrentFont(fontId, type = "body_font") {
- const fontsStep = this.steps.findBy("id", "fonts");
+ const fontsStep = this.steps.findBy("id", "styling");
if (!fontsStep) {
return;
}
diff --git a/app/assets/javascripts/wizard/templates/components/font-preview.hbs b/app/assets/javascripts/wizard/templates/components/font-preview.hbs
deleted file mode 100644
index 2201f2a1a90..00000000000
--- a/app/assets/javascripts/wizard/templates/components/font-preview.hbs
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
diff --git a/app/assets/javascripts/wizard/templates/components/styling-preview.hbs b/app/assets/javascripts/wizard/templates/components/styling-preview.hbs
new file mode 100644
index 00000000000..9dde43e5d1b
--- /dev/null
+++ b/app/assets/javascripts/wizard/templates/components/styling-preview.hbs
@@ -0,0 +1,22 @@
+
+
+
+
+
+ {{homepage-preview
+ wizard=wizard
+ step=step
+ stylingDropdown=stylingDropdown
+ }}
+
+
+
+
diff --git a/app/assets/javascripts/wizard/templates/components/theme-previews.hbs b/app/assets/javascripts/wizard/templates/components/theme-previews.hbs
deleted file mode 100644
index f267e499525..00000000000
--- a/app/assets/javascripts/wizard/templates/components/theme-previews.hbs
+++ /dev/null
@@ -1,14 +0,0 @@
-
- {{#each field.choices as |choice|}}
- -
- {{theme-preview colorsId=choice.id
- wizard=wizard
- selectedId=field.value
- onChange=(action "changed")}}
- {{radio-button radioValue=choice.id
- label=choice.id
- value=field.value
- onChange=(action "changed")}}
-
- {{/each}}
-
diff --git a/app/assets/javascripts/wizard/templates/components/wizard-field-dropdown.hbs b/app/assets/javascripts/wizard/templates/components/wizard-field-dropdown.hbs
index e311b0183e9..2f7077aef21 100644
--- a/app/assets/javascripts/wizard/templates/components/wizard-field-dropdown.hbs
+++ b/app/assets/javascripts/wizard/templates/components/wizard-field-dropdown.hbs
@@ -1,9 +1,12 @@
-{{combo-box
- id=field.id
+{{component
+ componentName
class=fieldClass
value=field.value
content=field.choices
nameProperty="label"
tabindex="9"
- onChange=(action (mut field.value))
+ onChange=(action "onChangeValue")
+ options=(hash
+ translatedNone=false
+ )
}}
diff --git a/app/assets/javascripts/wizard/templates/components/wizard-field.hbs b/app/assets/javascripts/wizard/templates/components/wizard-field.hbs
index e347fb80b3f..d1d9fce684c 100644
--- a/app/assets/javascripts/wizard/templates/components/wizard-field.hbs
+++ b/app/assets/javascripts/wizard/templates/components/wizard-field.hbs
@@ -13,7 +13,14 @@
- {{component inputComponentName field=field step=step fieldClass=fieldClass wizard=wizard}}
+ {{component
+ inputComponentName
+ field=field step=step
+ fieldClass=fieldClass
+ wizard=wizard
+ stylingDropdownChanged=stylingDropdownChanged
+ stylingDropdown=stylingDropdown
+ }}
{{#if field.errorDescription}}
diff --git a/app/assets/javascripts/wizard/templates/components/wizard-step.hbs b/app/assets/javascripts/wizard/templates/components/wizard-step.hbs
index 01650e3ca0b..e7ae567047d 100644
--- a/app/assets/javascripts/wizard/templates/components/wizard-step.hbs
+++ b/app/assets/javascripts/wizard/templates/components/wizard-step.hbs
@@ -14,9 +14,32 @@
{{#wizard-step-form step=step}}
- {{#each step.fields as |field|}}
- {{wizard-field field=field step=step wizard=wizard}}
- {{/each}}
+ {{#if includeSidebar}}
+
+ {{/if}}
+
+ {{#each step.fields as |field|}}
+ {{#unless field.show_in_sidebar}}
+ {{wizard-field
+ field=field
+ step=step
+ wizard=wizard
+ stylingDropdown=stylingDropdown
+ }}
+ {{/unless}}
+ {{/each}}
+
{{/wizard-step-form}}
diff --git a/app/assets/stylesheets/wizard.scss b/app/assets/stylesheets/wizard.scss
index 648a4d736f2..9b2407987ce 100644
--- a/app/assets/stylesheets/wizard.scss
+++ b/app/assets/stylesheets/wizard.scss
@@ -820,66 +820,78 @@ body.wizard {
.wizard-step-form {
max-height: 500px;
-}
+ display: flex;
-.wizard-step-homepage {
- .field-homepage-style {
- width: 280px;
+ .wizard-fields-main {
+ width: 100%;
}
-}
-.wizard-step-colors {
- max-height: 465px;
- overflow-y: auto;
- .grid {
+ .wizard-fields-sidebar {
+ width: 170px;
box-sizing: border-box;
- display: flex;
- flex-wrap: wrap;
- justify-content: space-around;
- padding: 0;
- margin: 0 auto;
- list-style-type: none;
- text-align: center;
-
- li {
- display: inline-block;
- vertical-align: top;
- margin: 0 5px 25px 5px;
- label:checked + div {
- display: none;
- }
- .is-selected {
- box-shadow: 0 0 0 5px var(--tertiary);
- }
- div {
- display: flex;
- flex: 1 1 auto;
- }
- .radio-area {
- display: none;
- & > * {
- position: relative;
- right: 7px;
- }
- }
- canvas {
- transition: box-shadow 0.25s;
- &:hover {
- box-shadow: shadow("card");
- cursor: pointer;
- }
- }
+ padding: 30px 0px 15px 15px;
+ background: var(--primary-very-low);
+ + .wizard-fields-main {
+ padding: 15px;
+ padding-top: 30px;
+ background: var(--primary-very-low);
+ width: calc(100% - 170px);
}
}
}
-.wizard-step-fonts {
- .dropdown-field {
- float: left;
- margin-right: 1.5em;
+.wizard-step-styling {
+ .preview-nav {
+ display: flex;
+ justify-content: flex-end;
+ position: relative;
+ margin-top: -1px;
+ padding-right: 10px;
+ .preview-nav-button {
+ text-align: center;
+ padding: 10px 15px;
+ cursor: pointer;
+ margin-left: 10px;
+ font-size: 14px;
+ font-weight: bold;
+ color: var(--primary-high);
+ &.active {
+ background: var(--secondary);
+ border-bottom-left-radius: 10px;
+ border-bottom-right-radius: 10px;
+ color: var(--tertiary);
+ border: 1px dashed var(--tertiary-low);
+ border-top: none;
+ }
+ }
}
- .component-field {
- clear: both;
+
+ .previews {
+ position: relative;
+ height: 320px;
+ width: 100%;
+ overflow: hidden;
+ background: var(--secondary);
+ border: 1px dashed var(--tertiary-low);
+ border-radius: 10px;
+ cursor: grab;
+ user-select: none;
+ &.dragging {
+ cursor: grabbing;
+ }
+ .topic-preview {
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ transform: scale(0.85) translateX(-45px);
+ }
+ .homepage-preview {
+ position: absolute;
+ left: calc(100% + 25px);
+ top: 0px;
+ transform: scale(0.85);
+ padding-right: 20px;
+ }
}
}
@@ -891,7 +903,7 @@ body.wizard {
box-sizing: border-box;
margin: 1.5em auto;
padding: 0;
- max-width: 700px;
+ max-width: 820px;
min-width: 280px;
width: 100%;
border: 1px solid var(--primary-low-mid);
@@ -924,7 +936,7 @@ body.wizard {
}
.wizard-step-banner {
margin-bottom: 2em;
- width: 620px;
+ width: 100%;
display: block;
}
@@ -1178,6 +1190,10 @@ body.wizard {
margin-bottom: 2em;
}
+
+ .wizard-image-row canvas {
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ }
}
.textarea-field {
diff --git a/app/models/color_scheme.rb b/app/models/color_scheme.rb
index 22682be18dd..bcd7d7c02fe 100644
--- a/app/models/color_scheme.rb
+++ b/app/models/color_scheme.rb
@@ -133,10 +133,10 @@ class ColorScheme < ActiveRecord::Base
LIGHT_THEME_ID = 'Light'
def self.base_color_scheme_colors
- base_with_hash = {}
+ base_with_hash = []
base_colors.each do |name, color|
- base_with_hash[name] = "#{color}"
+ base_with_hash << { name: name, hex: "#{color}" }
end
list = [
@@ -144,7 +144,11 @@ class ColorScheme < ActiveRecord::Base
]
CUSTOM_SCHEMES.each do |k, v|
- list.push(id: k.to_s, colors: v)
+ colors = []
+ v.each do |name, color|
+ colors << { name: name, hex: "#{color}" }
+ end
+ list.push(id: k.to_s, colors: colors)
end
list
@@ -205,7 +209,7 @@ class ColorScheme < ActiveRecord::Base
def self.base_color_schemes
base_color_scheme_colors.map do |hash|
scheme = new(name: I18n.t("color_schemes.#{hash[:id].downcase.gsub(' ', '_')}"), base_scheme_id: hash[:id])
- scheme.colors = hash[:colors].map { |k, v| { name: k.to_s, hex: v.sub("#", "") } }
+ scheme.colors = hash[:colors].map { |k| { name: k[:name], hex: k[:hex] } }
scheme.is_base = true
scheme
end
diff --git a/app/serializers/wizard_field_serializer.rb b/app/serializers/wizard_field_serializer.rb
index 6d9617fd65f..0b9124fb7a1 100644
--- a/app/serializers/wizard_field_serializer.rb
+++ b/app/serializers/wizard_field_serializer.rb
@@ -2,7 +2,7 @@
class WizardFieldSerializer < ApplicationSerializer
- attributes :id, :type, :required, :value, :label, :placeholder, :description, :extra_description
+ attributes :id, :type, :required, :value, :label, :placeholder, :description, :extra_description, :show_in_sidebar
has_many :choices, serializer: WizardFieldChoiceSerializer, embed: :objects
def id
@@ -68,4 +68,12 @@ class WizardFieldSerializer < ApplicationSerializer
extra_description.present?
end
+ def show_in_sidebar
+ object.show_in_sidebar
+ end
+
+ def include_show_in_sidebar?
+ object.show_in_sidebar.present?
+ end
+
end
diff --git a/app/serializers/wizard_serializer.rb b/app/serializers/wizard_serializer.rb
index 4476c4ff4e3..12bcbe802b5 100644
--- a/app/serializers/wizard_serializer.rb
+++ b/app/serializers/wizard_serializer.rb
@@ -15,11 +15,6 @@ class WizardSerializer < ApplicationSerializer
def current_color_scheme
color_scheme = Theme.where(id: SiteSetting.default_theme_id).first&.color_scheme
- colors = color_scheme ? color_scheme.colors : ColorScheme.base.colors
-
- # The frontend expects the color hexs to start with '#'
- colors_with_hash = {}
- colors.each { |color| colors_with_hash[color.name] = color.hex_with_hash }
- colors_with_hash
+ color_scheme ? color_scheme.colors_hashes : ColorScheme.base.colors_hashes
end
end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index f88b8605738..fd0ff5eb290 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -5395,7 +5395,8 @@ en:
regular: "Regular User"
previews:
- topic_title: "Discussion topic"
- font_title: "%{font} Font"
+ topic_title: "A discussion topic heading"
share_button: "Share"
reply_button: "Reply"
+ topic_preview: "Topic preview"
+ homepage_preview: "Homepage preview"
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index c19136c70cf..3e555899a85 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -4863,18 +4863,34 @@ en:
label: "City for Disputes"
placeholder: "San Francisco, California"
- colors:
- title: "Colors"
-
- fonts:
- title: "Fonts"
+ styling:
+ title: "Styling"
fields:
+ color_scheme:
+ label: "Color scheme"
body_font:
label: "Body font"
heading_font:
label: "Heading font"
- font_preview:
+ styling_preview:
label: "Preview"
+ homepage_style:
+ label: "Homepage style"
+ choices:
+ latest:
+ label: "Latest Topics"
+ categories_only:
+ label: "Categories Only"
+ categories_with_featured_topics:
+ label: "Categories with Featured Topics"
+ categories_and_latest_topics:
+ label: "Categories and Latest Topics"
+ categories_and_top_topics:
+ label: "Categories and Top Topics"
+ categories_boxes:
+ label: "Categories boxes"
+ categories_boxes_with_topics:
+ label: "Categories boxes with Topics"
logos:
title: "Logos"
@@ -4896,28 +4912,6 @@ en:
label: "Large Icon"
description: "Icon image used to represent your site on modern devices that looks good at larger sizes. Ideally larger than 512 × 512. We'll use the square logo by default."
- homepage:
- description: "We recommend showing the latest topics on your homepage, but you can also show categories (groups of topics) on the homepage if you prefer."
- title: "Homepage"
-
- fields:
- homepage_style:
- choices:
- latest:
- label: "Latest Topics"
- categories_only:
- label: "Categories Only"
- categories_with_featured_topics:
- label: "Categories with Featured Topics"
- categories_and_latest_topics:
- label: "Categories and Latest Topics"
- categories_and_top_topics:
- label: "Categories and Top Topics"
- categories_boxes:
- label: "Categories boxes"
- categories_boxes_with_topics:
- label: "Categories boxes with Topics"
-
invites:
title: "Invite Staff"
description: "You’re almost done! Let’s invite some people to help seed your discussions with interesting topics and replies to get your community started."
diff --git a/lib/wizard/builder.rb b/lib/wizard/builder.rb
index 4dfee9af9c8..d6006682a12 100644
--- a/lib/wizard/builder.rb
+++ b/lib/wizard/builder.rb
@@ -141,7 +141,7 @@ class Wizard
end
end
- @wizard.append_step('colors') do |step|
+ @wizard.append_step('styling') do |step|
default_theme = Theme.find_by(id: SiteSetting.default_theme_id)
default_theme_override = SiteSetting.exists?(name: "default_theme_id")
@@ -151,29 +151,60 @@ class Wizard
scheme_id = default_theme_override ? (base_scheme || color_scheme_name) : ColorScheme::LIGHT_THEME_ID
themes = step.add_field(
- id: 'theme_previews',
- type: 'component',
+ id: 'color_scheme',
+ type: 'dropdown',
required: !default_theme_override,
- value: scheme_id || ColorScheme::LIGHT_THEME_ID
+ value: scheme_id || ColorScheme::LIGHT_THEME_ID,
+ show_in_sidebar: true
)
# fix for the case when base_scheme is nil
if scheme_id && default_theme_override && base_scheme.nil?
scheme = default_theme.color_scheme
- default_colors = scheme.colors.select(:name, :hex)
- choice_hash = default_colors.reduce({}) { |choice, color| choice[color.name] = "##{color.hex}"; choice }
- themes.add_choice(scheme_id, data: { colors: choice_hash })
+ themes.add_choice(scheme_id, data: { colors: scheme.colors_hashes })
end
ColorScheme.base_color_scheme_colors.each do |t|
- with_hash = t[:colors].dup
- with_hash.map { |k, v| with_hash[k] = "##{v}" }
- themes.add_choice(t[:id], data: { colors: with_hash })
+ themes.add_choice(t[:id], data: { colors: t[:colors] })
end
+ body_font = step.add_field(
+ id: 'body_font',
+ type: 'dropdown',
+ value: SiteSetting.base_font,
+ show_in_sidebar: true
+ )
+
+ heading_font = step.add_field(
+ id: 'heading_font',
+ type: 'dropdown',
+ value: SiteSetting.heading_font,
+ show_in_sidebar: true
+ )
+
+ DiscourseFonts.fonts.each do |font|
+ body_font.add_choice(font[:key], label: font[:name])
+ heading_font.add_choice(font[:key], label: font[:name])
+ end
+
+ current = SiteSetting.top_menu.starts_with?("categories") ? SiteSetting.desktop_category_page_style : "latest"
+ style = step.add_field(id: 'homepage_style', type: 'dropdown', required: true, value: current, show_in_sidebar: true)
+ style.add_choice('latest')
+ CategoryPageStyle.values.each do |page|
+ style.add_choice(page[:value])
+ end
+
+ step.add_field(
+ id: 'styling_preview',
+ type: 'component'
+ )
+
step.on_update do |updater|
+ updater.update_setting(:base_font, updater.fields[:body_font])
+ updater.update_setting(:heading_font, updater.fields[:heading_font])
+
scheme_name = (
- (updater.fields[:theme_previews] || "") ||
+ (updater.fields[:color_scheme] || "") ||
ColorScheme::LIGHT_THEME_ID
)
@@ -189,33 +220,21 @@ class Wizard
default_theme.save!
else
theme = Theme.create!(
- name: name,
+ name: I18n.t("color_schemes.default_theme_name"),
user_id: @wizard.user.id,
color_scheme_id: scheme.id
)
theme.set_default!
end
- end
- end
- @wizard.append_step('fonts') do |step|
- body_font = step.add_field(id: 'body_font', type: 'dropdown', value: SiteSetting.base_font)
- heading_font = step.add_field(id: 'heading_font', type: 'dropdown', value: SiteSetting.heading_font)
-
- DiscourseFonts.fonts.each do |font|
- body_font.add_choice(font[:key], label: font[:name])
- heading_font.add_choice(font[:key], label: font[:name])
- end
-
- step.add_field(
- id: 'font_preview',
- type: 'component'
- )
-
- step.on_update do |updater|
- updater.update_setting(:base_font, updater.fields[:body_font])
- updater.update_setting(:heading_font, updater.fields[:heading_font])
+ if updater.fields[:homepage_style] == 'latest'
+ top_menu = "latest|new|unread|top|categories"
+ else
+ top_menu = "categories|latest|new|unread|top"
+ updater.update_setting(:desktop_category_page_style, updater.fields[:homepage_style])
+ end
+ updater.update_setting(:top_menu, top_menu)
end
end
@@ -242,29 +261,6 @@ class Wizard
end
end
- @wizard.append_step('homepage') do |step|
-
- current = SiteSetting.top_menu.starts_with?("categories") ? SiteSetting.desktop_category_page_style : "latest"
-
- style = step.add_field(id: 'homepage_style', type: 'dropdown', required: true, value: current)
- style.add_choice('latest')
- CategoryPageStyle.values.each do |page|
- style.add_choice(page[:value])
- end
-
- step.add_field(id: 'homepage_preview', type: 'component')
-
- step.on_update do |updater|
- if updater.fields[:homepage_style] == 'latest'
- top_menu = "latest|new|unread|top|categories"
- else
- top_menu = "categories|latest|new|unread|top"
- updater.update_setting(:desktop_category_page_style, updater.fields[:homepage_style])
- end
- updater.update_setting(:top_menu, top_menu)
- end
- end
-
@wizard.append_step('invites') do |step|
if SiteSetting.enable_local_logins
staff_count = User.staff.human_users.where('username_lower not in (?)', reserved_usernames).count
diff --git a/lib/wizard/field.rb b/lib/wizard/field.rb
index 7c15ba09564..d085f959877 100644
--- a/lib/wizard/field.rb
+++ b/lib/wizard/field.rb
@@ -16,7 +16,7 @@ class Wizard
end
class Field
- attr_reader :id, :type, :required, :value, :choices
+ attr_reader :id, :type, :required, :value, :choices, :show_in_sidebar
attr_accessor :step
def initialize(attrs)
@@ -27,6 +27,7 @@ class Wizard
@required = !!attrs[:required]
@value = attrs[:value]
@choices = []
+ @show_in_sidebar = attrs[:show_in_sidebar]
end
def add_choice(id, opts = nil)
diff --git a/spec/components/wizard/step_updater_spec.rb b/spec/components/wizard/step_updater_spec.rb
index 1f508507794..d0d3f38865b 100644
--- a/spec/components/wizard/step_updater_spec.rb
+++ b/spec/components/wizard/step_updater_spec.rb
@@ -167,105 +167,145 @@ describe Wizard::StepUpdater do
end
end
- context "fonts step" do
+ context "styling step" do
it "updates fonts" do
- updater = wizard.create_updater('fonts', body_font: 'open_sans', heading_font: 'oswald')
+ updater = wizard.create_updater('styling', body_font: 'open_sans', heading_font: 'oswald')
updater.update
expect(updater.success?).to eq(true)
- expect(wizard.completed_steps?('fonts')).to eq(true)
+ expect(wizard.completed_steps?('styling')).to eq(true)
expect(SiteSetting.base_font).to eq('open_sans')
expect(SiteSetting.heading_font).to eq('oswald')
end
- end
- context "colors step" do
- context "with an existing color scheme" do
- fab!(:color_scheme) { Fabricate(:color_scheme, name: 'existing', via_wizard: true) }
+ context "colors" do
+ context "with an existing color scheme" do
+ fab!(:color_scheme) { Fabricate(:color_scheme, name: 'existing', via_wizard: true) }
- it "updates the scheme" do
- updater = wizard.create_updater('colors', theme_previews: 'Dark')
- updater.update
- expect(updater.success?).to eq(true)
- expect(wizard.completed_steps?('colors')).to eq(true)
- theme = Theme.find_by(id: SiteSetting.default_theme_id)
- expect(theme.color_scheme.base_scheme_id).to eq('Dark')
- end
- end
-
- context "with an existing default theme" do
- fab!(:theme) { Fabricate(:theme) }
-
- before do
- theme.set_default!
- end
-
- it "should not update the default theme when no option has been selected" do
- expect do
- wizard.create_updater('colors', {}).update
- end.to_not change { SiteSetting.default_theme_id }
- end
-
- it "should update the color scheme of the default theme" do
- updater = wizard.create_updater('colors', theme_previews: 'Neutral')
- expect { updater.update }.not_to change { Theme.count }
- theme.reload
- expect(theme.color_scheme.base_scheme_id).to eq('Neutral')
- end
- end
-
- context "without an existing theme" do
- before do
- Theme.delete_all
- end
-
- context 'dark theme' do
- it "creates the theme" do
- updater = wizard.create_updater('colors', theme_previews: 'Dark')
-
- expect { updater.update }.to change { Theme.count }.by(1)
-
- theme = Theme.last
-
- expect(theme.user_id).to eq(wizard.user.id)
+ it "updates the scheme" do
+ updater = wizard.create_updater('styling', color_scheme: 'Dark', body_font: 'arial', heading_font: 'arial', homepage_style: 'latest')
+ updater.update
+ expect(updater.success?).to eq(true)
+ expect(wizard.completed_steps?('styling')).to eq(true)
+ theme = Theme.find_by(id: SiteSetting.default_theme_id)
expect(theme.color_scheme.base_scheme_id).to eq('Dark')
end
end
- context 'light theme' do
- it "creates the theme" do
- updater = wizard.create_updater('colors',
- theme_previews: ColorScheme::LIGHT_THEME_ID
+ context "with an existing default theme" do
+ fab!(:theme) { Fabricate(:theme) }
+
+ before do
+ theme.set_default!
+ end
+
+ it "should update the color scheme of the default theme" do
+ updater = wizard.create_updater('styling',
+ color_scheme: 'Neutral',
+ body_font: 'arial',
+ heading_font: 'arial',
+ homepage_style: 'latest'
)
+ expect { updater.update }.not_to change { Theme.count }
+ theme.reload
+ expect(theme.color_scheme.base_scheme_id).to eq('Neutral')
+ end
+ end
- expect { updater.update }.to change { Theme.count }.by(1)
+ context "without an existing theme" do
+ before do
+ Theme.delete_all
+ end
- theme = Theme.last
+ context 'dark theme' do
+ it "creates the theme" do
+ updater = wizard.create_updater('styling',
+ color_scheme: 'Dark',
+ body_font: 'arial',
+ heading_font: 'arial',
+ homepage_style: 'latest'
+ )
- expect(theme.user_id).to eq(wizard.user.id)
+ expect { updater.update }.to change { Theme.count }.by(1)
- expect(theme.color_scheme).to eq(ColorScheme.find_by(name:
- ColorScheme::LIGHT_THEME_ID
- ))
+ theme = Theme.last
+
+ expect(theme.user_id).to eq(wizard.user.id)
+ expect(theme.color_scheme.base_scheme_id).to eq('Dark')
+ end
+ end
+
+ context 'light theme' do
+ it "creates the theme" do
+ updater = wizard.create_updater('styling',
+ color_scheme: ColorScheme::LIGHT_THEME_ID,
+ body_font: 'arial',
+ heading_font: 'arial',
+ homepage_style: 'latest'
+ )
+
+ expect { updater.update }.to change { Theme.count }.by(1)
+
+ theme = Theme.last
+
+ expect(theme.user_id).to eq(wizard.user.id)
+
+ expect(theme.color_scheme).to eq(ColorScheme.find_by(name:
+ ColorScheme::LIGHT_THEME_ID
+ ))
+ end
+ end
+ end
+
+ context "without an existing scheme" do
+ it "creates the scheme" do
+ ColorScheme.destroy_all
+ updater = wizard.create_updater('styling',
+ color_scheme: 'Dark',
+ body_font: 'arial',
+ heading_font: 'arial',
+ homepage_style: 'latest'
+ )
+ updater.update
+ expect(updater.success?).to eq(true)
+ expect(wizard.completed_steps?('styling')).to eq(true)
+
+ color_scheme = ColorScheme.where(via_wizard: true).first
+ expect(color_scheme).to be_present
+ expect(color_scheme.colors).to be_present
+
+ theme = Theme.find_by(id: SiteSetting.default_theme_id)
+ expect(theme.color_scheme_id).to eq(color_scheme.id)
end
end
end
- context "without an existing scheme" do
- it "creates the scheme" do
- ColorScheme.destroy_all
- updater = wizard.create_updater('colors', theme_previews: 'Dark')
+ context "homepage style" do
+ it "updates the fields correctly" do
+ updater = wizard.create_updater('styling',
+ color_scheme: 'Dark',
+ body_font: 'arial',
+ heading_font: 'arial',
+ homepage_style: "categories_and_top_topics"
+ )
updater.update
- expect(updater.success?).to eq(true)
- expect(wizard.completed_steps?('colors')).to eq(true)
- color_scheme = ColorScheme.where(via_wizard: true).first
- expect(color_scheme).to be_present
- expect(color_scheme.colors).to be_present
+ expect(updater).to be_success
+ expect(wizard.completed_steps?('styling')).to eq(true)
+ expect(SiteSetting.top_menu).to eq('categories|latest|new|unread|top')
+ expect(SiteSetting.desktop_category_page_style).to eq('categories_and_top_topics')
- theme = Theme.find_by(id: SiteSetting.default_theme_id)
- expect(theme.color_scheme_id).to eq(color_scheme.id)
+ updater = wizard.create_updater('styling',
+ color_scheme: 'Dark',
+ body_font: 'arial',
+ heading_font: 'arial',
+ homepage_style: "latest"
+ )
+ updater.update
+ expect(updater).to be_success
+ expect(SiteSetting.top_menu).to eq('latest|new|unread|top|categories')
end
end
+
end
context "logos step" do
@@ -307,23 +347,6 @@ describe Wizard::StepUpdater do
end
end
- context "homepage step" do
- it "updates the fields correctly" do
- updater = wizard.create_updater('homepage', homepage_style: "categories_and_top_topics")
- updater.update
-
- expect(updater).to be_success
- expect(wizard.completed_steps?('homepage')).to eq(true)
- expect(SiteSetting.top_menu).to eq('categories|latest|new|unread|top')
- expect(SiteSetting.desktop_category_page_style).to eq('categories_and_top_topics')
-
- updater = wizard.create_updater('homepage', homepage_style: "latest")
- updater.update
- expect(updater).to be_success
- expect(SiteSetting.top_menu).to eq('latest|new|unread|top|categories')
- end
- end
-
context "invites step" do
let(:invites) {
return [{ email: 'regular@example.com', role: 'regular' },
diff --git a/spec/components/wizard/wizard_builder_spec.rb b/spec/components/wizard/wizard_builder_spec.rb
index c1ea65136e3..b2d32e4ed35 100644
--- a/spec/components/wizard/wizard_builder_spec.rb
+++ b/spec/components/wizard/wizard_builder_spec.rb
@@ -41,12 +41,64 @@ describe Wizard::Builder do
expect(invites_step.disabled).to be_truthy
end
- context 'fonts step' do
- let(:fonts_step) { wizard.steps.find { |s| s.id == 'fonts' } }
- let(:field) { fonts_step.fields.first }
+ context 'styling step' do
+ let(:styling_step) { wizard.steps.find { |s| s.id == 'styling' } }
+ let(:font_field) { styling_step.fields[1] }
+ fab!(:theme) { Fabricate(:theme) }
+ let(:colors_field) { styling_step.fields.first }
- it 'should set the right font' do
- expect(field.choices.size).to eq(DiscourseFonts.fonts.size)
+ it 'has the full list of available fonts' do
+ expect(font_field.choices.size).to eq(DiscourseFonts.fonts.size)
+ end
+
+ context "colors" do
+ describe "when the default theme has not been override" do
+ before do
+ SiteSetting.find_by(name: "default_theme_id").destroy!
+ end
+
+ it 'should set the right default values' do
+ expect(colors_field.required).to eq(true)
+ expect(colors_field.value).to eq(ColorScheme::LIGHT_THEME_ID)
+ end
+ end
+
+ describe "when the default theme has been override and the color scheme doesn't have a base scheme" do
+ let(:color_scheme) { Fabricate(:color_scheme, base_scheme_id: nil) }
+
+ before do
+ SiteSetting.default_theme_id = theme.id
+ theme.update(color_scheme: color_scheme)
+ end
+
+ it 'fallbacks to the color scheme name' do
+ expect(colors_field.required).to eq(false)
+ expect(colors_field.value).to eq(color_scheme.name)
+ end
+ end
+
+ describe "when the default theme has been overridden by a theme without a color scheme" do
+ before do
+ theme.set_default!
+ end
+
+ it 'should set the right default values' do
+ expect(colors_field.required).to eq(false)
+ expect(colors_field.value).to eq("Light")
+ end
+ end
+
+ describe "when the default theme has been overridden by a theme with a color scheme" do
+ before do
+ theme.update(color_scheme_id: ColorScheme.find_by_name("Dark").id)
+ theme.set_default!
+ end
+
+ it 'should set the right default values' do
+ expect(colors_field.required).to eq(false)
+ expect(colors_field.value).to eq("Dark")
+ end
+ end
end
end
@@ -155,57 +207,4 @@ describe Wizard::Builder do
end
end
- context "colors step" do
- fab!(:theme) { Fabricate(:theme) }
- let(:colors_step) { wizard.steps.find { |s| s.id == 'colors' } }
- let(:field) { colors_step.fields.first }
-
- describe "when the default theme has not been override" do
- before do
- SiteSetting.find_by(name: "default_theme_id").destroy!
- end
-
- it 'should set the right default values' do
- expect(field.required).to eq(true)
- expect(field.value).to eq(ColorScheme::LIGHT_THEME_ID)
- end
- end
-
- describe "when the default theme has been override and the color scheme doesn't have a base scheme" do
- let(:color_scheme) { Fabricate(:color_scheme, base_scheme_id: nil) }
-
- before do
- SiteSetting.default_theme_id = theme.id
- theme.update(color_scheme: color_scheme)
- end
-
- it 'fallbacks to the color scheme name' do
- expect(field.required).to eq(false)
- expect(field.value).to eq(color_scheme.name)
- end
- end
-
- describe "when the default theme has been overridden by a theme without a color scheme" do
- before do
- theme.set_default!
- end
-
- it 'should set the right default values' do
- expect(field.required).to eq(false)
- expect(field.value).to eq("Light")
- end
- end
-
- describe "when the default theme has been overridden by a theme with a color scheme" do
- before do
- theme.update(color_scheme_id: ColorScheme.find_by_name("Dark").id)
- theme.set_default!
- end
-
- it 'should set the right default values' do
- expect(field.required).to eq(false)
- expect(field.value).to eq("Dark")
- end
- end
- end
end
diff --git a/spec/requests/admin/color_schemes_controller_spec.rb b/spec/requests/admin/color_schemes_controller_spec.rb
index 782d9ee5c2b..ae3905e612b 100644
--- a/spec/requests/admin/color_schemes_controller_spec.rb
+++ b/spec/requests/admin/color_schemes_controller_spec.rb
@@ -28,8 +28,13 @@ describe Admin::ColorSchemesController do
get "/admin/color_schemes.json"
expect(response.status).to eq(200)
- schemes = response.parsed_body.map { |scheme| scheme["name"] }
- expect(schemes).to include(scheme_name)
+ scheme_names = response.parsed_body.map { |scheme| scheme["name"] }
+ scheme_colors = response.parsed_body[0]["colors"]
+ base_scheme_colors = ColorScheme.base.colors
+
+ expect(scheme_names).to include(scheme_name)
+ expect(scheme_colors[0]["name"]).to eq(base_scheme_colors[0].name)
+ expect(scheme_colors[0]["hex"]).to eq(base_scheme_colors[0].hex)
end
end
diff --git a/spec/serializers/wizard_serializer_spec.rb b/spec/serializers/wizard_serializer_spec.rb
index cd66038dafd..ff9406f21b1 100644
--- a/spec/serializers/wizard_serializer_spec.rb
+++ b/spec/serializers/wizard_serializer_spec.rb
@@ -18,7 +18,8 @@ describe WizardSerializer do
json = MultiJson.load(MultiJson.dump(serializer.as_json))
wjson = json['wizard']
- expect(wjson['current_color_scheme']['primary']).to eq('#222222')
+ expect(wjson['current_color_scheme'][0]['name']).to eq('primary')
+ expect(wjson['current_color_scheme'][0]['hex']).to eq('222222')
end
it "should provide custom colors correctly" do
@@ -34,7 +35,7 @@ describe WizardSerializer do
json = MultiJson.load(MultiJson.dump(serializer.as_json))
wjson = json['wizard']
- expect(wjson['current_color_scheme']['header_background']).to eq('#00FF00')
+ expect(wjson['current_color_scheme'].to_s).to include('{"name"=>"header_background", "hex"=>"00FF00"}')
end
end