UX: Apply changes live when editing currently active palette (#31874)

When editing a color palette via the new page introduced in
https://github.com/discourse/discourse/pull/31742, it should apply the
color changes for the admin making the change automatically upon save.

Internal topic: t/148628/12.
This commit is contained in:
Osama Sayegh
2025-03-25 06:42:23 +03:00
committed by GitHub
parent 423191ea24
commit 1a4e09a23e
5 changed files with 120 additions and 5 deletions

View File

@ -5,6 +5,7 @@ import { LinkTo } from "@ember/routing";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import Form from "discourse/components/form";
import { ajax } from "discourse/lib/ajax";
import { extractError } from "discourse/lib/ajax-error";
import { i18n } from "discourse-i18n";
import AdminConfigAreaCard from "admin/components/admin-config-area-card";
@ -19,6 +20,8 @@ export default class AdminConfigAreasColorPalette extends Component {
@tracked editingName = false;
@tracked editorMode = LIGHT;
@tracked hasUnsavedChanges = false;
@tracked saving = false;
hasChangedColors = false;
@cached
get data() {
@ -40,6 +43,7 @@ export default class AdminConfigAreasColorPalette extends Component {
const color = this.data.colors.find((c) => c.name === name);
color.hex = value;
this.hasUnsavedChanges = true;
this.hasChangedColors = true;
}
@action
@ -47,10 +51,12 @@ export default class AdminConfigAreasColorPalette extends Component {
const color = this.data.colors.find((c) => c.name === name);
color.dark_hex = value;
this.hasUnsavedChanges = true;
this.hasChangedColors = true;
}
@action
async handleSubmit(data) {
this.saving = true;
this.args.colorPalette.name = data.name;
this.args.colorPalette.user_selectable = data.user_selectable;
@ -63,6 +69,10 @@ export default class AdminConfigAreasColorPalette extends Component {
message: i18n("saved"),
},
});
if (this.hasChangedColors) {
await this.applyColorChangesIfPossible();
this.hasChangedColors = false;
}
} catch (error) {
this.toasts.error({
duration: 3000,
@ -70,6 +80,8 @@ export default class AdminConfigAreasColorPalette extends Component {
message: extractError(error),
},
});
} finally {
this.saving = false;
}
}
@ -107,6 +119,47 @@ export default class AdminConfigAreasColorPalette extends Component {
this.hasUnsavedChanges = true;
}
async applyColorChangesIfPossible() {
const id = this.args.colorPalette.id;
if (!id) {
return;
}
const tags = document.querySelectorAll(`link[data-scheme-id="${id}"]`);
if (tags.length === 0) {
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;
}
} catch (error) {
// eslint-disable-next-line no-console
console.error(`Failed to apply changes to color palette ${id}`, error);
}
}
<template>
<Form
@data={{this.data}}
@ -216,6 +269,7 @@ export default class AdminConfigAreasColorPalette extends Component {
</span>
{{/if}}
<form.Submit
@isLoading={{this.saving}}
@label="admin.config_areas.color_palettes.save_changes"
/>
</div>

View File

@ -23,9 +23,16 @@ 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)
stylesheet =
manager.color_scheme_stylesheet_details(
params[:id],
fallback_to_base: true,
include_dark_scheme: !!params[:include_dark_scheme],
)
render json: stylesheet
end

View File

@ -674,14 +674,16 @@ module ApplicationHelper
light_href,
light_elements_media_query,
"light-scheme",
scheme_id,
)
result << color_scheme_stylesheet_link_tag(
dark_href,
dark_elements_media_query,
"dark-scheme",
dark_scheme_id,
)
else
result << color_scheme_stylesheet_link_tag(light_href, "all", "light-scheme")
result << color_scheme_stylesheet_link_tag(light_href, "all", "light-scheme", scheme_id)
end
result.html_safe
end
@ -857,7 +859,7 @@ module ApplicationHelper
end
end
def color_scheme_stylesheet_link_tag(href, media, css_class)
%[<link href="#{href}" media="#{media}" rel="stylesheet" class="#{css_class}"/>]
def color_scheme_stylesheet_link_tag(href, media, css_class, scheme_id)
%[<link href="#{href}" media="#{media}" rel="stylesheet" class="#{css_class}"#{scheme_id && scheme_id != -1 ? %[ data-scheme-id="#{scheme_id}"] : ""}/>]
end
end

View File

@ -341,7 +341,12 @@ class Stylesheet::Manager
end
end
def color_scheme_stylesheet_details(color_scheme_id = nil, dark: false, fallback_to_base: true)
def color_scheme_stylesheet_details(
color_scheme_id = nil,
dark: false,
fallback_to_base: true,
include_dark_scheme: false
)
theme_id = @theme_id || SiteSetting.default_theme_id
color_scheme = ColorScheme.find_by(id: color_scheme_id)
@ -373,6 +378,18 @@ 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

View File

@ -92,4 +92,39 @@ describe "Admin Color Palettes Config Area Page", type: :system do
)
expect(config_area.user_selectable_field.value).to eq(false)
end
it "applies the changes live when editing the currently active palette" do
admin.user_option.update!(color_scheme_id: color_scheme.id)
config_area.visit(color_scheme.id)
config_area.color_palette_editor.input_for_color("secondary").fill_in(with: "#aa339f")
expect(config_area).to have_unsaved_changes_indicator
config_area.form.submit
expect(toasts).to have_success(I18n.t("js.saved"))
expect(config_area).to have_no_unsaved_changes_indicator
href = Stylesheet::Manager.new.color_scheme_stylesheet_link_tag_href(color_scheme.id)
expect(page).to have_css(
"link[data-scheme-id=\"#{color_scheme.id}\"][href=\"#{href}\"]",
visible: false,
)
expect(find("html").native.css_value("background-color")).to eq(
"rgba(#{"aa".to_i(16)}, #{"33".to_i(16)}, #{"9f".to_i(16)}, 1)",
)
end
it "doesn't apply changes when editing a palette that's not currently active" do
config_area.visit(color_scheme.id)
config_area.color_palette_editor.input_for_color("secondary").fill_in(with: "#aa339f")
expect(config_area).to have_unsaved_changes_indicator
config_area.form.submit
expect(toasts).to have_success(I18n.t("js.saved"))
expect(config_area).to have_no_unsaved_changes_indicator
href = Stylesheet::Manager.new.color_scheme_stylesheet_link_tag_href(color_scheme.id)
expect(page).to have_no_css("link[href=\"#{href}\"]", visible: false)
end
end