From b145f14ff1bc371660fa846963bc2761952d00bd Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Wed, 3 Jan 2024 17:29:27 -1000 Subject: [PATCH] add ThemeInit component that place script inside tag (#176) * add ThemeInit component that place script inside tag * Fix bug * proper sorting * instantiate ThemeInit inside Settings component * add comment about stringified function --- .changeset/friendly-pets-reflect.md | 5 ++++ .../src/lib/components/Settings.svelte | 6 +++++ .../src/lib/components/ThemeInit.svelte | 12 ++++++++++ .../svelte-ux/src/lib/components/index.ts | 1 + packages/svelte-ux/src/lib/styles/theme.ts | 24 +++++++++++++++++++ 5 files changed, 48 insertions(+) create mode 100644 .changeset/friendly-pets-reflect.md create mode 100644 packages/svelte-ux/src/lib/components/ThemeInit.svelte diff --git a/.changeset/friendly-pets-reflect.md b/.changeset/friendly-pets-reflect.md new file mode 100644 index 000000000..e86611b37 --- /dev/null +++ b/.changeset/friendly-pets-reflect.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": patch +--- + +Add ThemeInit component to prevent flash of unstyled content when SSR is enabled diff --git a/packages/svelte-ux/src/lib/components/Settings.svelte b/packages/svelte-ux/src/lib/components/Settings.svelte index bae5e3e24..a2c0952e9 100644 --- a/packages/svelte-ux/src/lib/components/Settings.svelte +++ b/packages/svelte-ux/src/lib/components/Settings.svelte @@ -1,9 +1,15 @@ +{#if themeInit} + +{/if} diff --git a/packages/svelte-ux/src/lib/components/ThemeInit.svelte b/packages/svelte-ux/src/lib/components/ThemeInit.svelte new file mode 100644 index 000000000..6daffa81e --- /dev/null +++ b/packages/svelte-ux/src/lib/components/ThemeInit.svelte @@ -0,0 +1,12 @@ + + + + {@html headSnippet} + diff --git a/packages/svelte-ux/src/lib/components/index.ts b/packages/svelte-ux/src/lib/components/index.ts index acf035412..50e84ea25 100644 --- a/packages/svelte-ux/src/lib/components/index.ts +++ b/packages/svelte-ux/src/lib/components/index.ts @@ -83,6 +83,7 @@ export { default as Tab } from './Tab.svelte'; export { default as Tabs } from './Tabs.svelte'; export { default as TextField } from './TextField.svelte'; export { default as ThemeButton } from './ThemeButton.svelte'; +export { default as ThemeInit } from './ThemeInit.svelte'; export { default as Tilt } from './Tilt.svelte'; export { default as Toggle } from './Toggle.svelte'; export { default as ToggleButton } from './ToggleButton.svelte'; diff --git a/packages/svelte-ux/src/lib/styles/theme.ts b/packages/svelte-ux/src/lib/styles/theme.ts index aac38dadf..edb9d0872 100644 --- a/packages/svelte-ux/src/lib/styles/theme.ts +++ b/packages/svelte-ux/src/lib/styles/theme.ts @@ -20,3 +20,27 @@ export const colorNames = [ 'surface-300', 'surface-content', ]; + +/** Return a script tag that will set the initial theme from localStorage. This allows setting + * the theme before anything starts rendering, even when SSR is in use. + * + * This feels a bit weird compared to just placing the function directly in svelte:head, + * but it's the only way to inject the `darkThemes` array into the function. + **/ +export function createHeadSnippet(darkThemes: string[]) { + function _applyInitialStyle(darkThemes) { + let theme = localStorage.getItem('theme'); + if (theme) { + document.documentElement.dataset.theme = theme; + if (darkThemes.includes(theme)) { + document.documentElement.classList.add('dark'); + } + } else if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + document.documentElement.classList.add('dark'); + } + } + + let darkThemeList = darkThemes.map((theme) => `'${theme}'`).join(', '); + + return ``; +}