Skip to content
This repository has been archived by the owner on Oct 10, 2023. It is now read-only.

Commit

Permalink
Introduce ActionButton (#2452)
Browse files Browse the repository at this point in the history
* ActionButton
* Use ActionButton in ActivePools
* Use ActionButton in PoolTitle
* Fix AssetIcon style to avoid `max-width: 100%` - for img by default, which might troubles layouts (e.g. in PoolTitle)
  • Loading branch information
veado authored Nov 10, 2022
1 parent 14afcb3 commit 1ee78a2
Show file tree
Hide file tree
Showing 12 changed files with 228 additions and 65 deletions.
9 changes: 0 additions & 9 deletions src/renderer/components/pool/PoolTitle.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,6 @@ export const RowItem = styled(A.Col)`
align-items: center;
`

export const ButtonActions = styled.div`
display: flex;
align-items: center;
justify-content: center;
> :not(:first-child) {
margin-left: 10px;
}
`

export const TitleContainer = styled.div`
display: flex;
flex-direction: row;
Expand Down
76 changes: 45 additions & 31 deletions src/renderer/components/pool/PoolTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React, { useMemo } from 'react'

import * as RD from '@devexperts/remote-data-ts'
import { Asset, AssetAmount, assetToString, formatAssetAmount } from '@xchainjs/xchain-util'
import { Asset, AssetAmount, AssetRuneNative, assetToString, formatAssetAmount } from '@xchainjs/xchain-util'
import { Grid } from 'antd'
import * as FP from 'fp-ts/lib/function'
import { useIntl } from 'react-intl'
import { useNavigate } from 'react-router-dom'

import { Network } from '../../../shared/api/types'
import { Action as ActionButtonAction, ActionButton } from '../../components/uielements/button/ActionButton'
import { loadingString } from '../../helpers/stringHelper'
import * as poolsRoutes from '../../routes/pools'
import { AssetIcon } from '../uielements/assets/assetIcon'
import { SwapButton, ManageButton } from '../uielements/button'
import * as Styled from './PoolTitle.styles'

export type Props = {
Expand Down Expand Up @@ -41,6 +44,9 @@ export const PoolTitle: React.FC<Props> = ({
}) => {
const isDesktopView = Grid.useBreakpoint()?.md ?? false

const intl = useIntl()
const navigate = useNavigate()

const title = useMemo(() => {
const Star = watched ? Styled.StarFilled : Styled.StarOutlined
const starClickHandler = watched ? unwatch : watch
Expand Down Expand Up @@ -68,43 +74,51 @@ export const PoolTitle: React.FC<Props> = ({
[priceRD]
)

const buttons = useMemo(
() => (
<Styled.ButtonActions>
<ManageButton
disabled={disableAllPoolActions || disablePoolActions || walletLocked}
asset={asset}
size="normal"
isTextView={isDesktopView}
/>
{isAvailablePool && (
<SwapButton
disabled={disableAllPoolActions || disableTradingPoolAction}
size="normal"
asset={asset}
isTextView={isDesktopView}
/>
)}
</Styled.ButtonActions>
),
[
disableAllPoolActions,
disablePoolActions,
walletLocked,
asset,
isDesktopView,
isAvailablePool,
disableTradingPoolAction
const actionButton = useMemo(() => {
const actions: ActionButtonAction[] = [
{
label: intl.formatMessage({ id: 'common.swap' }),
disabled: !isAvailablePool || disableAllPoolActions || disableTradingPoolAction,
callback: () => {
navigate(poolsRoutes.swap.path({ source: assetToString(AssetRuneNative), target: assetToString(asset) }))
}
},
{
label: intl.formatMessage({ id: 'common.manage' }),
disabled: disableAllPoolActions || disablePoolActions || walletLocked,
callback: () => {
navigate(poolsRoutes.deposit.path({ asset: assetToString(asset) }))
}
},
{
label: intl.formatMessage({ id: 'common.savers' }),
disabled: !isAvailablePool || disableAllPoolActions || disableTradingPoolAction,
callback: () => {
navigate(poolsRoutes.savers.path({ asset: assetToString(asset) }))
}
}
]
)

return <ActionButton size={isDesktopView ? 'large' : 'normal'} actions={actions} />
}, [
intl,
isAvailablePool,
disableAllPoolActions,
disableTradingPoolAction,
disablePoolActions,
walletLocked,
isDesktopView,
navigate,
asset
])

return (
<Styled.Container>
<Styled.RowItem>
<Styled.TitleContainer>{title}</Styled.TitleContainer>
<Styled.Price>{priceStr}</Styled.Price>
</Styled.RowItem>
<Styled.RowItem>{buttons}</Styled.RowItem>
<Styled.RowItem>{actionButton}</Styled.RowItem>
</Styled.Container>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,5 @@ export const Icon = styled.img<IconProps>`
width: ${({ size, isSynth }) => `${sizes[size] - (isSynth ? 2 : 0) * borders[size]}px`};
height: ${({ size, isSynth }) => `${sizes[size] - (isSynth ? 2 : 0) * borders[size]}px`};
border-radius: 50%;
max-width: auto; // overridden to avoid max-w-100% (default)
`
75 changes: 75 additions & 0 deletions src/renderer/components/uielements/button/ActionButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { ComponentMeta, StoryFn } from '@storybook/react'

import { ActionButton as Component, Props } from './ActionButton'

const Template: StoryFn<Props> = (args) => <Component {...args} />
export const Default = Template.bind({})

const meta: ComponentMeta<typeof Component> = {
title: 'Components/button/ActionButton',
argTypes: {
size: {
control: {
type: 'select',
options: ['small', 'medium', 'normal', 'large']
}
}
},
args: {
actions: [
{
label: 'swap',
callback: () => {
console.log('swap')
},
disabled: false
},
{
label: 'manage',
callback: () => {
console.log('manage')
},
disabled: false
},
{
label: 'savers',
callback: () => {
console.log('savers')
},
disabled: true
},
{
label: 'send',
callback: () => {
console.log('send')
},
disabled: false
},
{
label: 'deposit',
callback: () => {
console.log('deposit')
},
disabled: false
},
{
label: 'upgrade',
callback: () => {
console.log('upgrade')
},
disabled: true
}
],
disabled: false,
size: 'normal'
},
decorators: [
(Story) => (
<div className="flex h-full w-full items-center justify-center">
<Story />
</div>
)
]
}

export default meta
66 changes: 66 additions & 0 deletions src/renderer/components/uielements/button/ActionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react'

import { Popover } from '@headlessui/react'
import { ChevronDownIcon } from '@heroicons/react/24/outline'
import * as A from 'fp-ts/lib/Array'
import * as FP from 'fp-ts/lib/function'
import { useIntl } from 'react-intl'

import type { Props as ButtonProps } from './FlatButton'
import { TextButton, FlatButton } from './index'

export type Action = { label: string; callback: FP.Lazy<void>; disabled?: boolean }
export type Props = Omit<ButtonProps, 'onClick'> & {
actions: Action[]
isTextView?: boolean
}

export const ActionButton: React.FC<Props> = (props): JSX.Element => {
const { size, actions, isTextView = true, disabled = false } = props

const intl = useIntl()

return (
<Popover className="relative">
<Popover.Button as="div" className="group">
{({ open }) => (
<FlatButton size={size} disabled={disabled}>
<span className={`${isTextView ? 'mr-10px' : 'hidden'}`}>
{intl.formatMessage({ id: 'common.action' })}
</span>
<ChevronDownIcon
className={`ease h-[20px] w-[20px] text-inherit group-hover:rotate-180 ${
open ? 'rotate-180' : 'rotate-0'
}`}
/>
</FlatButton>
)}
</Popover.Button>
<Popover.Panel className="absolute left-[50%] z-[2000] min-w-[100%] translate-x-[-50%] bg-bg0 shadow-full dark:bg-bg0d dark:shadow-fulld ">
{({ close }) => (
<div>
{FP.pipe(
actions,
A.mapWithIndex((index, { label, callback, disabled = false }) => (
<TextButton
className={`w-full hover:bg-bg2 dark:hover:bg-bg2d`}
disabled={disabled}
size={size}
color="neutral"
key={index}
onClick={(event: React.MouseEvent<HTMLElement, MouseEvent>) => {
event.preventDefault()
event.stopPropagation()
callback()
close()
}}>
{label}
</TextButton>
))
)}
</div>
)}
</Popover.Panel>
</Popover>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const meta: ComponentMeta<typeof Component> = {
size: {
control: {
type: 'select',
options: ['small', 'normal', 'large']
options: ['small', 'medium', 'normal', 'large']
}
}
},
Expand Down
1 change: 1 addition & 0 deletions src/renderer/i18n/de/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const common: CommonMessages = {
'common.searchAsset': 'Suche Asset',
'common.retry': 'Wiederholen',
'common.reload': 'Neuladen',
'common.action': 'Aktion',
'common.add': 'Einzahlen',
'common.swap': 'Swap',
'common.savers': 'Savers',
Expand Down
1 change: 1 addition & 0 deletions src/renderer/i18n/en/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const common: CommonMessages = {
'common.searchAsset': 'Search Asset',
'common.retry': 'Retry',
'common.reload': 'Reload',
'common.action': 'Action',
'common.add': 'Add',
'common.swap': 'Swap',
'common.savers': 'Savers',
Expand Down
1 change: 1 addition & 0 deletions src/renderer/i18n/fr/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const common: CommonMessages = {
'common.searchAsset': 'Rechercher un actif',
'common.retry': 'Réessayer',
'common.reload': 'Recharger',
'common.action': 'Action - FR',
'common.add': 'Ajouter',
'common.swap': 'Échanger',
'common.savers': 'Savers - FR',
Expand Down
1 change: 1 addition & 0 deletions src/renderer/i18n/ru/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const common: CommonMessages = {
'common.searchAsset': 'Поиск актива',
'common.retry': 'Повторить',
'common.reload': 'Обновить',
'common.action': 'Action - RU',
'common.add': 'Добавить',
'common.swap': 'Обмен',
'common.savers': 'Savers - RU',
Expand Down
1 change: 1 addition & 0 deletions src/renderer/i18n/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export type CommonMessageKey =
| 'common.searchAsset'
| 'common.retry'
| 'common.reload'
| 'common.action'
| 'common.add'
| 'common.swap'
| 'common.savers'
Expand Down
Loading

0 comments on commit 1ee78a2

Please sign in to comment.