@@ -274,26 +274,83 @@ export function getCurrentTheme(): string {
274274}
275275
276276/**
277- * Check if we should auto-apply winter theme
278- * Returns true if current month is December or January,
279- * and the last theme change was NOT in December or January
277+ * Configuration for a seasonal period.
278+ * - id: stable identifier for the season (used to remember banner dismissal)
279+ * - themeId: the color theme auto-applied during this season
280+ * - banner: dismissable banner text shown during this season (empty string = no banner)
280281 */
281- function shouldAutoApplyWinterTheme ( ) : boolean {
282- if ( typeof localStorage === "undefined" ) {
283- return true ;
284- }
282+ export interface SeasonalConfig {
283+ id : string ;
284+ themeId : string ;
285+ banner : string ;
286+ }
287+
288+ /**
289+ * Seasonal configuration keyed by month (0 = January, 11 = December).
290+ * Edit the `banner` text here to change what the seasonal banner says.
291+ */
292+ export const seasonalConfigs : Record < number , SeasonalConfig > = {
293+ 0 : {
294+ id : "winter" ,
295+ themeId : "winter" ,
296+ banner : "❄️ Happy holidays from the IPython team!" ,
297+ } ,
298+ 5 : {
299+ id : "pride" ,
300+ themeId : "rainbow" ,
301+ banner :
302+ "🏳️🌈 Happy Pride Month! IPython celebrates and supports our diverse community." ,
303+ } ,
304+ 11 : {
305+ id : "winter" ,
306+ themeId : "winter" ,
307+ banner : "❄️ Happy holidays from the IPython team!" ,
308+ } ,
309+ } ;
285310
311+ /**
312+ * Get the seasonal configuration for a given month, or null if none.
313+ */
314+ export function getSeasonalConfigForMonth ( month : number ) : SeasonalConfig | null {
315+ return seasonalConfigs [ month ] ?? null ;
316+ }
317+
318+ /**
319+ * Get the current month's seasonal configuration, or null if none.
320+ */
321+ export function getCurrentSeasonalConfig ( ) : SeasonalConfig | null {
322+ return getSeasonalConfigForMonth ( new Date ( ) . getMonth ( ) ) ;
323+ }
324+
325+ /**
326+ * Get the seasonal theme for a given month (0 = January, 11 = December),
327+ * or null if that month has no seasonal theme.
328+ */
329+ function getSeasonalThemeForMonth ( month : number ) : string | null {
330+ return getSeasonalConfigForMonth ( month ) ?. themeId ?? null ;
331+ }
332+
333+ /**
334+ * Determine which seasonal theme should be auto-applied right now, if any.
335+ * Returns the seasonal theme id (e.g. "winter" or "rainbow") when the current
336+ * month has one and the user has NOT manually picked a theme during the same
337+ * season; otherwise returns null.
338+ */
339+ function getAutoSeasonalTheme ( ) : string | null {
286340 const now = new Date ( ) ;
287- const currentMonth = now . getMonth ( ) ; // 0 = January, 11 = December
288- const isDecOrJan = currentMonth === 11 || currentMonth === 0 ;
341+ const seasonalTheme = getSeasonalThemeForMonth ( now . getMonth ( ) ) ;
289342
290- if ( ! isDecOrJan ) {
343+ if ( ! seasonalTheme ) {
291344 console . info ( "Nothing specific using default theme" ) ;
292- return false ;
345+ return null ;
346+ }
347+
348+ if ( typeof localStorage === "undefined" ) {
349+ return seasonalTheme ;
293350 }
294351
295352 const stored = localStorage . getItem ( "colorTheme" ) ;
296- if ( ! stored ) return true ; // No stored theme, apply winter
353+ if ( ! stored ) return seasonalTheme ; // No stored theme, apply seasonal
297354
298355 try {
299356 const parsed = JSON . parse ( stored ) ;
@@ -308,19 +365,21 @@ function shouldAutoApplyWinterTheme(): boolean {
308365 }
309366
310367 if ( storedDate ) {
311- const storedMonth = storedDate . getMonth ( ) ;
312- const storedIsDecOrJan = storedMonth === 11 || storedMonth === 0 ;
313- // If stored date is NOT in Dec/Jan, auto-apply winter
314- return ! storedIsDecOrJan ;
368+ // If the stored theme was chosen during the current season, respect the
369+ // user's choice; otherwise auto-apply the seasonal theme.
370+ const storedSeasonalTheme = getSeasonalThemeForMonth (
371+ storedDate . getMonth ( )
372+ ) ;
373+ return storedSeasonalTheme === seasonalTheme ? null : seasonalTheme ;
315374 }
316375 } catch {
317376 console . log ( "Something wrong in local storage" ) ;
318377
319- // If parsing fails, assume old format - apply winter
320- return true ;
378+ // If parsing fails, assume old format - apply seasonal
379+ return seasonalTheme ;
321380 }
322381
323- return false ;
382+ return seasonalTheme ;
324383}
325384
326385/**
@@ -444,15 +503,16 @@ export function initializeThemeWatcher(): () => void {
444503 themeWatcherInitialized = true ;
445504
446505 const checkTheme = ( ) => {
447- // Check if we should auto-apply winter theme first
448- if ( shouldAutoApplyWinterTheme ( ) ) {
506+ // Check if we should auto-apply a seasonal theme first
507+ const seasonalTheme = getAutoSeasonalTheme ( ) ;
508+ if ( seasonalTheme ) {
449509 const currentApplied = getCurrentTheme ( ) ;
450- // Only apply winter if it's not already applied
451- if ( currentApplied !== "winter" ) {
452- applyTheme ( "winter" , false ) ; // Apply winter but don't store it
453- notifyThemeChange ( getStoredTheme ( ) ) ; // Notify with stored theme, not 'winter'
510+ // Only apply the seasonal theme if it's not already applied
511+ if ( currentApplied !== seasonalTheme ) {
512+ applyTheme ( seasonalTheme , false ) ; // Apply seasonal theme but don't store it
513+ notifyThemeChange ( getStoredTheme ( ) ) ; // Notify with stored theme, not the seasonal one
454514 }
455- return ; // Don't check stored theme when winter is auto-applied
515+ return ; // Don't check stored theme when a seasonal theme is auto-applied
456516 }
457517
458518 const storedTheme = getStoredTheme ( ) ;
@@ -533,11 +593,12 @@ export function initializeThemeWatcher(): () => void {
533593
534594 // Apply initial theme (only if no valid theme parameter was provided)
535595 if ( ! themeParamApplied ) {
536- // Check if we should auto-apply winter theme
537- if ( shouldAutoApplyWinterTheme ( ) ) {
538- console . log ( "will apply winter" ) ;
539- applyTheme ( "winter" , false ) ; // Apply winter but don't store it
540- notifyThemeChange ( "winter" ) ; // Notify with the stored theme, not 'winter'
596+ // Check if we should auto-apply a seasonal theme
597+ const seasonalTheme = getAutoSeasonalTheme ( ) ;
598+ if ( seasonalTheme ) {
599+ console . log ( "will apply seasonal theme" , seasonalTheme ) ;
600+ applyTheme ( seasonalTheme , false ) ; // Apply seasonal theme but don't store it
601+ notifyThemeChange ( seasonalTheme ) ;
541602 } else {
542603 const initialTheme = getStoredTheme ( ) ;
543604 applyTheme ( initialTheme ) ;
0 commit comments