feat(ThemeSwitch): create ThemeSwitch component that uses ThemeMager toggle to switch theme
This commit is contained in:
2
src/features/ChangeAppTheme/index.ts
Normal file
2
src/features/ChangeAppTheme/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './model';
|
||||||
|
export * from './ui';
|
||||||
1
src/features/ChangeAppTheme/model/index.ts
Normal file
1
src/features/ChangeAppTheme/model/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export { themeManager } from './store/ThemeManager/ThemeManager.svelte';
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<script module>
|
||||||
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||||
|
import ThemeSwitch from './ThemeSwitch.svelte';
|
||||||
|
|
||||||
|
const { Story } = defineMeta({
|
||||||
|
title: 'Features/ThemeSwitch',
|
||||||
|
component: ThemeSwitch,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
component:
|
||||||
|
'Theme toggle button that switches between light and dark modes. Uses ThemeManager to persist user preference and sync with system preference. Displays sun/moon icon based on current theme.',
|
||||||
|
},
|
||||||
|
story: { inline: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
// ThemeSwitch has no explicit props - it uses themeManager internally
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { themeManager } from '$features/ChangeAppTheme';
|
||||||
|
import {
|
||||||
|
onDestroy,
|
||||||
|
onMount,
|
||||||
|
} from 'svelte';
|
||||||
|
|
||||||
|
// Current theme state for display
|
||||||
|
const currentTheme = $derived(themeManager.value);
|
||||||
|
const themeSource = $derived(themeManager.source);
|
||||||
|
const isDark = $derived(themeManager.isDark);
|
||||||
|
|
||||||
|
// Initialize themeManager on mount
|
||||||
|
onMount(() => {
|
||||||
|
themeManager.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clean up themeManager when story unmounts
|
||||||
|
onDestroy(() => {
|
||||||
|
themeManager.destroy();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Story name="Default">
|
||||||
|
<div class="flex items-center justify-center p-8 gap-4">
|
||||||
|
<ThemeSwitch />
|
||||||
|
<div class="text-sm text-muted-foreground">
|
||||||
|
Theme: <span class="font-semibold">{currentTheme}</span>
|
||||||
|
{#if themeSource === 'user'}
|
||||||
|
<span class="text-xs ml-2">(user preference)</span>
|
||||||
|
{:else}
|
||||||
|
<span class="text-xs ml-2">(system preference)</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Story>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<!--
|
||||||
|
Component: ThemeSwitch
|
||||||
|
Toggles the theme between light and dark mode.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import type { ResponsiveManager } from '$shared/lib';
|
||||||
|
import { IconButton } from '$shared/ui';
|
||||||
|
import MoonIcon from '@lucide/svelte/icons/moon';
|
||||||
|
import SunIcon from '@lucide/svelte/icons/sun';
|
||||||
|
import { getContext } from 'svelte';
|
||||||
|
import { themeManager } from '../../model';
|
||||||
|
|
||||||
|
const responsive = getContext<ResponsiveManager>('responsive');
|
||||||
|
|
||||||
|
const theme = $derived(themeManager.value);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<IconButton onclick={() => themeManager.toggle()} size={responsive.isMobile ? 'sm' : 'md'} title="Toggle theme">
|
||||||
|
{#snippet icon()}
|
||||||
|
{#if theme === 'light'}
|
||||||
|
<MoonIcon />
|
||||||
|
{:else}
|
||||||
|
<SunIcon />
|
||||||
|
{/if}
|
||||||
|
{/snippet}
|
||||||
|
</IconButton>
|
||||||
1
src/features/ChangeAppTheme/ui/index.ts
Normal file
1
src/features/ChangeAppTheme/ui/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export { default as ThemeSwitch } from './ThemeSwitch/ThemeSwitch.svelte';
|
||||||
Reference in New Issue
Block a user