From 1a4e09a23e06fa2f70d148f0d3f650442d81ff06 Mon Sep 17 00:00:00 2001 From: Osama Sayegh Date: Tue, 25 Mar 2025 06:42:23 +0300 Subject: [PATCH] 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. --- .../admin-config-areas/color-palette.gjs | 54 +++++++++++++++++++ app/controllers/stylesheets_controller.rb | 9 +++- app/helpers/application_helper.rb | 8 +-- lib/stylesheet/manager.rb | 19 ++++++- .../admin_color_palettes_config_area_spec.rb | 35 ++++++++++++ 5 files changed, 120 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/admin/addon/components/admin-config-areas/color-palette.gjs b/app/assets/javascripts/admin/addon/components/admin-config-areas/color-palette.gjs index 764a0d18d88..16ac0d55717 100644 --- a/app/assets/javascripts/admin/addon/components/admin-config-areas/color-palette.gjs +++ b/app/assets/javascripts/admin/addon/components/admin-config-areas/color-palette.gjs @@ -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); + } + } +