fix(seasonal): auto theme re-evaluates over time; auto clears chat background
- The "auto" seasonal theme was computed once at mount, so a long-lived session
never crossed a season/holiday-window boundary. SeasonalEffect now re-evaluates
on an hourly ticker (auto mode only) AND refreshes on entering auto — the
interval only runs while auto, so a stale mount-time timestamp would otherwise
resurface on a pinned/off → auto switch (the exact frozen-at-mount bug, caught
in review). The decision is extracted to a pure resolveSeasonTheme(override,
now) in seasonSchedule.ts (removing an unsafe cast) and unit-tested.
- Selecting seasonal "auto" while a chat background was set was a silent no-op:
the seasonal picker only cleared the background for a *specific* theme, and the
overlay is suppressed while a background is set. Now any active seasonal mode
("auto" included) clears the background; only "off" leaves it — symmetric with
the background picker (which sets seasonal "off"). The overlay guard stays as a
backstop for legacy persisted state.
Bug-hunt findings from LOTUS_TODO. Three review passes (the 2nd caught the
switch-into-auto staleness); +2 unit tests. Gate-green (tsc, eslint, prettier,
922 tests, build).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -93,3 +93,18 @@ export function getActiveSeason(now: Date): SeasonTheme | null {
|
||||
const day = now.getDate();
|
||||
return SEASON_SCHEDULE.find((entry) => entry.matches(month, day))?.theme ?? null;
|
||||
}
|
||||
|
||||
/** A seasonal-theme setting value: the active season, a pinned theme, or off. */
|
||||
export type SeasonalOverride = SeasonTheme | 'auto' | 'off';
|
||||
|
||||
/**
|
||||
* The theme to render for a `seasonalThemeOverride` at time `now` (epoch ms):
|
||||
* 'off' → none, 'auto' → the active season for that instant, else the pinned
|
||||
* theme. Kept pure (and unit-tested) so the decision is verifiable without
|
||||
* mounting the React overlay.
|
||||
*/
|
||||
export function resolveSeasonTheme(override: SeasonalOverride, now: number): SeasonTheme | null {
|
||||
if (override === 'off') return null;
|
||||
if (override === 'auto') return getActiveSeason(new Date(now));
|
||||
return override;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user