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:
Paul Nothaft
2026-06-20 23:17:34 +02:00
parent 38514ce60f
commit 7cf26795ec
2 changed files with 26 additions and 8 deletions
@@ -259,7 +259,13 @@ export const ThemeCustomizerEnhanced: React.FC<ThemeCustomizerEnhancedProps> = (
if (preset) {
setSelectedPreset(presetKey);
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) {
onPresetChange(presetKey);
}