From 027ddb647cbe9a37a969005d8bd7c3f644b31d7b Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 25 Apr 2022 16:56:55 +0200 Subject: [PATCH] Improve Switch component (#89) --- .../src/components/Inputs/Switch/index.tsx | 62 ---------- .../src/components/Inputs/Switch/types.ts | 7 -- .../{Inputs => }/Switch/Switch.test.tsx | 10 +- .../src/components/Switch/index.tsx | 107 ++++++++++++++++++ .../components/{Inputs => }/Switch/styles.ts | 12 +- .../src/components/Switch/types.ts | 10 ++ .../launchpad_v2/src/components/Text/types.ts | 15 ++- .../src/components/TitleBar/index.tsx | 11 +- .../src/containers/MiningContainer/index.tsx | 19 +++- 9 files changed, 170 insertions(+), 83 deletions(-) delete mode 100644 applications/launchpad_v2/src/components/Inputs/Switch/index.tsx delete mode 100644 applications/launchpad_v2/src/components/Inputs/Switch/types.ts rename applications/launchpad_v2/src/components/{Inputs => }/Switch/Switch.test.tsx (70%) create mode 100644 applications/launchpad_v2/src/components/Switch/index.tsx rename applications/launchpad_v2/src/components/{Inputs => }/Switch/styles.ts (81%) create mode 100644 applications/launchpad_v2/src/components/Switch/types.ts diff --git a/applications/launchpad_v2/src/components/Inputs/Switch/index.tsx b/applications/launchpad_v2/src/components/Inputs/Switch/index.tsx deleted file mode 100644 index c9e336b1e4..0000000000 --- a/applications/launchpad_v2/src/components/Inputs/Switch/index.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { useContext } from 'react' -import { useSpring } from 'react-spring' -import { ThemeContext } from 'styled-components' - -import { - LabelText, - SwitchContainer, - SwitchController, - SwitchCircle, -} from './styles' -import { SwitchProps } from './types' - -/** - * Switch input controller - * @param {SwitchProps} props - */ -const Switch = ({ - value, - label, - onClick, - invertedStyle, - testId, -}: SwitchProps) => { - const theme = useContext(ThemeContext) - - const themeStyle = invertedStyle ? theme.inverted : theme - - const circleAnim = useSpring({ - left: value ? 10 : -1, - }) - - const labelColorAnim = useSpring({ - color: themeStyle.primary, - }) - - const controllerAnim = useSpring({ - background: value ? themeStyle.accent : 'transparent', - }) - - return ( - onClick && onClick(!value)} - data-testid={testId || 'switch-input-cmp'} - > - - - - - {label ? ( - - {label} - - ) : null} - - ) -} - -export default Switch diff --git a/applications/launchpad_v2/src/components/Inputs/Switch/types.ts b/applications/launchpad_v2/src/components/Inputs/Switch/types.ts deleted file mode 100644 index d7ca7aeb35..0000000000 --- a/applications/launchpad_v2/src/components/Inputs/Switch/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface SwitchProps { - value: boolean - label?: string - onClick: (val: boolean) => void - invertedStyle?: boolean - testId?: string -} diff --git a/applications/launchpad_v2/src/components/Inputs/Switch/Switch.test.tsx b/applications/launchpad_v2/src/components/Switch/Switch.test.tsx similarity index 70% rename from applications/launchpad_v2/src/components/Inputs/Switch/Switch.test.tsx rename to applications/launchpad_v2/src/components/Switch/Switch.test.tsx index 07066c6d23..3f31c5c952 100644 --- a/applications/launchpad_v2/src/components/Inputs/Switch/Switch.test.tsx +++ b/applications/launchpad_v2/src/components/Switch/Switch.test.tsx @@ -2,16 +2,22 @@ import { fireEvent, render, screen } from '@testing-library/react' import { ThemeProvider } from 'styled-components' import Switch from '.' -import themes from '../../../styles/themes' +import themes from '../../styles/themes' describe('Switch', () => { it('should render without crash', () => { const onClick = jest.fn() const testLabel = 'Test label for the switch component' + const anotherTestLabel = 'Test label for the switch component' const val = false render( - + , ) diff --git a/applications/launchpad_v2/src/components/Switch/index.tsx b/applications/launchpad_v2/src/components/Switch/index.tsx new file mode 100644 index 0000000000..4e8163e582 --- /dev/null +++ b/applications/launchpad_v2/src/components/Switch/index.tsx @@ -0,0 +1,107 @@ +import { animated, useSpring } from 'react-spring' +import { useTheme } from 'styled-components' + +import Text from '../Text' + +import { + LabelText, + SwitchContainer, + SwitchController, + SwitchCircle, +} from './styles' +import { SwitchProps } from './types' + +/** + * Switch input controller + * + * @param {boolean} value - the input value + * @param {string | ReactNode} [leftLabel] - the text or ReactNode element on the left side of the switch. + * @param {string | ReactNode} [rightLabel] - the text or ReactNode element on the right side of the switch. + * @param {(val: boolean) => void} onClick - when the switch is clicked. Returns the new value. + * @param {boolean} [inverted] - use inverted styles + * @param {string} [testId] - the test ID (react-testing/jest) + * + * @example + * } + * rightLabel={'The label text'} + * value={currentTheme === 'dark'} + * onClick={v => dispatch(setTheme(v ? 'dark' : 'light'))} + * /> + */ +const Switch = ({ + value, + leftLabel, + rightLabel, + onClick, + inverted, + testId, +}: SwitchProps) => { + const theme = useTheme() + + const themeStyle = inverted ? theme.inverted : theme + + const circleAnim = useSpring({ + left: value ? 10 : -1, + }) + + const labelColorAnim = useSpring({ + color: themeStyle.primary, + }) + + const controllerAnim = useSpring({ + background: value ? themeStyle.accent : 'transparent', + }) + + const leftLabelEl = + leftLabel && typeof leftLabel === 'string' ? ( + + {leftLabel} + + ) : ( + leftLabel + ) + const rightLabelEl = + rightLabel && typeof rightLabel === 'string' ? ( + + {rightLabel} + + ) : ( + rightLabel + ) + + return ( + onClick && onClick(!value)} + data-testid={testId || 'switch-input-cmp'} + > + {leftLabelEl ? ( + + {leftLabelEl} + + ) : null} + + + + + + {rightLabelEl ? ( + + {rightLabelEl} + + ) : null} + + ) +} + +export default Switch diff --git a/applications/launchpad_v2/src/components/Inputs/Switch/styles.ts b/applications/launchpad_v2/src/components/Switch/styles.ts similarity index 81% rename from applications/launchpad_v2/src/components/Inputs/Switch/styles.ts rename to applications/launchpad_v2/src/components/Switch/styles.ts index 5d845fc027..c2b49dd338 100644 --- a/applications/launchpad_v2/src/components/Inputs/Switch/styles.ts +++ b/applications/launchpad_v2/src/components/Switch/styles.ts @@ -1,10 +1,11 @@ import { animated } from 'react-spring' import styled from 'styled-components' -import colors from '../../../styles/styles/colors' +import colors from '../../styles/styles/colors' export const SwitchContainer = styled.label` display: flex; align-items: center; + cursor: pointer; ` export const SwitchController = styled(animated.div)` @@ -12,18 +13,18 @@ export const SwitchController = styled(animated.div)` width: 24px; border: 1.5px solid ${colors.dark.primary}; border-radius: 6px; - margin-right: 12px; position: relative; box-sizing: border-box; box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.08); + cursor: pointer; ` export const SwitchCircle = styled(animated.div)` position: absolute; width: 14px; height: 14px; - top: -1.5px; - bottom: 0; + top: 0; + margin-top: -1px; border-radius: 6px; box-sizing: border-box; background: #fff; @@ -34,4 +35,7 @@ export const LabelText = styled(animated.span)` font-weight: 500; font-size: 14px; line-height: 160%; + display: flex; + align-items: center; + margin: 0; ` diff --git a/applications/launchpad_v2/src/components/Switch/types.ts b/applications/launchpad_v2/src/components/Switch/types.ts new file mode 100644 index 0000000000..babed3dfc0 --- /dev/null +++ b/applications/launchpad_v2/src/components/Switch/types.ts @@ -0,0 +1,10 @@ +import { ReactNode } from 'react' + +export interface SwitchProps { + value: boolean + leftLabel?: string | ReactNode + rightLabel?: string | ReactNode + onClick: (val: boolean) => void + inverted?: boolean + testId?: string +} diff --git a/applications/launchpad_v2/src/components/Text/types.ts b/applications/launchpad_v2/src/components/Text/types.ts index 807c81d964..653542a276 100644 --- a/applications/launchpad_v2/src/components/Text/types.ts +++ b/applications/launchpad_v2/src/components/Text/types.ts @@ -1,5 +1,6 @@ import { CSSProperties } from 'styled-components' import { ReactNode } from 'react' +import { AnimatedComponent } from 'react-spring' /** * @typedef TextProps @@ -26,6 +27,18 @@ export interface TextProps { children: ReactNode color?: string style?: CSSProperties - as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h4' | 'h5' | 'h6' | 'h7' | 'p' | 'span' + as?: + | 'h1' + | 'h2' + | 'h3' + | 'h4' + | 'h4' + | 'h5' + | 'h6' + | 'p' + | 'span' + | AnimatedComponent< + 'h1' | 'h2' | 'h3' | 'h4' | 'h4' | 'h5' | 'h6' | 'p' | 'span' + > testId?: string } diff --git a/applications/launchpad_v2/src/components/TitleBar/index.tsx b/applications/launchpad_v2/src/components/TitleBar/index.tsx index 82cf9463e1..d61cdad9e6 100644 --- a/applications/launchpad_v2/src/components/TitleBar/index.tsx +++ b/applications/launchpad_v2/src/components/TitleBar/index.tsx @@ -1,12 +1,11 @@ -import { useContext } from 'react' -import { ThemeContext } from 'styled-components' +import { useTheme } from 'styled-components' import { useDispatch, useSelector } from 'react-redux' import { animated, useSpring } from 'react-spring' import { appWindow } from '@tauri-apps/api/window' import Button from '../Button' import Logo from '../Logo' -import Switch from '../Inputs/Switch' +import Switch from '../Switch' import { selectExpertView } from '../../store/app/selectors' import { setExpertView } from '../../store/app' @@ -30,7 +29,7 @@ const TitleBar = ({ drawerViewWidth = '50%' }: TitleBarProps) => { const dispatch = useDispatch() const expertView = useSelector(selectExpertView) - const theme = useContext(ThemeContext) + const theme = useTheme() const [expertViewSize] = ExpertViewUtils.convertExpertViewModeToValue( expertView, @@ -196,10 +195,10 @@ const TitleBar = ({ drawerViewWidth = '50%' }: TitleBarProps) => { diff --git a/applications/launchpad_v2/src/containers/MiningContainer/index.tsx b/applications/launchpad_v2/src/containers/MiningContainer/index.tsx index d325bb38a3..c5842a5189 100644 --- a/applications/launchpad_v2/src/containers/MiningContainer/index.tsx +++ b/applications/launchpad_v2/src/containers/MiningContainer/index.tsx @@ -1,6 +1,12 @@ -import { useDispatch } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' +import Switch from '../../components/Switch' + +import Text from '../../components/Text' +import SvgSun from '../../styles/Icons/Sun' +import SvgMoon from '../../styles/Icons/Moon' import { setTheme } from '../../store/app' +import { selectTheme } from '../../store/app/selectors' /** * @TODO move user-facing text to i18n file when implementing @@ -8,6 +14,8 @@ import { setTheme } from '../../store/app' const MiningContainer = () => { const dispatch = useDispatch() + const currentTheme = useSelector(selectTheme) + return (

Mining

@@ -15,6 +23,15 @@ const MiningContainer = () => { Set light theme +
+ Select theme + } + rightLabel={} + value={currentTheme === 'dark'} + onClick={v => dispatch(setTheme(v ? 'dark' : 'light'))} + /> +
) }