diff --git a/src/app/components/seasonal/SeasonalEffect.tsx b/src/app/components/seasonal/SeasonalEffect.tsx index caf40d9ff..1d570fe66 100644 --- a/src/app/components/seasonal/SeasonalEffect.tsx +++ b/src/app/components/seasonal/SeasonalEffect.tsx @@ -1,21 +1,49 @@ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { Suspense, useEffect, useMemo, useState } from 'react'; import { useAtomValue } from 'jotai'; import { settingsAtom } from '../../state/settings'; import { useReducedMotion } from '../../hooks/useReducedMotion'; import { zIndices } from '../../styles/zIndex'; import { SeasonTheme } from './types'; import { resolveSeasonTheme } from './seasonSchedule'; -import { HalloweenOverlay } from './themes/Halloween'; -import { ChristmasOverlay } from './themes/Christmas'; -import { NewYearOverlay } from './themes/NewYear'; -import { AutumnOverlay } from './themes/Autumn'; -import { AprilFoolsOverlay } from './themes/AprilFools'; -import { LunarNewYearOverlay } from './themes/LunarNewYear'; -import { ValentinesOverlay } from './themes/Valentines'; -import { StPatricksOverlay } from './themes/StPatricks'; -import { EarthDayOverlay } from './themes/EarthDay'; -import { DeepSpaceOverlay } from './themes/DeepSpace'; -import { ArcadeOverlay } from './themes/Arcade'; + +// [Gitea #167] Each overlay (its particles + keyframes) is its own chunk, +// fetched only when that season is active or previewed in Settings — the +// date/override decision stays in the main bundle. +const lazyOverlay = (load: () => Promise<{ default: React.ComponentType<{ reduced: boolean }> }>) => + React.lazy(load); +const HalloweenOverlay = lazyOverlay(() => + import('./themes/Halloween').then((m) => ({ default: m.HalloweenOverlay })), +); +const ChristmasOverlay = lazyOverlay(() => + import('./themes/Christmas').then((m) => ({ default: m.ChristmasOverlay })), +); +const NewYearOverlay = lazyOverlay(() => + import('./themes/NewYear').then((m) => ({ default: m.NewYearOverlay })), +); +const AutumnOverlay = lazyOverlay(() => + import('./themes/Autumn').then((m) => ({ default: m.AutumnOverlay })), +); +const AprilFoolsOverlay = lazyOverlay(() => + import('./themes/AprilFools').then((m) => ({ default: m.AprilFoolsOverlay })), +); +const LunarNewYearOverlay = lazyOverlay(() => + import('./themes/LunarNewYear').then((m) => ({ default: m.LunarNewYearOverlay })), +); +const ValentinesOverlay = lazyOverlay(() => + import('./themes/Valentines').then((m) => ({ default: m.ValentinesOverlay })), +); +const StPatricksOverlay = lazyOverlay(() => + import('./themes/StPatricks').then((m) => ({ default: m.StPatricksOverlay })), +); +const EarthDayOverlay = lazyOverlay(() => + import('./themes/EarthDay').then((m) => ({ default: m.EarthDayOverlay })), +); +const DeepSpaceOverlay = lazyOverlay(() => + import('./themes/DeepSpace').then((m) => ({ default: m.DeepSpaceOverlay })), +); +const ArcadeOverlay = lazyOverlay(() => + import('./themes/Arcade').then((m) => ({ default: m.ArcadeOverlay })), +); // SeasonTheme + the date-window logic now live in leaf modules (single source // of truth, shared with the settings UI). Re-exported here for existing @@ -69,7 +97,7 @@ function SeasonalOverlay({ theme, reduced }: { theme: SeasonTheme; reduced: bool overflow: 'hidden', }} > - {buildOverlayContent(theme, reduced)} + {buildOverlayContent(theme, reduced)} ); } @@ -94,7 +122,7 @@ export function SeasonalPreview({ theme }: { theme: SeasonTheme }) { containerType: 'inline-size', }} > - {buildOverlayContent(theme, true)} + {buildOverlayContent(theme, true)} ); }