feat(seasonal): show Auto activation dates in settings + single-source schedule
Settings never told the user which days "Auto" turns each seasonal theme on.
Extracted the date windows out of getActiveSeason into a shared SEASON_SCHEDULE
(seasonSchedule.ts) — the single source of truth for both the runtime Auto
selector and the settings UI, so displayed dates can't drift from real activation.
- seasonal/types.ts: SeasonTheme + SeasonalOverlayProps (leaf module).
- seasonal/seasonSchedule.ts: priority-ordered SEASON_SCHEDULE with human date
ranges + SEASON_DATE_RANGES + getActiveSeason (behavior-preserving refactor).
- SeasonalEffect.tsx: consume the shared type/selector; re-export SeasonTheme.
- General.tsx: per-theme date caption under each swatch ("Oct 15 – Nov 1"), Auto
reads "By calendar", and the section description explains it.
- seasonSchedule.test.ts (6): representative day per theme, overlap priority
(Deep Space > Autumn, New Year > Lunar), inclusive boundaries, off-season null.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,8 @@ import React, { useMemo } from 'react';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { settingsAtom } from '../../state/settings';
|
||||
import { zIndices } from '../../styles/zIndex';
|
||||
import { SeasonTheme } from './types';
|
||||
import { getActiveSeason } from './seasonSchedule';
|
||||
import {
|
||||
animSeasonFall,
|
||||
animLeafFall,
|
||||
@@ -16,48 +18,10 @@ import {
|
||||
animPixelBlink,
|
||||
} from './Seasonal.css';
|
||||
|
||||
export type SeasonTheme =
|
||||
| 'halloween'
|
||||
| 'christmas'
|
||||
| 'newyear'
|
||||
| 'autumn'
|
||||
| 'aprilfools'
|
||||
| 'lunar'
|
||||
| 'valentines'
|
||||
| 'stpatricks'
|
||||
| 'earthday'
|
||||
| 'deepspace'
|
||||
| 'arcade';
|
||||
|
||||
function getActiveSeason(now: Date): SeasonTheme | null {
|
||||
const m = now.getMonth() + 1; // 1-12
|
||||
const d = now.getDate();
|
||||
|
||||
// New Year takes highest priority (Dec 31 – Jan 2)
|
||||
if ((m === 12 && d === 31) || (m === 1 && d <= 2)) return 'newyear';
|
||||
// Valentine's Day (Feb 10–15)
|
||||
if (m === 2 && d >= 10 && d <= 15) return 'valentines';
|
||||
// St. Patrick's Day (March 15–18)
|
||||
if (m === 3 && d >= 15 && d <= 18) return 'stpatricks';
|
||||
// April Fool's (April 1)
|
||||
if (m === 4 && d === 1) return 'aprilfools';
|
||||
// Earth Day (April 20–23)
|
||||
if (m === 4 && d >= 20 && d <= 23) return 'earthday';
|
||||
// Lunar New Year (Jan 22 – Feb 5, approximate fixed window)
|
||||
if ((m === 1 && d >= 22) || (m === 2 && d <= 5)) return 'lunar';
|
||||
// International Video Game Day (Sept 12)
|
||||
if (m === 9 && d === 12) return 'arcade';
|
||||
// World Space Week (Oct 4–10)
|
||||
if (m === 10 && d >= 4 && d <= 10) return 'deepspace';
|
||||
// Halloween (Oct 15 – Nov 1)
|
||||
if ((m === 10 && d >= 15) || (m === 11 && d === 1)) return 'halloween';
|
||||
// Christmas (Dec 10–30)
|
||||
if (m === 12 && d >= 10) return 'christmas';
|
||||
// Autumn (Sept 21 – Oct 31, excluding Halloween/Deep Space windows above)
|
||||
if ((m === 9 && d >= 21) || (m === 10 && d <= 14)) return 'autumn';
|
||||
|
||||
return null;
|
||||
}
|
||||
// SeasonTheme + the date-window logic now live in leaf modules (single source
|
||||
// of truth, shared with the settings UI). Re-exported here for existing
|
||||
// importers that still reach for it from this file.
|
||||
export type { SeasonTheme };
|
||||
|
||||
// ─── Individual theme overlays ────────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user