fix: script in app.html

This commit is contained in:
martabal 2024-10-24 10:18:00 +02:00
parent 7e9fb5df5e
commit 7e433d6194
No known key found for this signature in database
GPG Key ID: C00196E3148A52BD
12 changed files with 52 additions and 53 deletions

View File

@ -66,37 +66,8 @@
background-color: black; background-color: black;
} }
</style> </style>
<script>
/**
* Prevent FOUC on page load.
*/
const colorThemeKeyName = 'color-theme';
let theme = localStorage.getItem(colorThemeKeyName); %app.fouc%
if (!theme) {
theme = { value: 'light', system: true };
} else if (theme === 'dark' || theme === 'light') {
theme = { value: theme, system: false };
localStorage.setItem(colorThemeKeyName, JSON.stringify(theme));
} else {
theme = JSON.parse(theme);
}
let themeValue = theme.value;
if (theme.system) {
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
themeValue = 'dark';
} else {
themeValue = 'light';
}
}
if (themeValue === 'light') {
document.documentElement.classList.remove('dark');
} else {
document.documentElement.classList.add('dark');
}
</script>
<link rel="stylesheet" href="/custom.css" /> <link rel="stylesheet" href="/custom.css" />
</head> </head>

View File

@ -1,12 +1,22 @@
import overpass from '$lib/assets/fonts/overpass/Overpass.ttf?url'; import overpass from '$lib/assets/fonts/overpass/Overpass.ttf?url';
import overpassMono from '$lib/assets/fonts/overpass/OverpassMono.ttf?url'; import overpassMono from '$lib/assets/fonts/overpass/OverpassMono.ttf?url';
import { transpileFile } from '$lib/utils';
import fouc from '$lib/utils/fouc?raw';
import theme from '$lib/utils/theme?raw';
import type { Handle } from '@sveltejs/kit'; import type { Handle } from '@sveltejs/kit';
// only used during the build to replace the variables from app.html // only used during the build to replace the variables from app.html
export const handle = (async ({ event, resolve }) => { export const handle = (async ({ event, resolve }) => {
return resolve(event, { return resolve(event, {
transformPageChunk: ({ html }) => { transformPageChunk: ({ html }) => {
return html.replace('%app.font%', overpass).replace('%app.monofont%', overpassMono); const themePrepared = theme.replaceAll(/^export\s+/gm, '');
const foucPrepared = fouc.replaceAll(/^import.*$/gm, themePrepared);
const scriptFouc = `<script>${transpileFile(foucPrepared)}</script>`;
return html
.replace('%app.font%', overpass)
.replace('%app.monofont%', overpassMono)
.replace('%app.fouc%', scriptFouc);
}, },
}); });
}) satisfies Handle; }) satisfies Handle;

View File

@ -5,7 +5,7 @@
import OnboardingCard from './onboarding-card.svelte'; import OnboardingCard from './onboarding-card.svelte';
import { colorTheme } from '$lib/stores/preferences.store'; import { colorTheme } from '$lib/stores/preferences.store';
import { moonPath, moonViewBox, sunPath, sunViewBox } from '$lib/assets/svg-paths'; import { moonPath, moonViewBox, sunPath, sunViewBox } from '$lib/assets/svg-paths';
import { Theme } from '$lib/constants'; import { Theme } from '$lib/utils/theme';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
export let onDone: () => void; export let onDone: () => void;

View File

@ -3,7 +3,7 @@
import logoLightUrl from '$lib/assets/immich-logo-inline-light.svg'; import logoLightUrl from '$lib/assets/immich-logo-inline-light.svg';
import logoNoText from '$lib/assets/immich-logo.svg'; import logoNoText from '$lib/assets/immich-logo.svg';
import { content as alternativeLogo } from '$lib/assets/immich-logo.json'; import { content as alternativeLogo } from '$lib/assets/immich-logo.json';
import { Theme } from '$lib/constants'; import { Theme } from '$lib/utils/theme';
import { colorTheme } from '$lib/stores/preferences.store'; import { colorTheme } from '$lib/stores/preferences.store';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import type { HTMLImgAttributes } from 'svelte/elements'; import type { HTMLImgAttributes } from 'svelte/elements';

View File

@ -4,9 +4,9 @@
<script lang="ts"> <script lang="ts">
import Icon from '$lib/components/elements/icon.svelte'; import Icon from '$lib/components/elements/icon.svelte';
import { Theme } from '$lib/constants';
import { colorTheme, mapSettings } from '$lib/stores/preferences.store'; import { colorTheme, mapSettings } from '$lib/stores/preferences.store';
import { getAssetThumbnailUrl, handlePromiseError } from '$lib/utils'; import { getAssetThumbnailUrl, handlePromiseError } from '$lib/utils';
import { Theme } from '$lib/utils/theme';
import { getServerConfig, type MapMarkerResponseDto } from '@immich/sdk'; import { getServerConfig, type MapMarkerResponseDto } from '@immich/sdk';
import mapboxRtlUrl from '@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js?url'; import mapboxRtlUrl from '@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js?url';
import { mdiCog, mdiMap, mdiMapMarker } from '@mdi/js'; import { mdiCog, mdiMap, mdiMapMarker } from '@mdi/js';

View File

@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import { moonPath, moonViewBox, sunPath, sunViewBox } from '$lib/assets/svg-paths'; import { moonPath, moonViewBox, sunPath, sunViewBox } from '$lib/assets/svg-paths';
import CircleIconButton, { type Padding } from '$lib/components/elements/buttons/circle-icon-button.svelte'; import CircleIconButton, { type Padding } from '$lib/components/elements/buttons/circle-icon-button.svelte';
import { Theme } from '$lib/constants';
import { colorTheme, handleToggleTheme } from '$lib/stores/preferences.store'; import { colorTheme, handleToggleTheme } from '$lib/stores/preferences.store';
import { Theme } from '$lib/utils/theme';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
$: icon = $colorTheme.value === Theme.LIGHT ? moonPath : sunPath; $: icon = $colorTheme.value === Theme.LIGHT ? moonPath : sunPath;

View File

@ -102,12 +102,6 @@ export const timeBeforeShowLoadingSpinner: number = 100;
export const timeDebounceOnSearch: number = 300; export const timeDebounceOnSearch: number = 300;
// should be the same values as the ones in the app.html
export enum Theme {
LIGHT = 'light',
DARK = 'dark',
}
export const fallbackLocale = { export const fallbackLocale = {
code: 'en-US', code: 'en-US',
name: 'English (US)', name: 'English (US)',

View File

@ -1,14 +1,10 @@
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import { Theme, defaultLang } from '$lib/constants'; import { defaultLang } from '$lib/constants';
import { getPreferredLocale } from '$lib/utils/i18n'; import { getPreferredLocale } from '$lib/utils/i18n';
import { colorThemeKeyName, Theme, type ThemeSetting } from '$lib/utils/theme';
import { persisted } from 'svelte-local-storage-store'; import { persisted } from 'svelte-local-storage-store';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
export interface ThemeSetting {
value: Theme;
system: boolean;
}
export const handleToggleTheme = () => { export const handleToggleTheme = () => {
const theme = get(colorTheme); const theme = get(colorTheme);
theme.value = theme.value === Theme.DARK ? Theme.LIGHT : Theme.DARK; theme.value = theme.value === Theme.DARK ? Theme.LIGHT : Theme.DARK;
@ -24,8 +20,7 @@ const initTheme = (): ThemeSetting => {
const initialTheme = initTheme(); const initialTheme = initTheme();
// The 'color-theme' key is also used by app.html to prevent FOUC on page load. export const colorTheme = persisted<ThemeSetting>(colorThemeKeyName, initialTheme, {
export const colorTheme = persisted<ThemeSetting>('color-theme', initialTheme, {
serializer: { serializer: {
parse: (text: string): ThemeSetting => { parse: (text: string): ThemeSetting => {
const parsedText: ThemeSetting = JSON.parse(text); const parsedText: ThemeSetting = JSON.parse(text);

View File

@ -25,6 +25,7 @@ import { mdiCogRefreshOutline, mdiDatabaseRefreshOutline, mdiHeadSyncOutline, md
import { sortBy } from 'lodash-es'; import { sortBy } from 'lodash-es';
import { init, register, t } from 'svelte-i18n'; import { init, register, t } from 'svelte-i18n';
import { derived, get } from 'svelte/store'; import { derived, get } from 'svelte/store';
import { ModuleKind, transpileModule } from 'typescript';
interface DownloadRequestOptions<T = unknown> { interface DownloadRequestOptions<T = unknown> {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
@ -337,3 +338,10 @@ export const suggestDuplicateByFileSize = (assets: AssetResponseDto[]): AssetRes
// eslint-disable-next-line unicorn/prefer-code-point // eslint-disable-next-line unicorn/prefer-code-point
export const decodeBase64 = (data: string) => Uint8Array.from(atob(data), (c) => c.charCodeAt(0)); export const decodeBase64 = (data: string) => Uint8Array.from(atob(data), (c) => c.charCodeAt(0));
export const transpileFile = (content: string) => {
const result = transpileModule(content, {
compilerOptions: { module: ModuleKind.ES2020, removeComments: true },
});
return result.outputText;
};

12
web/src/lib/utils/fouc.ts Normal file
View File

@ -0,0 +1,12 @@
/*
* 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';
const storedTheme = localStorage.getItem(colorThemeKeyName);
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;
document.documentElement.classList.toggle('dark', themeValue === Theme.DARK);

View File

@ -0,0 +1,11 @@
export interface ThemeSetting {
value: Theme;
system: boolean;
}
export enum Theme {
LIGHT = 'light',
DARK = 'dark',
}
export const colorThemeKeyName = 'color-theme';

View File

@ -8,11 +8,9 @@
import NotificationList from '$lib/components/shared-components/notification/notification-list.svelte'; import NotificationList from '$lib/components/shared-components/notification/notification-list.svelte';
import UploadPanel from '$lib/components/shared-components/upload-panel.svelte'; import UploadPanel from '$lib/components/shared-components/upload-panel.svelte';
import VersionAnnouncementBox from '$lib/components/shared-components/version-announcement-box.svelte'; import VersionAnnouncementBox from '$lib/components/shared-components/version-announcement-box.svelte';
import { Theme } from '$lib/constants'; import { Theme, type ThemeSetting } from '$lib/utils/theme';
import { colorTheme, handleToggleTheme, type ThemeSetting } from '$lib/stores/preferences.store'; import { colorTheme, handleToggleTheme } from '$lib/stores/preferences.store';
import { serverConfig } from '$lib/stores/server-config.store'; import { serverConfig } from '$lib/stores/server-config.store';
import { user } from '$lib/stores/user.store'; import { user } from '$lib/stores/user.store';
import { closeWebsocketConnection, openWebsocketConnection } from '$lib/stores/websocket'; import { closeWebsocketConnection, openWebsocketConnection } from '$lib/stores/websocket';
import { copyToClipboard, setKey } from '$lib/utils'; import { copyToClipboard, setKey } from '$lib/utils';