Skip to content

Commit

Permalink
[ThemeSelect] Use simplified menu when single light/dark themes are u…
Browse files Browse the repository at this point in the history
…sed, and show current scheme (light/dark) as icon
  • Loading branch information
techniq committed Jun 12, 2024
1 parent a86aa6a commit 2c49470
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 80 deletions.
5 changes: 5 additions & 0 deletions .changeset/rich-plants-invent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte-ux': patch
---

[ThemeSelect] Use simplified menu when single light/dark themes are used
5 changes: 5 additions & 0 deletions .changeset/sweet-eggs-pull.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte-ux': patch
---

[ThemeSelect] Show current scheme (light/dark) as icon
208 changes: 130 additions & 78 deletions packages/svelte-ux/src/lib/components/ThemeSelect.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { fly } from 'svelte/transition';
import { mdiPalette, mdiUndoVariant, mdiWeatherNight, mdiWhiteBalanceSunny } from '@mdi/js';
import { mdiMonitor, mdiUndoVariant, mdiWeatherNight, mdiWhiteBalanceSunny } from '@mdi/js';
import Button from './Button.svelte';
import Kbd from './Kbd.svelte';
Expand Down Expand Up @@ -44,88 +44,140 @@
}
</script>

<Button icon={mdiPalette} iconOnly on:click={() => (open = !open)}>
<Menu
bind:open
on:close={() => (open = false)}
offset={4}
explicitClose
resize="height"
classes={{ root: 'w-[400px] max-w-[95vw]' }}
>
<label
for="switch-color-scheme"
class="grid grid-cols-[1fr,auto,auto] items-center p-2 border-b border-surface-content/10 mb-1 text-sm font-medium"
>
Mode

{#if $currentTheme.theme}
<span transition:fly={{ x: 8 }}>
<Tooltip title="Reset to System" offset={2}>
<Button
icon={mdiUndoVariant}
color="primary"
size="sm"
class="mr-1"
on:click={() => {
currentTheme.setTheme('system');
}}
/>
</Tooltip>
</span>
{/if}
{#if darkThemes.length > 1 || lightThemes.length > 1}
<Button iconOnly on:click={() => (open = !open)}>
<div class="grid grid-cols-1 grid-rows-1 overflow-hidden">
<Icon
data={mdiWhiteBalanceSunny}
class="row-[1] col-[1] translate-x-0 dark:-translate-x-full transition-transform duration-300"
/>
<Icon
data={mdiWeatherNight}
class="row-[1] col-[1] translate-x-full dark:translate-x-0 transition-transform duration-300"
/>
</div>

<Switch
id="switch-color-scheme"
checked={$currentTheme.dark}
on:change={(e) => {
let newTheme = e.target?.checked ? 'dark' : 'light';
currentTheme.setTheme(newTheme);
}}
class="my-1"
let:checked
<Menu
bind:open
on:close={() => (open = false)}
explicitClose
resize="height"
classes={{ root: 'w-[400px] max-w-[95vw]' }}
>
<label
for="switch-color-scheme"
class="grid grid-cols-[1fr,auto,auto] items-center p-2 border-b border-surface-content/10 mb-1 text-sm font-medium sticky top-0 bg-surface-100"
>
{#if checked}
<Icon data={mdiWeatherNight} size=".8rem" class="text-primary" />
{:else}
<Icon data={mdiWhiteBalanceSunny} size=".8rem" class="text-primary" />
Mode
{#if $currentTheme.theme}
<span transition:fly={{ x: 8 }}>
<Tooltip title="Reset to System" offset={2}>
<Button
icon={mdiUndoVariant}
color="primary"
size="sm"
class="mr-1"
on:click={() => {
currentTheme.setTheme('system');
}}
/>
</Tooltip>
</span>
{/if}
</Switch>
</label>

<div class="grid grid-cols-2 gap-2 p-2 border-b border-surface-content/10">
{#each themes as themeName}
<MenuItem
on:click={() => currentTheme.setTheme(themeName)}
data-theme={themeName}
class={cls(
'bg-surface-100 text-surface-content font-semibold border shadow',
$currentTheme.resolvedTheme === themeName && 'ring-2 ring-surface-content'
)}

<Switch
id="switch-color-scheme"
checked={$currentTheme.dark}
on:change={(e) => {
let newTheme = e.target?.checked ? 'dark' : 'light';
currentTheme.setTheme(newTheme);
}}
class="my-1"
let:checked
>
{#if checked}
<Icon data={mdiWeatherNight} size=".8rem" class="text-primary" />
{:else}
<Icon data={mdiWhiteBalanceSunny} size=".8rem" class="text-primary" />
{/if}
</Switch>
</label>

<div class="grid grid-cols-2 gap-2 p-2">
{#each themes as themeName}
<MenuItem
on:click={() => currentTheme.setTheme(themeName)}
data-theme={themeName}
class={cls(
'bg-surface-100 text-surface-content font-semibold border shadow',
$currentTheme.resolvedTheme === themeName && 'ring-2 ring-surface-content'
)}
>
<div class="grid gap-1">
<div class="w-4 h-4 rounded-full bg-primary" />
<div class="w-4 h-4 rounded-full bg-secondary" />
</div>
{themeName}
</MenuItem>
{/each}
</div>

{#if keyboardShortcuts}
<div
class="p-2 grid grid-cols-[auto,1fr] gap-2 items-center text-xs sticky bottom-0 bg-surface-100 border-t border-surface-content/10"
>
<div class="grid gap-1">
<div class="w-4 h-4 rounded-full bg-primary" />
<div class="w-4 h-4 rounded-full bg-secondary" />
</div>
{themeName}
</MenuItem>
{/each}
<span class="font-medium">Toggle scheme:</span>
<span>
<Kbd control /> + <Kbd>T</Kbd>
</span>

<span class="font-medium">Next theme:</span>
<span>
<Kbd control /> + <Kbd shift /> + <Kbd>T</Kbd>
</span>
</div>
{/if}
</Menu>
</Button>
{:else}
<Button iconOnly on:click={() => (open = !open)}>
<div class="grid grid-stack overflow-hidden">
<Icon
data={mdiWhiteBalanceSunny}
class="translate-x-0 dark:-translate-x-full transition-transform duration-300"
/>
<Icon
data={mdiWeatherNight}
class="translate-x-full dark:translate-x-0 transition-transform duration-300"
/>
</div>

{#if keyboardShortcuts}
<div class="p-2 grid grid-cols-[auto,1fr] gap-2 items-center text-xs">
<span class="font-medium">Toggle scheme:</span>
<span>
<Kbd control /> + <Kbd>T</Kbd>
</span>

<span class="font-medium">Next theme:</span>
<span>
<Kbd control /> + <Kbd shift /> + <Kbd>T</Kbd>
</span>
</div>
{/if}
</Menu>
</Button>
<Menu bind:open on:close={() => (open = false)} classes={{ menu: 'p-1' }}>
<MenuItem
icon={mdiWhiteBalanceSunny}
selected={$currentTheme.theme === 'light'}
on:click={() => currentTheme.setTheme('light')}
>
Light
</MenuItem>

<MenuItem
icon={mdiWeatherNight}
selected={$currentTheme.theme === 'dark'}
on:click={() => currentTheme.setTheme('dark')}
>
Dark
</MenuItem>

<MenuItem
icon={mdiMonitor}
selected={$currentTheme.theme == null}
on:click={() => currentTheme.setTheme('system')}
>
System
</MenuItem>
</Menu>
</Button>
{/if}

<svelte:window on:keydown={keyboardShortcuts ? onKeyDown : undefined} />
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
<script lang="ts">
import Preview from '$lib/components/Preview.svelte';
import ThemeSelect from '$lib/components/ThemeSelect.svelte';
export let data;
</script>

<h1>Examples</h1>

<h2>Default</h2>

<h2>Default (based on settings)</h2>
<Preview>
<ThemeSelect />
</Preview>

<h2>Single light/dark theme</h2>

<Preview>
<ThemeSelect lightThemes={['light']} darkThemes={['dark']} />
</Preview>

<h2>Multiple light/dark themes</h2>

<Preview>
<!-- Use docs themes for convenience of many themes -->
<ThemeSelect lightThemes={data.themes.light} darkThemes={data.themes.dark} />
</Preview>

0 comments on commit 2c49470

Please sign in to comment.