diff --git a/package.json b/package.json index a4b8f71..05b60ce 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ ] }, "dependencies": { + "moment": "^2.30.1", "svelte-material-icons": "^3.0.5" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c4a74a0..6c3412e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + moment: + specifier: ^2.30.1 + version: 2.30.1 svelte-material-icons: specifier: ^3.0.5 version: 3.0.5(svelte@5.25.3) @@ -938,6 +941,9 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -2012,6 +2018,8 @@ snapshots: dependencies: brace-expansion: 2.0.1 + moment@2.30.1: {} + mri@1.2.0: {} mrmime@2.0.1: {} diff --git a/src/lib/stores.ts b/src/lib/stores.ts new file mode 100644 index 0000000..771c62c --- /dev/null +++ b/src/lib/stores.ts @@ -0,0 +1,21 @@ +import { readable } from 'svelte/store'; +import moment from 'moment'; +import { themes } from './themes'; +import { seconds } from './time'; + +export const theme = readable('default', (set) => { + const updateTheme = () => { + const today = moment(); + const monthName = today.format('MMMM').toLowerCase(); + const day = today.date(); + + Object.entries(themes).forEach(([themeName, [month, date]]) => { + if (monthName === month && day === date) set(themeName); + }); + }; + + updateTheme(); + const interval = setInterval(updateTheme, seconds(30)); + + return () => clearInterval(interval); +}); diff --git a/src/lib/themes.ts b/src/lib/themes.ts new file mode 100644 index 0000000..2474b61 --- /dev/null +++ b/src/lib/themes.ts @@ -0,0 +1,49 @@ +import moment, { type Moment } from 'moment'; + +type MonthName = + | 'january' + | 'february' + | 'march' + | 'april' + | 'may' + | 'june' + | 'july' + | 'august' + | 'september' + | 'october' + | 'november' + | 'december'; + +const getEaster = (): Moment => { + const currentYear = new Date().getFullYear(); + + const a = currentYear % 19, + b = Math.floor(currentYear / 100), + c = currentYear % 100, + d = Math.floor(b / 4), + e = b % 4, + f = Math.floor((b + 8) / 25), + g = Math.floor((b - f + 1) / 3), + h = (19 * a + b - d - g + 15) % 30, + i = Math.floor(c / 4), + k = c % 4, + L = (32 + 2 * e + 2 * i - h - k) % 7, + m = Math.floor((a + 11 * h + 22 * L) / 451), + month = Math.floor((h + L - 7 * m + 114) / 31), + day = ((h + L - 7 * m + 114) % 31) + 1; + + return moment(new Date(currentYear, month - 1, day)); +}; + +export const themes = { + new_year: ['january', 1], + christmas: ['december', 25], + valentine: ['february', 14], + halloween: ['october', 31], + // prettier-ignore + easter: [ + getEaster().format('MMMM').toLowerCase() as MonthName, + getEaster().date() + ], + april_fools: ['april', 1] +} as const satisfies Record; diff --git a/src/lib/time.ts b/src/lib/time.ts new file mode 100644 index 0000000..386914b --- /dev/null +++ b/src/lib/time.ts @@ -0,0 +1,4 @@ +export const seconds = (seconds: number): number => seconds * 1000; +export const minutes = (minutes: number): number => seconds(minutes * 60); +export const hours = (hours: number): number => minutes(hours * 60); +export const days = (days: number): number => hours(days * 24); diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte new file mode 100644 index 0000000..bb3e180 --- /dev/null +++ b/src/routes/+layout.svelte @@ -0,0 +1,13 @@ + + +{@render children()}