summaryrefslogtreecommitdiffhomepage
path: root/packages/frontend/src/lib/components/ThemeSwitcher.svelte
diff options
context:
space:
mode:
Diffstat (limited to 'packages/frontend/src/lib/components/ThemeSwitcher.svelte')
-rw-r--r--packages/frontend/src/lib/components/ThemeSwitcher.svelte65
1 files changed, 65 insertions, 0 deletions
diff --git a/packages/frontend/src/lib/components/ThemeSwitcher.svelte b/packages/frontend/src/lib/components/ThemeSwitcher.svelte
new file mode 100644
index 0000000..6984e3f
--- /dev/null
+++ b/packages/frontend/src/lib/components/ThemeSwitcher.svelte
@@ -0,0 +1,65 @@
+<script lang="ts">
+const THEMES = [
+ "light",
+ "dark",
+ "dracula",
+ "night",
+ "nord",
+ "sunset",
+ "cyberpunk",
+ "forest",
+ "cmyk",
+ "coffee",
+ "caramellatte",
+] as const;
+
+const STORAGE_KEY = "dispatch-theme";
+
+const { onclose }: { onclose: () => void } = $props();
+
+let currentTheme = $state(
+ (typeof localStorage !== "undefined" && localStorage.getItem(STORAGE_KEY)) || "dark",
+);
+
+function selectTheme(theme: string) {
+ currentTheme = theme;
+ document.documentElement.setAttribute("data-theme", theme);
+ localStorage.setItem(STORAGE_KEY, theme);
+ onclose();
+}
+</script>
+
+<!-- Backdrop -->
+<div
+ class="fixed inset-0 z-40 bg-black/40"
+ role="button"
+ tabindex="0"
+ onclick={onclose}
+ onkeydown={(e) => e.key === "Escape" && onclose()}
+ aria-label="Close theme switcher"
+></div>
+
+<!-- Modal -->
+<div
+ class="fixed top-16 right-4 z-50 bg-base-100 border border-base-300 rounded-xl shadow-xl p-4 w-56"
+ role="dialog"
+ aria-label="Theme switcher"
+>
+ <p class="text-sm font-semibold mb-3 text-base-content">Select Theme</p>
+ <ul class="space-y-1">
+ {#each THEMES as theme}
+ <li>
+ <button
+ type="button"
+ class="w-full text-left px-3 py-1.5 rounded-lg text-sm capitalize hover:bg-base-200 transition-colors {currentTheme ===
+ theme
+ ? 'bg-primary text-primary-content'
+ : ''}"
+ onclick={() => selectTheme(theme)}
+ >
+ {theme}
+ </button>
+ </li>
+ {/each}
+ </ul>
+</div>