fix(branding): preserve customCss through preset switches + theme changes (#645)
Reporter @aemisrogers nailed the root cause: same #317 class of bug as logoUrl. None of `GALLERY_THEME_PRESETS` (`theme.types.ts:125`) include `customCss` in their `config` object, so any path that REPLACES `currentTheme` with `preset.config` (or with a sparse `newTheme` that came from `preset.config` upstream) silently dropped `customCss` from React state. The persisted value in `theme_config` stayed correct (the public gallery still rendered it), but the admin textarea showed empty on reload — admin-UI display drift, not data loss. Three surgical fixes, mirroring the #317 logoUrl pattern: 1. `BrandingPage.tsx` `handleThemeChange` — `customCss: newTheme.customCss ?? currentTheme.customCss` alongside the existing `logoUrl` fallback. Closes the propagation hole where the customizer's `handlePresetSelect` fires `onChange(preset.config)` (no customCss) and the parent wipes it from currentTheme. 2. `BrandingPage.tsx` `handlePresetChange` — preserve `customCss` from prev/currentTheme on preset switch, same shape as the existing `logoUrl: prev.logoUrl` preservation. Touches both the `setCurrentTheme` and the preview-mode `setTheme` paths. 3. `ThemeCustomizerEnhanced.tsx` `handlePresetSelect` — remove the `setCustomCss('')` that wiped the local textarea state on preset pick. The previous comment ("Clear custom CSS when selecting a preset") described the original intent but produced data drift across the preset round-trip. The sibling `ThemeCustomizer.tsx` already never cleared it; this aligns the two. Verified against `v3.44.0` and `origin/beta`: identical code on both branches, so the bug exists on stable + beta. Lint + tsc clean on the two changed files. Closes #645.
This commit is contained in:
@@ -259,7 +259,13 @@ export const ThemeCustomizerEnhanced: React.FC<ThemeCustomizerEnhancedProps> = (
|
|||||||
if (preset) {
|
if (preset) {
|
||||||
setSelectedPreset(presetKey);
|
setSelectedPreset(presetKey);
|
||||||
setLocalTheme(preset.config);
|
setLocalTheme(preset.config);
|
||||||
setCustomCss(''); // Clear custom CSS when selecting a preset
|
// Don't wipe customCss on preset pick — preset configs carry no
|
||||||
|
// customCss, and the admin's persisted styling extras should
|
||||||
|
// survive a layout switch (#645). Matches ThemeCustomizer.tsx
|
||||||
|
// which never cleared it. The parent's handleThemeChange merges
|
||||||
|
// via `customCss: newTheme.customCss ?? currentTheme.customCss`,
|
||||||
|
// so propagating preset.config (no customCss) keeps the saved
|
||||||
|
// value intact end-to-end.
|
||||||
if (onPresetChange) {
|
if (onPresetChange) {
|
||||||
onPresetChange(presetKey);
|
onPresetChange(presetKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,12 +186,14 @@ export const BrandingPage: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleThemeChange = (newTheme: ThemeConfig) => {
|
const handleThemeChange = (newTheme: ThemeConfig) => {
|
||||||
// Preset configs don't carry a logoUrl, so a preset change inside the
|
// Preset configs don't carry a logoUrl or customCss, so a preset change
|
||||||
// customizer arrives here with newTheme.logoUrl=undefined. Keep the
|
// inside the customizer arrives here with those fields undefined. Keep
|
||||||
// existing logo instead of wiping branding_logo_url on save (#317).
|
// the existing values instead of wiping the persisted ones on save
|
||||||
|
// (#317 for logoUrl, #645 for customCss).
|
||||||
const mergedTheme: ThemeConfig = {
|
const mergedTheme: ThemeConfig = {
|
||||||
...newTheme,
|
...newTheme,
|
||||||
logoUrl: newTheme.logoUrl ?? currentTheme.logoUrl
|
logoUrl: newTheme.logoUrl ?? currentTheme.logoUrl,
|
||||||
|
customCss: newTheme.customCss ?? currentTheme.customCss
|
||||||
};
|
};
|
||||||
setCurrentTheme(mergedTheme);
|
setCurrentTheme(mergedTheme);
|
||||||
if (newTheme.logoUrl !== undefined && newTheme.logoUrl !== currentTheme.logoUrl) {
|
if (newTheme.logoUrl !== undefined && newTheme.logoUrl !== currentTheme.logoUrl) {
|
||||||
@@ -207,10 +209,20 @@ export const BrandingPage: React.FC = () => {
|
|||||||
// Get the preset theme config
|
// Get the preset theme config
|
||||||
const preset = GALLERY_THEME_PRESETS[presetName];
|
const preset = GALLERY_THEME_PRESETS[presetName];
|
||||||
if (preset) {
|
if (preset) {
|
||||||
// Preserve the existing logo when switching presets (#317).
|
// Preserve the existing logo + custom CSS when switching presets
|
||||||
setCurrentTheme(prev => ({ ...preset.config, logoUrl: prev.logoUrl }));
|
// (#317 for logo, #645 for customCss). Presets define a look; they
|
||||||
|
// shouldn't silently drop the admin's persisted styling extras.
|
||||||
|
setCurrentTheme(prev => ({
|
||||||
|
...preset.config,
|
||||||
|
logoUrl: prev.logoUrl,
|
||||||
|
customCss: prev.customCss
|
||||||
|
}));
|
||||||
if (isPreviewMode) {
|
if (isPreviewMode) {
|
||||||
setTheme({ ...preset.config, logoUrl: currentTheme.logoUrl });
|
setTheme({
|
||||||
|
...preset.config,
|
||||||
|
logoUrl: currentTheme.logoUrl,
|
||||||
|
customCss: currentTheme.customCss
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user