FEATURE: Added settings/translations support to theme editor UI (#7026)
- 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
This commit is contained in:
parent
0616837a5d
commit
05ee1d1aba
|
@ -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;
|
||||
},
|
||||
|
||||
@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.set("addingField", false);
|
||||
this.fieldAdded(this.get("currentTargetName"), name);
|
||||
},
|
||||
|
||||
toggleMaximize: function() {
|
||||
this.toggleProperty("maximized");
|
||||
Ember.run.next(() => {
|
||||
this.appEvents.trigger("ace:resize");
|
||||
});
|
||||
},
|
||||
|
||||
onlyOverriddenChanged(value) {
|
||||
this.onlyOverriddenChanged(value);
|
||||
}
|
||||
}
|
||||
});
|
|
@ -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");
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -9,11 +9,87 @@ export const COMPONENTS = "components";
|
|||
const SETTINGS_TYPE_ID = 5;
|
||||
|
||||
const Theme = RestModel.extend({
|
||||
FIELDS_IDS: [0, 1],
|
||||
FIELDS_IDS: [0, 1, 5],
|
||||
isActive: Ember.computed.or("default", "user_selectable"),
|
||||
isPendingUpdates: Ember.computed.gt("remote_theme.commits_behind", 0),
|
||||
hasEditedFields: Ember.computed.gt("editedFields.length", 0),
|
||||
|
||||
@computed("theme_fields.[]")
|
||||
targets() {
|
||||
return [
|
||||
{ id: 0, name: "common" },
|
||||
{ id: 1, name: "desktop", icon: "desktop" },
|
||||
{ id: 2, name: "mobile", icon: "mobile-alt" },
|
||||
{ id: 3, name: "settings", icon: "cog", advanced: true },
|
||||
{
|
||||
id: 4,
|
||||
name: "translations",
|
||||
icon: "globe",
|
||||
advanced: true,
|
||||
customNames: true
|
||||
}
|
||||
].map(target => {
|
||||
target["edited"] = this.hasEdited(target.name);
|
||||
target["error"] = this.hasError(target.name);
|
||||
return target;
|
||||
});
|
||||
},
|
||||
|
||||
@computed("theme_fields.[]")
|
||||
fieldNames() {
|
||||
const common = [
|
||||
"scss",
|
||||
"head_tag",
|
||||
"header",
|
||||
"after_header",
|
||||
"body_tag",
|
||||
"footer"
|
||||
];
|
||||
|
||||
return {
|
||||
common: [...common, "embedded_scss"],
|
||||
desktop: common,
|
||||
mobile: common,
|
||||
settings: ["yaml"],
|
||||
translations: [
|
||||
"en",
|
||||
...(this.get("theme_fields") || [])
|
||||
.filter(f => f.target === "translations" && f.name !== "en")
|
||||
.map(f => f.name)
|
||||
]
|
||||
};
|
||||
},
|
||||
|
||||
@computed("fieldNames", "theme_fields.@each.error")
|
||||
fields(fieldNames) {
|
||||
const hash = {};
|
||||
Object.keys(fieldNames).forEach(target => {
|
||||
hash[target] = fieldNames[target].map(fieldName => {
|
||||
const field = {
|
||||
name: fieldName,
|
||||
edited: this.hasEdited(target, fieldName),
|
||||
error: this.hasError(target, fieldName)
|
||||
};
|
||||
|
||||
if (target === "translations") {
|
||||
field.translatedName = fieldName;
|
||||
} else {
|
||||
field.translatedName = I18n.t(
|
||||
`admin.customize.theme.${fieldName}.text`
|
||||
);
|
||||
field.title = I18n.t(`admin.customize.theme.${fieldName}.title`);
|
||||
}
|
||||
|
||||
if (fieldName.indexOf("_tag") > 0) {
|
||||
field.icon = "far-file-alt";
|
||||
}
|
||||
|
||||
return field;
|
||||
});
|
||||
});
|
||||
return hash;
|
||||
},
|
||||
|
||||
@computed("theme_fields")
|
||||
themeFields(fields) {
|
||||
if (!fields) {
|
||||
|
@ -76,6 +152,14 @@ const Theme = RestModel.extend({
|
|||
}
|
||||
},
|
||||
|
||||
hasError(target, name) {
|
||||
return this.get("theme_fields")
|
||||
.filter(f => {
|
||||
return f.target === target && (!name || name === f.name);
|
||||
})
|
||||
.any(f => f.error);
|
||||
},
|
||||
|
||||
getError(target, name) {
|
||||
let themeFields = this.get("themeFields");
|
||||
let key = this.getKey({ target, name });
|
||||
|
@ -114,7 +198,7 @@ const Theme = RestModel.extend({
|
|||
existing.value = value;
|
||||
existing.upload_id = upload_id;
|
||||
} else {
|
||||
fields.push(field);
|
||||
fields.pushObject(field);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -123,10 +207,15 @@ const Theme = RestModel.extend({
|
|||
let key = this.getKey({ target, name });
|
||||
let existingField = themeFields[key];
|
||||
if (!existingField) {
|
||||
this.theme_fields.push(field);
|
||||
this.theme_fields.pushObject(field);
|
||||
themeFields[key] = field;
|
||||
} else {
|
||||
existingField.value = value;
|
||||
if (Ember.isEmpty(value)) {
|
||||
this.theme_fields.removeObject(themeFields[key]);
|
||||
themeFields[key] = null;
|
||||
} else {
|
||||
existingField.value = value;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ export default Ember.Route.extend({
|
|||
},
|
||||
|
||||
setupController(controller, wrapper) {
|
||||
const fields = controller.fieldsForTarget(wrapper.target);
|
||||
const fields = wrapper.model.get("fields")[wrapper.target].map(f => f.name);
|
||||
if (!fields.includes(wrapper.field_name)) {
|
||||
this.transitionTo(
|
||||
"adminCustomizeThemes.edit",
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
<div class='edit-main-nav admin-controls'>
|
||||
<nav>
|
||||
<ul class='nav nav-pills target'>
|
||||
{{#each visibleTargets as |target|}}
|
||||
<li>
|
||||
{{#link-to editRouteName
|
||||
theme.id
|
||||
target.name
|
||||
fieldName
|
||||
replace=true
|
||||
title=field.title
|
||||
class=(if target.edited 'edited' 'blank')
|
||||
}}
|
||||
{{#if target.error}}{{d-icon 'exclamation-triangle'}}{{/if}}
|
||||
{{#if target.icon}}
|
||||
{{d-icon target.icon}}
|
||||
{{/if}}
|
||||
{{i18n (concat 'admin.customize.theme.' target.name)}}
|
||||
{{/link-to}}
|
||||
</li>
|
||||
{{/each}}
|
||||
<li>
|
||||
<a {{action "toggleShowAdvanced"}}
|
||||
class='no-text'
|
||||
title="{{i18n (concat "admin.customize.theme." (if showAdvanced "hide_advanced" "show_advanced"))}}"
|
||||
>
|
||||
{{#if showAdvanced}}
|
||||
{{d-icon "angle-double-left"}}
|
||||
{{else}}
|
||||
{{d-icon "angle-double-right"}}
|
||||
{{/if}}
|
||||
</a>
|
||||
</li>
|
||||
<li class="spacer"></li>
|
||||
<li>
|
||||
<label>
|
||||
{{input type="checkbox" checked=onlyOverridden click=(action "onlyOverriddenChanged" value="target.checked")}}
|
||||
{{i18n 'admin.customize.theme.hide_unused_fields'}}
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class='admin-controls'>
|
||||
<nav>
|
||||
<ul class='nav nav-pills fields'>
|
||||
{{#each visibleFields as |field|}}
|
||||
<li>
|
||||
{{#link-to editRouteName
|
||||
theme.id
|
||||
currentTargetName
|
||||
field.name
|
||||
replace=true
|
||||
title=field.title
|
||||
class=(if field.edited 'edited' 'blank')
|
||||
}}
|
||||
{{#if field.error}}{{d-icon 'exclamation-triangle'}}{{/if}}
|
||||
{{#if field.icon}}{{d-icon field.icon}}{{/if}}
|
||||
{{field.translatedName}}
|
||||
|
||||
{{/link-to}}
|
||||
</li>
|
||||
{{/each}}
|
||||
|
||||
{{#if showAddField}}
|
||||
<li>
|
||||
{{#if addingField}}
|
||||
{{input type=text value=newFieldName enter=(action 'addField') escape-press=(action "cancelAddField")}}
|
||||
{{d-button class="ok" action=(action "addField" newFieldName) icon="check"}}
|
||||
{{d-button class="cancel" action=(action "cancelAddField") icon="times"}}
|
||||
{{else}}
|
||||
<a {{action "toggleAddField" currentTargetName}} class="no-text">
|
||||
{{d-icon "plus"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/if}}
|
||||
<li class='spacer'></li>
|
||||
<li>
|
||||
<a {{action "toggleMaximize"}} class="no-text">
|
||||
{{d-icon maximizeIcon}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
{{#if error}}
|
||||
<pre class='field-error'>{{error}}</pre>
|
||||
{{/if}}
|
||||
|
||||
{{ace-editor content=activeSection editorId=editorId mode=activeSectionMode autofocus="true"}}
|
|
@ -1,66 +1,17 @@
|
|||
<div class="current-style {{if maximized 'maximized'}}">
|
||||
<div class='wrapper'>
|
||||
<h2>{{i18n 'admin.customize.theme.edit_css_html'}} {{#link-to 'adminCustomizeThemes.show' model.id replace=true}}{{model.name}}{{/link-to}}</h2>
|
||||
|
||||
{{#if error}}
|
||||
<pre class='field-error'>{{error}}</pre>
|
||||
{{/if}}
|
||||
|
||||
<div class='edit-main-nav'>
|
||||
<ul class='nav nav-pills target'>
|
||||
{{#if showCommon}}
|
||||
<li>
|
||||
{{#link-to 'adminCustomizeThemes.edit' model.id 'common' fieldName replace=true}}
|
||||
{{i18n 'admin.customize.theme.common'}}
|
||||
{{/link-to}}
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if showDesktop}}
|
||||
<li>
|
||||
{{#link-to 'adminCustomizeThemes.edit' model.id 'desktop' fieldName replace=true}}
|
||||
{{i18n 'admin.customize.theme.desktop'}}
|
||||
{{d-icon 'desktop'}}
|
||||
{{/link-to}}
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if showMobile}}
|
||||
<li class='mobile'>
|
||||
{{#link-to 'adminCustomizeThemes.edit' model.id 'mobile' fieldName replace=true}}
|
||||
{{i18n 'admin.customize.theme.mobile'}}
|
||||
{{d-icon 'mobile'}}
|
||||
{{/link-to}}
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
<div class='show-overidden'>
|
||||
<label>
|
||||
{{input type="checkbox" checked=onlyOverridden}}
|
||||
{{i18n 'admin.settings.show_overriden'}}
|
||||
</label>
|
||||
</div>
|
||||
<div class='clearfix'></div>
|
||||
</div>
|
||||
|
||||
<div class='admin-controls'>
|
||||
<ul class='nav nav-pills fields'>
|
||||
{{#each fields as |field|}}
|
||||
<li>
|
||||
{{#link-to 'adminCustomizeThemes.edit' model.id currentTargetName field.name replace=true title=field.title}}
|
||||
{{#if field.icon}}{{d-icon field.icon}} {{/if}}
|
||||
{{i18n field.key}}
|
||||
{{/link-to}}
|
||||
</li>
|
||||
{{/each}}
|
||||
<li class='toggle-maximize'>
|
||||
<a {{action "toggleMaximize"}}>
|
||||
{{d-icon maximizeIcon}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{{ace-editor content=activeSection editorId=editorId mode=activeSectionMode autofocus="true"}}
|
||||
<h2>{{i18n 'admin.customize.theme.edit_css_html'}} {{#link-to showRouteName model.id replace=true}}{{model.name}}{{/link-to}}</h2>
|
||||
|
||||
{{admin-theme-editor
|
||||
theme=model
|
||||
editRouteName=editRouteName
|
||||
currentTargetName=currentTargetName
|
||||
fieldName=fieldName
|
||||
fieldAdded=(action 'fieldAdded')
|
||||
maximized=maximized
|
||||
onlyOverriddenChanged=(action 'onlyOverriddenChanged')
|
||||
}}
|
||||
|
||||
<div class='admin-footer'>
|
||||
<div class='status-actions'>
|
||||
{{#unless model.changed}}
|
||||
|
|
|
@ -91,18 +91,6 @@
|
|||
padding: 5px;
|
||||
}
|
||||
|
||||
.edit-main-nav {
|
||||
.nav-pills:after,
|
||||
.nav-pills:before {
|
||||
display: inline;
|
||||
content: "";
|
||||
}
|
||||
.show-overidden {
|
||||
float: right;
|
||||
}
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.admin-container {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
|
@ -390,9 +378,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.nav-pills.fields {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.content-list,
|
||||
.current-style {
|
||||
float: left;
|
||||
|
@ -407,34 +392,50 @@
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.nav.target {
|
||||
margin-top: 15px;
|
||||
|
||||
li {
|
||||
position: relative;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.fa {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.d-icon-mobile {
|
||||
position: relative;
|
||||
top: -3px;
|
||||
font-size: $font-up-3;
|
||||
max-height: 20px;
|
||||
}
|
||||
.edit-main-nav .nav-pills > li a.active {
|
||||
background-color: $quaternary;
|
||||
color: $secondary;
|
||||
}
|
||||
|
||||
.toggle-maximize {
|
||||
position: absolute;
|
||||
right: -5px;
|
||||
.edit-main-nav ul {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.nav-pills {
|
||||
li {
|
||||
margin-right: 0;
|
||||
display: flex;
|
||||
|
||||
&.spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
&:last-of-type > a {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
a.no-text .d-icon {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
padding: 6px 12px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
a.blank:not(.active) {
|
||||
color: $primary-medium;
|
||||
}
|
||||
|
||||
input {
|
||||
margin-bottom: 0;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ace-wrapper {
|
||||
|
|
|
@ -3344,7 +3344,11 @@ en:
|
|||
desktop: "Desktop"
|
||||
mobile: "Mobile"
|
||||
settings: "Settings"
|
||||
translations: "Translations"
|
||||
preview: "Preview"
|
||||
show_advanced: "Show advanced fields"
|
||||
hide_advanced: "Hide advanced fields"
|
||||
hide_unused_fields: "Hide unused fields"
|
||||
is_default: "Theme is enabled by default"
|
||||
user_selectable: "Theme can be selected by users"
|
||||
color_scheme: "Color Palette"
|
||||
|
|
|
@ -9,6 +9,8 @@ module SvgSprite
|
|||
"anchor",
|
||||
"angle-double-down",
|
||||
"angle-double-up",
|
||||
"angle-double-right",
|
||||
"angle-double-left",
|
||||
"angle-down",
|
||||
"angle-right",
|
||||
"angle-up",
|
||||
|
|
Loading…
Reference in New Issue