mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-25 23:21:58 +08:00
This commit removes the color palette dropdown from the theme page and replaces it with a new "Colors" tab where the theme's color palette can be edited directly in that tab on the theme page. With this change, a theme's color palette is strongly tied to its theme and can't be linked to other themes and it can't be selected by users without using the theme as well. All of the changes are behind a feature flag. To enable it, turn on the `use_overhauled_theme_color_palette` setting. Co-authored-by: Ella <ella.estigoy@gmail.com>
440 lines
12 KiB
JavaScript
Vendored
440 lines
12 KiB
JavaScript
Vendored
import Controller from "@ember/controller";
|
|
import { action } from "@ember/object";
|
|
import {
|
|
empty,
|
|
filterBy,
|
|
mapBy,
|
|
notEmpty,
|
|
readOnly,
|
|
} from "@ember/object/computed";
|
|
import { service } from "@ember/service";
|
|
import { ajax } from "discourse/lib/ajax";
|
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
|
import { url } from "discourse/lib/computed";
|
|
import discourseComputed from "discourse/lib/decorators";
|
|
import { makeArray } from "discourse/lib/helpers";
|
|
import { i18n } from "discourse-i18n";
|
|
import ThemeSettingsEditor from "admin/components/theme-settings-editor";
|
|
import SiteSetting from "admin/models/site-setting";
|
|
import { COMPONENTS, THEMES } from "admin/models/theme";
|
|
import ThemeSettings from "admin/models/theme-settings";
|
|
import ThemeUploadAddModal from "../components/theme-upload-add";
|
|
|
|
const THEME_UPLOAD_VAR = 2;
|
|
|
|
export default class AdminCustomizeThemesShowIndexController extends Controller {
|
|
@service dialog;
|
|
@service router;
|
|
@service siteSettings;
|
|
@service modal;
|
|
|
|
editRouteName = "adminCustomizeThemes.edit";
|
|
|
|
@url("model.id", "/admin/customize/themes/%@/export") downloadUrl;
|
|
@url("model.id", "/admin/themes/%@/preview") previewUrl;
|
|
@url("model.id", "model.locale", "/admin/themes/%@/translations/%@")
|
|
getTranslationsUrl;
|
|
@empty("selectedChildThemeId") addButtonDisabled;
|
|
@mapBy("model.parentThemes", "name") parentThemesNames;
|
|
@filterBy("allThemes", "component", false) availableParentThemes;
|
|
@filterBy("availableParentThemes", "isActive") availableActiveParentThemes;
|
|
@mapBy("availableParentThemes", "name") availableThemesNames;
|
|
@mapBy("availableActiveParentThemes", "name") availableActiveThemesNames;
|
|
@filterBy("availableChildThemes", "hasParents") availableActiveChildThemes;
|
|
@mapBy("availableChildThemes", "name") availableComponentsNames;
|
|
@mapBy("availableActiveChildThemes", "name") availableActiveComponentsNames;
|
|
@mapBy("model.childThemes", "name") childThemesNames;
|
|
@filterBy("model.theme_fields", "target", "extra_js") extraFiles;
|
|
@notEmpty("settings") hasSettings;
|
|
@notEmpty("translations") hasTranslations;
|
|
@readOnly("model.settings") settings;
|
|
|
|
@discourseComputed("model.component", "model.remote_theme")
|
|
showCheckboxes() {
|
|
return !this.model.component || this.model.remote_theme;
|
|
}
|
|
|
|
@discourseComputed("model.editedFields")
|
|
editedFieldsFormatted() {
|
|
const descriptions = [];
|
|
["common", "desktop", "mobile"].forEach((target) => {
|
|
const fields = this.editedFieldsForTarget(target);
|
|
if (fields.length < 1) {
|
|
return;
|
|
}
|
|
let resultString = i18n("admin.customize.theme." + target);
|
|
const formattedFields = fields
|
|
.map((f) => i18n("admin.customize.theme." + f.name + ".text"))
|
|
.join(" , ");
|
|
resultString += `: ${formattedFields}`;
|
|
descriptions.push(resultString);
|
|
});
|
|
return descriptions;
|
|
}
|
|
|
|
@discourseComputed("colorSchemeId", "model.color_scheme_id")
|
|
colorSchemeChanged(colorSchemeId, existingId) {
|
|
colorSchemeId = colorSchemeId === null ? null : parseInt(colorSchemeId, 10);
|
|
return colorSchemeId !== existingId;
|
|
}
|
|
|
|
@discourseComputed("availableChildThemes", "model.childThemes.[]", "model")
|
|
selectableChildThemes(available, childThemes) {
|
|
if (available) {
|
|
const themes = !childThemes
|
|
? available
|
|
: available.filter((theme) => !childThemes.includes(theme));
|
|
return themes.length === 0 ? null : themes;
|
|
}
|
|
}
|
|
|
|
@discourseComputed("model.parentThemes.[]")
|
|
relativesSelectorSettingsForComponent() {
|
|
return SiteSetting.create({
|
|
list_type: "compact",
|
|
type: "list",
|
|
preview: null,
|
|
allow_any: false,
|
|
setting: "parent_theme_ids",
|
|
label: i18n("admin.customize.theme.component_on_themes"),
|
|
choices: this.availableThemesNames,
|
|
default: this.parentThemesNames.join("|"),
|
|
value: this.parentThemesNames.join("|"),
|
|
defaultValues: this.availableActiveThemesNames.join("|"),
|
|
allThemes: this.allThemes,
|
|
setDefaultValuesLabel: i18n("admin.customize.theme.add_all_themes"),
|
|
});
|
|
}
|
|
|
|
@discourseComputed("model.childThemesNames.[]")
|
|
relativesSelectorSettingsForTheme() {
|
|
return SiteSetting.create({
|
|
list_type: "compact",
|
|
type: "list",
|
|
preview: null,
|
|
allow_any: false,
|
|
setting: "child_theme_ids",
|
|
label: i18n("admin.customize.theme.included_components"),
|
|
choices: this.availableComponentsNames,
|
|
default: this.childThemesNames.join("|"),
|
|
value: this.childThemesNames.join("|"),
|
|
defaultValues: this.availableActiveComponentsNames.join("|"),
|
|
allThemes: this.allThemes,
|
|
setDefaultValuesLabel: i18n("admin.customize.theme.add_all"),
|
|
});
|
|
}
|
|
|
|
@discourseComputed("allThemes", "model.component", "model")
|
|
availableChildThemes(allThemes) {
|
|
if (!this.get("model.component")) {
|
|
const themeId = this.get("model.id");
|
|
return allThemes.filter(
|
|
(theme) => theme.get("id") !== themeId && theme.get("component")
|
|
);
|
|
}
|
|
}
|
|
|
|
@discourseComputed("model.component")
|
|
convertKey(component) {
|
|
const type = component ? "component" : "theme";
|
|
return `admin.customize.theme.convert_${type}`;
|
|
}
|
|
|
|
@discourseComputed("model.component")
|
|
convertIcon(component) {
|
|
return component ? "cube" : "";
|
|
}
|
|
|
|
@discourseComputed("model.component")
|
|
convertTooltip(component) {
|
|
const type = component ? "component" : "theme";
|
|
return `admin.customize.theme.convert_${type}_tooltip`;
|
|
}
|
|
|
|
@discourseComputed("model.translations")
|
|
translations(translations) {
|
|
return translations.map((setting) =>
|
|
ThemeSettings.create({ ...setting, textarea: true })
|
|
);
|
|
}
|
|
|
|
@discourseComputed(
|
|
"model.remote_theme.local_version",
|
|
"model.remote_theme.remote_version",
|
|
"model.remote_theme.commits_behind"
|
|
)
|
|
hasOverwrittenHistory(localVersion, remoteVersion, commitsBehind) {
|
|
return localVersion !== remoteVersion && commitsBehind === -1;
|
|
}
|
|
|
|
@discourseComputed("model.remoteError", "updatingRemote")
|
|
showRemoteError(errorMessage, updating) {
|
|
return errorMessage && !updating;
|
|
}
|
|
|
|
editedFieldsForTarget(target) {
|
|
return this.get("model.editedFields").filter(
|
|
(field) => field.target === target
|
|
);
|
|
}
|
|
|
|
commitSwitchType() {
|
|
const model = this.model;
|
|
const newValue = !model.get("component");
|
|
model.set("component", newValue);
|
|
|
|
if (newValue) {
|
|
this.set("parentController.currentTab", COMPONENTS);
|
|
} else {
|
|
this.set("parentController.currentTab", THEMES);
|
|
}
|
|
|
|
model
|
|
.saveChanges("component")
|
|
.then(() => {
|
|
this.set("colorSchemeId", null);
|
|
|
|
model.setProperties({
|
|
default: false,
|
|
color_scheme_id: null,
|
|
user_selectable: false,
|
|
child_themes: [],
|
|
childThemes: [],
|
|
});
|
|
|
|
this.get("parentController.model.content").forEach((theme) => {
|
|
const children = makeArray(theme.get("childThemes"));
|
|
const rawChildren = makeArray(theme.get("child_themes"));
|
|
const index = children ? children.indexOf(model) : -1;
|
|
if (index > -1) {
|
|
children.splice(index, 1);
|
|
rawChildren.splice(index, 1);
|
|
theme.setProperties({
|
|
childThemes: children,
|
|
child_themes: rawChildren,
|
|
});
|
|
}
|
|
});
|
|
})
|
|
.catch(popupAjaxError);
|
|
}
|
|
|
|
transitionToEditRoute() {
|
|
this.router.transitionTo(
|
|
this.editRouteName,
|
|
this.get("model.id"),
|
|
"common",
|
|
"scss"
|
|
);
|
|
}
|
|
|
|
@discourseComputed("model.user.id", "model.default")
|
|
showConvert(userId, defaultTheme) {
|
|
return userId > 0 && !defaultTheme;
|
|
}
|
|
|
|
@action
|
|
refreshModel() {
|
|
this.send("routeRefreshModel");
|
|
}
|
|
|
|
@action
|
|
updateToLatest() {
|
|
this.set("updatingRemote", true);
|
|
this.model
|
|
.updateToLatest()
|
|
.catch(popupAjaxError)
|
|
.finally(() => {
|
|
this.set("updatingRemote", false);
|
|
});
|
|
}
|
|
|
|
@action
|
|
checkForThemeUpdates() {
|
|
this.set("updatingRemote", true);
|
|
this.model
|
|
.checkForUpdates()
|
|
.catch(popupAjaxError)
|
|
.finally(() => {
|
|
this.set("updatingRemote", false);
|
|
});
|
|
}
|
|
|
|
@action
|
|
addUploadModal() {
|
|
this.modal.show(ThemeUploadAddModal, {
|
|
model: {
|
|
themeFields: this.model.theme_fields,
|
|
addUpload: this.addUpload,
|
|
},
|
|
});
|
|
}
|
|
|
|
@action
|
|
addUpload(info) {
|
|
let model = this.model;
|
|
model.setField("common", info.name, "", info.upload_id, THEME_UPLOAD_VAR);
|
|
model.saveChanges("theme_fields").catch((e) => popupAjaxError(e));
|
|
}
|
|
|
|
get availableLocales() {
|
|
return JSON.parse(this.siteSettings.available_locales);
|
|
}
|
|
|
|
get locale() {
|
|
return (
|
|
this.get("model.locale") ||
|
|
this.userLocale ||
|
|
this.siteSettings.default_locale
|
|
);
|
|
}
|
|
|
|
@action
|
|
updateLocale(value) {
|
|
this.set("model.loadingTranslations", true);
|
|
this.set("model.locale", value);
|
|
ajax(this.getTranslationsUrl).then(({ translations }) => {
|
|
this.set("model.translations", translations);
|
|
this.set("model.loadingTranslations", false);
|
|
});
|
|
}
|
|
|
|
@action
|
|
cancelChangeScheme() {
|
|
this.set("colorSchemeId", this.get("model.color_scheme_id"));
|
|
}
|
|
|
|
@action
|
|
changeScheme() {
|
|
let schemeId = this.colorSchemeId;
|
|
this.set(
|
|
"model.color_scheme_id",
|
|
schemeId === null ? null : parseInt(schemeId, 10)
|
|
);
|
|
this.model.saveChanges("color_scheme_id");
|
|
}
|
|
|
|
@action
|
|
editTheme() {
|
|
if (this.get("model.remote_theme.is_git")) {
|
|
this.dialog.confirm({
|
|
message: i18n("admin.customize.theme.edit_confirm"),
|
|
didConfirm: () => this.transitionToEditRoute(),
|
|
});
|
|
} else {
|
|
this.transitionToEditRoute();
|
|
}
|
|
}
|
|
|
|
@action
|
|
applyDefault() {
|
|
const model = this.model;
|
|
model.saveChanges("default").then(() => {
|
|
if (model.get("default")) {
|
|
this.allThemes.forEach((theme) => {
|
|
if (theme !== model && theme.get("default")) {
|
|
theme.set("default", false);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
@action
|
|
applyUserSelectable() {
|
|
this.model.saveChanges("user_selectable");
|
|
}
|
|
|
|
@action
|
|
applyAutoUpdateable() {
|
|
this.model.saveChanges("auto_update");
|
|
}
|
|
|
|
@action
|
|
addChildTheme() {
|
|
let themeId = parseInt(this.selectedChildThemeId, 10);
|
|
let theme = this.allThemes.findBy("id", themeId);
|
|
this.model.addChildTheme(theme).then(() => this.store.findAll("theme"));
|
|
}
|
|
|
|
@action
|
|
removeUpload(upload) {
|
|
return this.dialog.deleteConfirm({
|
|
title: i18n("admin.customize.theme.delete_upload_confirm"),
|
|
didConfirm: () => this.model.removeField(upload),
|
|
});
|
|
}
|
|
|
|
@action
|
|
removeChildTheme(theme) {
|
|
this.model.removeChildTheme(theme).then(() => this.store.findAll("theme"));
|
|
}
|
|
|
|
@action
|
|
destroyTheme() {
|
|
return this.dialog.deleteConfirm({
|
|
title: i18n("admin.customize.delete_confirm", {
|
|
theme_name: this.get("model.name"),
|
|
}),
|
|
didConfirm: () => {
|
|
const model = this.model;
|
|
model.setProperties({ recentlyInstalled: false });
|
|
model.destroyRecord().then(() => {
|
|
this.allThemes.removeObject(model);
|
|
this.router.transitionTo("adminConfig.customize.themes");
|
|
});
|
|
},
|
|
});
|
|
}
|
|
|
|
@action
|
|
showThemeSettingsEditor() {
|
|
this.dialog.alert({
|
|
title: "Edit Settings",
|
|
bodyComponent: ThemeSettingsEditor,
|
|
bodyComponentModel: { model: this.model, controller: this },
|
|
class: "theme-settings-editor-dialog",
|
|
});
|
|
}
|
|
|
|
@action
|
|
switchType() {
|
|
const relatives = this.get("model.component")
|
|
? this.get("model.parentThemes")
|
|
: this.get("model.childThemes");
|
|
|
|
let message = i18n(`${this.convertKey}_alert_generic`);
|
|
|
|
if (relatives && relatives.length > 0) {
|
|
message = i18n(`${this.convertKey}_alert`, {
|
|
relatives: relatives.map((relative) => relative.get("name")).join(", "),
|
|
});
|
|
}
|
|
|
|
return this.dialog.yesNoConfirm({
|
|
message,
|
|
didConfirm: () => this.commitSwitchType(),
|
|
});
|
|
}
|
|
|
|
@action
|
|
enableComponent() {
|
|
this.model.set("enabled", true);
|
|
this.model
|
|
.saveChanges("enabled")
|
|
.catch(() => this.model.set("enabled", false));
|
|
}
|
|
|
|
@action
|
|
disableComponent() {
|
|
this.model.set("enabled", false);
|
|
this.model
|
|
.saveChanges("enabled")
|
|
.catch(() => this.model.set("enabled", true));
|
|
}
|
|
|
|
@action
|
|
editColorScheme() {
|
|
this.router.transitionTo("adminCustomize.colors.show", this.colorSchemeId);
|
|
}
|
|
}
|