From e9d39759d4e9e3210f69c70693826bb4285b3998 Mon Sep 17 00:00:00 2001 From: Djuri Baars <dsbaars@users.noreply.github.com> Date: Thu, 28 Nov 2024 23:30:14 +0100 Subject: [PATCH] Add color mode switcher --- src/components/ColorSchemeSwitcher.svelte | 53 +++++++++++++++++++++++ src/lib/style/app.scss | 2 +- src/routes/+layout.svelte | 2 + 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/components/ColorSchemeSwitcher.svelte diff --git a/src/components/ColorSchemeSwitcher.svelte b/src/components/ColorSchemeSwitcher.svelte new file mode 100644 index 0000000..49e3175 --- /dev/null +++ b/src/components/ColorSchemeSwitcher.svelte @@ -0,0 +1,53 @@ +<script lang="ts"> + import { onMount } from 'svelte'; + import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from '@sveltestrap/sveltestrap'; + + type Theme = 'light' | 'dark' | 'auto'; + + let theme: Theme = 'auto'; + + // Set the theme based on user selection and store it in localStorage + function setTheme(newTheme: Theme) { + theme = newTheme; + localStorage.setItem('theme', newTheme); + applyTheme(newTheme); + } + + // Apply the selected theme to the document + function applyTheme(selectedTheme: Theme) { + if (selectedTheme === 'auto') { + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; + document.documentElement.setAttribute('data-bs-theme', prefersDark ? 'dark' : 'light'); + } else { + document.documentElement.setAttribute('data-bs-theme', selectedTheme); + } + } + + // On component mount, check localStorage and apply the saved theme + onMount(() => { + const savedTheme = (localStorage.getItem('theme') as Theme) || 'auto'; + applyTheme(savedTheme); + theme = savedTheme; + + // Listen for changes in the system color scheme preference + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + mediaQuery.addEventListener('change', () => { + if (theme === 'auto') { + applyTheme('auto'); + } + }); + }); +</script> + +<Dropdown inNavbar class="ms-3"> + <DropdownToggle nav caret> + {theme === 'auto' ? '🌗' : theme === 'dark' ? '🌙' : '☀️'} + </DropdownToggle> + <DropdownMenu end> + <DropdownItem active={theme === 'light'} on:click={() => setTheme('light')} + >☀️ Light</DropdownItem + > + <DropdownItem active={theme === 'dark'} on:click={() => setTheme('dark')}>🌙 Dark</DropdownItem> + <DropdownItem active={theme === 'auto'} on:click={() => setTheme('auto')}>🌗 Auto</DropdownItem> + </DropdownMenu> +</Dropdown> diff --git a/src/lib/style/app.scss b/src/lib/style/app.scss index 00bf40b..0fd0702 100644 --- a/src/lib/style/app.scss +++ b/src/lib/style/app.scss @@ -9,7 +9,7 @@ @import './satsymbol'; -$color-mode-type: media-query; +$color-mode-type: data; $font-family-base: 'Ubuntu'; $font-size-base: 0.9rem; $input-font-size-sm: $font-size-base * 0.875; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index a34ea20..494ab86 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -15,6 +15,7 @@ import { page } from '$app/stores'; import { locale, locales, isLoading } from 'svelte-i18n'; + import ColorSchemeSwitcher from '../components/ColorSchemeSwitcher.svelte'; export const setLocale = (lang: string) => () => { locale.set(lang); @@ -88,6 +89,7 @@ </DropdownMenu> </Dropdown> {/if} + <ColorSchemeSwitcher></ColorSchemeSwitcher> </Collapse> </Navbar>