diff --git a/web/src/hooks.server.ts b/web/src/hooks.server.ts index 0ac1285179..e9e5e1f149 100644 --- a/web/src/hooks.server.ts +++ b/web/src/hooks.server.ts @@ -1,7 +1,6 @@ import overpass from '$lib/assets/fonts/overpass/Overpass.ttf?url'; import overpassMono from '$lib/assets/fonts/overpass/OverpassMono.ttf?url'; import fouc from '$lib/utils/app?raw'; -import theme from '$lib/utils/theme?raw'; import type { Handle } from '@sveltejs/kit'; import { ModuleKind, transpileModule } from 'typescript'; @@ -16,9 +15,7 @@ const transpileFile = (content: string) => { export const handle = (async ({ event, resolve }) => { return resolve(event, { transformPageChunk: ({ html }) => { - const themePrepared = theme.replaceAll(/^export\s+/gm, ''); - const foucPrepared = fouc.replaceAll(/^import.*$/gm, themePrepared); - const scriptFouc = ``; + const scriptFouc = ``; return html .replace('%app.font%', overpass) diff --git a/web/src/lib/components/onboarding-page/onboarding-theme.svelte b/web/src/lib/components/onboarding-page/onboarding-theme.svelte index f16f9b8be2..975dbd1ec3 100644 --- a/web/src/lib/components/onboarding-page/onboarding-theme.svelte +++ b/web/src/lib/components/onboarding-page/onboarding-theme.svelte @@ -5,7 +5,7 @@ import OnboardingCard from './onboarding-card.svelte'; import { colorTheme } from '$lib/stores/preferences.store'; import { moonPath, moonViewBox, sunPath, sunViewBox } from '$lib/assets/svg-paths'; - import { Theme } from '$lib/utils/theme'; + import { Theme } from '$lib/constants'; import { t } from 'svelte-i18n'; export let onDone: () => void; diff --git a/web/src/lib/components/shared-components/immich-logo.svelte b/web/src/lib/components/shared-components/immich-logo.svelte index cb77f40ca0..34f4b9707c 100644 --- a/web/src/lib/components/shared-components/immich-logo.svelte +++ b/web/src/lib/components/shared-components/immich-logo.svelte @@ -3,11 +3,11 @@ import logoLightUrl from '$lib/assets/immich-logo-inline-light.svg'; import logoNoText from '$lib/assets/immich-logo.svg'; import { content as alternativeLogo } from '$lib/assets/immich-logo.json'; - import { Theme } from '$lib/utils/theme'; import { colorTheme } from '$lib/stores/preferences.store'; import { DateTime } from 'luxon'; import type { HTMLImgAttributes } from 'svelte/elements'; import { t } from 'svelte-i18n'; + import { Theme } from '$lib/constants'; // eslint-disable-next-line @typescript-eslint/no-unused-vars interface $$Props extends HTMLImgAttributes { diff --git a/web/src/lib/components/shared-components/map/map.svelte b/web/src/lib/components/shared-components/map/map.svelte index 036da41e1e..db5f520c87 100644 --- a/web/src/lib/components/shared-components/map/map.svelte +++ b/web/src/lib/components/shared-components/map/map.svelte @@ -6,7 +6,7 @@ import Icon from '$lib/components/elements/icon.svelte'; import { colorTheme, mapSettings } from '$lib/stores/preferences.store'; import { getAssetThumbnailUrl, handlePromiseError } from '$lib/utils'; - import { Theme } from '$lib/utils/theme'; + import { Theme } from '$lib/constants'; import { getServerConfig, type MapMarkerResponseDto } from '@immich/sdk'; import mapboxRtlUrl from '@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js?url'; import { mdiCog, mdiMap, mdiMapMarker } from '@mdi/js'; diff --git a/web/src/lib/components/shared-components/theme-button.svelte b/web/src/lib/components/shared-components/theme-button.svelte index 8fee1b2bed..81622174e2 100644 --- a/web/src/lib/components/shared-components/theme-button.svelte +++ b/web/src/lib/components/shared-components/theme-button.svelte @@ -2,7 +2,7 @@ import { moonPath, moonViewBox, sunPath, sunViewBox } from '$lib/assets/svg-paths'; import CircleIconButton, { type Padding } from '$lib/components/elements/buttons/circle-icon-button.svelte'; import { colorTheme, handleToggleTheme } from '$lib/stores/preferences.store'; - import { Theme } from '$lib/utils/theme'; + import { Theme } from '$lib/constants'; import { t } from 'svelte-i18n'; $: icon = $colorTheme.value === Theme.LIGHT ? moonPath : sunPath; diff --git a/web/src/lib/constants.ts b/web/src/lib/constants.ts index ad51935465..8462596806 100644 --- a/web/src/lib/constants.ts +++ b/web/src/lib/constants.ts @@ -102,6 +102,12 @@ export const timeBeforeShowLoadingSpinner: number = 100; export const timeDebounceOnSearch: number = 300; +// should be the same values as the ones in the app.ts +export enum Theme { + LIGHT = 'light', + DARK = 'dark', +} + export const fallbackLocale = { code: 'en-US', name: 'English (US)', diff --git a/web/src/lib/stores/preferences.store.ts b/web/src/lib/stores/preferences.store.ts index 11ae70e56b..16a0da08b8 100644 --- a/web/src/lib/stores/preferences.store.ts +++ b/web/src/lib/stores/preferences.store.ts @@ -1,10 +1,14 @@ import { browser } from '$app/environment'; -import { defaultLang } from '$lib/constants'; +import { defaultLang, Theme } from '$lib/constants'; import { getPreferredLocale } from '$lib/utils/i18n'; -import { colorThemeKeyName, Theme, type ThemeSetting } from '$lib/utils/theme'; import { persisted } from 'svelte-local-storage-store'; import { get } from 'svelte/store'; +export interface ThemeSetting { + value: Theme; + system: boolean; +} + export const handleToggleTheme = () => { const theme = get(colorTheme); theme.value = theme.value === Theme.DARK ? Theme.LIGHT : Theme.DARK; @@ -20,7 +24,8 @@ const initTheme = (): ThemeSetting => { const initialTheme = initTheme(); -export const colorTheme = persisted(colorThemeKeyName, initialTheme, { +// The 'color-theme' key is also used by app.ts to prevent FOUC on page load. +export const colorTheme = persisted('color-theme', initialTheme, { serializer: { parse: (text: string): ThemeSetting => { const parsedText: ThemeSetting = JSON.parse(text); diff --git a/web/src/lib/utils/app.ts b/web/src/lib/utils/app.ts index 96e9a0adf0..8e1b904e9b 100644 --- a/web/src/lib/utils/app.ts +++ b/web/src/lib/utils/app.ts @@ -1,11 +1,17 @@ -/* - * we don't want to deal with imports so that import should be - * replaced by the actual content of the file before fouc.ts is transpiled - * - */ -import { colorThemeKeyName, Theme, type ThemeSetting } from '$lib/utils/theme'; +// should be the same values as the one in perferences.store.ts +interface ThemeSetting { + value: Theme; + system: boolean; +} -const storedTheme = localStorage.getItem(colorThemeKeyName); +// should be the same values as the ones in constants.ts +enum Theme { + LIGHT = 'light', + DARK = 'dark', +} + +// should be the same key as the one in preferences.store.ts +const storedTheme = localStorage.getItem('color-theme'); const theme: ThemeSetting = storedTheme ? JSON.parse(storedTheme) : { value: Theme.LIGHT, system: true }; const themeValue = theme.system && window.matchMedia('(prefers-color-scheme: dark)').matches ? Theme.DARK : theme.value; diff --git a/web/src/lib/utils/theme.ts b/web/src/lib/utils/theme.ts deleted file mode 100644 index 8f4a9db658..0000000000 --- a/web/src/lib/utils/theme.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface ThemeSetting { - value: Theme; - system: boolean; -} - -export enum Theme { - LIGHT = 'light', - DARK = 'dark', -} - -export const colorThemeKeyName = 'color-theme'; diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index cc2f821537..5a6610609e 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -8,8 +8,8 @@ import NotificationList from '$lib/components/shared-components/notification/notification-list.svelte'; import UploadPanel from '$lib/components/shared-components/upload-panel.svelte'; import VersionAnnouncementBox from '$lib/components/shared-components/version-announcement-box.svelte'; - import { Theme, type ThemeSetting } from '$lib/utils/theme'; - import { colorTheme, handleToggleTheme } from '$lib/stores/preferences.store'; + import { Theme } from '$lib/constants'; + import { colorTheme, handleToggleTheme, type ThemeSetting } from '$lib/stores/preferences.store'; import { serverConfig } from '$lib/stores/server-config.store'; import { user } from '$lib/stores/user.store'; import { closeWebsocketConnection, openWebsocketConnection } from '$lib/stores/websocket';