Skip to content

Commit

Permalink
FEATURE: Added settings/translations support to theme editor UI (#7026)
Browse files Browse the repository at this point in the history
- These advanced fields are hidden behind an 'advanced' button, so will not affect normal use
- The editor has been refactored into a component, and styling cleaned up so menu items do not overlap on small screens
- Styling has been added to indicate which fields are in use for a theme
- Icons have been added to identify which fields have errors
  • Loading branch information
davidtaylorhq committed Feb 19, 2019
1 parent 0616837 commit 05ee1d1
Show file tree
Hide file tree
Showing 9 changed files with 375 additions and 248 deletions.
96 changes: 96 additions & 0 deletions app/assets/javascripts/admin/components/admin-theme-editor.js.es6
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { default as computed } from "ember-addons/ember-computed-decorators";

export default Ember.Component.extend({
@computed("theme.targets", "onlyOverridden", "showAdvanced")
visibleTargets(targets, onlyOverridden, showAdvanced) {
return targets.filter(target => {
if (target.advanced && !showAdvanced) {
return false;
}
if (!onlyOverridden) {
return true;
}
return target.edited;
});
},

@computed("currentTargetName", "onlyOverridden", "theme.fields")
visibleFields(targetName, onlyOverridden, fields) {
fields = fields[targetName];
if (onlyOverridden) {
fields = fields.filter(field => field.edited);
}
return fields;
},

@computed("currentTargetName", "fieldName")
activeSectionMode(targetName, fieldName) {
if (["settings", "translations"].includes(targetName)) return "yaml";
return fieldName && fieldName.indexOf("scss") > -1 ? "scss" : "html";
},

@computed("fieldName", "currentTargetName", "theme")
activeSection: {
get(fieldName, target, model) {
return model.getField(target, fieldName);
},
set(value, fieldName, target, model) {
model.setField(target, fieldName, value);
return value;
}
},

@computed("fieldName", "currentTargetName")
editorId(fieldName, currentTarget) {
return fieldName + "|" + currentTarget;

This comment has been minimized.

Copy link
@jjaffeux

jjaffeux Feb 19, 2019

Contributor

you can use fmt() for this.

import { fmt } from "discourse/lib/computed";

editorId: fmt("fieldName", "currentTargetName", "%@|%@")
},

@computed("maximized")
maximizeIcon(maximized) {
return maximized ? "discourse-compress" : "discourse-expand";
},

@computed("currentTargetName", "theme.targets")
showAddField(currentTargetName, targets) {
return targets.find(t => t.name === currentTargetName).customNames;
},

@computed("currentTargetName", "fieldName", "theme.theme_fields.@each.error")
error(target, fieldName) {
return this.get("theme").getError(target, fieldName);
},

actions: {
toggleShowAdvanced() {
this.toggleProperty("showAdvanced");
},

toggleAddField() {
this.toggleProperty("addingField");
},

cancelAddField() {
this.set("addingField", false);
},

addField(name) {
if (!name) return;
name = name.replace(/\W/g, "");
this.get("theme").setField(this.get("currentTargetName"), name, "");
this.set("newFieldName", "");

This comment has been minimized.

Copy link
@jjaffeux

jjaffeux Feb 19, 2019

Contributor

You should group when possible with setProperties

this.set("addingField", false);
this.fieldAdded(this.get("currentTargetName"), name);
},

toggleMaximize: function() {
this.toggleProperty("maximized");
Ember.run.next(() => {

This comment has been minimized.

Copy link
@jjaffeux

jjaffeux Feb 19, 2019

Contributor

Ember.run.next(() => this.appEvents.trigger("ace:resize"));

this.appEvents.trigger("ace:resize");
});
},

onlyOverriddenChanged(value) {
this.onlyOverriddenChanged(value);
}
}
});
Original file line number Diff line number Diff line change
@@ -1,163 +1,28 @@
import { url } from "discourse/lib/computed";
import {
default as computed,
observes
} from "ember-addons/ember-computed-decorators";
import { default as computed } from "ember-addons/ember-computed-decorators";

export default Ember.Controller.extend({
section: null,
currentTarget: 0,
maximized: false,
previewUrl: url("model.id", "/admin/themes/%@/preview"),

showAdvanced: false,
editRouteName: "adminCustomizeThemes.edit",

targets: [
{ id: 0, name: "common" },
{ id: 1, name: "desktop" },
{ id: 2, name: "mobile" },
{ id: 3, name: "settings" },
{ id: 4, name: "translations" }
],

fieldsForTarget: function(target) {
const common = [
"scss",
"head_tag",
"header",
"after_header",
"body_tag",
"footer"
];
switch (target) {
case "common":
return [...common, "embedded_scss"];
case "desktop":
return common;
case "mobile":
return common;
case "settings":
return ["yaml"];
}
},

@computed("onlyOverridden")
showCommon() {
return this.shouldShow("common");
},

@computed("onlyOverridden")
showDesktop() {
return this.shouldShow("desktop");
},

@computed("onlyOverridden")
showMobile() {
return this.shouldShow("mobile");
},

@observes("onlyOverridden")
onlyOverriddenChanged() {
if (this.get("onlyOverridden")) {
if (
!this.get("model").hasEdited(
this.get("currentTargetName"),
this.get("fieldName")
)
) {
let target =
(this.get("showCommon") && "common") ||
(this.get("showDesktop") && "desktop") ||
(this.get("showMobile") && "mobile");

let fields = this.get("model.theme_fields");
let field = fields && fields.find(f => f.target === target);
this.replaceRoute(
this.get("editRouteName"),
this.get("model.id"),
target,
field && field.name
);
}
}
},

shouldShow(target) {
if (!this.get("onlyOverridden")) {
return true;
}
return this.get("model").hasEdited(target);
},
showRouteName: "adminCustomizeThemes.show",

setTargetName: function(name) {
const target = this.get("targets").find(t => t.name === name);
const target = this.get("model.targets").find(t => t.name === name);
this.set("currentTarget", target && target.id);
},

@computed("currentTarget")
currentTargetName(id) {
const target = this.get("targets").find(t => t.id === parseInt(id, 10));
const target = this.get("model.targets").find(
t => t.id === parseInt(id, 10)
);
return target && target.name;
},

@computed("fieldName")
activeSectionMode(fieldName) {
if (fieldName === "yaml") return "yaml";
return fieldName && fieldName.indexOf("scss") > -1 ? "scss" : "html";
},

@computed("currentTargetName", "fieldName", "saving")
error(target, fieldName) {
return this.get("model").getError(target, fieldName);
},

@computed("fieldName", "currentTargetName")
editorId(fieldName, currentTarget) {
return fieldName + "|" + currentTarget;
},

@computed("fieldName", "currentTargetName", "model")
activeSection: {
get(fieldName, target, model) {
return model.getField(target, fieldName);
},
set(value, fieldName, target, model) {
model.setField(target, fieldName, value);
return value;
}
},

@computed("currentTargetName", "onlyOverridden")
fields(target, onlyOverridden) {
let fields = this.fieldsForTarget(target);

if (onlyOverridden) {
const model = this.get("model");
const targetName = this.get("currentTargetName");
fields = fields.filter(name => model.hasEdited(targetName, name));
}

return fields.map(name => {
let hash = {
key: `admin.customize.theme.${name}.text`,
name: name
};

if (name.indexOf("_tag") > 0) {
hash.icon = "file-text-o";
}

hash.title = I18n.t(`admin.customize.theme.${name}.title`);

return hash;
});
},

@computed("maximized")
maximizeIcon(maximized) {
return maximized ? "discourse-compress" : "discourse-expand";
},

@computed("model.isSaving")
saveButtonText(isSaving) {
return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save");
Expand All @@ -178,11 +43,36 @@ export default Ember.Controller.extend({
});
},

toggleMaximize: function() {
this.toggleProperty("maximized");
Ember.run.next(() => {
this.appEvents.trigger("ace:resize");
});
fieldAdded(target, name) {
this.replaceRoute(
this.get("editRouteName"),
this.get("model.id"),
target,
name
);
},

onlyOverriddenChanged(onlyShowOverridden) {
if (onlyShowOverridden) {
if (
!this.get("model").hasEdited(
this.get("currentTargetName"),
this.get("fieldName")
)
) {
let firstTarget = this.get("model.targets").find(t => t.edited);
let firstField = this.get(`model.fields.${firstTarget.name}`).find(
f => f.edited
);

this.replaceRoute(
this.get("editRouteName"),
this.get("model.id"),
firstTarget.name,
firstField.name
);
}
}
}
}
});
Loading

1 comment on commit 05ee1d1

@davidtaylorhq
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.