53 lines
1.6 KiB
Svelte
53 lines
1.6 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from 'svelte';
|
|
import AppIcon from './AppIcon.svelte';
|
|
|
|
type Preference = 'system' | 'light' | 'dark';
|
|
const preferences: Preference[] = ['system', 'light', 'dark'];
|
|
const labels: Record<Preference, string> = {
|
|
system: 'System',
|
|
light: 'Hell',
|
|
dark: 'Dunkel'
|
|
};
|
|
let preference = $state<Preference>('system');
|
|
|
|
function apply(next: Preference) {
|
|
preference = next;
|
|
const dark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
document.documentElement.dataset.theme = next === 'system' ? (dark ? 'dark' : 'light') : next;
|
|
document.documentElement.dataset.themePreference = next;
|
|
localStorage.setItem('sendewerk-theme', next);
|
|
}
|
|
|
|
function cycle() {
|
|
const index = preferences.indexOf(preference);
|
|
apply(preferences[(index + 1) % preferences.length]);
|
|
}
|
|
|
|
onMount(() => {
|
|
const stored = localStorage.getItem('sendewerk-theme');
|
|
preference = preferences.includes(stored as Preference) ? (stored as Preference) : 'system';
|
|
apply(preference);
|
|
const media = window.matchMedia('(prefers-color-scheme: dark)');
|
|
const followSystem = () => {
|
|
if (preference === 'system') apply('system');
|
|
};
|
|
media.addEventListener('change', followSystem);
|
|
return () => media.removeEventListener('change', followSystem);
|
|
});
|
|
</script>
|
|
|
|
<button
|
|
class="theme-toggle"
|
|
type="button"
|
|
onclick={cycle}
|
|
aria-label={`Darstellung: ${labels[preference]}`}
|
|
>
|
|
<span class="theme-symbol" aria-hidden="true"
|
|
><AppIcon
|
|
name={preference === 'system' ? 'display' : preference === 'light' ? 'sun' : 'moon'}
|
|
/></span
|
|
>
|
|
<span>{labels[preference]}</span>
|
|
</button>
|