chore(trading): notification component redesign (#2845)

This commit is contained in:
macqbat 2023-02-06 13:31:35 +01:00 committed by GitHub
parent 06ea3924fa
commit 710e2daa27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 100 additions and 38 deletions

View File

@ -15,7 +15,7 @@ export const Header = ({ title, children }: TradeMarketHeaderProps) => {
<div className="px-4 xl:px-0 pb-2 xl:pb-3">{title}</div> <div className="px-4 xl:px-0 pb-2 xl:pb-3">{title}</div>
<div <div
data-testid="header-summary" data-testid="header-summary"
className="flex flex-nowrap items-start xl:flex-1 w-full overflow-x-auto text-xs" className="flex flex-nowrap items-end xl:flex-1 w-full overflow-x-auto text-xs"
> >
{Children.map(children, (child, index) => { {Children.map(children, (child, index) => {
if (!child) return null; if (!child) return null;

View File

@ -20,14 +20,19 @@ export const AssetProposalNotification = ({
const proposalLink = tokenLink( const proposalLink = tokenLink(
TOKEN_PROPOSAL.replace(':id', proposal.id || '') TOKEN_PROPOSAL.replace(':id', proposal.id || '')
); );
const message = (
<>
{t('Changes have been proposed for this asset.')}{' '}
<ExternalLink href={proposalLink}>{t('View proposal')}</ExternalLink>
</>
);
return ( return (
<Notification <Notification
intent={Intent.Warning} intent={Intent.Warning}
message={t('Changes have been proposed for this asset')} message={message}
testId="asset-proposal-notification" testId="asset-proposal-notification"
> className="mb-2"
<ExternalLink href={proposalLink}>{t('View proposal')}</ExternalLink> />
</Notification>
); );
} }

View File

@ -20,14 +20,23 @@ export const MarketProposalNotification = ({
const proposalLink = tokenLink( const proposalLink = tokenLink(
TOKEN_PROPOSAL.replace(':id', proposal.id || '') TOKEN_PROPOSAL.replace(':id', proposal.id || '')
); );
const message = (
<div className="flex flex-col text-sm">
{t('Changes have been proposed for this market.')}{' '}
<ExternalLink href={proposalLink} className="w-fit">
{t('View proposal')}
</ExternalLink>
</div>
);
return ( return (
<div className="border-l border-default pl-1 pr-1 pb-1 min-w-min whitespace-nowrap">
<Notification <Notification
intent={Intent.Warning} intent={Intent.Warning}
message={t('Changes have been proposed for this market')} message={message}
testId="market-proposal-notification" testId="market-proposal-notification"
> className="px-2 py-1"
<ExternalLink href={proposalLink}>{t('View proposal')}</ExternalLink> />
</Notification> </div>
); );
} }

View File

@ -1,29 +1,33 @@
import type { Meta, Story } from '@storybook/react'; import type { Meta } from '@storybook/react';
import { Intent } from '../../utils/intent'; import { Intent } from '../../utils/intent';
import { ExternalLink, Link } from '../link'; import { Link } from '../link';
import { Notification } from './notification'; import { Notification } from './notification';
import type { ComponentStory } from '@storybook/react';
export default { export default {
component: Notification, component: Notification,
title: 'Notification', title: 'Notification',
} as Meta; } as Meta;
const Template: Story = ({ intent, message, children }) => ( const Template: ComponentStory<typeof Notification> = (props) => (
<div className="flex"> <div className="max-w-[410px]">
<Notification intent={intent} message={message}> <Notification {...props} />
{children}
</Notification>
</div> </div>
); );
const props = { const props = {
message: 'Exercitationem doloremque neque laborum incidunt consectetur amet', message: (
children: ( <>
<div className="flex space-x-1"> This is a default message with an{' '}
<Link>Action</Link> <Link href="/?path=/story/notification--default">optional link</Link> that
<ExternalLink>External action</ExternalLink> returns onto multiple lines.
</div> </>
), ),
title: 'Optional title',
buttonProps: {
text: 'Optional button',
action: () => alert('Optional button action'),
},
}; };
export const Default = Template.bind({}); export const Default = Template.bind({});
@ -36,22 +40,50 @@ export const Primary = Template.bind({});
Primary.args = { Primary.args = {
...props, ...props,
intent: Intent.Primary, intent: Intent.Primary,
message: (
<>
This is a info message with an{' '}
<Link href="/?path=/story/notification--primary">optional link</Link> that
returns onto multiple lines.
</>
),
}; };
export const Success = Template.bind({}); export const Success = Template.bind({});
Success.args = { Success.args = {
...props, ...props,
intent: Intent.Success, intent: Intent.Success,
message: (
<>
This is a success message with an{' '}
<Link href="/?path=/story/notification--success">optional link</Link> that
returns onto multiple lines.
</>
),
}; };
export const Warning = Template.bind({}); export const Warning = Template.bind({});
Warning.args = { Warning.args = {
...props, ...props,
intent: Intent.Warning, intent: Intent.Warning,
message: (
<>
This is a warning message with an{' '}
<Link href="/?path=/story/notification--warning">optional link</Link> that
returns onto multiple lines.
</>
),
}; };
export const Danger = Template.bind({}); export const Danger = Template.bind({});
Danger.args = { Danger.args = {
...props, ...props,
intent: Intent.Danger, intent: Intent.Danger,
message: (
<>
This is an error message with an{' '}
<Link href="/?path=/story/notification--danger">optional link</Link> that
returns onto multiple lines.
</>
),
}; };

View File

@ -4,12 +4,15 @@ import classNames from 'classnames';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { Intent } from '../../utils/intent'; import { Intent } from '../../utils/intent';
import { Icon } from '../icon'; import { Icon } from '../icon';
import { Button } from '../button';
type NotificationProps = { type NotificationProps = {
intent: Intent; intent: Intent;
message: string; message: ReactNode | string;
title?: string;
buttonProps?: { text: string; action: () => void; className?: string };
testId?: string; testId?: string;
children?: ReactNode; className?: string;
}; };
const getIcon = (intent: Intent): IconName => { const getIcon = (intent: Intent): IconName => {
@ -26,8 +29,10 @@ const getIcon = (intent: Intent): IconName => {
export const Notification = ({ export const Notification = ({
intent, intent,
message, message,
title,
testId, testId,
children, buttonProps,
className,
}: NotificationProps) => { }: NotificationProps) => {
return ( return (
<div <div
@ -40,7 +45,8 @@ export const Notification = ({
'border-yellow-500': intent === Intent.Warning, 'border-yellow-500': intent === Intent.Warning,
'border-vega-pink': intent === Intent.Danger, 'border-vega-pink': intent === Intent.Danger,
}, },
'border rounded px-3 py-1 text-xs mb-1 mr-1' 'border rounded text-xs p-4 flex items-start gap-2.5 bg-neutral-100 dark:bg-neutral-900',
className
)} )}
> >
<div <div
@ -52,18 +58,28 @@ export const Notification = ({
'text-yellow-600 dark:text-yellow-500': intent === Intent.Warning, 'text-yellow-600 dark:text-yellow-500': intent === Intent.Warning,
'text-vega-pink': intent === Intent.Danger, 'text-vega-pink': intent === Intent.Danger,
}, },
'flex items-start' 'flex items-start mt-1'
)} )}
> >
<Icon size={3} className="mr-1 mt-[2px]" name={getIcon(intent)} /> <Icon size={4} name={getIcon(intent)} />
<span </div>
title={message} <div className="flex flex-col flex-grow items-start gap-1.5 text-base">
className="whitespace-nowrap overflow-hidden text-ellipsis" {title && (
> <div className="whitespace-nowrap overflow-hidden text-ellipsis uppercase text-sm leading-6">
{message} {title}
</span> </div>
)}
<div>{message}</div>
{buttonProps && (
<Button
size="sm"
onClick={buttonProps.action}
className={classNames('mt-2 px-6 py-3', buttonProps.className)}
>
{buttonProps.text}
</Button>
)}
</div> </div>
{children}
</div> </div>
); );
}; };