From edcfbe0caafa6a4216de80429b55ca4fb859c8bb Mon Sep 17 00:00:00 2001 From: Steven Date: Wed, 20 Nov 2024 14:02:12 +0100 Subject: [PATCH] feat(ui): add notifications provider in sidebarlayout (#2672) --- .changeset/chatty-birds-invite.md | 5 + .../src/patterns/SideBarLayout/SideBar.tsx | 1 - .../SideBarLayout/SideBarLayout.stories.tsx | 212 ++++++++++++++---- .../patterns/SideBarLayout/SideBarLayout.tsx | 2 + .../LayoutProvider/LayoutProvider.tsx | 12 + .../LayoutProvider/NotificationsProvider.tsx | 63 ++++++ .../SideBarLayoutProvider.tsx} | 4 +- .../components/LayoutProvider/index.ts | 3 + .../NotificationSlot/NotificationSlot.tsx | 25 +++ .../NotificationSlot/NotificationWrapper.tsx | 21 ++ .../components/NotificationSlot/style.css.ts | 26 +++ .../src/patterns/SideBarLayout/index.ts | 6 +- packages/libs/kode-ui/src/patterns/index.ts | 1 + 13 files changed, 333 insertions(+), 48 deletions(-) create mode 100644 .changeset/chatty-birds-invite.md create mode 100644 packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/LayoutProvider.tsx create mode 100644 packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/NotificationsProvider.tsx rename packages/libs/kode-ui/src/patterns/SideBarLayout/components/{LayoutProvider.tsx => LayoutProvider/SideBarLayoutProvider.tsx} (97%) create mode 100644 packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/index.ts create mode 100644 packages/libs/kode-ui/src/patterns/SideBarLayout/components/NotificationSlot/NotificationSlot.tsx create mode 100644 packages/libs/kode-ui/src/patterns/SideBarLayout/components/NotificationSlot/NotificationWrapper.tsx create mode 100644 packages/libs/kode-ui/src/patterns/SideBarLayout/components/NotificationSlot/style.css.ts diff --git a/.changeset/chatty-birds-invite.md b/.changeset/chatty-birds-invite.md new file mode 100644 index 0000000000..d18850be2e --- /dev/null +++ b/.changeset/chatty-birds-invite.md @@ -0,0 +1,5 @@ +--- +'@kadena/kode-ui': minor +--- + +add notifications hook to the sidebar layout diff --git a/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBar.tsx b/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBar.tsx index 46d47baa06..982048aa4b 100644 --- a/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBar.tsx +++ b/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBar.tsx @@ -66,7 +66,6 @@ export const SideBar: FC = ({ startVisual={isExpanded ? : } /> - {appContext && {appContext}} {navigation && {navigation}} {context && {context}} diff --git a/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBarLayout.stories.tsx b/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBarLayout.stories.tsx index 2f143c8c11..b59c8cb9ee 100644 --- a/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBarLayout.stories.tsx +++ b/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBarLayout.stories.tsx @@ -13,7 +13,11 @@ import React, { useState } from 'react'; import { Button, Dialog, DialogHeader, Stack } from './../../components'; import { SideBarBreadcrumbs } from './components/Breadcrumbs/SideBarBreadcrumbs'; import { SideBarBreadcrumbsItem } from './components/Breadcrumbs/SideBarBreadcrumbsItem'; -import { LayoutProvider, useLayout } from './components/LayoutProvider'; +import { + LayoutProvider, + useLayout, + useNotifications, +} from './components/LayoutProvider'; import { KLogo } from './components/Logo/KLogo'; import { RightAside, @@ -63,6 +67,34 @@ const LinkComponent: FC> = ({ return {children}; }; +const InnerFooter = () => { + return ( + + } + component={LinkComponent} + href="https://kadena.io" + label="option 1" + /> + } + onPress={() => {}} + label="option 2" + /> + } + onPress={() => {}} + label="option 3" + /> + } + onPress={() => {}} + label="option 4" + /> + + ); +}; + const InnerLayout = () => { const { isExpanded, setIsRightAsideExpanded, isRightAsideExpanded } = useLayout(); @@ -196,31 +228,7 @@ const InnerLayout = () => { } /> } - footer={ - - } - component={LinkComponent} - href="https://kadena.io" - label="option 1" - /> - } - onPress={() => {}} - label="option 2" - /> - } - onPress={() => {}} - label="option 3" - /> - } - onPress={() => {}} - label="option 4" - /> - - } + footer={} > { +const NotificationsLayout = () => { + const { addNotification } = useNotifications(); + const { isExpanded, setIsRightAsideExpanded, isRightAsideExpanded } = + useLayout(); + return ( - - - - } - variant="full" - > - content - + <> + {isRightAsideExpanded && ( + { + setIsRightAsideExpanded(false); + }} + > + + + content + + )} + + + + } + location={{ + url: 'https://kadena.io', + push: console.log, + }} + sidebar={ + + + + } + navigation={ + <> + } + label="Mainnet" + href="javascript:void()" + /> + + } + context={ + <> + + } + label="Profile" + onPress={() => {}} + /> + + } + label="Change theme" + onPress={() => {}} + > + + + + + + + + + ); }; -export const Full: IStory = { - name: 'Full centered layout', +export const Notifications: IStory = { + name: 'Notifications', args: {}, render: () => { return ( - + }> + + He-man + + + Skeletor + + + ); }, diff --git a/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBarLayout.tsx b/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBarLayout.tsx index 49ec48e64d..c73fd05b1c 100644 --- a/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBarLayout.tsx +++ b/packages/libs/kode-ui/src/patterns/SideBarLayout/SideBarLayout.tsx @@ -3,6 +3,7 @@ import type { FC, PropsWithChildren, ReactElement } from 'react'; import React, { useEffect } from 'react'; import { MediaContextProvider, Stack } from './../../components'; import { useLayout } from './components/LayoutProvider'; +import { NotificationSlot } from './components/NotificationSlot/NotificationSlot'; import { SideBarAside } from './components/SideBarAside'; import { SideBarHeader } from './components/SideBarHeader'; import { @@ -80,6 +81,7 @@ export const SideBarLayout: FC = ({ {children} + {footer} diff --git a/packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/LayoutProvider.tsx b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/LayoutProvider.tsx new file mode 100644 index 0000000000..5e311f9769 --- /dev/null +++ b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/LayoutProvider.tsx @@ -0,0 +1,12 @@ +import type { FC, PropsWithChildren } from 'react'; +import React from 'react'; +import { NotificationsProvider } from './NotificationsProvider'; +import { SideBarLayoutProvider } from './SideBarLayoutProvider'; + +export const LayoutProvider: FC = ({ children }) => { + return ( + + {children} + + ); +}; diff --git a/packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/NotificationsProvider.tsx b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/NotificationsProvider.tsx new file mode 100644 index 0000000000..a6f183a054 --- /dev/null +++ b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/NotificationsProvider.tsx @@ -0,0 +1,63 @@ +import type { FC, PropsWithChildren } from 'react'; +import React, { createContext, useContext, useState } from 'react'; +import type { INotificationProps } from 'src/components'; + +export type INotificationMinimizedProps = Pick< + INotificationProps, + 'icon' | 'role' | 'isDismissable' | 'onDismiss' | 'intent' +> & { + id: string; + label: string; + message: string; +}; + +interface INotificationsContext { + notifications: INotificationMinimizedProps[]; + addNotification: (notification: Partial) => void; + removeNotification: (notification: INotificationMinimizedProps) => void; +} + +export const NotificationsContext = createContext({ + notifications: [], + addNotification: () => {}, + removeNotification: () => {}, +}); + +export const useNotifications = () => useContext(NotificationsContext); + +export interface INotificationsProvider extends PropsWithChildren {} + +export const NotificationsProvider: FC = ({ + children, +}) => { + const [notifications, setNotifications] = useState< + INotificationMinimizedProps[] + >([]); + + const removeNotification = (notification: INotificationMinimizedProps) => { + setNotifications((v) => v.filter((not) => not.id !== notification.id)); + }; + + const addNotification = ( + notification: Partial, + ) => { + const notificationProps: INotificationMinimizedProps = { + ...notification, + id: crypto.randomUUID(), + role: notification.role ?? 'status', + intent: notification.intent ?? 'info', + label: notification.label!, + message: notification.message!, + }; + + setNotifications((v) => [...v, notificationProps]); + }; + + return ( + + {children} + + ); +}; diff --git a/packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider.tsx b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/SideBarLayoutProvider.tsx similarity index 97% rename from packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider.tsx rename to packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/SideBarLayoutProvider.tsx index 5799a5cc09..aa24eaac30 100644 --- a/packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider.tsx +++ b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/SideBarLayoutProvider.tsx @@ -7,7 +7,7 @@ import React, { useState, } from 'react'; import type { PressEvent } from 'react-aria'; -import type { ISideBarLayoutLocation } from '../types'; +import type { ISideBarLayoutLocation } from '../../types'; export interface IAppContextProps { visual: React.ReactElement; @@ -67,7 +67,7 @@ export const useLayout = () => useContext(LayoutContext); export interface ILayoutProvider extends PropsWithChildren {} -export const LayoutProvider: FC = ({ children }) => { +export const SideBarLayoutProvider: FC = ({ children }) => { const [rightAsideRef, setRightAsideRefState] = useState(null); diff --git a/packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/index.ts b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/index.ts new file mode 100644 index 0000000000..60b4cf7431 --- /dev/null +++ b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/LayoutProvider/index.ts @@ -0,0 +1,3 @@ +export { LayoutProvider } from './LayoutProvider'; +export { useNotifications } from './NotificationsProvider'; +export { useLayout } from './SideBarLayoutProvider'; diff --git a/packages/libs/kode-ui/src/patterns/SideBarLayout/components/NotificationSlot/NotificationSlot.tsx b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/NotificationSlot/NotificationSlot.tsx new file mode 100644 index 0000000000..80a396c3e9 --- /dev/null +++ b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/NotificationSlot/NotificationSlot.tsx @@ -0,0 +1,25 @@ +import type { FC } from 'react'; +import React from 'react'; +import { useNotifications } from '../LayoutProvider'; +import { NotificationHeading, Stack } from './../../../../components'; +import { NotificationWrapper } from './NotificationWrapper'; +import { notificationsSlotClass } from './style.css'; + +export const NotificationSlot: FC = () => { + const { notifications } = useNotifications(); + const reversedNotifications = [...notifications].reverse(); + console.log(reversedNotifications); + return ( + + {reversedNotifications.map((props) => { + const { label, message } = props; + return ( + + {label && {label}} + {message} + + ); + })} + + ); +}; diff --git a/packages/libs/kode-ui/src/patterns/SideBarLayout/components/NotificationSlot/NotificationWrapper.tsx b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/NotificationSlot/NotificationWrapper.tsx new file mode 100644 index 0000000000..e3e1ff5a55 --- /dev/null +++ b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/NotificationSlot/NotificationWrapper.tsx @@ -0,0 +1,21 @@ +import type { FC, PropsWithChildren } from 'react'; +import React, { useEffect } from 'react'; +import type { INotificationMinimizedProps } from '../LayoutProvider/NotificationsProvider'; +import { useNotifications } from '../LayoutProvider/NotificationsProvider'; +import { Notification } from './../../../../components'; + +type IProps = PropsWithChildren & INotificationMinimizedProps; + +export const NotificationWrapper: FC = ({ children, ...props }) => { + const { removeNotification } = useNotifications(); + + useEffect(() => { + if (!props.isDismissable) { + setTimeout(() => { + removeNotification(props); + }, 12000); + } + }, []); + + return {children}; +}; diff --git a/packages/libs/kode-ui/src/patterns/SideBarLayout/components/NotificationSlot/style.css.ts b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/NotificationSlot/style.css.ts new file mode 100644 index 0000000000..df53bc59b7 --- /dev/null +++ b/packages/libs/kode-ui/src/patterns/SideBarLayout/components/NotificationSlot/style.css.ts @@ -0,0 +1,26 @@ +import { globalStyle } from '@vanilla-extract/css'; +import { atoms, responsiveStyle, style, token } from './../../../../styles'; + +export const notificationsSlotClass = style([ + atoms({ + position: 'absolute', + flexDirection: 'column', + top: 0, + right: 0, + width: '100%', + gap: 'sm', + }), + { + zIndex: token('zIndex.toast'), + maxWidth: '100%', + }, + responsiveStyle({ + md: { + maxWidth: '400px', + }, + }), +]); + +globalStyle(`${notificationsSlotClass} > *:nth-child(n+4)`, { + display: 'none', +}); diff --git a/packages/libs/kode-ui/src/patterns/SideBarLayout/index.ts b/packages/libs/kode-ui/src/patterns/SideBarLayout/index.ts index 5fc9f4e537..5b6712d7c1 100644 --- a/packages/libs/kode-ui/src/patterns/SideBarLayout/index.ts +++ b/packages/libs/kode-ui/src/patterns/SideBarLayout/index.ts @@ -1,4 +1,8 @@ -export { LayoutProvider, useLayout } from './components/LayoutProvider'; +export { + LayoutProvider, + useLayout, + useNotifications, +} from './components/LayoutProvider'; export { SideBarFooter } from './components/SideBarFooter'; export { SideBarFooterItem } from './components/SideBarFooterItem'; export type { ISideBarFooterItemProps } from './components/SideBarFooterItem'; diff --git a/packages/libs/kode-ui/src/patterns/index.ts b/packages/libs/kode-ui/src/patterns/index.ts index 417e6fbb62..60848e7f79 100644 --- a/packages/libs/kode-ui/src/patterns/index.ts +++ b/packages/libs/kode-ui/src/patterns/index.ts @@ -28,6 +28,7 @@ export { SideBarTree, SideBarTreeItem, useLayout, + useNotifications, } from './SideBarLayout'; export type { ISideBarFooterItemProps,