-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature: APP-2445 - ActionItemAddress (#24)
- Loading branch information
1 parent
d187275
commit bb773c6
Showing
6 changed files
with
276 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// Button.stories.ts|tsx | ||
|
||
import type { Meta, StoryObj } from '@storybook/react'; | ||
import React from 'react'; | ||
|
||
import { IconCopy, IconGovernance, IconLinkExternal } from '../icons'; | ||
import { ListItemAction } from '../listItem'; | ||
import { ActionItemAddress, TAG_WALLET_ID_VARIANTS } from './actionItemAddress'; | ||
|
||
const meta: Meta<typeof ActionItemAddress> = { | ||
component: ActionItemAddress, | ||
title: 'Components/ActionItems/Address', | ||
tags: ['autodocs'], | ||
argTypes: { | ||
addressOrEns: { control: { type: 'text' } }, | ||
avatar: { control: { type: 'text' } }, | ||
tagLabel: { control: { type: 'text' } }, | ||
walletId: { | ||
options: TAG_WALLET_ID_VARIANTS, | ||
control: { type: 'radio' }, | ||
}, | ||
}, | ||
}; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof ActionItemAddress>; | ||
|
||
export const Primary: Story = { | ||
render: ({ ...args }) => <ActionItemAddress {...args} />, | ||
args: { | ||
addressOrEns: '0x0000000000000000000000000000000000000000', | ||
tagLabel: 'You', | ||
delegations: 2, | ||
delegationLabel: 'Delegations', | ||
supplyPercentage: 10, | ||
tokenAmount: '1000', | ||
tokenSymbol: 'ANT', | ||
menuOptions: [ | ||
{ | ||
component: ( | ||
<ListItemAction title="Copy Address" iconRight={<IconCopy className="text-ui-300" />} bgWhite /> | ||
), | ||
}, | ||
{ | ||
component: ( | ||
<ListItemAction | ||
title="View on block explorer" | ||
iconRight={<IconLinkExternal className="text-ui-300" />} | ||
bgWhite | ||
/> | ||
), | ||
}, | ||
{ | ||
component: ( | ||
<ListItemAction | ||
title="Delegate to" | ||
iconRight={<IconGovernance className="text-ui-300" />} | ||
bgWhite | ||
/> | ||
), | ||
}, | ||
], | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
import React from 'react'; | ||
import styled from 'styled-components'; | ||
|
||
import { useScreen } from '../../hooks'; | ||
import { shortenAddress } from '../../utils'; | ||
import { Avatar } from '../avatar'; | ||
import { ButtonIcon } from '../button'; | ||
import { Dropdown, type ListItemProps } from '../dropdown'; | ||
import { IconLinkExternal, IconMenuVertical } from '../icons'; | ||
import { Tag } from '../tag'; | ||
|
||
/** | ||
* Type declarations for `ActionItemAddressProps`. | ||
*/ | ||
export type ActionItemAddressProps = { | ||
/** Wallet address or ENS domain name. */ | ||
addressOrEns: string; | ||
|
||
/** Optional ENS avatar URL. If not provided and the wallet address is valid, | ||
* it will be used to generate a Blockies avatar. | ||
*/ | ||
avatar?: string; | ||
|
||
/** Label for the delegation amount. */ | ||
delegationLabel: string; | ||
|
||
/** Number of delegations. */ | ||
delegations: number; | ||
|
||
/** List of dropdown menu options. */ | ||
menuOptions: ListItemProps[]; | ||
|
||
/** Optional click handler for the "view on-chain" action. */ | ||
onViewOnChainClick?: React.MouseEventHandler; | ||
|
||
/** Percentage of supply. */ | ||
supplyPercentage: number; | ||
|
||
/** Optional label for the wallet tag. */ | ||
tagLabel?: string; | ||
|
||
/** Number of tokens delegated. */ | ||
tokenAmount: string; | ||
|
||
/** Symbol of the token delegated. */ | ||
tokenSymbol: string; | ||
|
||
/** ID variant for the wallet, which can be 'delegate' or 'you'. */ | ||
walletId?: TagWalletIdProps['variant']; | ||
}; | ||
|
||
/** | ||
* `ActionItemAddress` component: Displays an address item with associated actions. | ||
* @param props - Component properties following `ActionItemAddressProps` type. | ||
* @returns JSX Element. | ||
*/ | ||
export const ActionItemAddress: React.FC<ActionItemAddressProps> = (props) => { | ||
const { | ||
addressOrEns, | ||
avatar, | ||
delegationLabel, | ||
delegations, | ||
menuOptions, | ||
onViewOnChainClick, | ||
supplyPercentage, | ||
tagLabel, | ||
tokenAmount, | ||
tokenSymbol, | ||
walletId, | ||
} = props; | ||
|
||
const { isDesktop } = useScreen(); | ||
|
||
return ( | ||
<Container> | ||
<Avatar size="small" mode="circle" src={avatar ?? addressOrEns} /> | ||
|
||
<ContentWrapper> | ||
<Wallet> | ||
<AddressOrEns>{shortenAddress(addressOrEns)}</AddressOrEns> | ||
{walletId && tagLabel && ( | ||
<TagWalletId | ||
label={tagLabel} | ||
variant={walletId} | ||
className="inline-flex relative -top-0.5 -right-0.5" | ||
/> | ||
)} | ||
</Wallet> | ||
<Content> | ||
<InfoWrapper> | ||
<span>{tokenAmount}</span> | ||
<span>{tokenSymbol}</span> | ||
<InfoLabel>{supplyPercentage}%</InfoLabel> | ||
</InfoWrapper> | ||
<InfoWrapper> | ||
{delegations > 0 && ( | ||
<> | ||
<span>{delegations}</span> | ||
<InfoLabel>{delegationLabel}</InfoLabel> | ||
</> | ||
)} | ||
</InfoWrapper> | ||
</Content> | ||
</ContentWrapper> | ||
<ButtonGroup> | ||
{isDesktop && ( | ||
<ButtonIcon | ||
mode="ghost" | ||
icon={<IconLinkExternal />} | ||
size="small" | ||
bgWhite | ||
onClick={onViewOnChainClick} | ||
/> | ||
)} | ||
|
||
<Dropdown | ||
align="end" | ||
alignOffset={isDesktop ? 0 : -4} | ||
className="py-1 px-0" | ||
listItems={menuOptions} | ||
side="top" | ||
sideOffset={isDesktop ? -40 : -44} | ||
trigger={<ButtonIcon mode="secondary" icon={<IconMenuVertical />} size="small" bgWhite />} | ||
/> | ||
</ButtonGroup> | ||
</Container> | ||
); | ||
}; | ||
|
||
export const TAG_WALLET_ID_VARIANTS = ['delegate', 'you'] as const; | ||
type TagWalletIdVariant = (typeof TAG_WALLET_ID_VARIANTS)[number]; | ||
|
||
/** | ||
* Type declarations for `TagWalletIdProps`. | ||
*/ | ||
type TagWalletIdProps = { | ||
/** Optional CSS classes to apply to the tag. */ | ||
className?: string; | ||
/** Label to display on the tag. */ | ||
label: string; | ||
/** Variant of the tag which affects its color. Can be 'delegate' or 'you'. */ | ||
variant: TagWalletIdVariant; | ||
}; | ||
|
||
/** | ||
* `TagWalletId` component: Displays a styled tag based on the provided variant. | ||
* @param props - Component properties following `TagWalletIdProps` type. | ||
* @returns JSX Element. | ||
*/ | ||
const TagWalletId: React.FC<TagWalletIdProps> = ({ className, label, variant }) => { | ||
const colorScheme = variant === 'you' ? 'neutral' : 'info'; | ||
return <Tag label={label} colorScheme={colorScheme} className={className} />; | ||
}; | ||
|
||
const Container = styled.div.attrs({ | ||
className: | ||
'bg-ui-0 flex py-2 items-center px-1.5 desktop:pr-2 desktop:pl-3 space-x-2 w-full border-b border-b-ui-100', | ||
})``; | ||
|
||
const ContentWrapper = styled.div.attrs({ className: 'desktop:flex flex-1 space-y-0.5' })``; | ||
|
||
const Content = styled.div.attrs({ | ||
className: 'flex desktop:flex-1 space-x-1.5 font-semibold text-ui-600 ft-text-sm', | ||
})``; | ||
|
||
const InfoWrapper = styled.div.attrs({ | ||
className: 'flex desktop:flex-1 space-x-0.25', | ||
})``; | ||
|
||
const InfoLabel = styled.span.attrs({ className: 'font-normal text-ui-500' })``; | ||
|
||
const Wallet = styled.div.attrs({ className: 'flex desktop:flex-1 items-center' })``; | ||
|
||
const AddressOrEns = styled.div.attrs({ className: 'font-semibold text-ui-800 ft-text-base' })``; | ||
|
||
const ButtonGroup = styled.div.attrs({ className: 'flex gap-x-1.5' })``; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './actionItemAddress'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './actionItems'; | ||
export * from './alerts'; | ||
export * from './avatar'; | ||
export * from './backdrop'; | ||
|