mirror of
https://github.com/discourse/discourse.git
synced 2025-10-03 17:21:20 +08:00
DEV: Remove dual mode support for palettes and drop theme-owned palettes (#34467)
We're not going to finish/release dual-mode palettes and theme-owned palettes at this time, so we're cleaning up the code that we've already merged for these features. Internal topic: t/161279.
This commit is contained in:
parent
5cfda47b25
commit
7ee52c8f85
45 changed files with 208 additions and 1107 deletions
|
@ -186,33 +186,16 @@ export default class AdminConfigAreasColorPalette extends Component {
|
|||
return;
|
||||
}
|
||||
|
||||
const tags = document.querySelectorAll(`link[data-scheme-id="${id}"]`);
|
||||
const tag = document.querySelector(`link[data-scheme-id="${id}"]`);
|
||||
|
||||
if (tags.length === 0) {
|
||||
if (!tag) {
|
||||
return;
|
||||
}
|
||||
|
||||
let darkTag;
|
||||
let lightTag;
|
||||
for (const tag of tags) {
|
||||
if (tag.classList.contains("dark-scheme")) {
|
||||
darkTag = tag;
|
||||
} else if (tag.classList.contains("light-scheme")) {
|
||||
lightTag = tag;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await ajax(`/color-scheme-stylesheet/${id}.json`, {
|
||||
data: {
|
||||
include_dark_scheme: !!darkTag,
|
||||
},
|
||||
});
|
||||
if (data?.new_href && lightTag) {
|
||||
lightTag.href = data.new_href;
|
||||
}
|
||||
if (data?.new_dark_href && darkTag) {
|
||||
darkTag.href = data.new_dark_href;
|
||||
const data = await ajax(`/color-scheme-stylesheet/${id}.json`);
|
||||
if (data?.new_href) {
|
||||
tag.href = data.new_href;
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
import { tracked } from "@glimmer/tracking";
|
||||
import Controller from "@ember/controller";
|
||||
import { TrackedSet } from "@ember-compat/tracked-built-ins";
|
||||
|
||||
class ChangeTracker {
|
||||
@tracked dirtyLightColors = new TrackedSet();
|
||||
@tracked dirtyDarkColors = new TrackedSet();
|
||||
|
||||
addDirtyLightColor(name) {
|
||||
this.dirtyLightColors.add(name);
|
||||
}
|
||||
|
||||
addDirtyDarkColor(name) {
|
||||
this.dirtyDarkColors.add(name);
|
||||
}
|
||||
|
||||
removeDirtyLightColor(name) {
|
||||
this.dirtyLightColors.delete(name);
|
||||
}
|
||||
|
||||
removeDirtyDarkColor(name) {
|
||||
this.dirtyDarkColors.delete(name);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.dirtyLightColors.clear();
|
||||
this.dirtyDarkColors.clear();
|
||||
}
|
||||
|
||||
get dirtyColorsCount() {
|
||||
return this.dirtyLightColors.size + this.dirtyDarkColors.size;
|
||||
}
|
||||
}
|
||||
|
||||
export default class AdminCustomizeThemesShowColorsController extends Controller {
|
||||
colorPaletteChangeTracker = new ChangeTracker();
|
||||
}
|
|
@ -70,12 +70,7 @@ export async function applyColorScheme(scheme, options = {}) {
|
|||
|
||||
const apiUrl = `/color-scheme-stylesheet/${id}.json`;
|
||||
|
||||
const data = await ajax(apiUrl, {
|
||||
data: {
|
||||
include_dark_scheme: !!darkTag,
|
||||
},
|
||||
dataType: "json",
|
||||
});
|
||||
const data = await ajax(apiUrl);
|
||||
|
||||
if (data?.new_href && lightTag) {
|
||||
lightTag.href = data.new_href;
|
||||
|
@ -87,16 +82,6 @@ export async function applyColorScheme(scheme, options = {}) {
|
|||
}
|
||||
}
|
||||
|
||||
if (data?.new_dark_href && darkTag) {
|
||||
darkTag.href = data.new_dark_href;
|
||||
|
||||
if (replace && id) {
|
||||
darkTag.setAttribute("data-scheme-id", id);
|
||||
} else if (replace && !id) {
|
||||
darkTag.removeAttribute("data-scheme-id");
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
|
|
@ -7,10 +7,8 @@ import { i18n } from "discourse-i18n";
|
|||
|
||||
export default class ColorSchemeColor extends EmberObject {
|
||||
@tracked hex;
|
||||
@tracked dark_hex;
|
||||
|
||||
@tracked originalHex;
|
||||
@tracked originalDarkHex;
|
||||
|
||||
// Whether the current value is different than Discourse's default color scheme.
|
||||
@propertyNotEqual("hex", "default_hex") overridden;
|
||||
|
@ -18,19 +16,16 @@ export default class ColorSchemeColor extends EmberObject {
|
|||
init(object) {
|
||||
super.init(...arguments);
|
||||
this.originalHex = object.hex;
|
||||
this.originalDarkHex = object.dark_hex;
|
||||
}
|
||||
|
||||
discardColorChange() {
|
||||
this.hex = this.originalHex;
|
||||
this.dark_hex = this.originalDarkHex;
|
||||
}
|
||||
|
||||
@on("init")
|
||||
startTrackingChanges() {
|
||||
this.set("originals", {
|
||||
hex: this.hex || "FFFFFF",
|
||||
darkHex: this.dark_hex,
|
||||
});
|
||||
|
||||
// force changed property to be recalculated
|
||||
|
@ -38,18 +33,14 @@ export default class ColorSchemeColor extends EmberObject {
|
|||
}
|
||||
|
||||
// Whether value has changed since it was last saved.
|
||||
@discourseComputed("hex", "dark_hex")
|
||||
changed(hex, darkHex) {
|
||||
@discourseComputed("hex")
|
||||
changed(hex) {
|
||||
if (!this.originals) {
|
||||
return false;
|
||||
}
|
||||
if (hex !== this.originals.hex) {
|
||||
return true;
|
||||
}
|
||||
if (darkHex !== this.originals.darkHex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,15 +11,10 @@ import ColorSchemeColor from "admin/models/color-scheme-color";
|
|||
class ColorSchemes extends ArrayProxy {}
|
||||
|
||||
export default class ColorScheme extends EmberObject {
|
||||
static findAll({ excludeThemeOwned = false } = {}) {
|
||||
static findAll() {
|
||||
const colorSchemes = ColorSchemes.create({ content: [], loading: true });
|
||||
|
||||
const data = {};
|
||||
if (excludeThemeOwned) {
|
||||
data.exclude_theme_owned = true;
|
||||
}
|
||||
|
||||
return ajax("/admin/color_schemes", { data }).then((all) => {
|
||||
return ajax("/admin/color_schemes").then((all) => {
|
||||
all.forEach((colorScheme) => {
|
||||
colorSchemes.pushObject(
|
||||
ColorScheme.create({
|
||||
|
@ -89,14 +84,11 @@ export default class ColorScheme extends EmberObject {
|
|||
}
|
||||
|
||||
schemeObject() {
|
||||
const extractColors = (property) =>
|
||||
Object.fromEntries(
|
||||
this.colors.map((color) => [color.name, color[property]])
|
||||
);
|
||||
return {
|
||||
name: this.name,
|
||||
dark: extractColors("dark_hex"),
|
||||
light: extractColors("hex"),
|
||||
light: Object.fromEntries(
|
||||
this.colors.map((color) => [color.name, color.hex])
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -115,9 +107,7 @@ export default class ColorScheme extends EmberObject {
|
|||
});
|
||||
this.colors.forEach((c) => {
|
||||
newScheme.colors.pushObject(
|
||||
ColorSchemeColor.create(
|
||||
c.getProperties("name", "hex", "default_hex", "dark_hex")
|
||||
)
|
||||
ColorSchemeColor.create(c.getProperties("name", "hex", "default_hex"))
|
||||
);
|
||||
});
|
||||
return newScheme;
|
||||
|
@ -172,7 +162,7 @@ export default class ColorScheme extends EmberObject {
|
|||
data.colors = [];
|
||||
this.colors.forEach((c) => {
|
||||
if (!this.id || c.get("changed")) {
|
||||
data.colors.pushObject(c.getProperties("name", "hex", "dark_hex"));
|
||||
data.colors.pushObject(c.getProperties("name", "hex"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
import { tracked } from "@glimmer/tracking";
|
||||
import { get } from "@ember/object";
|
||||
import { gt, or } from "@ember/object/computed";
|
||||
import { isBlank, isEmpty } from "@ember/utils";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import discourseComputed from "discourse/lib/decorators";
|
||||
import RestModel from "discourse/models/rest";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import ColorScheme from "admin/models/color-scheme";
|
||||
import ThemeSettings from "admin/models/theme-settings";
|
||||
import ThemeSiteSettings from "admin/models/theme-site-settings";
|
||||
|
||||
|
@ -34,17 +31,9 @@ class Theme extends RestModel {
|
|||
);
|
||||
}
|
||||
|
||||
const palette =
|
||||
json.owned_color_palette || json.color_scheme || json.base_palette;
|
||||
if (palette) {
|
||||
json.colorPalette = ColorScheme.create(palette);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@tracked colorPalette;
|
||||
|
||||
@or("default", "user_selectable") isActive;
|
||||
@gt("remote_theme.commits_behind", 0) isPendingUpdates;
|
||||
@gt("editedFields.length", 0) hasEditedFields;
|
||||
|
@ -192,34 +181,6 @@ class Theme extends RestModel {
|
|||
return field ? field.error : "";
|
||||
}
|
||||
|
||||
async changeColors() {
|
||||
const colors = [];
|
||||
|
||||
for (const color of this.colorPalette.colors) {
|
||||
const colorPayload = {
|
||||
name: color.name,
|
||||
hex: color.hex,
|
||||
dark_hex: color.dark_hex,
|
||||
};
|
||||
|
||||
colors.push(colorPayload);
|
||||
}
|
||||
|
||||
const paletteData = await ajax(`/admin/themes/${this.id}/change-colors`, {
|
||||
type: "PUT",
|
||||
data: JSON.stringify({ colors }),
|
||||
contentType: "application/json",
|
||||
});
|
||||
this.owned_color_palette = paletteData;
|
||||
this.colorPalette = ColorScheme.create(paletteData);
|
||||
}
|
||||
|
||||
discardColorChanges() {
|
||||
for (const color of this.colorPalette.colors) {
|
||||
color.discardColorChange();
|
||||
}
|
||||
}
|
||||
|
||||
getField(target, name) {
|
||||
if (target === "common" && name === "js") {
|
||||
target = "extra_js";
|
||||
|
|
|
@ -3,6 +3,6 @@ import ColorScheme from "admin/models/color-scheme";
|
|||
|
||||
export default class AdminConfigColorPalettesRoute extends DiscourseRoute {
|
||||
model() {
|
||||
return ColorScheme.findAll({ excludeThemeOwned: true });
|
||||
return ColorScheme.findAll();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminCustomizeThemesShowColorsRoute extends DiscourseRoute {
|
||||
@service dialog;
|
||||
|
||||
@action
|
||||
willTransition(transition) {
|
||||
if (
|
||||
this.controller.colorPaletteChangeTracker.dirtyColorsCount > 0 &&
|
||||
transition.intent.name !== "adminCustomizeThemes.show.index"
|
||||
) {
|
||||
transition.abort();
|
||||
this.dialog.yesNoConfirm({
|
||||
message: i18n(
|
||||
"admin.customize.theme.unsaved_colors_leave_route_confirmation"
|
||||
),
|
||||
didConfirm: () => {
|
||||
this.controller.colorPaletteChangeTracker.clear();
|
||||
transition.retry();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
titleToken() {
|
||||
return i18n("admin.customize.theme.colors_title");
|
||||
}
|
||||
}
|
|
@ -69,7 +69,6 @@ export default function () {
|
|||
function () {
|
||||
this.route("show", { path: "/:theme_id" }, function () {
|
||||
this.route("schema", { path: "schema/:setting_name" });
|
||||
this.route("colors");
|
||||
});
|
||||
this.route("edit", { path: "/:theme_id/:target/:field_name/edit" });
|
||||
}
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { action } from "@ember/object";
|
||||
import RouteTemplate from "ember-route-template";
|
||||
import { gt } from "truth-helpers";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import ChangesBanner from "admin/components/changes-banner";
|
||||
import ColorPaletteEditor from "admin/components/color-palette-editor";
|
||||
|
||||
export default RouteTemplate(
|
||||
class extends Component {
|
||||
get pendingChangesBannerLabel() {
|
||||
return i18n("admin.customize.theme.unsaved_colors", {
|
||||
count: this.args.controller.colorPaletteChangeTracker.dirtyColorsCount,
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
onColorChange(color, value) {
|
||||
color.hex = value;
|
||||
if (color.hex !== color.originalHex) {
|
||||
this.args.controller.colorPaletteChangeTracker.addDirtyLightColor(
|
||||
color.name
|
||||
);
|
||||
} else {
|
||||
this.args.controller.colorPaletteChangeTracker.removeDirtyLightColor(
|
||||
color.name
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async save() {
|
||||
await this.args.model.changeColors();
|
||||
this.args.controller.colorPaletteChangeTracker.clear();
|
||||
}
|
||||
|
||||
@action
|
||||
discard() {
|
||||
this.args.model.discardColorChanges();
|
||||
this.args.controller.colorPaletteChangeTracker.clear();
|
||||
}
|
||||
|
||||
<template>
|
||||
<ColorPaletteEditor
|
||||
@colors={{@model.colorPalette.colors}}
|
||||
@onColorChange={{this.onColorChange}}
|
||||
@hideRevertButton={{true}}
|
||||
@system={{@model.system}}
|
||||
/>
|
||||
{{#if (gt @controller.colorPaletteChangeTracker.dirtyColorsCount 0)}}
|
||||
<ChangesBanner
|
||||
@bannerLabel={{this.pendingChangesBannerLabel}}
|
||||
@saveLabel={{i18n "admin.customize.theme.save_colors"}}
|
||||
@discardLabel={{i18n "admin.customize.theme.discard_colors"}}
|
||||
@save={{this.save}}
|
||||
@discard={{this.discard}}
|
||||
/>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
||||
);
|
|
@ -119,7 +119,6 @@ export default RouteTemplate(
|
|||
{{/if}}
|
||||
|
||||
{{#unless @controller.model.component}}
|
||||
{{#unless @controller.siteSettings.use_overhauled_theme_color_palette}}
|
||||
<section
|
||||
class="form-horizontal theme settings control-unit theme-settings__light-color-scheme"
|
||||
>
|
||||
|
@ -227,7 +226,6 @@ export default RouteTemplate(
|
|||
</div>
|
||||
</section>
|
||||
{{/unless}}
|
||||
{{/unless}}
|
||||
|
||||
{{#if @controller.model.component}}
|
||||
<section
|
||||
|
|
|
@ -2,8 +2,6 @@ import { LinkTo } from "@ember/routing";
|
|||
import { htmlSafe } from "@ember/template";
|
||||
import RouteTemplate from "ember-route-template";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DPageHeader from "discourse/components/d-page-header";
|
||||
import NavItem from "discourse/components/nav-item";
|
||||
import PluginOutlet from "discourse/components/plugin-outlet";
|
||||
import TextField from "discourse/components/text-field";
|
||||
import UserLink from "discourse/components/user-link";
|
||||
|
@ -250,27 +248,6 @@ export default RouteTemplate(
|
|||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if @controller.siteSettings.use_overhauled_theme_color_palette}}
|
||||
{{#unless @controller.model.component}}
|
||||
<DPageHeader>
|
||||
<:tabs>
|
||||
<NavItem
|
||||
class="admin-customize-theme-tabs__settings"
|
||||
@route="adminCustomizeThemes.show.index"
|
||||
@routeParam={{@controller.model.id}}
|
||||
@label="admin.customize.theme.settings"
|
||||
/>
|
||||
<NavItem
|
||||
class="admin-customize-theme-tabs__colors"
|
||||
@route="adminCustomizeThemes.show.colors"
|
||||
@routeParam={{@controller.model.id}}
|
||||
@label="admin.customize.theme.colors"
|
||||
/>
|
||||
</:tabs>
|
||||
</DPageHeader>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
||||
{{outlet}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -374,16 +374,6 @@ export default class AdminSidebarPanel extends BaseCustomSidebarPanel {
|
|||
]);
|
||||
}
|
||||
|
||||
if (siteSettings.use_overhauled_theme_color_palette) {
|
||||
this.adminNavManager.overrideSectionLink(
|
||||
"appearance",
|
||||
"admin_color_palettes",
|
||||
{
|
||||
route: "adminConfig.colorPalettes",
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
for (const [sectionName, additionalLinks] of Object.entries(
|
||||
additionalAdminSidebarSectionLinks
|
||||
)) {
|
||||
|
|
|
@ -57,7 +57,6 @@ acceptance("Admin - Customize - Themes - Show", function (needs) {
|
|||
"/uploads/default/original/1X/f8a61b9a0bfac672daec9e401787812f8c5e28df.png",
|
||||
system: true,
|
||||
color_scheme: null,
|
||||
owned_color_palette: null,
|
||||
user: {
|
||||
id: -1,
|
||||
username: "system",
|
||||
|
|
|
@ -13,328 +13,246 @@ const example_scheme = {
|
|||
hex: "F0ECD7",
|
||||
default_hex: "F0ECD7",
|
||||
is_advanced: true,
|
||||
dark_hex: "F0ECD7",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary_low",
|
||||
hex: "D6D8C7",
|
||||
default_hex: "D6D8C7",
|
||||
is_advanced: true,
|
||||
dark_hex: "D6D8C7",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary_low_mid",
|
||||
hex: "A4AFA5",
|
||||
default_hex: "A4AFA5",
|
||||
is_advanced: true,
|
||||
dark_hex: "A4AFA5",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary_medium",
|
||||
hex: "7E918C",
|
||||
default_hex: "7E918C",
|
||||
is_advanced: true,
|
||||
dark_hex: "7E918C",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary_high",
|
||||
hex: "4C6869",
|
||||
default_hex: "4C6869",
|
||||
is_advanced: true,
|
||||
dark_hex: "4C6869",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary",
|
||||
hex: "002B36",
|
||||
default_hex: "002B36",
|
||||
is_advanced: false,
|
||||
dark_hex: "002B36",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary-50",
|
||||
hex: "F0EBDA",
|
||||
default_hex: "F0EBDA",
|
||||
is_advanced: true,
|
||||
dark_hex: "F0EBDA",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary-100",
|
||||
hex: "DAD8CA",
|
||||
default_hex: "DAD8CA",
|
||||
is_advanced: true,
|
||||
dark_hex: "DAD8CA",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary-200",
|
||||
hex: "B2B9B3",
|
||||
default_hex: "B2B9B3",
|
||||
is_advanced: true,
|
||||
dark_hex: "B2B9B3",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary-300",
|
||||
hex: "839496",
|
||||
default_hex: "839496",
|
||||
is_advanced: true,
|
||||
dark_hex: "839496",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary-400",
|
||||
hex: "76898C",
|
||||
default_hex: "76898C",
|
||||
is_advanced: true,
|
||||
dark_hex: "76898C",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary-500",
|
||||
hex: "697F83",
|
||||
default_hex: "697F83",
|
||||
is_advanced: true,
|
||||
dark_hex: "697F83",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary-600",
|
||||
hex: "627A7E",
|
||||
default_hex: "627A7E",
|
||||
is_advanced: true,
|
||||
dark_hex: "627A7E",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary-700",
|
||||
hex: "556F74",
|
||||
default_hex: "556F74",
|
||||
is_advanced: true,
|
||||
dark_hex: "556F74",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary-800",
|
||||
hex: "415F66",
|
||||
default_hex: "415F66",
|
||||
is_advanced: true,
|
||||
dark_hex: "415F66",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "primary-900",
|
||||
hex: "21454E",
|
||||
default_hex: "21454E",
|
||||
is_advanced: true,
|
||||
dark_hex: "21454E",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "secondary_low",
|
||||
hex: "325458",
|
||||
default_hex: "325458",
|
||||
is_advanced: true,
|
||||
dark_hex: "325458",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "secondary_medium",
|
||||
hex: "6C8280",
|
||||
default_hex: "6C8280",
|
||||
is_advanced: true,
|
||||
dark_hex: "6C8280",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "secondary_high",
|
||||
hex: "97A59D",
|
||||
default_hex: "97A59D",
|
||||
is_advanced: true,
|
||||
dark_hex: "97A59D",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "secondary_very_high",
|
||||
hex: "E8E6D3",
|
||||
default_hex: "E8E6D3",
|
||||
is_advanced: true,
|
||||
dark_hex: "E8E6D3",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "secondary",
|
||||
hex: "FCF6E1",
|
||||
default_hex: "FCF6E1",
|
||||
is_advanced: false,
|
||||
dark_hex: "FCF6E1",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "tertiary_low",
|
||||
hex: "D6E6DE",
|
||||
default_hex: "D6E6DE",
|
||||
is_advanced: true,
|
||||
dark_hex: "D6E6DE",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "tertiary_medium",
|
||||
hex: "7EBFD7",
|
||||
default_hex: "7EBFD7",
|
||||
is_advanced: true,
|
||||
dark_hex: "7EBFD7",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "tertiary",
|
||||
hex: "0088cc",
|
||||
default_hex: "0088cc",
|
||||
is_advanced: false,
|
||||
dark_hex: "0088cc",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "tertiary_high",
|
||||
hex: "329ED0",
|
||||
default_hex: "329ED0",
|
||||
is_advanced: true,
|
||||
dark_hex: "329ED0",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "quaternary",
|
||||
hex: "e45735",
|
||||
default_hex: "e45735",
|
||||
is_advanced: false,
|
||||
dark_hex: "e45735",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "header_background",
|
||||
hex: "FCF6E1",
|
||||
default_hex: "FCF6E1",
|
||||
is_advanced: false,
|
||||
dark_hex: "FCF6E1",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "header_primary",
|
||||
hex: "002B36",
|
||||
default_hex: "002B36",
|
||||
is_advanced: false,
|
||||
dark_hex: "002B36",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "highlight_low",
|
||||
hex: "FDF9AD",
|
||||
default_hex: "FDF9AD",
|
||||
is_advanced: true,
|
||||
dark_hex: "FDF9AD",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "highlight_medium",
|
||||
hex: "E3D0A3",
|
||||
default_hex: "E3D0A3",
|
||||
is_advanced: true,
|
||||
dark_hex: "E3D0A3",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "highlight",
|
||||
hex: "F2F481",
|
||||
default_hex: "F2F481",
|
||||
is_advanced: false,
|
||||
dark_hex: "F2F481",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "highlight_high",
|
||||
hex: "BCAA7F",
|
||||
default_hex: "BCAA7F",
|
||||
is_advanced: true,
|
||||
dark_hex: "BCAA7F",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "selected",
|
||||
hex: "E8E6D3",
|
||||
default_hex: "E8E6D3",
|
||||
is_advanced: false,
|
||||
dark_hex: "E8E6D3",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "hover",
|
||||
hex: "F0EBDA",
|
||||
default_hex: "F0EBDA",
|
||||
is_advanced: false,
|
||||
dark_hex: "F0EBDA",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "danger_low",
|
||||
hex: "F8D9C2",
|
||||
default_hex: "F8D9C2",
|
||||
is_advanced: true,
|
||||
dark_hex: "F8D9C2",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "danger",
|
||||
hex: "e45735",
|
||||
default_hex: "e45735",
|
||||
is_advanced: false,
|
||||
dark_hex: "e45735",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "success_low",
|
||||
hex: "CFE5B9",
|
||||
default_hex: "CFE5B9",
|
||||
is_advanced: true,
|
||||
dark_hex: "CFE5B9",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "success_medium",
|
||||
hex: "4CB544",
|
||||
default_hex: "4CB544",
|
||||
is_advanced: true,
|
||||
dark_hex: "4CB544",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "success",
|
||||
hex: "009900",
|
||||
default_hex: "009900",
|
||||
is_advanced: false,
|
||||
dark_hex: "009900",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "love_low",
|
||||
hex: "FCDDD2",
|
||||
default_hex: "FCDDD2",
|
||||
is_advanced: true,
|
||||
dark_hex: "FCDDD2",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "love",
|
||||
hex: "fa6c8d",
|
||||
default_hex: "fa6c8d",
|
||||
is_advanced: false,
|
||||
dark_hex: "fa6c8d",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
],
|
||||
is_dark: false,
|
||||
|
|
|
@ -17,24 +17,18 @@ const DEFAULT_CONTENT = [
|
|||
hex: "1a1a1a",
|
||||
default_hex: "222",
|
||||
is_advanced: false,
|
||||
dark_hex: "1a1a1a",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "secondary",
|
||||
hex: "ffffff",
|
||||
default_hex: "fff",
|
||||
is_advanced: false,
|
||||
dark_hex: "ffffff",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "tertiary",
|
||||
hex: "595bca",
|
||||
default_hex: "08c",
|
||||
is_advanced: false,
|
||||
dark_hex: "595bca",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
],
|
||||
is_dark: false,
|
||||
|
@ -49,24 +43,18 @@ const DEFAULT_CONTENT = [
|
|||
hex: "dddddd",
|
||||
default_hex: "dddddd",
|
||||
is_advanced: false,
|
||||
dark_hex: "dddddd",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "secondary",
|
||||
hex: "222222",
|
||||
default_hex: "222222",
|
||||
is_advanced: false,
|
||||
dark_hex: "222222",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
{
|
||||
name: "tertiary",
|
||||
hex: "099dd7",
|
||||
default_hex: "099dd7",
|
||||
is_advanced: false,
|
||||
dark_hex: "099dd7",
|
||||
default_dark_hex: null,
|
||||
},
|
||||
],
|
||||
is_dark: true,
|
||||
|
|
|
@ -4,10 +4,7 @@ class Admin::ColorSchemesController < Admin::AdminController
|
|||
before_action :fetch_color_scheme, only: %i[update destroy]
|
||||
|
||||
def index
|
||||
schemes =
|
||||
ColorScheme.without_theme_owned_palettes.includes(:base_scheme).order("color_schemes.id ASC")
|
||||
|
||||
schemes = schemes.where(theme_id: nil) if params[:exclude_theme_owned]
|
||||
schemes = ColorScheme.includes(:base_scheme).order("color_schemes.id ASC")
|
||||
|
||||
render_serialized(ColorScheme.base_color_schemes + schemes.to_a, ColorSchemeSerializer)
|
||||
end
|
||||
|
@ -38,13 +35,11 @@ class Admin::ColorSchemesController < Admin::AdminController
|
|||
private
|
||||
|
||||
def fetch_color_scheme
|
||||
@color_scheme = ColorScheme.without_theme_owned_palettes.find(params[:id])
|
||||
@color_scheme = ColorScheme.find(params[:id])
|
||||
end
|
||||
|
||||
def color_scheme_params
|
||||
params.permit(
|
||||
color_scheme: [:base_scheme_id, :name, :user_selectable, colors: %i[name hex dark_hex]],
|
||||
)[
|
||||
params.permit(color_scheme: [:base_scheme_id, :name, :user_selectable, colors: %i[name hex]])[
|
||||
:color_scheme
|
||||
]
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
class Admin::Config::ColorPalettesController < Admin::AdminController
|
||||
def index
|
||||
palettes = ColorScheme.without_theme_owned_palettes.to_a
|
||||
palettes = ColorScheme.all.to_a
|
||||
palettes.unshift(ColorScheme.base)
|
||||
default_theme = Theme.find_default
|
||||
default_light_palette = default_theme&.color_scheme_id
|
||||
|
@ -55,10 +55,6 @@ class Admin::Config::ColorPalettesController < Admin::AdminController
|
|||
end
|
||||
|
||||
def show
|
||||
render_serialized(
|
||||
ColorScheme.without_theme_owned_palettes.find(params[:id]),
|
||||
ColorSchemeSerializer,
|
||||
root: false,
|
||||
)
|
||||
render_serialized(ColorScheme.find(params[:id]), ColorSchemeSerializer, root: false)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -176,7 +176,6 @@ class Admin::ThemesController < Admin::AdminController
|
|||
ColorScheme
|
||||
.strict_loading
|
||||
.all
|
||||
.without_theme_owned_palettes
|
||||
.includes(
|
||||
:theme,
|
||||
:base_scheme,
|
||||
|
@ -402,20 +401,6 @@ class Admin::ThemesController < Admin::AdminController
|
|||
render_serialized(theme_setting, ThemeObjectsSettingMetadataSerializer, root: false)
|
||||
end
|
||||
|
||||
def change_colors
|
||||
raise Discourse::InvalidAccess if params[:id].to_i.negative?
|
||||
theme = Theme.find_by(id: params[:id], component: false)
|
||||
raise Discourse::NotFound if !theme
|
||||
|
||||
palette = theme.find_or_create_owned_color_palette
|
||||
|
||||
colors = params.permit(colors: %i[name hex dark_hex])
|
||||
|
||||
ColorSchemeRevisor.revise_existing_colors_only(palette, colors)
|
||||
|
||||
render_serialized(palette, ColorSchemeSerializer, root: false)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ban_in_allowlist_mode!
|
||||
|
|
|
@ -23,15 +23,9 @@ class StylesheetsController < ApplicationController
|
|||
def color_scheme
|
||||
params.require("id")
|
||||
params.permit("theme_id")
|
||||
params.permit("include_dark_scheme")
|
||||
|
||||
manager = Stylesheet::Manager.new(theme_id: params[:theme_id])
|
||||
stylesheet =
|
||||
manager.color_scheme_stylesheet_details(
|
||||
params[:id],
|
||||
fallback_to_base: true,
|
||||
include_dark_scheme: !!params[:include_dark_scheme],
|
||||
)
|
||||
stylesheet = manager.color_scheme_stylesheet_details(params[:id], fallback_to_base: true)
|
||||
|
||||
render json: stylesheet
|
||||
end
|
||||
|
|
|
@ -575,10 +575,7 @@ module ApplicationHelper
|
|||
return user_scheme_id if user_scheme_id
|
||||
return if theme_id.blank?
|
||||
|
||||
if SiteSetting.use_overhauled_theme_color_palette
|
||||
@scheme_id = ThemeColorScheme.where(theme_id: theme_id).pick(:color_scheme_id)
|
||||
end
|
||||
@scheme_id ||= Theme.where(id: theme_id).pick(:color_scheme_id)
|
||||
@scheme_id = Theme.where(id: theme_id).pick(:color_scheme_id)
|
||||
end
|
||||
|
||||
def user_dark_scheme_id
|
||||
|
@ -588,13 +585,9 @@ module ApplicationHelper
|
|||
end
|
||||
|
||||
def dark_scheme_id
|
||||
if SiteSetting.use_overhauled_theme_color_palette
|
||||
scheme_id
|
||||
else
|
||||
user_dark_scheme_id ||
|
||||
(theme_id ? Theme.find_by_id(theme_id) : Theme.find_default)&.dark_color_scheme_id || -1
|
||||
end
|
||||
end
|
||||
|
||||
def current_homepage
|
||||
current_user&.user_option&.homepage || HomepageHelper.resolve(request, current_user)
|
||||
|
@ -684,7 +677,6 @@ module ApplicationHelper
|
|||
if dark_scheme_id != -1
|
||||
result << stylesheet_manager.color_scheme_stylesheet_preload_tag(
|
||||
dark_scheme_id,
|
||||
dark: SiteSetting.use_overhauled_theme_color_palette,
|
||||
fallback_to_base: false,
|
||||
)
|
||||
end
|
||||
|
@ -702,7 +694,6 @@ module ApplicationHelper
|
|||
dark_href =
|
||||
stylesheet_manager.color_scheme_stylesheet_link_tag_href(
|
||||
dark_scheme_id,
|
||||
dark: SiteSetting.use_overhauled_theme_color_palette,
|
||||
fallback_to_base: false,
|
||||
)
|
||||
end
|
||||
|
@ -786,11 +777,7 @@ module ApplicationHelper
|
|||
end
|
||||
|
||||
def dark_color_hex_for_name(name)
|
||||
ColorScheme.hex_for_name(
|
||||
name,
|
||||
dark_scheme_id,
|
||||
dark: SiteSetting.use_overhauled_theme_color_palette,
|
||||
)
|
||||
ColorScheme.hex_for_name(name, dark_scheme_id)
|
||||
end
|
||||
|
||||
def dark_elements_media_query
|
||||
|
|
|
@ -346,12 +346,6 @@ class ColorScheme < ActiveRecord::Base
|
|||
belongs_to :theme
|
||||
belongs_to :base_scheme, class_name: "ColorScheme"
|
||||
|
||||
has_one :theme_color_scheme, dependent: :destroy
|
||||
has_one :owning_theme, class_name: "Theme", through: :theme_color_scheme, source: :theme
|
||||
|
||||
scope :without_theme_owned_palettes,
|
||||
-> { where("color_schemes.id NOT IN (SELECT color_scheme_id FROM theme_color_schemes)") }
|
||||
|
||||
validates_associated :color_scheme_colors
|
||||
|
||||
BASE_COLORS_FILE = "#{Rails.root}/app/assets/stylesheets/common/foundation/colors.scss"
|
||||
|
@ -450,18 +444,17 @@ class ColorScheme < ActiveRecord::Base
|
|||
new_color_scheme
|
||||
end
|
||||
|
||||
def self.lookup_hex_for_name(name, scheme_id = nil, dark: false)
|
||||
def self.lookup_hex_for_name(name, scheme_id = nil)
|
||||
enabled_color_scheme = find_by(id: scheme_id) if scheme_id
|
||||
enabled_color_scheme ||= Theme.where(id: SiteSetting.default_theme_id).first&.color_scheme
|
||||
color_record = (enabled_color_scheme || base).colors.find { |c| c.name == name }
|
||||
return if !color_record
|
||||
dark ? color_record.dark_hex || color_record.hex : color_record.hex
|
||||
color_record.hex
|
||||
end
|
||||
|
||||
def self.hex_for_name(name, scheme_id = nil, dark: false)
|
||||
def self.hex_for_name(name, scheme_id = nil)
|
||||
cache_key = scheme_id ? "#{name}_#{scheme_id}" : name
|
||||
cache_key += "_dark" if dark
|
||||
hex_cache.defer_get_set(cache_key) { lookup_hex_for_name(name, scheme_id, dark:) }
|
||||
hex_cache.defer_get_set(cache_key) { lookup_hex_for_name(name, scheme_id) }
|
||||
end
|
||||
|
||||
def colors=(arr)
|
||||
|
@ -501,16 +494,10 @@ class ColorScheme < ActiveRecord::Base
|
|||
colors || (base_scheme_id ? {} : ColorScheme.base_colors)
|
||||
end
|
||||
|
||||
def resolved_colors(dark: false)
|
||||
def resolved_colors
|
||||
from_base = ColorScheme.base_colors
|
||||
from_custom_scheme = base_colors
|
||||
from_db =
|
||||
colors
|
||||
.map do |c|
|
||||
hex = dark ? (c.dark_hex || c.hex) : c.hex
|
||||
[c.name, hex]
|
||||
end
|
||||
.to_h
|
||||
from_db = colors.map { |c| [c.name, c.hex] }.to_h
|
||||
|
||||
resolved = from_base.merge(from_custom_scheme).except("hover", "selected").merge(from_db)
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ColorSchemeColor < ActiveRecord::Base
|
||||
self.ignored_columns = [
|
||||
"dark_hex", # TODO: Remove when 20250821155127_drop_dark_hex_from_color_scheme_color has been promoted to pre-deploy
|
||||
]
|
||||
|
||||
belongs_to :color_scheme
|
||||
|
||||
validates :hex, format: { with: /\A([0-9a-fA-F]{3}|[0-9a-fA-F]{6})\z/ }
|
||||
validates :dark_hex, format: { with: /\A([0-9a-fA-F]{3}|[0-9a-fA-F]{6})\z/ }, allow_nil: true
|
||||
|
||||
def hex_with_hash
|
||||
"##{hex}"
|
||||
|
@ -16,12 +19,11 @@ end
|
|||
# Table name: color_scheme_colors
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# name :string not null
|
||||
# hex :string not null
|
||||
# color_scheme_id :integer not null
|
||||
# name :string not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# dark_hex :string(6)
|
||||
# color_scheme_id :integer not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
class ColorSchemeSetting < EnumSiteSetting
|
||||
def self.valid_value?(val)
|
||||
val == -1 || ColorScheme.without_theme_owned_palettes.find_by_id(val)
|
||||
val == -1 || ColorScheme.find_by_id(val)
|
||||
end
|
||||
|
||||
def self.values
|
||||
values = [{ name: I18n.t("site_settings.dark_mode_none"), value: -1 }]
|
||||
ColorScheme.all.without_theme_owned_palettes.map { |c| values << { name: c.name, value: c.id } }
|
||||
ColorScheme.all.map { |c| values << { name: c.name, value: c.id } }
|
||||
values
|
||||
end
|
||||
end
|
||||
|
|
|
@ -66,13 +66,6 @@ class Theme < ActiveRecord::Base
|
|||
-> { where(target_id: Theme.targets[:settings], name: "yaml") },
|
||||
class_name: "ThemeField"
|
||||
has_one :javascript_cache, dependent: :destroy
|
||||
has_one :theme_color_scheme, dependent: :destroy
|
||||
has_one :owned_color_scheme,
|
||||
class_name: "ColorScheme",
|
||||
through: :theme_color_scheme,
|
||||
source: :color_scheme
|
||||
alias_method :owned_color_palette, :owned_color_scheme
|
||||
alias_method :owned_color_palette=, :owned_color_scheme=
|
||||
|
||||
has_many :locale_fields,
|
||||
-> { filter_locale_fields(I18n.fallbacks[I18n.locale]) },
|
||||
|
@ -129,7 +122,6 @@ class Theme < ActiveRecord::Base
|
|||
:locale_fields,
|
||||
:theme_translation_overrides,
|
||||
color_scheme: %i[theme color_scheme_colors base_scheme],
|
||||
owned_color_scheme: %i[theme color_scheme_colors base_scheme],
|
||||
parent_themes: %i[color_scheme locale_fields theme_translation_overrides],
|
||||
)
|
||||
end
|
||||
|
@ -1089,40 +1081,6 @@ class Theme < ActiveRecord::Base
|
|||
ThemeSiteSettingResolver.new(theme: self).resolved_theme_site_settings
|
||||
end
|
||||
|
||||
def find_or_create_owned_color_palette
|
||||
Theme.transaction do
|
||||
next self.owned_color_palette if self.owned_color_palette
|
||||
|
||||
palette = self.color_palette || ColorScheme.base
|
||||
|
||||
copy = palette.dup
|
||||
copy.theme_id = self.id
|
||||
copy.base_scheme_id = nil
|
||||
copy.user_selectable = false
|
||||
copy.via_wizard = false
|
||||
copy.save!
|
||||
|
||||
result =
|
||||
ThemeColorScheme.insert_all(
|
||||
[{ theme_id: self.id, color_scheme_id: copy.id }],
|
||||
unique_by: :index_theme_color_schemes_on_theme_id,
|
||||
)
|
||||
|
||||
if result.rows.size == 0
|
||||
# race condition, a palette has already been associated with this theme
|
||||
copy.destroy!
|
||||
self.reload.owned_color_palette
|
||||
else
|
||||
ColorSchemeColor.insert_all(
|
||||
palette.colors.map do |color|
|
||||
{ color_scheme_id: copy.id, name: color.name, hex: color.hex, dark_hex: color.dark_hex }
|
||||
end,
|
||||
)
|
||||
copy.reload
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_accessor :theme_setting_requests_refresh
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ThemeColorScheme < ActiveRecord::Base
|
||||
belongs_to :theme
|
||||
belongs_to :color_scheme, dependent: :destroy
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: theme_color_schemes
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# theme_id :integer not null
|
||||
# color_scheme_id :integer not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_theme_color_schemes_on_color_scheme_id (color_scheme_id) UNIQUE
|
||||
# index_theme_color_schemes_on_theme_id (theme_id) UNIQUE
|
||||
#
|
|
@ -1,16 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ColorSchemeColorSerializer < ApplicationSerializer
|
||||
attributes :name, :hex, :default_hex, :is_advanced, :dark_hex, :default_dark_hex
|
||||
attributes :name, :hex, :default_hex, :is_advanced
|
||||
|
||||
def hex
|
||||
object.hex
|
||||
end
|
||||
|
||||
def dark_hex
|
||||
object.dark_hex || object.hex
|
||||
end
|
||||
|
||||
def default_hex
|
||||
# return the hex value of the color when it is already a base color or no base_scheme is set
|
||||
if !object.color_scheme || object.color_scheme.base_scheme_id == 0
|
||||
|
@ -20,12 +16,6 @@ class ColorSchemeColorSerializer < ApplicationSerializer
|
|||
end
|
||||
end
|
||||
|
||||
def default_dark_hex
|
||||
# TODO(osama) implement this when we add dark mode colors for built-in
|
||||
# palettes
|
||||
nil
|
||||
end
|
||||
|
||||
def is_advanced
|
||||
!ColorScheme.base_colors.keys.include?(object.name)
|
||||
end
|
||||
|
|
|
@ -19,8 +19,6 @@ class ThemeSerializer < BasicThemeSerializer
|
|||
:system
|
||||
|
||||
has_one :color_scheme, serializer: ColorSchemeSerializer, embed: :object
|
||||
has_one :owned_color_palette, serializer: ColorSchemeSerializer, embed: :object
|
||||
has_one :base_palette, serializer: ColorSchemeSerializer, embed: :object
|
||||
has_one :user, serializer: UserNameSerializer, embed: :object
|
||||
has_one :disabled_by, serializer: UserNameSerializer, embed: :object
|
||||
|
||||
|
@ -60,14 +58,6 @@ class ThemeSerializer < BasicThemeSerializer
|
|||
object.parent_themes
|
||||
end
|
||||
|
||||
def base_palette
|
||||
ColorScheme.base
|
||||
end
|
||||
|
||||
def include_base_palette?
|
||||
object.color_scheme_id.blank? && object.owned_color_palette.blank?
|
||||
end
|
||||
|
||||
def settings
|
||||
object.settings.map do |_name, setting|
|
||||
ThemeSettingsSerializer.new(setting, scope:, root: false)
|
||||
|
|
|
@ -28,11 +28,7 @@ class ColorSchemeRevisor
|
|||
if existing = @color_scheme.colors_by_name[c[:name]]
|
||||
existing.update(c)
|
||||
elsif !update_existing_colors_only
|
||||
@color_scheme.color_scheme_colors << ColorSchemeColor.new(
|
||||
name: c[:name],
|
||||
hex: c[:hex],
|
||||
dark_hex: c[:dark_hex],
|
||||
)
|
||||
@color_scheme.color_scheme_colors << ColorSchemeColor.new(name: c[:name], hex: c[:hex])
|
||||
end
|
||||
end
|
||||
@color_scheme.clear_colors_cache
|
||||
|
|
|
@ -7051,15 +7051,6 @@ en:
|
|||
repo_unreachable: "Couldn't contact the Git repository of this theme. Error message:"
|
||||
built_in_description: "This theme is preinstalled and can not be deleted or customized"
|
||||
imported_from_archive: "This theme was imported from a .zip file"
|
||||
settings: "Settings"
|
||||
colors: "Colors"
|
||||
unsaved_colors:
|
||||
one: "You have %{count} unsaved color"
|
||||
other: "You have %{count} unsaved colors"
|
||||
unsaved_colors_leave_route_confirmation: "You haven't saved your color palette changes yet. Are you sure you want to leave?"
|
||||
save_colors: "Save colors"
|
||||
discard_colors: "Discard"
|
||||
colors_title: "Colors"
|
||||
scss:
|
||||
text: "CSS"
|
||||
title: "Custom CSS rules with support for SCSS syntax"
|
||||
|
|
|
@ -254,7 +254,6 @@ Discourse::Application.routes.draw do
|
|||
put "setting" => "themes#update_single_setting"
|
||||
put "site-setting" => "themes#update_theme_site_setting"
|
||||
get "objects_setting_metadata/:setting_name" => "themes#objects_setting_metadata"
|
||||
put "change-colors" => "themes#change_colors"
|
||||
end
|
||||
|
||||
collection do
|
||||
|
@ -275,7 +274,6 @@ Discourse::Application.routes.draw do
|
|||
get "components/:id" => "themes#index"
|
||||
get "components/:id/:target/:field_name/edit" => "themes#index"
|
||||
get "themes/:id/export" => "themes#export"
|
||||
get "themes/:id/colors" => "themes#index"
|
||||
get "themes/:id/schema/:setting_name" => "themes#schema"
|
||||
get "components/:id/schema/:setting_name" => "themes#schema"
|
||||
|
||||
|
|
|
@ -4150,11 +4150,6 @@ experimental:
|
|||
type: group_list
|
||||
list_type: compact
|
||||
area: "group_permissions|experimental"
|
||||
use_overhauled_theme_color_palette:
|
||||
default: false
|
||||
hidden: true
|
||||
client: true
|
||||
area: "experimental"
|
||||
reviewable_ui_refresh:
|
||||
client: true
|
||||
type: group_list
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveUseOverhauledThemeColorPaletteSetting < ActiveRecord::Migration[8.0]
|
||||
def up
|
||||
execute "DELETE FROM site_settings WHERE name = 'use_overhauled_theme_color_palette'"
|
||||
end
|
||||
|
||||
def down
|
||||
raise ActiveRecord::IrreversibleMigration
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DropDarkHexFromColorSchemeColor < ActiveRecord::Migration[8.0]
|
||||
DROPPED_COLUMNS = { color_scheme_colors: %i[dark_hex] }
|
||||
|
||||
def up
|
||||
DROPPED_COLUMNS.each { |table, columns| Migration::ColumnDropper.execute_drop(table, columns) }
|
||||
end
|
||||
|
||||
def down
|
||||
raise ActiveRecord::IrreversibleMigration
|
||||
end
|
||||
end
|
20
db/post_migrate/20250821155615_drop_theme_color_scheme.rb
Normal file
20
db/post_migrate/20250821155615_drop_theme_color_scheme.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DropThemeColorScheme < ActiveRecord::Migration[8.0]
|
||||
DROPPED_TABLES = %i[theme_color_schemes]
|
||||
|
||||
def up
|
||||
delete_ids = DB.query_single("SELECT color_scheme_id FROM theme_color_schemes")
|
||||
|
||||
if delete_ids.length > 0
|
||||
execute("DELETE FROM color_schemes WHERE id IN (#{delete_ids.join(",")})")
|
||||
execute("DELETE FROM color_scheme_colors WHERE color_scheme_id IN (#{delete_ids.join(",")})")
|
||||
end
|
||||
|
||||
DROPPED_TABLES.each { |table| Migration::TableDropper.execute_drop(table) }
|
||||
end
|
||||
|
||||
def down
|
||||
raise ActiveRecord::IrreversibleMigration
|
||||
end
|
||||
end
|
|
@ -160,21 +160,19 @@ module Stylesheet
|
|||
if @color_scheme_id
|
||||
colors =
|
||||
begin
|
||||
ColorScheme.find(@color_scheme_id).resolved_colors(dark: @dark)
|
||||
ColorScheme.find(@color_scheme_id).resolved_colors
|
||||
rescue StandardError
|
||||
ColorScheme.base_colors
|
||||
end
|
||||
elsif (@theme_id && !theme.component)
|
||||
colors = theme&.color_scheme&.resolved_colors(dark: @dark) || ColorScheme.base_colors
|
||||
colors = theme&.color_scheme&.resolved_colors || ColorScheme.base_colors
|
||||
else
|
||||
# this is a slightly ugly backwards compatibility fix,
|
||||
# we shouldn't be using the default theme color scheme for components
|
||||
# (most components use CSS custom properties which work fine without this)
|
||||
colors =
|
||||
Theme
|
||||
.find_by_id(SiteSetting.default_theme_id)
|
||||
&.color_scheme
|
||||
&.resolved_colors(dark: @dark) || ColorScheme.base_colors
|
||||
Theme.find_by_id(SiteSetting.default_theme_id)&.color_scheme&.resolved_colors ||
|
||||
ColorScheme.base_colors
|
||||
end
|
||||
|
||||
colors.each { |n, hex| contents << "$#{n}: ##{hex} !default; " }
|
||||
|
@ -195,7 +193,6 @@ module Stylesheet
|
|||
@theme = options[:theme]
|
||||
@theme_id = options[:theme_id]
|
||||
@color_scheme_id = options[:color_scheme_id]
|
||||
@dark = options[:dark]
|
||||
|
||||
if @theme && !@theme_id
|
||||
# make up an id so other stuff does not bail out
|
||||
|
|
|
@ -42,11 +42,10 @@ class Stylesheet::Manager
|
|||
cache.clear_regex(/#{plugin}/)
|
||||
end
|
||||
|
||||
def self.color_scheme_cache_key(color_scheme, theme_id = nil, dark: false)
|
||||
def self.color_scheme_cache_key(color_scheme, theme_id = nil)
|
||||
color_scheme_name = Slug.for(color_scheme.name) + color_scheme&.id.to_s
|
||||
theme_string = theme_id ? "_theme#{theme_id}" : ""
|
||||
dark_string = dark ? "_dark" : ""
|
||||
"#{COLOR_SCHEME_STYLESHEET}_#{color_scheme_name}_#{theme_string}_#{Discourse.current_hostname}_#{GlobalSetting.relative_url_root}_#{dark_string}"
|
||||
"#{COLOR_SCHEME_STYLESHEET}_#{color_scheme_name}_#{theme_string}_#{Discourse.current_hostname}_#{GlobalSetting.relative_url_root}"
|
||||
end
|
||||
|
||||
def self.precompile_css
|
||||
|
@ -117,18 +116,14 @@ class Stylesheet::Manager
|
|||
theme_dark_color_scheme = ColorScheme.find_by_id(dark_color_scheme_id)
|
||||
theme = manager.get_theme(theme_id)
|
||||
[theme_color_scheme, theme_dark_color_scheme, *color_schemes].compact.uniq.each do |scheme|
|
||||
[true, false].each do |dark|
|
||||
mode = dark ? "dark" : "light"
|
||||
$stderr.puts "precompile target: #{COLOR_SCHEME_STYLESHEET} #{theme.name} (#{scheme.name}) (#{mode})"
|
||||
$stderr.puts "precompile target: #{COLOR_SCHEME_STYLESHEET} #{theme.name} (#{scheme.name})"
|
||||
Stylesheet::Manager::Builder.new(
|
||||
target: COLOR_SCHEME_STYLESHEET,
|
||||
theme: theme,
|
||||
color_scheme: scheme,
|
||||
manager: manager,
|
||||
dark:,
|
||||
).compile(force: true)
|
||||
end
|
||||
end
|
||||
|
||||
clear_color_scheme_cache!
|
||||
end
|
||||
|
@ -344,12 +339,7 @@ class Stylesheet::Manager
|
|||
end
|
||||
end
|
||||
|
||||
def color_scheme_stylesheet_details(
|
||||
color_scheme_id = nil,
|
||||
dark: false,
|
||||
fallback_to_base: true,
|
||||
include_dark_scheme: false
|
||||
)
|
||||
def color_scheme_stylesheet_details(color_scheme_id = nil, fallback_to_base: true)
|
||||
theme_id = @theme_id || SiteSetting.default_theme_id
|
||||
|
||||
color_scheme = ColorScheme.find_by(id: color_scheme_id)
|
||||
|
@ -361,10 +351,10 @@ class Stylesheet::Manager
|
|||
|
||||
target = COLOR_SCHEME_STYLESHEET.to_sym
|
||||
current_hostname = Discourse.current_hostname
|
||||
cache_key = self.class.color_scheme_cache_key(color_scheme, theme_id, dark:)
|
||||
cache_key = self.class.color_scheme_cache_key(color_scheme, theme_id)
|
||||
|
||||
cache.defer_get_set(cache_key) do
|
||||
stylesheet = { color_scheme_id: color_scheme.id, dark: }
|
||||
stylesheet = { color_scheme_id: color_scheme.id }
|
||||
|
||||
theme = get_theme(theme_id)
|
||||
|
||||
|
@ -374,7 +364,6 @@ class Stylesheet::Manager
|
|||
theme: get_theme(theme_id),
|
||||
color_scheme: color_scheme,
|
||||
manager: self,
|
||||
dark:,
|
||||
)
|
||||
|
||||
builder.compile unless File.exist?(builder.stylesheet_fullpath)
|
||||
|
@ -382,27 +371,12 @@ class Stylesheet::Manager
|
|||
href = builder.stylesheet_absolute_url
|
||||
stylesheet[:new_href] = href
|
||||
|
||||
if include_dark_scheme
|
||||
dark_href =
|
||||
self.color_scheme_stylesheet_link_tag_href(
|
||||
color_scheme_id,
|
||||
dark: true,
|
||||
fallback_to_base: false,
|
||||
)
|
||||
|
||||
stylesheet[:new_dark_href] = dark_href if dark_href
|
||||
end
|
||||
|
||||
stylesheet.freeze
|
||||
end
|
||||
end
|
||||
|
||||
def color_scheme_stylesheet_preload_tag(
|
||||
color_scheme_id = nil,
|
||||
dark: false,
|
||||
fallback_to_base: true
|
||||
)
|
||||
stylesheet = color_scheme_stylesheet_details(color_scheme_id, dark:, fallback_to_base:)
|
||||
def color_scheme_stylesheet_preload_tag(color_scheme_id = nil, fallback_to_base: true)
|
||||
stylesheet = color_scheme_stylesheet_details(color_scheme_id, fallback_to_base:)
|
||||
|
||||
return "" if !stylesheet
|
||||
|
||||
|
@ -411,12 +385,8 @@ class Stylesheet::Manager
|
|||
%[<link href="#{href}" rel="preload" as="style"/>].html_safe
|
||||
end
|
||||
|
||||
def color_scheme_stylesheet_link_tag_href(
|
||||
color_scheme_id = nil,
|
||||
dark: false,
|
||||
fallback_to_base: true
|
||||
)
|
||||
stylesheet = color_scheme_stylesheet_details(color_scheme_id, dark:, fallback_to_base:)
|
||||
def color_scheme_stylesheet_link_tag_href(color_scheme_id = nil, fallback_to_base: true)
|
||||
stylesheet = color_scheme_stylesheet_details(color_scheme_id, fallback_to_base:)
|
||||
|
||||
return if !stylesheet
|
||||
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
class Stylesheet::Manager::Builder
|
||||
attr_reader :theme
|
||||
|
||||
def initialize(target: :desktop, theme: nil, color_scheme: nil, manager:, dark: false)
|
||||
def initialize(target: :desktop, theme: nil, color_scheme: nil, manager:)
|
||||
@target = target
|
||||
@theme = theme
|
||||
@color_scheme = color_scheme
|
||||
@manager = manager
|
||||
@dark = dark
|
||||
end
|
||||
|
||||
def compile(opts = {})
|
||||
|
@ -47,7 +46,6 @@ class Stylesheet::Manager::Builder
|
|||
source_map_file: source_map_url_relative_from_stylesheet,
|
||||
color_scheme_id: @color_scheme&.id,
|
||||
load_paths: load_paths,
|
||||
dark: @dark,
|
||||
strict_deprecations: %i[desktop mobile admin wizard].include?(@target),
|
||||
)
|
||||
rescue SassC::SyntaxError, SassC::NotRenderedError, DiscourseJsProcessor::TranspileError => e
|
||||
|
@ -122,14 +120,13 @@ class Stylesheet::Manager::Builder
|
|||
end
|
||||
|
||||
def qualified_target
|
||||
dark_string = @dark ? "_dark" : ""
|
||||
if is_theme?
|
||||
"#{@target}_#{theme&.id}"
|
||||
elsif @color_scheme
|
||||
"#{@target}_#{scheme_slug}_#{@color_scheme&.id}_#{@theme&.id}#{dark_string}"
|
||||
"#{@target}_#{scheme_slug}_#{@color_scheme&.id}_#{@theme&.id}"
|
||||
else
|
||||
scheme_string = theme&.color_scheme ? "_#{theme.color_scheme.id}" : ""
|
||||
"#{@target}#{scheme_string}#{dark_string}"
|
||||
"#{@target}#{scheme_string}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -250,9 +247,8 @@ class Stylesheet::Manager::Builder
|
|||
digest_string = "#{current_hostname}-"
|
||||
if cs
|
||||
theme_color_defs = resolve_baked_field(:common, :color_definitions)
|
||||
dark_string = @dark ? "-dark" : ""
|
||||
digest_string +=
|
||||
"#{RailsMultisite::ConnectionManagement.current_db}-#{cs&.id}-#{cs&.version}-#{theme_color_defs}-#{Stylesheet::Manager.fs_asset_cachebuster}-#{fonts}#{dark_string}"
|
||||
"#{RailsMultisite::ConnectionManagement.current_db}-#{cs&.id}-#{cs&.version}-#{theme_color_defs}-#{Stylesheet::Manager.fs_asset_cachebuster}-#{fonts}"
|
||||
else
|
||||
digest_string += "defaults-#{Stylesheet::Manager.fs_asset_cachebuster}-#{fonts}"
|
||||
|
||||
|
|
|
@ -956,20 +956,12 @@ RSpec.describe ApplicationHelper do
|
|||
describe "#discourse_theme_color_meta_tags" do
|
||||
before do
|
||||
light = Fabricate(:color_scheme)
|
||||
light.color_scheme_colors << ColorSchemeColor.new(
|
||||
name: "header_background",
|
||||
hex: "abcdef",
|
||||
dark_hex: "fedcba",
|
||||
)
|
||||
light.color_scheme_colors << ColorSchemeColor.new(name: "header_background", hex: "abcdef")
|
||||
light.save!
|
||||
helper.request.cookies["color_scheme_id"] = light.id
|
||||
|
||||
dark = Fabricate(:color_scheme)
|
||||
dark.color_scheme_colors << ColorSchemeColor.new(
|
||||
name: "header_background",
|
||||
hex: "defabc",
|
||||
dark_hex: "cbafed",
|
||||
)
|
||||
dark.color_scheme_colors << ColorSchemeColor.new(name: "header_background", hex: "defabc")
|
||||
dark.save!
|
||||
helper.request.cookies["dark_scheme_id"] = dark.id
|
||||
end
|
||||
|
@ -989,17 +981,6 @@ RSpec.describe ApplicationHelper do
|
|||
<meta name="theme-color" media="all" content="#abcdef">
|
||||
HTML
|
||||
end
|
||||
|
||||
context "when use_overhauled_theme_color_palette setting is true" do
|
||||
before { SiteSetting.use_overhauled_theme_color_palette = true }
|
||||
|
||||
it "renders a light and dark theme-color meta tag using the light and dark palettes of the same color scheme record" do
|
||||
expect(helper.discourse_theme_color_meta_tags).to eq(<<~HTML)
|
||||
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#abcdef">
|
||||
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#fedcba">
|
||||
HTML
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#discourse_color_scheme_meta_tag" do
|
||||
|
@ -1055,15 +1036,6 @@ RSpec.describe ApplicationHelper do
|
|||
it "returns the value set in the dark_scheme_id cookie" do
|
||||
expect(helper.dark_scheme_id).to eq(dark_scheme.id)
|
||||
end
|
||||
|
||||
context "when use_overhauled_theme_color_palette is true" do
|
||||
before { SiteSetting.use_overhauled_theme_color_palette = true }
|
||||
|
||||
it "returns the same value as #scheme_id" do
|
||||
expect(helper.dark_scheme_id).to eq(helper.scheme_id)
|
||||
expect(helper.scheme_id).to eq(light_scheme.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#forced_light_mode?" do
|
||||
|
|
|
@ -688,81 +688,6 @@ RSpec.describe Stylesheet::Manager do
|
|||
expect(href).to include("/stylesheets/color_definitions_funky-bunch_#{cs.id}_")
|
||||
end
|
||||
|
||||
it "generates the dark mode of a color scheme when the dark option is specified" do
|
||||
scheme =
|
||||
ColorScheme.create_from_base(
|
||||
name: "Neutral",
|
||||
base_scheme_id: ColorScheme::NAMES_TO_ID_MAP["Neutral"],
|
||||
)
|
||||
ColorSchemeRevisor.revise(
|
||||
scheme,
|
||||
colors: [{ name: "primary", hex: "CABFAF", dark_hex: "FAFCAB" }],
|
||||
)
|
||||
theme = Fabricate(:theme)
|
||||
manager = manager(theme.id)
|
||||
|
||||
dark_stylesheet =
|
||||
Stylesheet::Manager::Builder.new(
|
||||
target: :color_definitions,
|
||||
theme: theme,
|
||||
color_scheme: scheme,
|
||||
manager: manager,
|
||||
dark: true,
|
||||
).compile
|
||||
light_stylesheet =
|
||||
Stylesheet::Manager::Builder.new(
|
||||
target: :color_definitions,
|
||||
theme: theme,
|
||||
color_scheme: scheme,
|
||||
manager: manager,
|
||||
).compile
|
||||
|
||||
expect(light_stylesheet).to include("--primary: #CABFAF;")
|
||||
expect(light_stylesheet).to include("color_definitions_neutral_#{scheme.id}_#{theme.id}")
|
||||
expect(light_stylesheet).not_to include(
|
||||
"color_definitions_neutral_#{scheme.id}_#{theme.id}_dark",
|
||||
)
|
||||
|
||||
expect(dark_stylesheet).to include("--primary: #FAFCAB;")
|
||||
expect(dark_stylesheet).to include("color_definitions_neutral_#{scheme.id}_#{theme.id}_dark")
|
||||
end
|
||||
|
||||
it "uses the light colors as fallback if the dark scheme doesn't define them" do
|
||||
scheme =
|
||||
ColorScheme.create_from_base(
|
||||
name: "Neutral",
|
||||
base_scheme_id: ColorScheme::NAMES_TO_ID_MAP["Neutral"],
|
||||
)
|
||||
ColorSchemeRevisor.revise(scheme, colors: [{ name: "primary", hex: "BACFAB", dark_hex: nil }])
|
||||
theme = Fabricate(:theme)
|
||||
manager = manager(theme.id)
|
||||
|
||||
dark_stylesheet =
|
||||
Stylesheet::Manager::Builder.new(
|
||||
target: :color_definitions,
|
||||
theme: theme,
|
||||
color_scheme: scheme,
|
||||
manager: manager,
|
||||
dark: true,
|
||||
).compile
|
||||
light_stylesheet =
|
||||
Stylesheet::Manager::Builder.new(
|
||||
target: :color_definitions,
|
||||
theme: theme,
|
||||
color_scheme: scheme,
|
||||
manager: manager,
|
||||
).compile
|
||||
|
||||
expect(light_stylesheet).to include("--primary: #BACFAB;")
|
||||
expect(light_stylesheet).to include("color_definitions_neutral_#{scheme.id}_#{theme.id}")
|
||||
expect(light_stylesheet).not_to include(
|
||||
"color_definitions_neutral_#{scheme.id}_#{theme.id}_dark",
|
||||
)
|
||||
|
||||
expect(dark_stylesheet).to include("--primary: #BACFAB;")
|
||||
expect(dark_stylesheet).to include("color_definitions_neutral_#{scheme.id}_#{theme.id}_dark")
|
||||
end
|
||||
|
||||
it "updates outputted colors when updating a color scheme" do
|
||||
scheme =
|
||||
ColorScheme.create_from_base(
|
||||
|
@ -1004,7 +929,7 @@ RSpec.describe Stylesheet::Manager do
|
|||
|
||||
# Ensure we force compile each theme only once
|
||||
expect(output.scan(/#{child_theme_with_css.name}/).length).to eq(2) # ltr/rtl
|
||||
expect(StylesheetCache.count).to eq(10) # (2 theme with rtl/ltr) + 8 color schemes (2 themes * 2 color schemes (1 base light palette + 1 theme scheme) * 2 (light and dark mode per scheme))
|
||||
expect(StylesheetCache.count).to eq(6) # (2 theme with rtl/ltr) + 4 color schemes (2 themes * 2 color schemes (1 base light palette + 1 theme scheme))
|
||||
end
|
||||
|
||||
it "generates precompiled CSS - core and themes" do
|
||||
|
@ -1012,7 +937,7 @@ RSpec.describe Stylesheet::Manager do
|
|||
Stylesheet::Manager.precompile_theme_css
|
||||
|
||||
results = StylesheetCache.pluck(:target)
|
||||
expect(results.size).to eq(20) # 10 core targets + 2 theme (ltr/rtl) + 8 color schemes (light and dark mode per scheme)
|
||||
expect(results.size).to eq(16) # 10 core targets + 2 theme (ltr/rtl) + 4 color schemes
|
||||
|
||||
expect(results.count { |target| target =~ /^common_theme_/ }).to eq(2) # ltr/rtl
|
||||
end
|
||||
|
@ -1024,7 +949,7 @@ RSpec.describe Stylesheet::Manager do
|
|||
Stylesheet::Manager.precompile_theme_css
|
||||
|
||||
results = StylesheetCache.pluck(:target)
|
||||
expect(results.size).to eq(24) # 10 core targets + 2 theme rtl/ltr + 12 color schemes (light and dark mode per scheme)
|
||||
expect(results.size).to eq(18) # 10 core targets + 2 theme rtl/ltr + 6 color schemes
|
||||
|
||||
expect(results).to include("color_definitions_#{scheme1.name}_#{scheme1.id}_#{user_theme.id}")
|
||||
expect(results).to include(
|
||||
|
|
|
@ -1575,17 +1575,6 @@ HTML
|
|||
end
|
||||
end
|
||||
|
||||
describe "#owned_color_scheme" do
|
||||
it "is destroyed when the theme is destroyed" do
|
||||
scheme = Fabricate(:color_scheme, owning_theme: theme)
|
||||
|
||||
theme.destroy!
|
||||
|
||||
expect(ThemeColorScheme.exists?(color_scheme_id: scheme.id)).to eq(false)
|
||||
expect(ColorScheme.unscoped.exists?(id: scheme.id)).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".include_basic_relations" do
|
||||
fab!(:parent_theme_1) do
|
||||
Fabricate(
|
||||
|
@ -1705,51 +1694,6 @@ HTML
|
|||
end
|
||||
end
|
||||
|
||||
describe "#find_or_create_owned_color_palette" do
|
||||
it "correctly associates a theme with its owned color palette" do
|
||||
palette = theme.find_or_create_owned_color_palette
|
||||
|
||||
expect(palette.owning_theme).to eq(theme)
|
||||
expect(theme.reload.owned_color_palette).to eq(palette)
|
||||
end
|
||||
|
||||
it "ensures owned color palette is not user selectable" do
|
||||
palette = theme.find_or_create_owned_color_palette
|
||||
|
||||
expect(palette.user_selectable).to eq(false)
|
||||
end
|
||||
|
||||
it "copies colors from base or theme color scheme" do
|
||||
theme_without_scheme = Fabricate(:theme, color_scheme: nil)
|
||||
base_palette = theme_without_scheme.find_or_create_owned_color_palette
|
||||
|
||||
expect(base_palette.colors.length).to be > 0
|
||||
expect(base_palette.colors.map(&:name).sort).to eq(ColorScheme.base.colors.map(&:name).sort)
|
||||
|
||||
custom_palette =
|
||||
Fabricate(
|
||||
:color_scheme,
|
||||
colors: [ColorSchemeColor.new(name: "custom", hex: "11ccff", dark_hex: "ee9955")],
|
||||
)
|
||||
theme_with_scheme = Fabricate(:theme, color_scheme: custom_palette)
|
||||
custom_palette = theme_with_scheme.find_or_create_owned_color_palette
|
||||
|
||||
expect(custom_palette.colors.length).to be > 0
|
||||
expect(custom_palette.colors.map(&:name).sort).to eq(custom_palette.colors.map(&:name).sort)
|
||||
end
|
||||
|
||||
it "returns the existing palette if a race condition occurs and a theme-owned palette is created while it's executing" do
|
||||
expect(theme.owned_color_palette).to eq(nil)
|
||||
|
||||
palette = Fabricate(:color_scheme)
|
||||
ThemeColorScheme.create!(theme_id: theme.id, color_scheme_id: palette.id)
|
||||
|
||||
expect(theme.owned_color_palette).to eq(nil)
|
||||
expect(theme.find_or_create_owned_color_palette.id).to eq(palette.id)
|
||||
expect(theme.owned_color_palette).to eq(palette)
|
||||
end
|
||||
end
|
||||
|
||||
it "checks if fields can be updated for system themes" do
|
||||
foundation_theme.update!(user_selectable: true)
|
||||
expect(foundation_theme.user_selectable).to be true
|
||||
|
|
|
@ -45,45 +45,6 @@ RSpec.describe Admin::ColorSchemesController do
|
|||
expect(scheme_colors[0]["name"]).to eq("primary")
|
||||
expect(scheme_colors[0]["hex"]).to eq(scheme.resolved_colors["primary"])
|
||||
end
|
||||
|
||||
it "doesn't list theme-owned color schemes" do
|
||||
owned_scheme = Fabricate(:color_scheme, owning_theme: Fabricate(:theme))
|
||||
scheme = Fabricate(:color_scheme)
|
||||
|
||||
get "/admin/color_schemes.json"
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
ids = response.parsed_body.map { |obj| obj["id"] }
|
||||
expect(ids).to include(scheme.id)
|
||||
expect(ids).not_to include(owned_scheme.id)
|
||||
end
|
||||
|
||||
it "filters out theme-owned color schemes when exclude_theme_owned is true" do
|
||||
theme = Fabricate(:theme)
|
||||
theme_owned_scheme = Fabricate(:color_scheme, name: "Theme Scheme")
|
||||
|
||||
ThemeColorScheme.create!(theme: theme, color_scheme: theme_owned_scheme)
|
||||
|
||||
owned_scheme = Fabricate(:color_scheme, name: "Directly Owned", theme: theme)
|
||||
regular_scheme = Fabricate(:color_scheme, name: "Regular Scheme")
|
||||
|
||||
get "/admin/color_schemes.json", params: { exclude_theme_owned: true }
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
scheme_names = response.parsed_body.map { |scheme| scheme["name"] }
|
||||
expect(scheme_names).to include("Regular Scheme")
|
||||
expect(scheme_names).not_to include("Theme Scheme")
|
||||
expect(scheme_names).not_to include("Directly Owned")
|
||||
|
||||
get "/admin/color_schemes.json"
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
scheme_names = response.parsed_body.map { |scheme| scheme["name"] }
|
||||
expect(scheme_names).to include("Regular Scheme")
|
||||
expect(scheme_names).to include("Directly Owned")
|
||||
expect(scheme_names).not_to include("Theme Scheme")
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples "color schemes inaccessible" do
|
||||
|
@ -187,15 +148,6 @@ RSpec.describe Admin::ColorSchemesController do
|
|||
expect(response.status).to eq(422)
|
||||
expect(response.parsed_body["errors"]).to be_present
|
||||
end
|
||||
|
||||
it "doesn't allow editing theme-owned schemes" do
|
||||
color_scheme = Fabricate(:color_scheme, owning_theme: Fabricate(:theme))
|
||||
|
||||
put "/admin/color_schemes/#{color_scheme.id}.json", params: valid_params
|
||||
expect(response.status).to eq(404)
|
||||
color_scheme.reload
|
||||
expect(color_scheme.name).not_to eq(valid_params[:color_scheme][:name])
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples "color scheme update not allowed" do
|
||||
|
@ -232,14 +184,6 @@ RSpec.describe Admin::ColorSchemesController do
|
|||
}.by(-1)
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
|
||||
it "doesn't allow deleting theme-owned schemes" do
|
||||
color_scheme = Fabricate(:color_scheme, owning_theme: Fabricate(:theme))
|
||||
|
||||
delete "/admin/color_schemes/#{color_scheme.id}.json"
|
||||
expect(response.status).to eq(404)
|
||||
expect(color_scheme.reload).to be_persisted
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples "color scheme deletion not allowed" do
|
||||
|
|
|
@ -1690,98 +1690,6 @@ RSpec.describe Admin::ThemesController do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#change_colors" do
|
||||
fab!(:theme)
|
||||
|
||||
before { sign_in(admin) }
|
||||
|
||||
context "with valid parameters" do
|
||||
it "creates a theme-owned color palette if one doesn't exist" do
|
||||
expect(theme.owned_color_palette).to be_nil
|
||||
|
||||
put "/admin/themes/#{theme.id}/change-colors.json",
|
||||
params: {
|
||||
colors: [{ name: "primary", hex: "ff0000", dark_hex: "0000ff" }],
|
||||
}
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
theme.reload
|
||||
expect(theme.owned_color_palette.id).to eq(response.parsed_body["id"])
|
||||
|
||||
color = theme.owned_color_palette.colors.find_by(name: "primary")
|
||||
expect(color.hex).to eq("ff0000")
|
||||
expect(color.dark_hex).to eq("0000ff")
|
||||
end
|
||||
|
||||
it "updates an existing theme-owned color palette" do
|
||||
palette = theme.find_or_create_owned_color_palette
|
||||
primary_color = palette.colors.find_by(name: "primary")
|
||||
secondary_color = palette.colors.find_by(name: "secondary")
|
||||
|
||||
original_secondary_hex = secondary_color.hex
|
||||
original_secondary_dark_hex = secondary_color.dark_hex
|
||||
|
||||
put "/admin/themes/#{theme.id}/change-colors.json",
|
||||
params: {
|
||||
colors: [{ name: "primary", hex: "aabbcc", dark_hex: "ccddee" }],
|
||||
}
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
primary_color.reload
|
||||
secondary_color.reload
|
||||
|
||||
expect(primary_color.hex).to eq("aabbcc")
|
||||
expect(primary_color.dark_hex).to eq("ccddee")
|
||||
|
||||
expect(secondary_color.hex).to eq(original_secondary_hex)
|
||||
expect(secondary_color.dark_hex).to eq(original_secondary_dark_hex)
|
||||
end
|
||||
|
||||
it "returns the updated palette in the response" do
|
||||
put "/admin/themes/#{theme.id}/change-colors.json",
|
||||
params: {
|
||||
colors: [{ name: "primary", hex: "abcdef", dark_hex: "fedcba" }],
|
||||
}
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
json = response.parsed_body
|
||||
|
||||
expect(json["colors"]).to be_present
|
||||
primary_color = json["colors"].find { |c| c["name"] == "primary" }
|
||||
expect(primary_color["hex"]).to eq("abcdef")
|
||||
expect(primary_color["dark_hex"]).to eq("fedcba")
|
||||
end
|
||||
end
|
||||
|
||||
context "with invalid parameters" do
|
||||
it "returns 404 for non-existent theme" do
|
||||
max_id = (Theme.maximum(:id) || 0) + 1
|
||||
|
||||
put "/admin/themes/#{max_id}/change-colors.json",
|
||||
params: {
|
||||
colors: [{ name: "primary", hex: "ff0000", dark_hex: "0000ff" }],
|
||||
}
|
||||
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
end
|
||||
|
||||
context "when system theme" do
|
||||
before { theme.update_columns(id: -10) }
|
||||
|
||||
it "returns invalid access" do
|
||||
put "/admin/themes/#{theme.id}/change-colors.json",
|
||||
params: {
|
||||
colors: [{ name: "primary", hex: "ff0000", dark_hex: "0000ff" }],
|
||||
}
|
||||
|
||||
expect(response.status).to eq(403)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#show" do
|
||||
let(:theme) { Fabricate(:theme) }
|
||||
|
||||
|
|
|
@ -189,8 +189,6 @@ describe "Admin Color Palette Config Area Page", type: :system do
|
|||
|
||||
color_scheme.colors.each do |color|
|
||||
expect(color.hex).to eq(clipboard_scheme["light"][color.name])
|
||||
next if color.dark_hex.nil?
|
||||
expect(color.dark_hex).to eq(clipboard_scheme["dark"][color.name])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -268,95 +268,6 @@ describe "Admin Customize Themes", type: :system do
|
|||
end
|
||||
end
|
||||
|
||||
describe "theme color palette editor" do
|
||||
before { SiteSetting.use_overhauled_theme_color_palette = true }
|
||||
|
||||
it "allows editing colors of theme-owned palette" do
|
||||
theme_page.visit(theme.id)
|
||||
theme_page.colors_tab.click
|
||||
|
||||
expect(theme_page).to have_current_path("/admin/customize/themes/#{theme.id}/colors")
|
||||
|
||||
theme_page.color_palette_editor.change_color("primary", "#ff000e")
|
||||
|
||||
expect(theme_page.changes_banner).to be_visible
|
||||
theme_page.changes_banner.click_save
|
||||
|
||||
page.refresh
|
||||
expect(theme_page).to have_colors_tab_active
|
||||
|
||||
updated_color = theme_page.color_palette_editor.get_color_value("primary")
|
||||
expect(updated_color).to eq("#ff000e")
|
||||
end
|
||||
|
||||
it "allows discarding unsaved color changes" do
|
||||
theme_page.visit(theme.id)
|
||||
theme_page.colors_tab.click
|
||||
|
||||
original_hex = theme_page.color_palette_editor.get_color_value("primary")
|
||||
|
||||
theme_page.color_palette_editor.change_color("primary", "#10ff00")
|
||||
|
||||
theme_page.changes_banner.click_discard
|
||||
|
||||
expect(theme_page.changes_banner).to be_hidden
|
||||
|
||||
updated_color = theme_page.color_palette_editor.get_color_value("primary")
|
||||
expect(updated_color).to eq(original_hex)
|
||||
end
|
||||
|
||||
it "shows count of unsaved colors" do
|
||||
theme_page.visit(theme.id)
|
||||
theme_page.colors_tab.click
|
||||
|
||||
theme_page.color_palette_editor.change_color("primary", "#eeff80")
|
||||
|
||||
expect(theme_page.changes_banner).to have_label(
|
||||
I18n.t("admin_js.admin.customize.theme.unsaved_colors", count: 1),
|
||||
)
|
||||
|
||||
theme_page.color_palette_editor.change_color("secondary", "#ee30ab")
|
||||
expect(theme_page.changes_banner).to have_label(
|
||||
I18n.t("admin_js.admin.customize.theme.unsaved_colors", count: 2),
|
||||
)
|
||||
end
|
||||
|
||||
it "doesn't show colors tab or DPageHeader for components" do
|
||||
component = Fabricate(:theme, component: true)
|
||||
theme_page.visit(component.id)
|
||||
expect(theme_page.header).to be_hidden
|
||||
|
||||
expect(theme_page).to have_no_color_scheme_selector
|
||||
end
|
||||
|
||||
it "shows a confirmation dialog when leaving the page with unsaved changes" do
|
||||
theme_page.visit(theme.id)
|
||||
theme_page.colors_tab.click
|
||||
|
||||
theme_page.color_palette_editor.change_color("primary", "#eeff80")
|
||||
|
||||
expect(theme_page.changes_banner).to be_visible
|
||||
|
||||
find("#site-logo").click
|
||||
|
||||
expect(dialog).to be_open
|
||||
expect(page).to have_content(
|
||||
I18n.t("admin_js.admin.customize.theme.unsaved_colors_leave_route_confirmation"),
|
||||
)
|
||||
|
||||
dialog.click_no
|
||||
|
||||
expect(dialog).to be_closed
|
||||
expect(page).to have_current_path("/admin/customize/themes/#{theme.id}/colors")
|
||||
|
||||
find("#site-logo").click
|
||||
expect(dialog).to be_open
|
||||
|
||||
dialog.click_yes
|
||||
expect(page).to have_current_path("/")
|
||||
end
|
||||
end
|
||||
|
||||
describe "editing theme site settings" do
|
||||
it "shows all themeable site settings and allows editing values" do
|
||||
theme_page.visit(theme.id)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue