-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(apps-ui-kit): add Account component (#1157)
* feat(apps-ui-kit): add Account component * feat(apps-ui-kit): refine account component * feat(apps-ui-kit): cleanup styels * feat(apps-ui-kit): move to molecules and use Address component * feat(apps-ui-kit): update classes * feat(apps-ui-kit): improve code * feat(apps-ui-kit): add missing props * feat(apps-ui-kit): refine account * feat(apps-ui-kit): add missing font family --------- Co-authored-by: Marc Espin <[email protected]>
- Loading branch information
1 parent
f40049c
commit f303b0a
Showing
4 changed files
with
206 additions
and
0 deletions.
There are no files selected for viewing
132 changes: 132 additions & 0 deletions
132
apps/ui-kit/src/lib/components/molecules/account/Account.tsx
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,132 @@ | ||
// Copyright (c) 2024 IOTA Stiftung | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
import React from 'react'; | ||
import cx from 'classnames'; | ||
import { Button, ButtonSize, ButtonType } from '../../atoms/button'; | ||
import { Address, Badge, BadgeType } from '../../atoms'; | ||
import { LockLocked, LockUnlocked, MoreHoriz } from '@iota/ui-icons'; | ||
|
||
interface AccountProps { | ||
/** | ||
* The title of the account. | ||
*/ | ||
title: string; | ||
/** | ||
* The subtitle of the account. | ||
*/ | ||
subtitle: string; | ||
/** | ||
* Whether the account is unlocked. | ||
*/ | ||
isLocked?: boolean; | ||
/** | ||
* Handler for more options click. | ||
*/ | ||
onOptionsClick: () => void; | ||
/** | ||
* Handler for the lock account icon click. | ||
*/ | ||
onLockAccountClick: () => void; | ||
/** | ||
* Handle for the unlock account icon click. | ||
*/ | ||
onUnlockAccountClick: () => void; | ||
/** | ||
* Function to render avatar content. | ||
*/ | ||
avatarContent: ({ isLocked }: { isLocked?: boolean }) => React.JSX.Element; | ||
/** | ||
* The onCopy event of the Address (optional). | ||
*/ | ||
onCopy?: (e: React.MouseEvent<SVGElement>) => void; | ||
/** | ||
* The onOpen event of the Address (optional). | ||
*/ | ||
onOpen?: (e: React.MouseEvent<SVGElement>) => void; | ||
/** | ||
* Has copy icon (optional). | ||
*/ | ||
isCopyable?: boolean; | ||
/** | ||
* Has open icon (optional). | ||
*/ | ||
isExternal?: boolean; | ||
/** | ||
* The type of the badge. | ||
*/ | ||
badgeType?: BadgeType; | ||
/** | ||
* The text of the badge. | ||
*/ | ||
badgeText?: string; | ||
} | ||
|
||
export function Account({ | ||
title, | ||
subtitle, | ||
badgeType, | ||
badgeText, | ||
isLocked, | ||
avatarContent, | ||
onOptionsClick, | ||
onLockAccountClick, | ||
onUnlockAccountClick, | ||
onCopy, | ||
onOpen, | ||
isCopyable, | ||
isExternal, | ||
}: AccountProps): React.JSX.Element { | ||
const Avatar = avatarContent; | ||
|
||
return ( | ||
<div className="state-layer group relative flex w-full items-center justify-between space-x-3 rounded-xl px-sm py-xs hover:cursor-pointer"> | ||
<div className="flex items-center space-x-3"> | ||
<Avatar isLocked={isLocked} /> | ||
<div className="flex flex-col items-start py-xs"> | ||
<div className="flex items-center space-x-2"> | ||
<span className="font-inter text-title-md text-neutral-10 dark:text-neutral-92"> | ||
{title} | ||
</span> | ||
{badgeType && badgeText && <Badge type={badgeType} label={badgeText} />} | ||
</div> | ||
<Address | ||
text={subtitle} | ||
onCopy={onCopy} | ||
onOpen={onOpen} | ||
isCopyable={isCopyable} | ||
isExternal={isExternal} | ||
/> | ||
</div> | ||
</div> | ||
<div | ||
className={cx( | ||
'z-10 ml-auto flex items-center space-x-2 [&_button]:hidden group-hover:[&_button]:flex', | ||
isLocked && '[&_button:last-child]:flex', | ||
)} | ||
> | ||
<Button | ||
size={ButtonSize.Small} | ||
type={ButtonType.Ghost} | ||
onClick={onOptionsClick} | ||
icon={<MoreHoriz />} | ||
/> | ||
{isLocked ? ( | ||
<Button | ||
size={ButtonSize.Small} | ||
type={ButtonType.Ghost} | ||
onClick={onUnlockAccountClick} | ||
icon={<LockLocked />} | ||
/> | ||
) : ( | ||
<Button | ||
size={ButtonSize.Small} | ||
type={ButtonType.Ghost} | ||
onClick={onLockAccountClick} | ||
icon={<LockUnlocked />} | ||
/> | ||
)} | ||
</div> | ||
</div> | ||
); | ||
} |
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,4 @@ | ||
// Copyright (c) 2024 IOTA Stiftung | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
export { Account } from './Account'; |
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 |
---|---|---|
|
@@ -3,3 +3,4 @@ | |
|
||
export * from './segmented-button'; | ||
export * from './title'; | ||
export * from './account'; |
69 changes: 69 additions & 0 deletions
69
apps/ui-kit/src/storybook/stories/molecules/Account.stories.tsx
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,69 @@ | ||
// Copyright (c) 2024 IOTA Stiftung | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
import type { Meta, StoryObj } from '@storybook/react'; | ||
import { Account, BadgeType } from '@/components'; | ||
import cx from 'classnames'; | ||
|
||
const meta = { | ||
component: Account, | ||
tags: ['autodocs'], | ||
render: (props) => { | ||
return ( | ||
<div className="w-1/2"> | ||
<Account {...props} /> | ||
</div> | ||
); | ||
}, | ||
} satisfies Meta<typeof Account>; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof meta>; | ||
|
||
const Avatar = ({ isLocked }: { isLocked?: boolean }) => { | ||
const circleFillClass = isLocked ? 'fill-neutral-80 dark:fill-neutral-30' : 'fill-primary-30'; | ||
return ( | ||
<svg | ||
xmlns="http://www.w3.org/2000/svg" | ||
width="33" | ||
height="32" | ||
viewBox="0 0 33 32" | ||
fill="none" | ||
> | ||
<circle cx="16.5" cy="16" r="16" className={cx(circleFillClass)} /> | ||
</svg> | ||
); | ||
}; | ||
|
||
export const Default: Story = { | ||
args: { | ||
title: 'Account', | ||
subtitle: '0x0d7...3f37', | ||
isLocked: true, | ||
avatarContent: Avatar, | ||
}, | ||
argTypes: { | ||
badgeType: { | ||
control: 'select', | ||
options: Object.values(BadgeType), | ||
}, | ||
isLocked: { | ||
control: 'boolean', | ||
}, | ||
onOptionsClick: { | ||
action: 'onOptionsClick', | ||
control: 'none', | ||
}, | ||
onLockAccountClick: { | ||
action: 'onLockAccount', | ||
control: 'none', | ||
}, | ||
avatarContent: { | ||
control: 'none', | ||
}, | ||
badgeText: { | ||
control: 'text', | ||
}, | ||
}, | ||
}; |