summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--packages/frontend/src/lib/components/SettingsPanel.svelte52
-rw-r--r--packages/frontend/src/lib/components/ThemeSwitcher.svelte58
2 files changed, 52 insertions, 58 deletions
diff --git a/packages/frontend/src/lib/components/SettingsPanel.svelte b/packages/frontend/src/lib/components/SettingsPanel.svelte
index 392852a..efbaf5f 100644
--- a/packages/frontend/src/lib/components/SettingsPanel.svelte
+++ b/packages/frontend/src/lib/components/SettingsPanel.svelte
@@ -11,6 +11,42 @@ const {
apiBase?: string;
} = $props();
+// Theme picker — was a header-triggered modal (`ThemeSwitcher.svelte`);
+// inlined here so theme picking lives in Settings alongside other UI
+// preferences. The list and localStorage key must stay in sync with the
+// boot-time theme apply in `App.svelte`'s `onMount`.
+const THEMES = [
+ "light",
+ "dark",
+ "dracula",
+ "night",
+ "nord",
+ "sunset",
+ "cyberpunk",
+ "forest",
+ "cmyk",
+ "coffee",
+ "caramellatte",
+ "garden",
+ "luxury",
+] as const;
+
+const THEME_STORAGE_KEY = "dispatch-theme";
+
+let currentTheme = $state(
+ (typeof localStorage !== "undefined" && localStorage.getItem(THEME_STORAGE_KEY)) || "dark",
+);
+
+function selectTheme(theme: string): void {
+ currentTheme = theme;
+ document.documentElement.setAttribute("data-theme", theme);
+ try {
+ localStorage.setItem(THEME_STORAGE_KEY, theme);
+ } catch {
+ // Best-effort — private mode / quota.
+ }
+}
+
let titleKeyId = $state<string | null>(null);
let titleModelId = $state<string | null>(null);
let availableModels = $state<string[]>([]);
@@ -136,6 +172,22 @@ $effect(() => {
<div class="text-xs font-semibold text-base-content/50 uppercase tracking-wide">Settings</div>
<div class="flex flex-col gap-2">
+ <p class="text-xs text-base-content/70">Theme</p>
+ <label class="text-xs text-base-content/60">
+ Appearance
+ <select
+ class="select select-bordered select-sm w-full capitalize"
+ value={currentTheme}
+ onchange={(e) => selectTheme(e.currentTarget.value)}
+ >
+ {#each THEMES as theme (theme)}
+ <option value={theme} class="capitalize">{theme}</option>
+ {/each}
+ </select>
+ </label>
+
+ <div class="divider my-0"></div>
+
<p class="text-xs text-base-content/70">Title Generation Model</p>
<p class="text-xs text-base-content/40">Used to generate short titles for new tabs after the first message.</p>
diff --git a/packages/frontend/src/lib/components/ThemeSwitcher.svelte b/packages/frontend/src/lib/components/ThemeSwitcher.svelte
deleted file mode 100644
index 418fcea..0000000
--- a/packages/frontend/src/lib/components/ThemeSwitcher.svelte
+++ /dev/null
@@ -1,58 +0,0 @@
-<script lang="ts">
-const THEMES = [
- "light",
- "dark",
- "dracula",
- "night",
- "nord",
- "sunset",
- "cyberpunk",
- "forest",
- "cmyk",
- "coffee",
- "caramellatte",
- "garden",
- "luxury",
-] as const;
-
-const STORAGE_KEY = "dispatch-theme";
-
-const { onclose }: { onclose: () => void } = $props();
-
-let currentTheme = $state(
- (typeof localStorage !== "undefined" && localStorage.getItem(STORAGE_KEY)) || "dark",
-);
-
-let dialogEl: HTMLDialogElement | undefined = $state();
-
-$effect(() => {
- if (dialogEl && !dialogEl.open) dialogEl.showModal();
-});
-
-function selectTheme(theme: string) {
- currentTheme = theme;
- document.documentElement.setAttribute("data-theme", theme);
- localStorage.setItem(STORAGE_KEY, theme);
- onclose();
-}
-</script>
-
-<dialog class="modal" bind:this={dialogEl} oncancel={onclose}>
- <div class="modal-box w-56">
- <h3 class="text-sm font-semibold mb-3">Select Theme</h3>
- <ul class="menu menu-sm">
- {#each THEMES as theme}
- <li>
- <button
- type="button"
- class="capitalize {currentTheme === theme ? 'menu-active' : ''}"
- onclick={() => selectTheme(theme)}
- >
- {theme}
- </button>
- </li>
- {/each}
- </ul>
- </div>
- <form method="dialog" class="modal-backdrop"><button>close</button></form>
-</dialog>