Skip to content

Commit 377000b

Browse files
feat(fuselage): SidebarBanner component (#975)
1 parent f4e9645 commit 377000b

File tree

4 files changed

+217
-1
lines changed

4 files changed

+217
-1
lines changed

packages/fuselage/src/components/Sidebar/Sidebar.stories.tsx

+76-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { action } from '@storybook/addon-actions';
12
import { Title, Description, Primary, Stories } from '@storybook/addon-docs';
23
import type { ComponentStory, ComponentMeta } from '@storybook/react';
34
import React from 'react';
@@ -19,7 +20,7 @@ import Sidebar, {
1920
SidebarFooterHighlight,
2021
SidebarItemIcon,
2122
} from '.';
22-
import { Avatar, Icon, Box, Tag, Divider } from '../..';
23+
import { Avatar, Icon, Box, Tag, Divider, SidebarBanner } from '../..';
2324

2425
export default {
2526
title: 'Sidebar/Sidebar',
@@ -383,3 +384,77 @@ export const Admin: ComponentStory<typeof Sidebar> = () => (
383384
</SidebarItem>
384385
</div>
385386
);
387+
388+
export const WithBanner: ComponentStory<typeof Sidebar> = () => (
389+
<div className='rcx-sidebar'>
390+
<Box display='flex' is='header' pbs='x16' pbe='x8' pi='x24'>
391+
<Box fontSize='p2' fontWeight='p2'>
392+
Administration
393+
</Box>
394+
<Box mi='x8'>
395+
<Tag variant='featured'>Development</Tag>
396+
</Box>
397+
</Box>
398+
<Divider />
399+
<SidebarBanner
400+
text='This is a sidebar banner'
401+
description='Learn more'
402+
onClick={action('click')}
403+
onClose={action('click')}
404+
/>
405+
<SidebarItem clickable>
406+
<Box display='flex' justifyContent='center' pb='x8'>
407+
<Icon name='import' mi='x4' size='x20' />
408+
Import
409+
</Box>
410+
</SidebarItem>
411+
<SidebarItem clickable>
412+
<Box display='flex' justifyContent='center' pb='x8'>
413+
<Icon name='user' mi='x4' size='x20' />
414+
Users
415+
</Box>
416+
</SidebarItem>
417+
<SidebarItem clickable>
418+
<Box display='flex' justifyContent='center' pb='x8'>
419+
<Icon name='hashtag' mi='x4' size='x20' />
420+
Rooms
421+
</Box>
422+
</SidebarItem>
423+
<SidebarItem clickable>
424+
<Box display='flex' justifyContent='center' pb='x8'>
425+
<Icon name='cube' mi='x4' size='x20' />
426+
Apps
427+
</Box>
428+
</SidebarItem>
429+
</div>
430+
);
431+
432+
export const CustomBannerContent: ComponentStory<typeof SidebarBanner> = () => (
433+
<SidebarBanner>
434+
<Box display='flex' justifyContent='space-between'>
435+
<Icon name='modal-warning' size='x20' mi='x8' />
436+
<div>This is a customized banner content</div>
437+
</Box>
438+
</SidebarBanner>
439+
);
440+
441+
export const BannerVariations: ComponentStory<typeof SidebarBanner> = () => (
442+
<>
443+
<SidebarBanner text='This is a default banner variation' />
444+
<Divider />
445+
<SidebarBanner text='This is an info banner variation' variant='info' />
446+
<Divider />
447+
<SidebarBanner
448+
text='This is a success banner variation'
449+
variant='success'
450+
/>
451+
<Divider />
452+
<SidebarBanner
453+
text='This is a warning banner variation'
454+
variant='warning'
455+
/>
456+
<Divider />
457+
<SidebarBanner text='This is a danger banner variation' variant='danger' />
458+
<Divider />
459+
</>
460+
);

packages/fuselage/src/components/Sidebar/Sidebar.styles.scss

+91
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,52 @@ $sidebar-footer-highlight-color: theme(
9292
colors.font(annotation)
9393
);
9494

95+
// sidebar-banner-colors
96+
$sidebar-banner-background-default: theme(
97+
'sidebar-banner-background-default',
98+
colors.surface(hover)
99+
);
100+
$sidebar-banner-color-default: theme(
101+
'sidebar-banner-background-default',
102+
colors.font(default)
103+
);
104+
105+
$sidebar-banner-background-info: theme(
106+
'sidebar-banner-background-info',
107+
colors.status-background(info)
108+
);
109+
$sidebar-banner-color-info: theme(
110+
'sidebar-banner-background-info',
111+
colors.status-font(on-info)
112+
);
113+
114+
$sidebar-banner-background-success: theme(
115+
'sidebar-banner-background-success',
116+
colors.status-background(success)
117+
);
118+
$sidebar-banner-color-success: theme(
119+
'sidebar-banner-background-success',
120+
colors.status-font(on-success)
121+
);
122+
123+
$sidebar-banner-background-warning: theme(
124+
'sidebar-banner-background-warning',
125+
colors.status-background(warning)
126+
);
127+
$sidebar-banner-color-warning: theme(
128+
'sidebar-banner-background-warning',
129+
colors.status-font(on-warning)
130+
);
131+
132+
$sidebar-banner-background-danger: theme(
133+
'sidebar-banner-background-danger',
134+
colors.status-background(danger)
135+
);
136+
$sidebar-banner-color-danger: theme(
137+
'sidebar-banner-background-danger',
138+
colors.status-font(on-danger)
139+
);
140+
95141
%sidebar-base {
96142
display: flex;
97143

@@ -311,6 +357,51 @@ $sidebar-footer-highlight-color: theme(
311357
padding-inline: lengths.padding(16);
312358
}
313359

360+
&-banner {
361+
display: flex;
362+
justify-content: space-between;
363+
align-items: center;
364+
365+
height: 100px;
366+
padding: lengths.padding(16);
367+
368+
color: $sidebar-banner-color-default;
369+
background-color: $sidebar-banner-background-default;
370+
371+
&--text {
372+
@include typography.use-font-scale(h5);
373+
}
374+
375+
&--description {
376+
@include typography.use-font-scale(p2m);
377+
color: currentColor;
378+
379+
&--clickable {
380+
cursor: pointer;
381+
}
382+
}
383+
384+
&--info {
385+
color: $sidebar-banner-color-info;
386+
background-color: $sidebar-banner-background-info;
387+
}
388+
389+
&--success {
390+
color: $sidebar-banner-color-success;
391+
background-color: $sidebar-banner-background-success;
392+
}
393+
394+
&--warning {
395+
color: $sidebar-banner-color-warning;
396+
background-color: $sidebar-banner-background-warning;
397+
}
398+
399+
&--danger {
400+
color: $sidebar-banner-color-danger;
401+
background-color: $sidebar-banner-background-danger;
402+
}
403+
}
404+
314405
&-footer {
315406
padding-block: lengths.padding(4);
316407

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type { ReactNode } from 'react';
2+
import React from 'react';
3+
4+
import { IconButton } from '../Button';
5+
6+
type VariantType = 'default' | 'info' | 'success' | 'warning' | 'danger';
7+
8+
type SidebarBannerProps = {
9+
text?: ReactNode;
10+
description?: ReactNode;
11+
onClick?: () => void;
12+
variant?: VariantType;
13+
onClose?: () => void;
14+
children?: ReactNode;
15+
};
16+
17+
export const SidebarBanner = ({
18+
text,
19+
description,
20+
onClick,
21+
variant = 'default',
22+
onClose,
23+
children,
24+
}: SidebarBannerProps) => (
25+
<div
26+
className={`rcx-box rcx-box--full rcx-sidebar-banner rcx-sidebar-banner--${variant}`}
27+
>
28+
<div>
29+
{text && <div className='rcx-sidebar-banner--text'>{text}</div>}
30+
{description && (
31+
<div
32+
className={[
33+
'rcx-sidebar-banner--description',
34+
onClick && 'rcx-sidebar-banner--description--clickable',
35+
]
36+
.filter(Boolean)
37+
.join(' ')}
38+
onClick={onClick}
39+
>
40+
{description}
41+
</div>
42+
)}
43+
{children}
44+
</div>
45+
{onClose && <IconButton onClick={onClose} tiny icon='cross' />}
46+
</div>
47+
);

packages/fuselage/src/components/Sidebar/index.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import React from 'react';
44
import Box from '../Box';
55
import SidebarItem from './Item';
66
import SidebarSection from './Section';
7+
import { SidebarBanner } from './SidebarBanner';
78
import { SidebarDivider } from './SidebarDivider';
89
import SidebarTopBar from './TopBar';
910

@@ -16,6 +17,7 @@ export default Object.assign(Sidebar, {
1617
Item: SidebarItem,
1718
Section: SidebarSection,
1819
Divider: SidebarDivider,
20+
Banner: SidebarBanner,
1921
});
2022

2123
export { default as SidebarItem } from './Item';
@@ -24,6 +26,7 @@ export { default as SidebarSection } from './Section';
2426
export * from './Section';
2527
export { default as SidebarTopBar } from './TopBar';
2628
export * from './TopBar';
29+
export * from './SidebarBanner';
2730

2831
export * from './SidebarFooter';
2932

0 commit comments

Comments
 (0)