|
1 | 1 | <script lang="ts"> |
| 2 | + import type { Snippet } from 'svelte' |
2 | 3 | import Transition from 'svelte-transition' |
3 | 4 | import { createMenu } from 'svelte-headlessui' |
4 | | - import { theme, themes, type Theme } from './state.svelte' |
5 | | - import Icon from './Icon.svelte' |
| 5 | + import { theme, Theme } from './state.svelte' |
| 6 | + import { defaultIcons } from './Theme.svelte' |
| 7 | +
|
| 8 | + interface Props { |
| 9 | + dropdownList?: string |
| 10 | + dropdownHover?: string |
| 11 | + textActive?: string |
| 12 | + labels?: Record<Theme, string> |
| 13 | + icons?: Snippet<[Theme, boolean]> |
| 14 | + } |
| 15 | +
|
| 16 | + let { |
| 17 | + dropdownList = 'text-slate-700 bg-white ring-1 ring-black/5 dark:bg-slate-700 dark:ring-0 dark:highlight-white/5 dark:text-slate-300', |
| 18 | + dropdownHover = 'hover:bg-slate-50 hover:dark:bg-slate-800/50', |
| 19 | + textActive = 'text-sky-500', |
| 20 | + labels = { |
| 21 | + light: 'Light', |
| 22 | + dark: 'Dark', |
| 23 | + system: 'System', |
| 24 | + }, |
| 25 | + icons = defaultIcons, |
| 26 | + }: Props = $props() |
6 | 27 |
|
7 | 28 | const menu = createMenu({ label: 'Theme' }) |
8 | 29 |
|
|
22 | 43 | function closed() { |
23 | 44 | // apply any pending setting once closed |
24 | 45 | if (pending) { |
25 | | - theme.current = pending |
| 46 | + theme.override = pending |
26 | 47 | pending = undefined |
27 | 48 | } |
28 | 49 | } |
29 | 50 | </script> |
30 | 51 |
|
31 | 52 | <div class="relative inline-block"> |
32 | 53 | <button class="w-6 h-6 leading-none" use:menu.button onchange={change}> |
33 | | - <Icon /> |
| 54 | + <span class="size-6" hidden={theme.override === 'system'}> |
| 55 | + <span class="dark:hidden inline">{@render icons('light', true)}</span> |
| 56 | + <span class="hidden dark:inline">{@render icons('dark', true)}</span> |
| 57 | + </span> |
| 58 | + <span class="size-6" hidden={theme.override !== 'system'}> |
| 59 | + <span class="dark:hidden inline">{@render icons('light', false)}</span> |
| 60 | + <span class="hidden dark:inline">{@render icons('dark', false)}</span> |
| 61 | + </span> |
34 | 62 | </button> |
35 | 63 |
|
36 | 64 | <Transition |
|
43 | 71 | leaveTo="transform opacity-0 scale-95" |
44 | 72 | on:after-leave={closed} |
45 | 73 | > |
46 | | - <ul class="origin-top-right absolute right-0 py-1 mt-2 w-28 rounded-md shadow-lg focus:outline-none {theme.colors.dropdownList}" use:menu.items> |
47 | | - {#each themes as value} |
| 74 | + <ul class="origin-top-right absolute right-0 py-1 mt-2 w-28 rounded-md shadow-lg focus:outline-none {dropdownList}" use:menu.items> |
| 75 | + {#each Theme as value} |
48 | 76 | {@const active = value === theme.override} |
49 | 77 | <li |
50 | | - class="flex items-center px-2 py-1 text-sm font-semibold cursor-pointer {theme.colors.dropdownHover} {active |
51 | | - ? theme.colors.textActive |
52 | | - : ''}" |
| 78 | + class="flex items-center px-2 py-1 text-sm font-semibold cursor-pointer {dropdownHover} {active ? textActive : ''}" |
53 | 79 | use:menu.item={{ value }} |
54 | 80 | > |
55 | | - <span class="w-6 h-6 mr-2" hidden={!active}>{@html theme.icons[value](true)}</span> |
56 | | - <span class="w-6 h-6 mr-2" hidden={active}>{@html theme.icons[value](false)}</span> |
57 | | - {theme.labels[value]} |
| 81 | + <span class="w-6 h-6 mr-2" hidden={!active}>{@render icons(value, true)}</span> |
| 82 | + <span class="w-6 h-6 mr-2" hidden={active}>{@render icons(value, false)}</span> |
| 83 | + {labels[value]} |
58 | 84 | </li> |
59 | 85 | {/each} |
60 | 86 | </ul> |
|
0 commit comments