diff --git a/src/components/Root.scss b/src/components/Root.scss index 0df5819..4ae7d5f 100644 --- a/src/components/Root.scss +++ b/src/components/Root.scss @@ -124,10 +124,16 @@ body { --select-bg-hover: url(data:image/svg+xml,%0A%20%20%20%20%3Csvg%20width%3D%228%22%20height%3D%2224%22%20viewBox%3D%220%200%208%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%20%20%3Cpath%20d%3D%22M4%207L7%2011H1L4%207Z%22%20fill%3D%22%23222222%22%20%2F%3E%0A%20%20%20%20%20%20%3Cpath%20d%3D%22M4%2017L1%2013L7%2013L4%2017Z%22%20fill%3D%22%23222222%22%20%2F%3E%0A%20%20%20%20%3C%2Fsvg%3E%0A%20%20); } -// we don't have a "system" or "auto" mode now -// it's just not make sense to have these yet -// @media (prefers-color-scheme: dark) {} -// @media (prefers-color-scheme: light) {} +:root[data-theme='auto'] { + @media (prefers-color-scheme: dark) { + @include dark; + color-scheme: dark; + } + @media (prefers-color-scheme: light) { + @include light; + color-scheme: light; + } +} :root[data-theme='dark'] { @include dark; diff --git a/src/components/shared/ThemeSwitcher.tsx b/src/components/shared/ThemeSwitcher.tsx index fba5b0b..90990b6 100644 --- a/src/components/shared/ThemeSwitcher.tsx +++ b/src/components/shared/ThemeSwitcher.tsx @@ -16,18 +16,38 @@ export function ThemeSwitcherImpl({ theme, dispatch }) { dispatch(switchTheme()); }, [dispatch]); + const nextThemeName = React.useMemo(() => { + switch (theme) { + case 'light': + return 'dark'; + case 'dark': + return 'auto'; + case 'auto': + return 'light'; + default: + console.assert(false, 'Unknown theme'); + return 'unknown'; + } + }, [theme]); + + const themeIcon = React.useMemo(() => { + switch (theme) { + case 'light': + return ; + case 'dark': + return ; + case 'auto': + return ; + default: + console.assert(false, 'Unknown theme'); + return ; + } + }, [theme]); + return ( - - ); @@ -75,11 +95,7 @@ function Sun() { strokeLinejoin="round" > - + @@ -93,5 +109,38 @@ function Sun() { ); } +function Auto() { + const module = framerMotionResouce.read(); + const motion = module.motion; + + return ( + + + + + + + + ); +} + const mapState = (s: State) => ({ theme: getTheme(s) }); export const ThemeSwitcher = connect(mapState)(ThemeSwitcherImpl); diff --git a/src/store/app.ts b/src/store/app.ts index ea14e84..2ccd960 100644 --- a/src/store/app.ts +++ b/src/store/app.ts @@ -94,25 +94,37 @@ export function updateClashAPIConfig({ baseURL, secret }) { } const rootEl = document.querySelector('html'); -const themeColorMeta = document.querySelector('meta[name="theme-color"]'); -function setTheme(theme = 'dark') { - if (theme === 'dark') { +type ThemeType = 'dark' | 'light' | 'auto'; +function setTheme(theme: ThemeType = 'dark') { + if (theme === 'auto') { + rootEl.setAttribute('data-theme', 'auto'); + } else if (theme === 'dark') { rootEl.setAttribute('data-theme', 'dark'); - themeColorMeta.setAttribute('content', '#202020'); } else { rootEl.setAttribute('data-theme', 'light'); - themeColorMeta.setAttribute('content', '#f7f7f7'); } } export function switchTheme() { return (dispatch: DispatchFn, getState: GetStateFn) => { const currentTheme = getTheme(getState()); - const theme = currentTheme === 'light' ? 'dark' : 'light'; + let nextTheme: ThemeType = 'auto'; + switch (currentTheme) { + case 'light': + nextTheme = 'dark'; + break; + case 'dark': + nextTheme = 'auto'; + break; + case 'auto': + nextTheme = 'light'; + break; + } + // side effect - setTheme(theme); + setTheme(nextTheme); dispatch('storeSwitchTheme', (s) => { - s.app.theme = theme; + s.app.theme = nextTheme; }); // side effect saveState(getState().app);