chore(trading): notification component redesign (#2845)
This commit is contained in:
parent
06ea3924fa
commit
710e2daa27
@ -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;
|
||||||
|
@ -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>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 (
|
||||||
<Notification
|
<div className="border-l border-default pl-1 pr-1 pb-1 min-w-min whitespace-nowrap">
|
||||||
intent={Intent.Warning}
|
<Notification
|
||||||
message={t('Changes have been proposed for this market')}
|
intent={Intent.Warning}
|
||||||
testId="market-proposal-notification"
|
message={message}
|
||||||
>
|
testId="market-proposal-notification"
|
||||||
<ExternalLink href={proposalLink}>{t('View proposal')}</ExternalLink>
|
className="px-2 py-1"
|
||||||
</Notification>
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
</>
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user