From 2e80652313102585efecf38f25adc9f05fed4b2e Mon Sep 17 00:00:00 2001 From: Peter Sanderson Date: Wed, 28 Aug 2024 10:54:51 +0200 Subject: [PATCH] feat(suite): quick-action refactotring, simplification of the UI and adding a update icon --- .../ComponentWithSubIcon.stories.tsx | 45 ++++++ .../ComponentWithSubIcon.tsx | 63 ++++++++ .../components/src/components/Icon/Icon.tsx | 7 +- packages/components/src/index.ts | 1 + .../SuiteLayout/Sidebar/QuickActions.tsx | 140 ------------------ .../Sidebar/QuickActions/CustomBackend.tsx | 39 +++++ .../DebugAndExperimental.tsx} | 2 +- .../Sidebar/QuickActions/HideBalances.tsx | 24 +++ .../Sidebar/QuickActions/QuickActions.tsx | 38 +++++ .../SuiteLayout/Sidebar/QuickActions/Tor.tsx | 52 +++++++ .../Sidebar/QuickActions/Update.tsx | 3 + .../layouts/SuiteLayout/Sidebar/Sidebar.tsx | 2 +- 12 files changed, 272 insertions(+), 144 deletions(-) create mode 100644 packages/components/src/components/ComponentWithSubIcon/ComponentWithSubIcon.stories.tsx create mode 100644 packages/components/src/components/ComponentWithSubIcon/ComponentWithSubIcon.tsx delete mode 100644 packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions.tsx create mode 100644 packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/CustomBackend.tsx rename packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/{HelperIcons.tsx => QuickActions/DebugAndExperimental.tsx} (98%) create mode 100644 packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/HideBalances.tsx create mode 100644 packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/QuickActions.tsx create mode 100644 packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Tor.tsx create mode 100644 packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update.tsx diff --git a/packages/components/src/components/ComponentWithSubIcon/ComponentWithSubIcon.stories.tsx b/packages/components/src/components/ComponentWithSubIcon/ComponentWithSubIcon.stories.tsx new file mode 100644 index 000000000000..2337f65bbd46 --- /dev/null +++ b/packages/components/src/components/ComponentWithSubIcon/ComponentWithSubIcon.stories.tsx @@ -0,0 +1,45 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { allowedIconFrameProps, iconVariants } from '../Icon/Icon'; +import { + ComponentWithSubIcon as ComponentWithSubIconComponent, + ComponentWithSubIconProps, +} from './IconWithSubIcon'; +import { IconName, icons } from '@suite-common/icons/src/icons'; +import { getFramePropsStory } from '../../utils/frameProps'; +import { Icon } from '@suite-common/icons'; + +const meta: Meta = { + title: 'IconWithSubIcon', + component: ComponentWithSubIconComponent, +} as Meta; +export default meta; + +const iconNames = Object.keys(icons) as IconName[]; + +export const ComponentWithSubIcon: StoryObj = { + args: { + subIconProps: { + name: 'check', + }, + subIconBackground: { + variant: 'destructive', + }, + children: , + }, + argTypes: { + name: { + options: iconNames, + control: { + type: 'select', + }, + }, + + variant: { + options: iconVariants, + control: { + type: 'select', + }, + }, + ...getFramePropsStory(allowedIconFrameProps).argTypes, + }, +}; diff --git a/packages/components/src/components/ComponentWithSubIcon/ComponentWithSubIcon.tsx b/packages/components/src/components/ComponentWithSubIcon/ComponentWithSubIcon.tsx new file mode 100644 index 000000000000..1b6c0935b0cb --- /dev/null +++ b/packages/components/src/components/ComponentWithSubIcon/ComponentWithSubIcon.tsx @@ -0,0 +1,63 @@ +import styled, { useTheme } from 'styled-components'; +import { ExclusiveColorOrVariant, getColorForIconVariant, Icon, IconProps } from '../Icon/Icon'; +import { borders, spacingsPx } from '@trezor/theme'; +import { makePropsTransient, TransientProps } from '../../utils/transientProps'; +import { getIconSize } from '@suite-common/icons'; +import { ReactNode } from 'react'; + +const Container = styled.div` + position: relative; +`; + +type SubIconWrapperProps = TransientProps & { + $subIconColor: string; + $subIconSize: number; +}; + +const SubIconWrapper = styled.div` + position: absolute; + + right: -${({ $subIconSize }) => $subIconSize / 2}px; + top: -${({ $subIconSize }) => $subIconSize / 2}px; + + background-color: ${({ theme, $variant, $color }) => + getColorForIconVariant({ theme, variant: $variant, color: $color })}; + border-radius: ${borders.radii.full}; + border: 1px solid ${({ $subIconColor }) => $subIconColor}; + padding: ${spacingsPx.xxxs}; +`; + +export type IconWithSubIconProps = IconProps & { + subIconProps: IconProps; + subIconBackground: ExclusiveColorOrVariant; + children: ReactNode; +}; + +export const IconWithSubIcon = ({ + subIconProps, + subIconBackground, + children, +}: IconWithSubIconProps) => { + const theme = useTheme(); + + const iconColor = getColorForIconVariant({ + theme, + color: subIconProps.color, + variant: subIconProps.variant, + }); + + const subIconSize = getIconSize(subIconProps.size ?? 12); + + return ( + + {children} + + + + + ); +}; diff --git a/packages/components/src/components/Icon/Icon.tsx b/packages/components/src/components/Icon/Icon.tsx index 139b2a92f851..27d88b9d0291 100644 --- a/packages/components/src/components/Icon/Icon.tsx +++ b/packages/components/src/components/Icon/Icon.tsx @@ -17,7 +17,7 @@ import { FrameProps, FramePropsKeys, withFrameProps } from '../../utils/framePro export const iconVariants = ['primary', 'tertiary', 'info', 'warning', 'destructive'] as const; export type IconVariant = Extract; -type ExclusiveColorOrVariant = +export type ExclusiveColorOrVariant = | { variant?: IconVariant; color?: undefined } | { variant?: undefined; @@ -36,7 +36,7 @@ const variantColorMap: Record = { destructive: 'iconAlertRed', }; -const getColorForIconVariant = ({ +export const getColorForIconVariant = ({ variant, theme, color, @@ -44,6 +44,9 @@ const getColorForIconVariant = ({ | CSSColor | 'inherit' | string => { + console.log('color', color); + console.log('variant', variant, variant !== undefined ? theme[variantColorMap[variant]] : ''); + if (color !== undefined) { return color; } diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index 0acd4d270bed..0a5c68b7652b 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -18,6 +18,7 @@ export * from './components/buttons/Button/Button'; export * from './components/buttons/ButtonGroup/ButtonGroup'; export * from './components/buttons/IconButton/IconButton'; export * from './components/Icon/Icon'; +export { IconWithSubIcon } from './components/IconWithSubIcon/IconWithSubIcon'; export * from './components/buttons/PinButton/PinButton'; export * from './components/buttons/TextButton/TextButton'; export * from './components/buttons/TooltipButton/TooltipButton'; diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions.tsx deleted file mode 100644 index 3e0212b82c08..000000000000 --- a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import styled, { useTheme } from 'styled-components'; -import { Icon, Tooltip } from '@trezor/components'; -import { isDesktop } from '@trezor/env-utils'; -import { borders, spacingsPx, typography } from '@trezor/theme'; -import { useDispatch, useSelector, useTranslation } from 'src/hooks/suite'; -import { goto } from 'src/actions/suite/routerActions'; -import { SettingsAnchor } from 'src/constants/suite/anchors'; -import { selectTorState } from 'src/reducers/suite/suiteReducer'; -import { setDiscreetMode } from 'src/actions/settings/walletSettingsActions'; -import { selectIsDiscreteModeActive } from 'src/reducers/wallet/settingsReducer'; -import { NavigationItemBase } from './NavigationItem'; -import { ActionButton } from './ActionButton'; -import { NavBackends } from './NavBackends'; -import { HelperIcons } from './HelperIcons'; -import { useEnabledBackends } from '../utils'; - -const Container = styled.div` - display: flex; - border-top: 1px solid ${({ theme }) => theme.borderElevation1}; -`; - -const DescreetContainer = styled(NavigationItemBase)` - width: 100%; - - &:hover { - background: ${({ theme }) => theme.backgroundTertiaryPressedOnElevation0}; - } -`; - -const ActionsContainer = styled.div` - flex: 1; - position: relative; - display: flex; - gap: ${spacingsPx.xxs}; - padding: ${spacingsPx.xxs}; - align-items: stretch; - - > * { - flex: 1; - } -`; - -const Label = styled.span` - ${typography.hint} - color: ${({ theme }) => theme.textSubdued}; -`; - -const StyledCheckIcon = styled(Icon)` - position: absolute; - bottom: 50%; - left: 50%; - background: ${({ theme }) => theme.backgroundSurfaceElevationNegative}; - border-radius: ${borders.radii.full}; -`; - -const TorToggleContainer = styled.div` - position: relative; - width: 100%; - - &:hover, - &:focus-within { - ${StyledCheckIcon} { - background-color: ${({ theme }) => theme.backgroundTertiaryPressedOnElevation0}; - } - } -`; - -export const QuickActions = () => { - const isDiscreetModeActive = useSelector(selectIsDiscreteModeActive); - const { isTorEnabled, isTorLoading } = useSelector(selectTorState); - const dispatch = useDispatch(); - const { translationString } = useTranslation(); - const theme = useTheme(); - const handleDiscreetModeClick = () => dispatch(setDiscreetMode(!isDiscreetModeActive)); - const enabledBackends = useEnabledBackends(); - const translationLabel = isDiscreetModeActive ? 'TR_SHOW_BALANCES' : 'TR_HIDE_BALANCES'; - const isCustomBackendIconVisible = enabledBackends.length > 0; - const isTorIconVisible = isDesktop(); - - const CheckIcon = () => ( - - ); - - return ( - - - - {!isCustomBackendIconVisible && !isTorIconVisible ? ( - - - - - ) : ( - <> - {isCustomBackendIconVisible && ( - - <> - - - - - )} - {isTorIconVisible && ( - - - dispatch( - goto('settings-index', { anchor: SettingsAnchor.Tor }), - ) - } - size="small" - variant="tertiary" - /> - - {isTorEnabled && } - - )} - - - - )} - - - ); -}; diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/CustomBackend.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/CustomBackend.tsx new file mode 100644 index 000000000000..359ab3ce8c35 --- /dev/null +++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/CustomBackend.tsx @@ -0,0 +1,39 @@ +import styled, { useTheme } from 'styled-components'; +import { useTranslation } from '../../../../../../hooks/suite'; +import { useEnabledBackends } from '../../utils'; +import { Icon, Tooltip } from '@trezor/components'; +import { NavBackends } from '../NavBackends'; +import { borders } from '@trezor/theme'; + +const StyledCheckIcon = styled(Icon)` + position: absolute; + bottom: 50%; + left: 50%; + background: ${({ theme }) => theme.backgroundSurfaceElevationNegative}; + border-radius: ${borders.radii.full}; +`; + +export const CustomBackend = () => { + const theme = useTheme(); + const { translationString } = useTranslation(); + + const enabledBackends = useEnabledBackends(); + const isCustomBackendIconVisible = enabledBackends.length > 0; + + console.log(enabledBackends); + + const CheckIcon = () => ( + + ); + + return ( + isCustomBackendIconVisible && ( + +
+ + +
+
+ ) + ); +}; diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/HelperIcons.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/DebugAndExperimental.tsx similarity index 98% rename from packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/HelperIcons.tsx rename to packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/DebugAndExperimental.tsx index 818674f5f353..bf355900bb73 100644 --- a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/HelperIcons.tsx +++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/DebugAndExperimental.tsx @@ -44,7 +44,7 @@ const DebugModeIcon = styled(HelperIcon)` background-color: ${({ theme }) => theme.backgroundAlertRedBold}; `; -export const HelperIcons = () => { +export const DebugAndExperimental = () => { const isEapEnabled = useSelector(state => state.desktopUpdate.allowPrerelease); const isExperimental = useSelector(state => !!state.suite.settings.experimental); const showExperimental = isEapEnabled || isExperimental; diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/HideBalances.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/HideBalances.tsx new file mode 100644 index 000000000000..50918eb82124 --- /dev/null +++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/HideBalances.tsx @@ -0,0 +1,24 @@ +import { setDiscreetMode } from '../../../../../../actions/settings/walletSettingsActions'; +import { useDispatch, useSelector, useTranslation } from '../../../../../../hooks/suite'; +import { selectIsDiscreteModeActive } from '../../../../../../reducers/wallet/settingsReducer'; +import { ActionButton } from './../ActionButton'; + +export const HideBalances = () => { + const dispatch = useDispatch(); + const { translationString } = useTranslation(); + + const isDiscreetModeActive = useSelector(selectIsDiscreteModeActive); + const translationLabel = isDiscreetModeActive ? 'TR_SHOW_BALANCES' : 'TR_HIDE_BALANCES'; + + const handleDiscreetModeClick = () => dispatch(setDiscreetMode(!isDiscreetModeActive)); + + return ( + + ); +}; diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/QuickActions.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/QuickActions.tsx new file mode 100644 index 000000000000..610590b44d98 --- /dev/null +++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/QuickActions.tsx @@ -0,0 +1,38 @@ +import styled from 'styled-components'; +import { spacingsPx } from '@trezor/theme'; + +import { Update } from './Update'; +import { DebugAndExperimental } from './DebugAndExperimental'; +import { Tor } from './Tor'; +import { HideBalances } from './HideBalances'; +import { CustomBackend } from './CustomBackend'; + +const Container = styled.div` + display: flex; + border-top: 1px solid ${({ theme }) => theme.borderElevation1}; +`; + +const ActionsContainer = styled.div` + flex: 1; + position: relative; + display: flex; + gap: ${spacingsPx.xxs}; + padding: ${spacingsPx.xxs}; + align-items: stretch; + + > * { + flex: 1; + } +`; + +export const QuickActions = () => ( + + + + + + + + + +); diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Tor.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Tor.tsx new file mode 100644 index 000000000000..e78923b8edf1 --- /dev/null +++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Tor.tsx @@ -0,0 +1,52 @@ +import { goto } from 'src/actions/suite/routerActions'; +import { SettingsAnchor } from 'src/constants/suite/anchors'; +import { useDispatch, useSelector, useTranslation } from 'src/hooks/suite'; +import { selectTorState } from '../../../../../../reducers/suite/suiteReducer'; +import styled, { useTheme } from 'styled-components'; +import { Icon } from '@trezor/components'; +import { borders } from '@trezor/theme'; +import { isDesktop } from '@trezor/env-utils'; +import { ActionButton } from '../ActionButton'; + + +const TorToggleContainer = styled.div` + position: relative; + width: 100%; + + &:hover, + &:focus-within { + ${StyledCheckIcon} { + background-color: ${({ theme }) => theme.backgroundTertiaryPressedOnElevation0}; + } + } +`; + +export const Tor = () => { + const { translationString } = useTranslation(); + const dispatch = useDispatch(); + + const { isTorEnabled, isTorLoading } = useSelector(selectTorState); + const isTorIconVisible = isDesktop(); + const theme = useTheme(); + + const CheckIcon = () => ( + + ); + + return ( + isTorIconVisible && ( + + dispatch(goto('settings-index', { anchor: SettingsAnchor.Tor }))} + size="small" + variant="tertiary" + /> + + {isTorEnabled && } + + ) + ); +}; diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update.tsx new file mode 100644 index 000000000000..b432e174d0a4 --- /dev/null +++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update.tsx @@ -0,0 +1,3 @@ +export const Update = () => { + return <>; +}; diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/Sidebar.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/Sidebar.tsx index b667c9971467..9233d704a854 100644 --- a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/Sidebar.tsx +++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/Sidebar.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components'; import { DeviceSelector } from '../DeviceSelector/DeviceSelector'; import { Navigation } from './Navigation'; import { AccountsMenu } from 'src/components/wallet/WalletLayout/AccountsMenu/AccountsMenu'; -import { QuickActions } from './QuickActions'; +import { QuickActions } from './QuickActions/QuickActions'; import { ElevationUp, ResizableBox, useElevation } from '@trezor/components'; import { Elevation, mapElevationToBackground, mapElevationToBorder, zIndices } from '@trezor/theme'; import { useActions, useSelector } from 'src/hooks/suite';