diff --git a/.storybook/preview.ts b/.storybook/preview.ts index 1a690d6..022dbb9 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -5,6 +5,29 @@ import './public/css/font.css' import './public/css/bgTransparent.css' const preview: Preview = { + globalTypes: { + theme: { + description: 'Site color theme', + toolbar: { + title: 'Theme', + icon: 'mirror', + items: [ + { value: 'light', icon: 'sun', title: 'Light' }, + { value: 'dark', icon: 'moon', title: 'Dark' }, + ], + dynamicTitle: true, + }, + }, + }, + initialGlobals: { + theme: 'light', + }, + decorators: [ + (Story, { globals }) => { + document.documentElement.setAttribute('data-theme', globals.theme) + return Story() + }, + ], parameters: { actions: { argTypesRegex: '^on[A-Z].*' }, controls: { diff --git a/src/app/_layout/_components/consentBanner.tsx b/src/app/_layout/_components/consentBanner.tsx index 9117dc8..c2c4e9c 100644 --- a/src/app/_layout/_components/consentBanner.tsx +++ b/src/app/_layout/_components/consentBanner.tsx @@ -57,7 +57,7 @@ const ConsentBanner = ({ return (

{text}{' '} diff --git a/src/app/_layout/_components/siteHeader.tsx b/src/app/_layout/_components/siteHeader.tsx index e0fb834..8eb3ea0 100644 --- a/src/app/_layout/_components/siteHeader.tsx +++ b/src/app/_layout/_components/siteHeader.tsx @@ -5,6 +5,7 @@ import { Container } from '@/components/Container' import { Brand } from './brand' import { LanguageToggle } from './languageToggle' import { Navigation } from './navigation' +import { ThemeToggle } from './themeToggle' const SiteHeader = ({ locale }: { locale: Locale }) => { const { ui } = getContent(locale) @@ -19,11 +20,10 @@ const SiteHeader = ({ locale }: { locale: Locale }) => { - +

+ + +
= { + system: Monitor, + light: Sun, + dark: Moon, +} + +type ThemeToggleProps = { + labels: SiteContent['ui']['theme'] + className?: string +} + +const ThemeToggle = ({ labels, className }: ThemeToggleProps) => { + const current = useSyncExternalStore( + subscribeTheme, + readTheme, + () => 'system' + ) + + return ( +
+ {themes.map((theme) => { + const Icon = icons[theme] + const active = theme === current + + return ( + + ) + })} +
+ ) +} + +export { ThemeToggle } diff --git a/src/app/_layout/global.css b/src/app/_layout/global.css index 6ba381e..f13613f 100644 --- a/src/app/_layout/global.css +++ b/src/app/_layout/global.css @@ -14,6 +14,7 @@ --line: 43 12% 83%; --pen: 224 69% 46%; --signal: 146 64% 38%; + --shadow: 220 13% 10%; --background: var(--paper); --foreground: var(--ink); @@ -60,6 +61,30 @@ font-family: var(--font-sans); } + :root { + color-scheme: light; + } + + :root[data-theme='dark'] { + color-scheme: dark; + + --paper: 40 6% 8%; + --paper-card: 40 6% 10.5%; + --ink: 42 24% 91%; + --ink-soft: 40 9% 76%; + --ink-subtle: 40 5% 61%; + --line: 40 5% 20%; + --pen: 222 88% 73%; + --signal: 146 50% 55%; + --shadow: 0 0% 0%; + + --muted: 40 5% 14%; + --muted-foreground: 40 9% 76%; + --primary: 40 5% 13%; + --primary-foreground: 42 24% 91%; + --secondary: 40 4% 36%; + } + html { @apply custom-scroll; scroll-behavior: smooth; diff --git a/src/app/_layout/index.tsx b/src/app/_layout/index.tsx index ce20989..2a8baa0 100644 --- a/src/app/_layout/index.tsx +++ b/src/app/_layout/index.tsx @@ -4,6 +4,7 @@ import { cn } from '@/utils/cn' import { getContent } from '@/config/content' import { htmlLang, languageRedirect, Locale, paths } from '@/config/i18n' +import { themeInit } from '@/config/theme' import { fontHand, fontMono, fontSans } from '@/lib/fonts' import { DevTools } from '@/components/DevTools' @@ -22,11 +23,12 @@ const RootLayout = ({ locale, children }: RootLayoutProps) => { return ( - {locale === 'en' && ( - + + {locale === 'en' && (