diff options
| author | Haishan <[email protected]> | 2021-06-13 15:20:12 +0800 |
|---|---|---|
| committer | Haishan <[email protected]> | 2021-06-13 18:26:30 +0800 |
| commit | c78dbcf8f89072dc9c2fa8ba81e2cf5a80218cd7 (patch) | |
| tree | 1801b2954623c3b6710ba769836e5c25a68cf65a /src/components/shared | |
| parent | aad1d2681e4415add1ab440159bf1253b5b34d8e (diff) | |
Support switch theme on backend config page
Diffstat (limited to 'src/components/shared')
| -rw-r--r-- | src/components/shared/ThemeSwitcher.module.css | 28 | ||||
| -rw-r--r-- | src/components/shared/ThemeSwitcher.tsx | 97 |
2 files changed, 125 insertions, 0 deletions
diff --git a/src/components/shared/ThemeSwitcher.module.css b/src/components/shared/ThemeSwitcher.module.css new file mode 100644 index 0000000..919c86c --- /dev/null +++ b/src/components/shared/ThemeSwitcher.module.css @@ -0,0 +1,28 @@ +.iconWrapper { + --sz: 40px; + + width: var(--sz); + height: var(--sz); + display: flex; + justify-content: center; + align-items: center; + + outline: none; + padding: 5px; + color: var(--color-text); + border-radius: 100%; + border: 1px solid transparent; +} +.iconWrapper:hover { + opacity: 0.6; +} +.iconWrapper:focus { + border-color: var(--color-focus-blue); +} + +.themeSwitchContainer { + appearance: none; + user-select: none; + background: none; + cursor: pointer; +} diff --git a/src/components/shared/ThemeSwitcher.tsx b/src/components/shared/ThemeSwitcher.tsx new file mode 100644 index 0000000..fba5b0b --- /dev/null +++ b/src/components/shared/ThemeSwitcher.tsx @@ -0,0 +1,97 @@ +import Tooltip from '@reach/tooltip'; +import cx from 'clsx'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { connect } from 'src/components/StateProvider'; +import { framerMotionResouce } from 'src/misc/motion'; +import { getTheme, switchTheme } from 'src/store/app'; +import { State } from 'src/store/types'; + +import s from './ThemeSwitcher.module.css'; + +export function ThemeSwitcherImpl({ theme, dispatch }) { + const { t } = useTranslation(); + + const switchThemeHooked = React.useCallback(() => { + dispatch(switchTheme()); + }, [dispatch]); + + return ( + <Tooltip + label={t('theme')} + aria-label={ + 'switch to ' + (theme === 'light' ? 'dark' : 'light') + ' theme' + } + > + <button + className={cx(s.iconWrapper, s.themeSwitchContainer)} + onClick={switchThemeHooked} + > + {theme === 'light' ? <MoonA /> : <Sun />} + </button> + </Tooltip> + ); +} + +function MoonA() { + const module = framerMotionResouce.read(); + const motion = module.motion; + return ( + <svg + xmlns="http://www.w3.org/2000/svg" + width="20" + height="20" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" + > + <motion.path + d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" + initial={{ rotate: -30 }} + animate={{ rotate: 0 }} + transition={{ duration: 0.7 }} + /> + </svg> + ); +} + +function Sun() { + const module = framerMotionResouce.read(); + const motion = module.motion; + + return ( + <svg + xmlns="http://www.w3.org/2000/svg" + width="20" + height="20" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" + > + <circle cx="12" cy="12" r="5"></circle> + <motion.g + initial={{ scale: 0.8 }} + animate={{ scale: 1 }} + transition={{ duration: 0.7 }} + > + <line x1="12" y1="1" x2="12" y2="3"></line> + <line x1="12" y1="21" x2="12" y2="23"></line> + <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> + <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> + <line x1="1" y1="12" x2="3" y2="12"></line> + <line x1="21" y1="12" x2="23" y2="12"></line> + <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> + <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> + </motion.g> + </svg> + ); +} + +const mapState = (s: State) => ({ theme: getTheme(s) }); +export const ThemeSwitcher = connect(mapState)(ThemeSwitcherImpl); |
