Skip to content

Commit

Permalink
feat(ui): add notifications provider in sidebarlayout (#2672)
Browse files Browse the repository at this point in the history
  • Loading branch information
sstraatemans authored Nov 20, 2024
1 parent 9cb2d37 commit edcfbe0
Show file tree
Hide file tree
Showing 13 changed files with 333 additions and 48 deletions.
5 changes: 5 additions & 0 deletions .changeset/chatty-birds-invite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@kadena/kode-ui': minor
---

add notifications hook to the sidebar layout
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ export const SideBar: FC<ISideBarProps> = ({
startVisual={isExpanded ? <MonoMenuOpen /> : <MonoMenu />}
/>
</Stack>

{appContext && <SideBarAppContext>{appContext}</SideBarAppContext>}
{navigation && <SideBarNavigation>{navigation}</SideBarNavigation>}
{context && <SideBarContext>{context}</SideBarContext>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -63,6 +67,34 @@ const LinkComponent: FC<PropsWithChildren<{ to: string }>> = ({
return <a {...props}>{children}</a>;
};

const InnerFooter = () => {
return (
<SideBarFooter>
<SideBarFooterItem
visual={<MonoWindow />}
component={LinkComponent}
href="https://kadena.io"
label="option 1"
/>
<SideBarFooterItem
visual={<MonoWifiTethering />}
onPress={() => {}}
label="option 2"
/>
<SideBarFooterItem
visual={<MonoWorkspaces />}
onPress={() => {}}
label="option 3"
/>
<SideBarFooterItem
visual={<MonoLightMode />}
onPress={() => {}}
label="option 4"
/>
</SideBarFooter>
);
};

const InnerLayout = () => {
const { isExpanded, setIsRightAsideExpanded, isRightAsideExpanded } =
useLayout();
Expand Down Expand Up @@ -196,31 +228,7 @@ const InnerLayout = () => {
}
/>
}
footer={
<SideBarFooter>
<SideBarFooterItem
visual={<MonoWindow />}
component={LinkComponent}
href="https://kadena.io"
label="option 1"
/>
<SideBarFooterItem
visual={<MonoWifiTethering />}
onPress={() => {}}
label="option 2"
/>
<SideBarFooterItem
visual={<MonoWorkspaces />}
onPress={() => {}}
label="option 3"
/>
<SideBarFooterItem
visual={<MonoLightMode />}
onPress={() => {}}
label="option 4"
/>
</SideBarFooter>
}
footer={<InnerFooter />}
>
<Stack
flexDirection="column"
Expand Down Expand Up @@ -365,33 +373,149 @@ export const Primary: IStory = {
},
};

const InnerLayoutFull = () => {
const NotificationsLayout = () => {
const { addNotification } = useNotifications();
const { isExpanded, setIsRightAsideExpanded, isRightAsideExpanded } =
useLayout();

return (
<SideBarLayout
location={{
url: 'https://kadena.io',
push: console.log,
}}
logo={
<a href="https://kadena.io" target="_blank" rel="noreferrer">
<KLogo height={40} />
</a>
}
variant="full"
>
<Stack style={{ maxWidth: '800px' }}>content</Stack>
</SideBarLayout>
<>
{isRightAsideExpanded && (
<RightAside
isOpen
onClose={() => {
setIsRightAsideExpanded(false);
}}
>
<RightAsideHeader label="test header" />

<RightAsideContent>content</RightAsideContent>
</RightAside>
)}
<SideBarLayout
logo={
<a href="https://kadena.io" target="_blank" rel="noreferrer">
<KLogo height={40} />
</a>
}
location={{
url: 'https://kadena.io',
push: console.log,
}}
sidebar={
<SideBar
logo={
<a href="https://kadena.io" target="_blank" rel="noreferrer">
<KLogo height={40} />
</a>
}
navigation={
<>
<SideBarItem
visual={<MonoWifiTethering />}
label="Mainnet"
href="javascript:void()"
/>
</>
}
context={
<>
<SideBarItemsInline>
<SideBarItem
visual={<MonoAccountTree />}
label="Profile"
onPress={() => {}}
/>

<SideBarItem
visual={<MonoLightMode />}
label="Change theme"
onPress={() => {}}
>
<Button
aria-label="Change theme"
variant={isExpanded ? 'transparent' : 'outlined'}
isCompact={!isExpanded}
startVisual={<MonoLightMode />}
onPress={() => {}}
/>
</SideBarItem>
</SideBarItemsInline>
</>
}
/>
}
footer={<InnerFooter />}
>
<Stack
flexDirection="column"
style={{ maxWidth: '800px', height: '400px' }}
>
<Stack
width="100%"
flexDirection="column"
justifyContent="center"
margin="md"
gap="md"
>
<p>content</p>

<Button
onPress={() => {
setIsRightAsideExpanded(true);
}}
>
Open sidebar
</Button>

<Button
onPress={() => {
addNotification({
icon: <MonoAccountTree />,
label: 'This is an error Notification',
message: 'And this is the message',
intent: 'negative',
});
}}
>
Add Error Notification
</Button>

<Button
onPress={() => {
addNotification({
icon: <MonoAccountTree />,
label: 'This is an info Notification',
message: 'And this is the message',
isDismissable: true,
});
}}
>
Add Info Notification
</Button>
</Stack>
</Stack>
</SideBarLayout>
</>
);
};

export const Full: IStory = {
name: 'Full centered layout',
export const Notifications: IStory = {
name: 'Notifications',

args: {},
render: () => {
return (
<LayoutProvider>
<InnerLayoutFull />
<SideBarBreadcrumbs icon={<MonoAccountTree />}>
<SideBarBreadcrumbsItem href="/accounts">
He-man
</SideBarBreadcrumbsItem>
<SideBarBreadcrumbsItem href="/accounts/2">
Skeletor
</SideBarBreadcrumbsItem>
</SideBarBreadcrumbs>
<NotificationsLayout />
</LayoutProvider>
);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -80,6 +81,7 @@ export const SideBarLayout: FC<ISideBarLayout> = ({
<Stack flex={1}>{children}</Stack>
</Stack>
<SideBarAside location={location} />
<NotificationSlot />
</main>

{footer}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<PropsWithChildren> = ({ children }) => {
return (
<NotificationsProvider>
<SideBarLayoutProvider>{children}</SideBarLayoutProvider>
</NotificationsProvider>
);
};
Original file line number Diff line number Diff line change
@@ -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<INotificationMinimizedProps>) => void;
removeNotification: (notification: INotificationMinimizedProps) => void;
}

export const NotificationsContext = createContext<INotificationsContext>({
notifications: [],
addNotification: () => {},
removeNotification: () => {},
});

export const useNotifications = () => useContext(NotificationsContext);

export interface INotificationsProvider extends PropsWithChildren {}

export const NotificationsProvider: FC<INotificationsProvider> = ({
children,
}) => {
const [notifications, setNotifications] = useState<
INotificationMinimizedProps[]
>([]);

const removeNotification = (notification: INotificationMinimizedProps) => {
setNotifications((v) => v.filter((not) => not.id !== notification.id));
};

const addNotification = (
notification: Partial<INotificationMinimizedProps>,
) => {
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 (
<NotificationsContext.Provider
value={{ notifications, addNotification, removeNotification }}
>
{children}
</NotificationsContext.Provider>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -67,7 +67,7 @@ export const useLayout = () => useContext(LayoutContext);

export interface ILayoutProvider extends PropsWithChildren {}

export const LayoutProvider: FC<ILayoutProvider> = ({ children }) => {
export const SideBarLayoutProvider: FC<ILayoutProvider> = ({ children }) => {
const [rightAsideRef, setRightAsideRefState] =
useState<HTMLDivElement | null>(null);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { LayoutProvider } from './LayoutProvider';
export { useNotifications } from './NotificationsProvider';
export { useLayout } from './SideBarLayoutProvider';
Loading

0 comments on commit edcfbe0

Please sign in to comment.