feat(ui-toolkit,trading): allow toast box configuration (#3811)
This commit is contained in:
parent
2904975fd3
commit
f7aab5a78a
@ -5,6 +5,7 @@ import {
|
|||||||
RoundedWrapper,
|
RoundedWrapper,
|
||||||
Switch,
|
Switch,
|
||||||
ThemeSwitcher,
|
ThemeSwitcher,
|
||||||
|
ToastPositionSetter,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||||
|
|
||||||
@ -41,6 +42,8 @@ export const Settings = () => {
|
|||||||
'Help identify bugs and improve the service by sharing anonymous usage data.'
|
'Help identify bugs and improve the service by sharing anonymous usage data.'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<Divider />
|
||||||
|
<ToastPositionSetter />
|
||||||
</RoundedWrapper>
|
</RoundedWrapper>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
export * from './toast';
|
export * from './toast';
|
||||||
export * from './toasts-container';
|
export * from './toasts-container';
|
||||||
export * from './use-toasts';
|
export * from './use-toasts';
|
||||||
|
export * from './toast-position-setter';
|
||||||
|
145
libs/ui-toolkit/src/components/toast/toast-position-setter.tsx
Normal file
145
libs/ui-toolkit/src/components/toast/toast-position-setter.tsx
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { IconNames } from '@blueprintjs/icons';
|
||||||
|
import { Icon } from '../icon';
|
||||||
|
import { Button } from '../button';
|
||||||
|
import { ToastPosition, useToastsConfiguration, useToasts } from './use-toasts';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { Intent } from '../../utils/intent';
|
||||||
|
|
||||||
|
const testToast = {
|
||||||
|
id: 'test-toast',
|
||||||
|
intent: Intent.Primary,
|
||||||
|
content: <>{t('This is an example of a toast notification')}</>,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ToastPositionSetter = () => {
|
||||||
|
const setPostion = useToastsConfiguration((store) => store.setPosition);
|
||||||
|
const position = useToastsConfiguration((store) => store.position);
|
||||||
|
const setToast = useToasts((store) => store.setToast);
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(position: ToastPosition) => {
|
||||||
|
setPostion(position);
|
||||||
|
setToast(testToast);
|
||||||
|
},
|
||||||
|
[setToast, setPostion]
|
||||||
|
);
|
||||||
|
const iconCssClasses = 'absolute top-[4px] left-[4px]';
|
||||||
|
const buttonCssClasses =
|
||||||
|
'relative border-none bg-neutral-500/20 dark:bg-neutral-500/40';
|
||||||
|
const activeButton = 'bg-neutral-800/80 dark:bg-neutral-200/40';
|
||||||
|
const activeIcon = 'fill-white dark:fill-black';
|
||||||
|
return (
|
||||||
|
<div className="flex justify-between py-3 items-center">
|
||||||
|
<span>{t('Toast location')}</span>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'grid grid-cols-3 grid-rows-2 w-[64px] h-[42px] gap-[2px]'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
className={classNames(
|
||||||
|
buttonCssClasses,
|
||||||
|
position === ToastPosition.TopLeft && activeButton
|
||||||
|
)}
|
||||||
|
onClick={() => handleChange(ToastPosition.TopLeft)}
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
className={classNames(
|
||||||
|
iconCssClasses,
|
||||||
|
position === ToastPosition.TopLeft && activeIcon
|
||||||
|
)}
|
||||||
|
size={3}
|
||||||
|
name={IconNames.ARROW_TOP_LEFT}
|
||||||
|
/>{' '}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className={classNames(
|
||||||
|
buttonCssClasses,
|
||||||
|
position === ToastPosition.TopCenter && activeButton
|
||||||
|
)}
|
||||||
|
onClick={() => handleChange(ToastPosition.TopCenter)}
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
className={classNames(
|
||||||
|
iconCssClasses,
|
||||||
|
position === ToastPosition.TopCenter && activeIcon
|
||||||
|
)}
|
||||||
|
size={3}
|
||||||
|
name={IconNames.ARROW_UP}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className={classNames(
|
||||||
|
buttonCssClasses,
|
||||||
|
position === ToastPosition.TopRight && activeButton
|
||||||
|
)}
|
||||||
|
onClick={() => handleChange(ToastPosition.TopRight)}
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
className={classNames(
|
||||||
|
iconCssClasses,
|
||||||
|
position === ToastPosition.TopRight && activeIcon
|
||||||
|
)}
|
||||||
|
size={3}
|
||||||
|
name={IconNames.ARROW_TOP_RIGHT}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className={classNames(
|
||||||
|
buttonCssClasses,
|
||||||
|
position === ToastPosition.BottomLeft && activeButton
|
||||||
|
)}
|
||||||
|
onClick={() => handleChange(ToastPosition.BottomLeft)}
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
className={classNames(
|
||||||
|
iconCssClasses,
|
||||||
|
position === ToastPosition.BottomLeft && activeIcon
|
||||||
|
)}
|
||||||
|
size={3}
|
||||||
|
name={IconNames.ARROW_BOTTOM_LEFT}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className={classNames(
|
||||||
|
buttonCssClasses,
|
||||||
|
position === ToastPosition.BottomCenter && activeButton
|
||||||
|
)}
|
||||||
|
onClick={() => handleChange(ToastPosition.BottomCenter)}
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
className={classNames(
|
||||||
|
iconCssClasses,
|
||||||
|
position === ToastPosition.BottomCenter && activeIcon
|
||||||
|
)}
|
||||||
|
size={3}
|
||||||
|
name={IconNames.ARROW_DOWN}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className={classNames(
|
||||||
|
buttonCssClasses,
|
||||||
|
position === ToastPosition.BottomRight && activeButton
|
||||||
|
)}
|
||||||
|
onClick={() => handleChange(ToastPosition.BottomRight)}
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
className={classNames(
|
||||||
|
iconCssClasses,
|
||||||
|
position === ToastPosition.BottomRight && activeIcon
|
||||||
|
)}
|
||||||
|
size={3}
|
||||||
|
name={IconNames.ARROW_BOTTOM_RIGHT}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -6,7 +6,7 @@ import { useLayoutEffect, useRef } from 'react';
|
|||||||
import { Button } from '../button';
|
import { Button } from '../button';
|
||||||
import { Toast } from './toast';
|
import { Toast } from './toast';
|
||||||
import type { Toasts } from './use-toasts';
|
import type { Toasts } from './use-toasts';
|
||||||
import { useToasts } from './use-toasts';
|
import { ToastPosition, useToasts, useToastsConfiguration } from './use-toasts';
|
||||||
|
|
||||||
import { Portal } from '@radix-ui/react-portal';
|
import { Portal } from '@radix-ui/react-portal';
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ export const ToastsContainer = ({
|
|||||||
}: ToastsContainerProps) => {
|
}: ToastsContainerProps) => {
|
||||||
const ref = useRef<HTMLDivElement>();
|
const ref = useRef<HTMLDivElement>();
|
||||||
const closeAll = useToasts((store) => store.closeAll);
|
const closeAll = useToasts((store) => store.closeAll);
|
||||||
|
const position = useToastsConfiguration((store) => store.position);
|
||||||
// Scroll to top for desc, bottom for asc when a toast is added.
|
// Scroll to top for desc, bottom for asc when a toast is added.
|
||||||
const count = usePrevious(Object.keys(toasts).length) || 0;
|
const count = usePrevious(Object.keys(toasts).length) || 0;
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
@ -46,7 +46,19 @@ export const ToastsContainer = ({
|
|||||||
ref={ref as Ref<HTMLDivElement>}
|
ref={ref as Ref<HTMLDivElement>}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'group',
|
'group',
|
||||||
'absolute bottom-0 right-0 z-20 ',
|
'absolute z-20',
|
||||||
|
{ 'bottom-0 right-0': position === ToastPosition.BottomRight },
|
||||||
|
{ 'bottom-0 left-0': position === ToastPosition.BottomLeft },
|
||||||
|
{ 'top-0 left-0': position === ToastPosition.TopLeft },
|
||||||
|
{ 'top-0 right-0': position === ToastPosition.TopRight },
|
||||||
|
{
|
||||||
|
'top-0 left-[50%] translate-x-[-50%]':
|
||||||
|
position === ToastPosition.TopCenter,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'bottom-0 left-[50%] translate-x-[-50%]':
|
||||||
|
position === ToastPosition.BottomCenter,
|
||||||
|
},
|
||||||
'p-[8px_16px_16px_16px]',
|
'p-[8px_16px_16px_16px]',
|
||||||
'max-w-full max-h-full overflow-x-hidden overflow-y-auto',
|
'max-w-full max-h-full overflow-x-hidden overflow-y-auto',
|
||||||
{
|
{
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
|
import { persist } from 'zustand/middleware';
|
||||||
import { immer } from 'zustand/middleware/immer';
|
import { immer } from 'zustand/middleware/immer';
|
||||||
import type { Toast } from './toast';
|
import type { Toast } from './toast';
|
||||||
import omit from 'lodash/omit';
|
import omit from 'lodash/omit';
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
|
|
||||||
|
const STORAGE_KEY = 'vega_toast_store';
|
||||||
|
|
||||||
export type Toasts = Record<string, Toast>;
|
export type Toasts = Record<string, Toast>;
|
||||||
|
|
||||||
const isUpdateable = (a: Toast, b: Toast) =>
|
const isUpdateable = (a: Toast, b: Toast) =>
|
||||||
@ -96,3 +99,27 @@ export const useToasts = create<ToastsStore>()(
|
|||||||
removeAll: () => set({ toasts: {}, count: 0 }),
|
removeAll: () => set({ toasts: {}, count: 0 }),
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export enum ToastPosition {
|
||||||
|
BottomRight,
|
||||||
|
BottomLeft,
|
||||||
|
TopLeft,
|
||||||
|
TopRight,
|
||||||
|
TopCenter,
|
||||||
|
BottomCenter,
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToastConfiguration = {
|
||||||
|
position: ToastPosition;
|
||||||
|
setPosition: (position: ToastPosition) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useToastsConfiguration = create<ToastConfiguration>()(
|
||||||
|
persist(
|
||||||
|
immer((set) => ({
|
||||||
|
position: ToastPosition.BottomRight,
|
||||||
|
setPosition: (position: ToastPosition) => set({ position }),
|
||||||
|
})),
|
||||||
|
{ name: STORAGE_KEY }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user