feat(theme): add halloween special theme

This commit is contained in:
Tommaso Casaburi
2026-05-29 17:45:18 +07:00
parent e082c7b428
commit 0469f61a45
14 changed files with 301 additions and 35 deletions
+11 -3
View File
@@ -26,10 +26,13 @@ describe('snow', () => {
mathRandomSpy.mockRestore();
});
it('prefers the special theme store and otherwise falls back to christmas dates', async () => {
it('shows snow only for christmas special theme dates', async () => {
const useSpecialThemeStore = (await import('../../stores/use-special-theme-store')).default;
const { shouldShowSnow } = await import('../snow');
vi.useFakeTimers();
vi.setSystemTime(new Date('2024-12-24T00:00:00Z'));
useSpecialThemeStore.setState({ isEnabled: true });
expect(shouldShowSnow()).toBe(true);
@@ -37,10 +40,15 @@ describe('snow', () => {
expect(shouldShowSnow()).toBe(false);
useSpecialThemeStore.setState({ isEnabled: null });
vi.useFakeTimers();
vi.setSystemTime(new Date('2024-12-24T00:00:00Z'));
expect(shouldShowSnow()).toBe(true);
vi.setSystemTime(new Date('2024-10-31T00:00:00Z'));
useSpecialThemeStore.setState({ isEnabled: true });
expect(shouldShowSnow()).toBe(false);
useSpecialThemeStore.setState({ isEnabled: null });
expect(shouldShowSnow()).toBe(false);
vi.setSystemTime(new Date('2024-07-04T00:00:00Z'));
expect(shouldShowSnow()).toBe(false);
});
+4 -5
View File
@@ -1,4 +1,5 @@
import useSpecialThemeStore from '../stores/use-special-theme-store';
import { getActiveSpecialTheme } from './utils/time-utils';
interface SnowOptions {
flakeCount: number;
@@ -84,10 +85,11 @@ export const removeSnow = (): void => {
export const shouldShowSnow = (): boolean => {
const isEnabled = useSpecialThemeStore.getState().isEnabled;
const activeSpecialTheme = getActiveSpecialTheme();
// Check store value first
if (isEnabled !== null) {
return isEnabled;
return isEnabled && activeSpecialTheme === 'christmas';
}
// Check manual override second
@@ -95,8 +97,5 @@ export const shouldShowSnow = (): boolean => {
return manualSnowOverride;
}
const today = new Date();
const month = today.getMonth();
const day = today.getDate();
return month === 11 && (day === 24 || day === 25);
return activeSpecialTheme === 'christmas';
};
+10 -1
View File
@@ -12,7 +12,7 @@ import {
} from '../replies-preview-utils';
import { getQuotedCidsFromContent, mergeQuotedCids } from '../reply-quote-utils';
import { formatUserIDForDisplay, truncateWithEllipsisInMiddle } from '../string-utils';
import { getFormattedDate, getFormattedTimeAgo, isChristmas } from '../time-utils';
import { getActiveSpecialTheme, getFormattedDate, getFormattedTimeAgo, getSpecialThemeClass, isChristmas, isHalloween } from '../time-utils';
const testState = vi.hoisted(() => ({
language: 'en',
@@ -276,8 +276,17 @@ describe('misc utils', () => {
vi.setSystemTime(new Date('2024-12-24T00:00:00Z'));
expect(isChristmas()).toBe(true);
expect(getActiveSpecialTheme()).toBe('christmas');
expect(getSpecialThemeClass('christmas')).toBe('tomorrow');
vi.setSystemTime(new Date('2024-10-31T00:00:00Z'));
expect(isHalloween()).toBe(true);
expect(getActiveSpecialTheme()).toBe('halloween');
expect(getSpecialThemeClass('halloween')).toBe('spooky');
vi.setSystemTime(new Date('2024-07-04T00:00:00Z'));
expect(isChristmas()).toBe(false);
expect(isHalloween()).toBe(false);
expect(getActiveSpecialTheme()).toBeNull();
});
});
+27
View File
@@ -92,3 +92,30 @@ export const isChristmas = (): boolean => {
const day = today.getDate();
return month === 11 && (day === 24 || day === 25);
};
export const isHalloween = (): boolean => {
const today = new Date();
const month = today.getMonth();
const day = today.getDate();
return month === 9 && day === 31;
};
export type ActiveSpecialTheme = 'christmas' | 'halloween';
export type SpecialThemeClass = 'tomorrow' | 'spooky';
export const getActiveSpecialTheme = (): ActiveSpecialTheme | null => {
if (isChristmas()) {
return 'christmas';
}
if (isHalloween()) {
return 'halloween';
}
return null;
};
export const getSpecialThemeClass = (specialTheme: ActiveSpecialTheme): SpecialThemeClass => {
if (specialTheme === 'halloween') {
return 'spooky';
}
return 'tomorrow';
};