You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/web/routes/active/_components/ThemeToggle.svelte

116 lines
2.7 KiB

<script lang="ts">
import { onMount } from 'svelte';
type Theme = 'light' | 'dark' | 'system';
const STOR_KEY = 'active-docs-theme';
let theme = $state<Theme>('system');
let resolved = $state<'light' | 'dark'>('light');
function applyTheme(next: Theme) {
const isDark =
next === 'dark' ||
(next === 'system' &&
window.matchMedia &&
window.matchMedia('(prefers-color-scheme: dark)').matches);
document.documentElement.dataset.theme = isDark ? 'dark' : 'light';
resolved = isDark ? 'dark' : 'light';
}
function setTheme(next: Theme) {
theme = next;
try {
localStorage.setItem(STOR_KEY, next);
} catch {
/* private mode or storage disabled */
}
applyTheme(next);
}
function cycle() {
const order: Theme[] = ['light', 'dark', 'system'];
const idx = order.indexOf(theme);
setTheme(order[(idx + 1) % order.length]);
}
onMount(() => {
try {
const saved = localStorage.getItem(STOR_KEY) as Theme | null;
if (saved === 'light' || saved === 'dark' || saved === 'system') theme = saved;
} catch {
/* ignore */
}
applyTheme(theme);
const mq = window.matchMedia('(prefers-color-scheme: dark)');
const handler = () => {
if (theme === 'system') applyTheme('system');
};
mq.addEventListener('change', handler);
return () => mq.removeEventListener('change', handler);
});
const label = $derived(
theme === 'system' ? `System (${resolved})` : theme === 'dark' ? 'Dark' : 'Light'
);
</script>
<button
class="toggle"
type="button"
aria-label="Toggle color theme — currently {label}"
title="Theme: {label}"
onclick={cycle}
>
{#if resolved === 'dark'}
<svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true">
<path
fill="currentColor"
d="M6.05 2.5a6 6 0 1 0 7.45 7.45 5 5 0 0 1-7.45-7.45Z"
/>
</svg>
{:else}
<svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true">
<circle cx="8" cy="8" r="3" fill="currentColor" />
<g stroke="currentColor" stroke-width="1.6" stroke-linecap="round">
<path d="M8 1.5v1.5" />
<path d="M8 13v1.5" />
<path d="M1.5 8h1.5" />
<path d="M13 8h1.5" />
<path d="m3.4 3.4 1.05 1.05" />
<path d="m11.55 11.55 1.05 1.05" />
<path d="m3.4 12.6 1.05-1.05" />
<path d="m11.55 4.45 1.05-1.05" />
</g>
</svg>
{/if}
</button>
<style>
.toggle {
display: inline-flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
border-radius: var(--r-md);
background: transparent;
border: none;
color: var(--c-fg-muted);
transition:
background-color 120ms var(--ease),
color 120ms var(--ease);
}
.toggle:hover {
background: var(--c-bg-muted);
color: var(--c-fg);
}
.toggle:focus-visible {
outline: 2px solid var(--c-accent);
outline-offset: 2px;
}
</style>

Powered by TurnKey Linux.