feat(ThemeSwitch): create ThemeSwitch component that uses ThemeMager toggle to switch theme

This commit is contained in:
Ilia Mashkov
2026-02-27 12:22:37 +03:00
parent c4daf47628
commit 7b8b41021c
5 changed files with 89 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
export * from './model';
export * from './ui';

View File

@@ -0,0 +1 @@
export { themeManager } from './store/ThemeManager/ThemeManager.svelte';

View File

@@ -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>

View File

@@ -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>

View File

@@ -0,0 +1 @@
export { default as ThemeSwitch } from './ThemeSwitch/ThemeSwitch.svelte';