mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
UX: Add Styling step to wizard (#14132)
Refactors three wizard steps (colors, fonts, homepage style) into one new step called Styling.
This commit is contained in:
parent
cfbf69848a
commit
85b8fea262
@ -1,6 +1,5 @@
|
|||||||
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
|
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
|
||||||
import { computed } from "@ember/object";
|
import { computed } from "@ember/object";
|
||||||
import { escapeExpression } from "discourse/lib/utilities";
|
|
||||||
import layout from "select-kit/templates/components/color-palettes/color-palettes-row";
|
import layout from "select-kit/templates/components/color-palettes/color-palettes-row";
|
||||||
|
|
||||||
export default SelectKitRowComponent.extend({
|
export default SelectKitRowComponent.extend({
|
||||||
@ -10,7 +9,7 @@ export default SelectKitRowComponent.extend({
|
|||||||
palettes: computed("item.colors.[]", function () {
|
palettes: computed("item.colors.[]", function () {
|
||||||
return (this.item.colors || [])
|
return (this.item.colors || [])
|
||||||
.filter((color) => color.name !== "secondary")
|
.filter((color) => color.name !== "secondary")
|
||||||
.map((color) => `#${escapeExpression(color.hex)}`)
|
.map((color) => `#${escape(color.hex)}`)
|
||||||
.map(
|
.map(
|
||||||
(hex) => `<span class="palette" style="background-color:${hex}"></span>`
|
(hex) => `<span class="palette" style="background-color:${hex}"></span>`
|
||||||
)
|
)
|
||||||
@ -22,7 +21,7 @@ export default SelectKitRowComponent.extend({
|
|||||||
const secondary = (this.item.colors || []).findBy("name", "secondary");
|
const secondary = (this.item.colors || []).findBy("name", "secondary");
|
||||||
|
|
||||||
if (secondary && secondary.hex) {
|
if (secondary && secondary.hex) {
|
||||||
return `background-color:#${escapeExpression(secondary.hex)}`.htmlSafe();
|
return `background-color:#${escape(secondary.hex)}`.htmlSafe();
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,14 @@ import {
|
|||||||
createPreviewComponent,
|
createPreviewComponent,
|
||||||
darkLightDiff,
|
darkLightDiff,
|
||||||
} from "wizard/lib/preview";
|
} from "wizard/lib/preview";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
|
||||||
|
|
||||||
export default createPreviewComponent(659, 320, {
|
export default createPreviewComponent(659, 320, {
|
||||||
logo: null,
|
logo: null,
|
||||||
avatar: null,
|
avatar: null,
|
||||||
|
|
||||||
@observes("step.fieldsById.homepage_style.value")
|
didUpdateAttrs() {
|
||||||
styleChanged() {
|
this._super(...arguments);
|
||||||
|
|
||||||
this.triggerRepaint();
|
this.triggerRepaint();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -22,7 +22,9 @@ export default createPreviewComponent(659, 320, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
paint({ ctx, colors, font, width, height }) {
|
paint({ ctx, colors, font, width, height }) {
|
||||||
|
if (this.logo) {
|
||||||
this.drawFullHeader(colors, font, this.logo);
|
this.drawFullHeader(colors, font, this.logo);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.get("step.fieldsById.homepage_style.value") === "latest") {
|
if (this.get("step.fieldsById.homepage_style.value") === "latest") {
|
||||||
this.drawPills(colors, font, height * 0.15);
|
this.drawPills(colors, font, height * 0.15);
|
||||||
|
@ -15,13 +15,66 @@ metus. Fusce in consequat augue, vel facilisis felis.`;
|
|||||||
export default createPreviewComponent(659, 320, {
|
export default createPreviewComponent(659, 320, {
|
||||||
logo: null,
|
logo: null,
|
||||||
avatar: 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();
|
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() {
|
images() {
|
||||||
@ -39,14 +92,14 @@ export default createPreviewComponent(659, 320, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const margin = 20;
|
const margin = 20;
|
||||||
const avatarSize = height * 0.2;
|
const avatarSize = height * 0.15;
|
||||||
const lineHeight = height / 11;
|
const lineHeight = height / 14;
|
||||||
|
|
||||||
// Draw a fake topic
|
// Draw a fake topic
|
||||||
this.scaleImage(
|
this.scaleImage(
|
||||||
this.avatar,
|
this.avatar,
|
||||||
margin,
|
margin,
|
||||||
headerHeight + height * 0.11,
|
headerHeight + height * 0.09,
|
||||||
avatarSize,
|
avatarSize,
|
||||||
avatarSize
|
avatarSize
|
||||||
);
|
);
|
||||||
@ -80,7 +133,7 @@ export default createPreviewComponent(659, 320, {
|
|||||||
ctx.fillText(
|
ctx.fillText(
|
||||||
I18n.t("wizard.previews.share_button"),
|
I18n.t("wizard.previews.share_button"),
|
||||||
margin + 10,
|
margin + 10,
|
||||||
line + lineHeight * 1.7
|
line + lineHeight * 1.9
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reply Button
|
// Reply Button
|
||||||
@ -100,7 +153,7 @@ export default createPreviewComponent(659, 320, {
|
|||||||
ctx.fillText(
|
ctx.fillText(
|
||||||
I18n.t("wizard.previews.reply_button"),
|
I18n.t("wizard.previews.reply_button"),
|
||||||
shareButtonWidth + margin + 20,
|
shareButtonWidth + margin + 20,
|
||||||
line + lineHeight * 1.7
|
line + lineHeight * 1.9
|
||||||
);
|
);
|
||||||
|
|
||||||
// Draw Timeline
|
// Draw Timeline
|
||||||
@ -124,4 +177,14 @@ export default createPreviewComponent(659, 320, {
|
|||||||
ctx.fillStyle = colors.primary;
|
ctx.fillStyle = colors.primary;
|
||||||
ctx.fillText("1 / 20", timelineX + margin, height * 0.3 + margin * 1.5);
|
ctx.fillText("1 / 20", timelineX + margin, height * 0.3 + margin * 1.5);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
setPreviewHomepage() {
|
||||||
|
this.set("previewTopic", false);
|
||||||
|
},
|
||||||
|
|
||||||
|
setPreviewTopic() {
|
||||||
|
this.set("previewTopic", true);
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
@ -1,8 +0,0 @@
|
|||||||
import Component from "@ember/component";
|
|
||||||
export default Component.extend({
|
|
||||||
actions: {
|
|
||||||
changed(value) {
|
|
||||||
this.set("field.value", value);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,7 +1,36 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
import { set } from "@ember/object";
|
||||||
|
|
||||||
export default Component.extend({
|
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) {
|
keyPress(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
onChangeValue(value) {
|
||||||
|
this.set("field.value", value);
|
||||||
|
this.stylingDropdownChanged(this.field.id, value);
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -3,10 +3,11 @@ import { dasherize } from "@ember/string";
|
|||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNameBindings: [":wizard-field", "typeClass", "field.invalid"],
|
classNameBindings: [":wizard-field", "typeClasses", "field.invalid"],
|
||||||
|
|
||||||
@discourseComputed("field.type")
|
@discourseComputed("field.type", "field.id")
|
||||||
typeClass: (type) => `${dasherize(type)}-field`,
|
typeClasses: (type, id) =>
|
||||||
|
`${dasherize(type)}-field ${dasherize(type)}-${dasherize(id)}`,
|
||||||
|
|
||||||
@discourseComputed("field.id")
|
@discourseComputed("field.id")
|
||||||
fieldClass: (id) => `field-${dasherize(id)} wizard-focusable`,
|
fieldClass: (id) => `field-${dasherize(id)} wizard-focusable`,
|
||||||
|
@ -27,6 +27,11 @@ export default Component.extend({
|
|||||||
classNames: ["wizard-step"],
|
classNames: ["wizard-step"],
|
||||||
saving: null,
|
saving: null,
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this._super(...arguments);
|
||||||
|
this.set("stylingDropdown", {});
|
||||||
|
},
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.autoFocus();
|
this.autoFocus();
|
||||||
@ -96,6 +101,11 @@ export default Component.extend({
|
|||||||
return htmlSafe(`width: ${ratio * 200}px`);
|
return htmlSafe(`width: ${ratio * 200}px`);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@discourseComputed("step.fields")
|
||||||
|
includeSidebar(fields) {
|
||||||
|
return !!fields.findBy("show_in_sidebar");
|
||||||
|
},
|
||||||
|
|
||||||
autoFocus() {
|
autoFocus() {
|
||||||
schedule("afterRender", () => {
|
schedule("afterRender", () => {
|
||||||
const $invalid = $(
|
const $invalid = $(
|
||||||
@ -130,6 +140,10 @@ export default Component.extend({
|
|||||||
document.location = getUrl("/");
|
document.location = getUrl("/");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
stylingDropdownChanged(id, value) {
|
||||||
|
this.set("stylingDropdown", { id, value });
|
||||||
|
},
|
||||||
|
|
||||||
exitEarly() {
|
exitEarly() {
|
||||||
const step = this.step;
|
const step = this.step;
|
||||||
step.validate();
|
step.validate();
|
||||||
|
@ -12,7 +12,7 @@ export default Controller.extend({
|
|||||||
|
|
||||||
@discourseComputed("model")
|
@discourseComputed("model")
|
||||||
fontClasses(model) {
|
fontClasses(model) {
|
||||||
const fontsStep = model.steps.findBy("id", "fonts");
|
const fontsStep = model.steps.findBy("id", "styling");
|
||||||
if (!fontsStep) {
|
if (!fontsStep) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import Component from "@ember/component";
|
|||||||
import { Promise } from "rsvp";
|
import { Promise } from "rsvp";
|
||||||
/*eslint no-bitwise:0 */
|
/*eslint no-bitwise:0 */
|
||||||
import getUrl from "discourse-common/lib/get-url";
|
import getUrl from "discourse-common/lib/get-url";
|
||||||
|
import { htmlSafe } from "@ember/template";
|
||||||
import { scheduleOnce } from "@ember/runloop";
|
import { scheduleOnce } from "@ember/runloop";
|
||||||
|
|
||||||
export const LOREM = `
|
export const LOREM = `
|
||||||
@ -41,7 +42,7 @@ export function createPreviewComponent(width, height, obj) {
|
|||||||
height,
|
height,
|
||||||
elementWidth: width * scale,
|
elementWidth: width * scale,
|
||||||
elementHeight: height * scale,
|
elementHeight: height * scale,
|
||||||
canvasStyle: `width:${width}px;height:${height}px`,
|
canvasStyle: htmlSafe(`width:${width}px;height:${height}px`),
|
||||||
ctx: null,
|
ctx: null,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
|
||||||
@ -87,11 +88,17 @@ export function createPreviewComponent(width, height, obj) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const colors = this.wizard.getCurrentColors(this.colorsId);
|
const colorsArray = this.wizard.getCurrentColors(this.colorsId);
|
||||||
if (!colors) {
|
if (!colorsArray) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let colors = {};
|
||||||
|
colorsArray.forEach(function (c) {
|
||||||
|
const name = c.name;
|
||||||
|
colors[name] = `#${c.hex}`;
|
||||||
|
});
|
||||||
|
|
||||||
const font = this.wizard.getCurrentFont(this.fontId);
|
const font = this.wizard.getCurrentFont(this.fontId);
|
||||||
const headingFont = this.wizard.getCurrentFont(
|
const headingFont = this.wizard.getCurrentFont(
|
||||||
this.fontId,
|
this.fontId,
|
||||||
@ -115,12 +122,6 @@ export function createPreviewComponent(width, height, obj) {
|
|||||||
height: this.height,
|
height: this.height,
|
||||||
};
|
};
|
||||||
this.paint(options);
|
this.paint(options);
|
||||||
|
|
||||||
// draw border
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.strokeStyle = "rgba(0, 0, 0, 0.2)";
|
|
||||||
ctx.rect(0, 0, width, height);
|
|
||||||
ctx.stroke();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
categories() {
|
categories() {
|
||||||
|
@ -26,12 +26,12 @@ const Wizard = EmberObject.extend({
|
|||||||
|
|
||||||
// A bit clunky, but get the current colors from the appropriate step
|
// A bit clunky, but get the current colors from the appropriate step
|
||||||
getCurrentColors(schemeId) {
|
getCurrentColors(schemeId) {
|
||||||
const colorStep = this.steps.findBy("id", "colors");
|
const colorStep = this.steps.findBy("id", "styling");
|
||||||
if (!colorStep) {
|
if (!colorStep) {
|
||||||
return this.current_color_scheme;
|
return this.current_color_scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
const themeChoice = colorStep.get("fieldsById.theme_previews");
|
const themeChoice = colorStep.get("fieldsById.color_scheme");
|
||||||
if (!themeChoice) {
|
if (!themeChoice) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@ const Wizard = EmberObject.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
getCurrentFont(fontId, type = "body_font") {
|
getCurrentFont(fontId, type = "body_font") {
|
||||||
const fontsStep = this.steps.findBy("id", "fonts");
|
const fontsStep = this.steps.findBy("id", "styling");
|
||||||
if (!fontsStep) {
|
if (!fontsStep) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
<div class="preview-area">
|
|
||||||
<canvas
|
|
||||||
width={{elementWidth}}
|
|
||||||
height={{elementHeight}}
|
|
||||||
style={{canvasStyle}}
|
|
||||||
>
|
|
||||||
</canvas>
|
|
||||||
</div>
|
|
@ -0,0 +1,22 @@
|
|||||||
|
<div class="previews {{if draggingActive "dragging"}}">
|
||||||
|
<div class="preview-area topic-preview">
|
||||||
|
<canvas width={{elementWidth}} height={{elementHeight}} style={{canvasStyle}}>
|
||||||
|
</canvas>
|
||||||
|
</div>
|
||||||
|
<div class="preview-area homepage-preview">
|
||||||
|
{{homepage-preview
|
||||||
|
wizard=wizard
|
||||||
|
step=step
|
||||||
|
stylingDropdown=stylingDropdown
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="preview-nav">
|
||||||
|
<a href class="preview-nav-button {{if previewTopic "active"}}" {{action "setPreviewTopic"}}>
|
||||||
|
{{i18n "wizard.previews.topic_preview"}}
|
||||||
|
</a>
|
||||||
|
<a href class="preview-nav-button {{unless previewTopic "active"}}" {{action "setPreviewHomepage"}}>
|
||||||
|
{{i18n "wizard.previews.homepage_preview"}}
|
||||||
|
</a>
|
||||||
|
</div>
|
@ -1,14 +0,0 @@
|
|||||||
<ul class="grid">
|
|
||||||
{{#each field.choices as |choice|}}
|
|
||||||
<li>
|
|
||||||
{{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")}}
|
|
||||||
</li>
|
|
||||||
{{/each}}
|
|
||||||
</ul>
|
|
@ -1,9 +1,12 @@
|
|||||||
{{combo-box
|
{{component
|
||||||
id=field.id
|
componentName
|
||||||
class=fieldClass
|
class=fieldClass
|
||||||
value=field.value
|
value=field.value
|
||||||
content=field.choices
|
content=field.choices
|
||||||
nameProperty="label"
|
nameProperty="label"
|
||||||
tabindex="9"
|
tabindex="9"
|
||||||
onChange=(action (mut field.value))
|
onChange=(action "onChangeValue")
|
||||||
|
options=(hash
|
||||||
|
translatedNone=false
|
||||||
|
)
|
||||||
}}
|
}}
|
||||||
|
@ -13,7 +13,14 @@
|
|||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div class="input-area">
|
<div class="input-area">
|
||||||
{{component inputComponentName field=field step=step fieldClass=fieldClass wizard=wizard}}
|
{{component
|
||||||
|
inputComponentName
|
||||||
|
field=field step=step
|
||||||
|
fieldClass=fieldClass
|
||||||
|
wizard=wizard
|
||||||
|
stylingDropdownChanged=stylingDropdownChanged
|
||||||
|
stylingDropdown=stylingDropdown
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if field.errorDescription}}
|
{{#if field.errorDescription}}
|
||||||
|
@ -14,9 +14,32 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#wizard-step-form step=step}}
|
{{#wizard-step-form step=step}}
|
||||||
|
{{#if includeSidebar}}
|
||||||
|
<div class="wizard-fields-sidebar">
|
||||||
{{#each step.fields as |field|}}
|
{{#each step.fields as |field|}}
|
||||||
{{wizard-field field=field step=step wizard=wizard}}
|
{{#if field.show_in_sidebar}}
|
||||||
|
{{wizard-field
|
||||||
|
field=field
|
||||||
|
step=step
|
||||||
|
wizard=wizard
|
||||||
|
stylingDropdownChanged=(action "stylingDropdownChanged")
|
||||||
|
}}
|
||||||
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
<div class="wizard-fields-main">
|
||||||
|
{{#each step.fields as |field|}}
|
||||||
|
{{#unless field.show_in_sidebar}}
|
||||||
|
{{wizard-field
|
||||||
|
field=field
|
||||||
|
step=step
|
||||||
|
wizard=wizard
|
||||||
|
stylingDropdown=stylingDropdown
|
||||||
|
}}
|
||||||
|
{{/unless}}
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
{{/wizard-step-form}}
|
{{/wizard-step-form}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -820,66 +820,78 @@ body.wizard {
|
|||||||
|
|
||||||
.wizard-step-form {
|
.wizard-step-form {
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.wizard-fields-main {
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wizard-step-homepage {
|
.wizard-fields-sidebar {
|
||||||
.field-homepage-style {
|
width: 170px;
|
||||||
width: 280px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.wizard-step-colors {
|
|
||||||
max-height: 465px;
|
|
||||||
overflow-y: auto;
|
|
||||||
.grid {
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
padding: 30px 0px 15px 15px;
|
||||||
flex-wrap: wrap;
|
background: var(--primary-very-low);
|
||||||
justify-content: space-around;
|
+ .wizard-fields-main {
|
||||||
padding: 0;
|
padding: 15px;
|
||||||
margin: 0 auto;
|
padding-top: 30px;
|
||||||
list-style-type: none;
|
background: var(--primary-very-low);
|
||||||
text-align: center;
|
width: calc(100% - 170px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
li {
|
.wizard-step-styling {
|
||||||
display: inline-block;
|
.preview-nav {
|
||||||
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;
|
display: flex;
|
||||||
flex: 1 1 auto;
|
justify-content: flex-end;
|
||||||
}
|
|
||||||
.radio-area {
|
|
||||||
display: none;
|
|
||||||
& > * {
|
|
||||||
position: relative;
|
position: relative;
|
||||||
right: 7px;
|
margin-top: -1px;
|
||||||
}
|
padding-right: 10px;
|
||||||
}
|
.preview-nav-button {
|
||||||
canvas {
|
text-align: center;
|
||||||
transition: box-shadow 0.25s;
|
padding: 10px 15px;
|
||||||
&:hover {
|
|
||||||
box-shadow: shadow("card");
|
|
||||||
cursor: pointer;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.wizard-step-fonts {
|
.previews {
|
||||||
.dropdown-field {
|
position: relative;
|
||||||
float: left;
|
height: 320px;
|
||||||
margin-right: 1.5em;
|
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;
|
||||||
}
|
}
|
||||||
.component-field {
|
|
||||||
clear: both;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -891,7 +903,7 @@ body.wizard {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 1.5em auto;
|
margin: 1.5em auto;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
max-width: 700px;
|
max-width: 820px;
|
||||||
min-width: 280px;
|
min-width: 280px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 1px solid var(--primary-low-mid);
|
border: 1px solid var(--primary-low-mid);
|
||||||
@ -924,7 +936,7 @@ body.wizard {
|
|||||||
}
|
}
|
||||||
.wizard-step-banner {
|
.wizard-step-banner {
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
width: 620px;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1178,6 +1190,10 @@ body.wizard {
|
|||||||
|
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wizard-image-row canvas {
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.textarea-field {
|
.textarea-field {
|
||||||
|
@ -133,10 +133,10 @@ class ColorScheme < ActiveRecord::Base
|
|||||||
LIGHT_THEME_ID = 'Light'
|
LIGHT_THEME_ID = 'Light'
|
||||||
|
|
||||||
def self.base_color_scheme_colors
|
def self.base_color_scheme_colors
|
||||||
base_with_hash = {}
|
base_with_hash = []
|
||||||
|
|
||||||
base_colors.each do |name, color|
|
base_colors.each do |name, color|
|
||||||
base_with_hash[name] = "#{color}"
|
base_with_hash << { name: name, hex: "#{color}" }
|
||||||
end
|
end
|
||||||
|
|
||||||
list = [
|
list = [
|
||||||
@ -144,7 +144,11 @@ class ColorScheme < ActiveRecord::Base
|
|||||||
]
|
]
|
||||||
|
|
||||||
CUSTOM_SCHEMES.each do |k, v|
|
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
|
end
|
||||||
|
|
||||||
list
|
list
|
||||||
@ -205,7 +209,7 @@ class ColorScheme < ActiveRecord::Base
|
|||||||
def self.base_color_schemes
|
def self.base_color_schemes
|
||||||
base_color_scheme_colors.map do |hash|
|
base_color_scheme_colors.map do |hash|
|
||||||
scheme = new(name: I18n.t("color_schemes.#{hash[:id].downcase.gsub(' ', '_')}"), base_scheme_id: hash[:id])
|
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.is_base = true
|
||||||
scheme
|
scheme
|
||||||
end
|
end
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
class WizardFieldSerializer < ApplicationSerializer
|
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
|
has_many :choices, serializer: WizardFieldChoiceSerializer, embed: :objects
|
||||||
|
|
||||||
def id
|
def id
|
||||||
@ -68,4 +68,12 @@ class WizardFieldSerializer < ApplicationSerializer
|
|||||||
extra_description.present?
|
extra_description.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show_in_sidebar
|
||||||
|
object.show_in_sidebar
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_show_in_sidebar?
|
||||||
|
object.show_in_sidebar.present?
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -15,11 +15,6 @@ class WizardSerializer < ApplicationSerializer
|
|||||||
|
|
||||||
def current_color_scheme
|
def current_color_scheme
|
||||||
color_scheme = Theme.where(id: SiteSetting.default_theme_id).first&.color_scheme
|
color_scheme = Theme.where(id: SiteSetting.default_theme_id).first&.color_scheme
|
||||||
colors = color_scheme ? color_scheme.colors : ColorScheme.base.colors
|
color_scheme ? color_scheme.colors_hashes : ColorScheme.base.colors_hashes
|
||||||
|
|
||||||
# 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
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -5395,7 +5395,8 @@ en:
|
|||||||
regular: "Regular User"
|
regular: "Regular User"
|
||||||
|
|
||||||
previews:
|
previews:
|
||||||
topic_title: "Discussion topic"
|
topic_title: "A discussion topic heading"
|
||||||
font_title: "%{font} Font"
|
|
||||||
share_button: "Share"
|
share_button: "Share"
|
||||||
reply_button: "Reply"
|
reply_button: "Reply"
|
||||||
|
topic_preview: "Topic preview"
|
||||||
|
homepage_preview: "Homepage preview"
|
||||||
|
@ -4863,18 +4863,34 @@ en:
|
|||||||
label: "City for Disputes"
|
label: "City for Disputes"
|
||||||
placeholder: "San Francisco, California"
|
placeholder: "San Francisco, California"
|
||||||
|
|
||||||
colors:
|
styling:
|
||||||
title: "Colors"
|
title: "Styling"
|
||||||
|
|
||||||
fonts:
|
|
||||||
title: "Fonts"
|
|
||||||
fields:
|
fields:
|
||||||
|
color_scheme:
|
||||||
|
label: "Color scheme"
|
||||||
body_font:
|
body_font:
|
||||||
label: "Body font"
|
label: "Body font"
|
||||||
heading_font:
|
heading_font:
|
||||||
label: "Heading font"
|
label: "Heading font"
|
||||||
font_preview:
|
styling_preview:
|
||||||
label: "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:
|
logos:
|
||||||
title: "Logos"
|
title: "Logos"
|
||||||
@ -4896,28 +4912,6 @@ en:
|
|||||||
label: "Large Icon"
|
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."
|
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:
|
invites:
|
||||||
title: "Invite Staff"
|
title: "Invite Staff"
|
||||||
description: "You’re almost done! Let’s invite some people to help <a href='https://blog.discourse.org/2014/08/building-a-discourse-community/' target='blank'>seed your discussions</a> with interesting topics and replies to get your community started."
|
description: "You’re almost done! Let’s invite some people to help <a href='https://blog.discourse.org/2014/08/building-a-discourse-community/' target='blank'>seed your discussions</a> with interesting topics and replies to get your community started."
|
||||||
|
@ -141,7 +141,7 @@ class Wizard
|
|||||||
end
|
end
|
||||||
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 = Theme.find_by(id: SiteSetting.default_theme_id)
|
||||||
default_theme_override = SiteSetting.exists?(name: "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
|
scheme_id = default_theme_override ? (base_scheme || color_scheme_name) : ColorScheme::LIGHT_THEME_ID
|
||||||
|
|
||||||
themes = step.add_field(
|
themes = step.add_field(
|
||||||
id: 'theme_previews',
|
id: 'color_scheme',
|
||||||
type: 'component',
|
type: 'dropdown',
|
||||||
required: !default_theme_override,
|
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
|
# fix for the case when base_scheme is nil
|
||||||
if scheme_id && default_theme_override && base_scheme.nil?
|
if scheme_id && default_theme_override && base_scheme.nil?
|
||||||
scheme = default_theme.color_scheme
|
scheme = default_theme.color_scheme
|
||||||
default_colors = scheme.colors.select(:name, :hex)
|
themes.add_choice(scheme_id, data: { colors: scheme.colors_hashes })
|
||||||
choice_hash = default_colors.reduce({}) { |choice, color| choice[color.name] = "##{color.hex}"; choice }
|
|
||||||
themes.add_choice(scheme_id, data: { colors: choice_hash })
|
|
||||||
end
|
end
|
||||||
|
|
||||||
ColorScheme.base_color_scheme_colors.each do |t|
|
ColorScheme.base_color_scheme_colors.each do |t|
|
||||||
with_hash = t[:colors].dup
|
themes.add_choice(t[:id], data: { colors: t[:colors] })
|
||||||
with_hash.map { |k, v| with_hash[k] = "##{v}" }
|
|
||||||
themes.add_choice(t[:id], data: { colors: with_hash })
|
|
||||||
end
|
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|
|
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 = (
|
scheme_name = (
|
||||||
(updater.fields[:theme_previews] || "") ||
|
(updater.fields[:color_scheme] || "") ||
|
||||||
ColorScheme::LIGHT_THEME_ID
|
ColorScheme::LIGHT_THEME_ID
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -189,33 +220,21 @@ class Wizard
|
|||||||
default_theme.save!
|
default_theme.save!
|
||||||
else
|
else
|
||||||
theme = Theme.create!(
|
theme = Theme.create!(
|
||||||
name: name,
|
name: I18n.t("color_schemes.default_theme_name"),
|
||||||
user_id: @wizard.user.id,
|
user_id: @wizard.user.id,
|
||||||
color_scheme_id: scheme.id
|
color_scheme_id: scheme.id
|
||||||
)
|
)
|
||||||
|
|
||||||
theme.set_default!
|
theme.set_default!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
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
|
end
|
||||||
end
|
updater.update_setting(:top_menu, top_menu)
|
||||||
|
|
||||||
@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])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -242,29 +261,6 @@ class Wizard
|
|||||||
end
|
end
|
||||||
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|
|
@wizard.append_step('invites') do |step|
|
||||||
if SiteSetting.enable_local_logins
|
if SiteSetting.enable_local_logins
|
||||||
staff_count = User.staff.human_users.where('username_lower not in (?)', reserved_usernames).count
|
staff_count = User.staff.human_users.where('username_lower not in (?)', reserved_usernames).count
|
||||||
|
@ -16,7 +16,7 @@ class Wizard
|
|||||||
end
|
end
|
||||||
|
|
||||||
class Field
|
class Field
|
||||||
attr_reader :id, :type, :required, :value, :choices
|
attr_reader :id, :type, :required, :value, :choices, :show_in_sidebar
|
||||||
attr_accessor :step
|
attr_accessor :step
|
||||||
|
|
||||||
def initialize(attrs)
|
def initialize(attrs)
|
||||||
@ -27,6 +27,7 @@ class Wizard
|
|||||||
@required = !!attrs[:required]
|
@required = !!attrs[:required]
|
||||||
@value = attrs[:value]
|
@value = attrs[:value]
|
||||||
@choices = []
|
@choices = []
|
||||||
|
@show_in_sidebar = attrs[:show_in_sidebar]
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_choice(id, opts = nil)
|
def add_choice(id, opts = nil)
|
||||||
|
@ -167,26 +167,25 @@ describe Wizard::StepUpdater do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "fonts step" do
|
context "styling step" do
|
||||||
it "updates fonts" 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
|
updater.update
|
||||||
expect(updater.success?).to eq(true)
|
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.base_font).to eq('open_sans')
|
||||||
expect(SiteSetting.heading_font).to eq('oswald')
|
expect(SiteSetting.heading_font).to eq('oswald')
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
context "colors step" do
|
context "colors" do
|
||||||
context "with an existing color scheme" do
|
context "with an existing color scheme" do
|
||||||
fab!(:color_scheme) { Fabricate(:color_scheme, name: 'existing', via_wizard: true) }
|
fab!(:color_scheme) { Fabricate(:color_scheme, name: 'existing', via_wizard: true) }
|
||||||
|
|
||||||
it "updates the scheme" do
|
it "updates the scheme" do
|
||||||
updater = wizard.create_updater('colors', theme_previews: 'Dark')
|
updater = wizard.create_updater('styling', color_scheme: 'Dark', body_font: 'arial', heading_font: 'arial', homepage_style: 'latest')
|
||||||
updater.update
|
updater.update
|
||||||
expect(updater.success?).to eq(true)
|
expect(updater.success?).to eq(true)
|
||||||
expect(wizard.completed_steps?('colors')).to eq(true)
|
expect(wizard.completed_steps?('styling')).to eq(true)
|
||||||
theme = Theme.find_by(id: SiteSetting.default_theme_id)
|
theme = Theme.find_by(id: SiteSetting.default_theme_id)
|
||||||
expect(theme.color_scheme.base_scheme_id).to eq('Dark')
|
expect(theme.color_scheme.base_scheme_id).to eq('Dark')
|
||||||
end
|
end
|
||||||
@ -199,14 +198,13 @@ describe Wizard::StepUpdater do
|
|||||||
theme.set_default!
|
theme.set_default!
|
||||||
end
|
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
|
it "should update the color scheme of the default theme" do
|
||||||
updater = wizard.create_updater('colors', theme_previews: 'Neutral')
|
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 }
|
expect { updater.update }.not_to change { Theme.count }
|
||||||
theme.reload
|
theme.reload
|
||||||
expect(theme.color_scheme.base_scheme_id).to eq('Neutral')
|
expect(theme.color_scheme.base_scheme_id).to eq('Neutral')
|
||||||
@ -220,7 +218,12 @@ describe Wizard::StepUpdater do
|
|||||||
|
|
||||||
context 'dark theme' do
|
context 'dark theme' do
|
||||||
it "creates the theme" do
|
it "creates the theme" do
|
||||||
updater = wizard.create_updater('colors', theme_previews: 'Dark')
|
updater = wizard.create_updater('styling',
|
||||||
|
color_scheme: 'Dark',
|
||||||
|
body_font: 'arial',
|
||||||
|
heading_font: 'arial',
|
||||||
|
homepage_style: 'latest'
|
||||||
|
)
|
||||||
|
|
||||||
expect { updater.update }.to change { Theme.count }.by(1)
|
expect { updater.update }.to change { Theme.count }.by(1)
|
||||||
|
|
||||||
@ -233,8 +236,11 @@ describe Wizard::StepUpdater do
|
|||||||
|
|
||||||
context 'light theme' do
|
context 'light theme' do
|
||||||
it "creates the theme" do
|
it "creates the theme" do
|
||||||
updater = wizard.create_updater('colors',
|
updater = wizard.create_updater('styling',
|
||||||
theme_previews: ColorScheme::LIGHT_THEME_ID
|
color_scheme: ColorScheme::LIGHT_THEME_ID,
|
||||||
|
body_font: 'arial',
|
||||||
|
heading_font: 'arial',
|
||||||
|
homepage_style: 'latest'
|
||||||
)
|
)
|
||||||
|
|
||||||
expect { updater.update }.to change { Theme.count }.by(1)
|
expect { updater.update }.to change { Theme.count }.by(1)
|
||||||
@ -253,10 +259,15 @@ describe Wizard::StepUpdater do
|
|||||||
context "without an existing scheme" do
|
context "without an existing scheme" do
|
||||||
it "creates the scheme" do
|
it "creates the scheme" do
|
||||||
ColorScheme.destroy_all
|
ColorScheme.destroy_all
|
||||||
updater = wizard.create_updater('colors', theme_previews: 'Dark')
|
updater = wizard.create_updater('styling',
|
||||||
|
color_scheme: 'Dark',
|
||||||
|
body_font: 'arial',
|
||||||
|
heading_font: 'arial',
|
||||||
|
homepage_style: 'latest'
|
||||||
|
)
|
||||||
updater.update
|
updater.update
|
||||||
expect(updater.success?).to eq(true)
|
expect(updater.success?).to eq(true)
|
||||||
expect(wizard.completed_steps?('colors')).to eq(true)
|
expect(wizard.completed_steps?('styling')).to eq(true)
|
||||||
|
|
||||||
color_scheme = ColorScheme.where(via_wizard: true).first
|
color_scheme = ColorScheme.where(via_wizard: true).first
|
||||||
expect(color_scheme).to be_present
|
expect(color_scheme).to be_present
|
||||||
@ -268,6 +279,35 @@ describe Wizard::StepUpdater do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
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).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')
|
||||||
|
|
||||||
|
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
|
context "logos step" do
|
||||||
it "updates the fields correctly" do
|
it "updates the fields correctly" do
|
||||||
upload = Fabricate(:upload)
|
upload = Fabricate(:upload)
|
||||||
@ -307,23 +347,6 @@ describe Wizard::StepUpdater do
|
|||||||
end
|
end
|
||||||
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
|
context "invites step" do
|
||||||
let(:invites) {
|
let(:invites) {
|
||||||
return [{ email: 'regular@example.com', role: 'regular' },
|
return [{ email: 'regular@example.com', role: 'regular' },
|
||||||
|
@ -41,12 +41,64 @@ describe Wizard::Builder do
|
|||||||
expect(invites_step.disabled).to be_truthy
|
expect(invites_step.disabled).to be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'fonts step' do
|
context 'styling step' do
|
||||||
let(:fonts_step) { wizard.steps.find { |s| s.id == 'fonts' } }
|
let(:styling_step) { wizard.steps.find { |s| s.id == 'styling' } }
|
||||||
let(:field) { fonts_step.fields.first }
|
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
|
it 'has the full list of available fonts' do
|
||||||
expect(field.choices.size).to eq(DiscourseFonts.fonts.size)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -155,57 +207,4 @@ describe Wizard::Builder do
|
|||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
@ -28,8 +28,13 @@ describe Admin::ColorSchemesController do
|
|||||||
get "/admin/color_schemes.json"
|
get "/admin/color_schemes.json"
|
||||||
|
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
schemes = response.parsed_body.map { |scheme| scheme["name"] }
|
scheme_names = response.parsed_body.map { |scheme| scheme["name"] }
|
||||||
expect(schemes).to include(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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -18,7 +18,8 @@ describe WizardSerializer do
|
|||||||
json = MultiJson.load(MultiJson.dump(serializer.as_json))
|
json = MultiJson.load(MultiJson.dump(serializer.as_json))
|
||||||
wjson = json['wizard']
|
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
|
end
|
||||||
|
|
||||||
it "should provide custom colors correctly" do
|
it "should provide custom colors correctly" do
|
||||||
@ -34,7 +35,7 @@ describe WizardSerializer do
|
|||||||
json = MultiJson.load(MultiJson.dump(serializer.as_json))
|
json = MultiJson.load(MultiJson.dump(serializer.as_json))
|
||||||
wjson = json['wizard']
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user