From c670ac177bae18ec10667d12ad867ecc5ec1197e Mon Sep 17 00:00:00 2001 From: juliajforesti Date: Thu, 5 Sep 2024 20:10:38 +0100 Subject: [PATCH] feat: `SideBarV2` components --- .../src/components/SideBarV2/SideBar.spec.tsx | 19 ++ .../components/SideBarV2/SideBar.stories.tsx | 184 ++++++++++ .../components/SideBarV2/SideBar.styles.scss | 318 ++++++++++++++++++ .../src/components/SideBarV2/SideBar.tsx | 20 ++ .../components/SideBarV2/SideBarAccordion.tsx | 19 ++ .../SideBarV2/SideBarAccordionItem.tsx | 79 +++++ .../components/SideBarV2/SideBarAction.tsx | 13 + .../components/SideBarV2/SideBarActions.tsx | 13 + .../components/SideBarV2/SideBarBanner.tsx | 54 +++ .../SideBarV2/SideBarButtonGroup.tsx | 11 + .../SideBarV2/SideBarCollapseGroup.tsx | 69 ++++ .../components/SideBarV2/SideBarDivider.tsx | 5 + .../SideBarFooter/SideBarFooter.styles.scss | 23 ++ .../SideBarV2/SideBarFooter/SideBarFooter.tsx | 10 + .../SideBarFooter/SideBarFooterContent.tsx | 12 + .../SideBarV2/SideBarFooter/index.ts | 2 + .../SideBarV2/SideBarGroupTitle.tsx | 42 +++ .../SideBarItem/SideBarItem.stories.tsx | 39 +++ .../SideBarItem/SideBarItem.styles.scss | 172 ++++++++++ .../SideBarV2/SideBarItem/SideBarItem.tsx | 25 ++ .../SideBarItem/SideBarItemAction.tsx | 29 ++ .../SideBarItem/SideBarItemAvatarWrapper.tsx | 13 + .../SideBarItem/SideBarItemBadge.tsx | 15 + .../SideBarV2/SideBarItem/SideBarItemCol.tsx | 13 + .../SideBarItem/SideBarItemContent.tsx | 18 + .../SideBarV2/SideBarItem/SideBarItemIcon.tsx | 32 ++ .../SideBarV2/SideBarItem/SideBarItemMenu.tsx | 26 ++ .../SideBarV2/SideBarItem/SideBarItemRow.tsx | 13 + .../SideBarItem/SideBarItemStatusBullet.tsx | 11 + .../SideBarItem/SideBarItemTimestamp.tsx | 16 + .../SideBarItem/SideBarItemTitle.tsx | 18 + .../SideBarV2/SideBarItem/SideBarListItem.tsx | 24 ++ .../components/SideBarV2/SideBarItem/index.ts | 13 + .../src/components/SideBarV2/SideBarLink.tsx | 52 +++ .../SideBarMedia/SideBarMedia.stories.tsx | 32 ++ .../SideBarMedia/SideBarMedia.styles.scss | 42 +++ .../SideBarV2/SideBarMedia/SideBarMedia.tsx | 11 + .../SideBarMedia/SideBarMediaController.tsx | 21 ++ .../SideBarMedia/SideBarMediaTitle.tsx | 13 + .../SideBarV2/SideBarMedia/index.ts | 3 + .../components/SideBarV2/SideBarSection.tsx | 10 + .../src/components/SideBarV2/helpers.tsx | 202 +++++++++++ .../SideBarV2/hooks/useCollapse.tsx | 66 ++++ .../src/components/SideBarV2/index.tsx | 15 + packages/fuselage/src/components/index.scss | 1 + packages/fuselage/src/components/index.ts | 1 + .../fuselage/src/styles/mixins/templates.scss | 8 +- 47 files changed, 1845 insertions(+), 2 deletions(-) create mode 100644 packages/fuselage/src/components/SideBarV2/SideBar.spec.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBar.stories.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBar.styles.scss create mode 100644 packages/fuselage/src/components/SideBarV2/SideBar.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarAccordion.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarAccordionItem.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarAction.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarActions.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarBanner.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarButtonGroup.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarCollapseGroup.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarDivider.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarFooter/SideBarFooter.styles.scss create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarFooter/SideBarFooter.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarFooter/SideBarFooterContent.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarFooter/index.ts create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarGroupTitle.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItem.stories.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItem.styles.scss create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItem.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItemAction.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItemAvatarWrapper.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItemBadge.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItemCol.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItemContent.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItemIcon.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItemMenu.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItemRow.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItemStatusBullet.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItemTimestamp.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarItemTitle.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/SideBarListItem.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarItem/index.ts create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarLink.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarMedia/SideBarMedia.stories.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarMedia/SideBarMedia.styles.scss create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarMedia/SideBarMedia.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarMedia/SideBarMediaController.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarMedia/SideBarMediaTitle.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarMedia/index.ts create mode 100644 packages/fuselage/src/components/SideBarV2/SideBarSection.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/helpers.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/hooks/useCollapse.tsx create mode 100644 packages/fuselage/src/components/SideBarV2/index.tsx diff --git a/packages/fuselage/src/components/SideBarV2/SideBar.spec.tsx b/packages/fuselage/src/components/SideBarV2/SideBar.spec.tsx new file mode 100644 index 0000000000..b93afec343 --- /dev/null +++ b/packages/fuselage/src/components/SideBarV2/SideBar.spec.tsx @@ -0,0 +1,19 @@ +import { composeStories } from '@storybook/react'; +import { axe } from 'jest-axe'; + +import { render } from '../../testing'; +import * as stories from './SideBar.stories'; + +const { Default } = composeStories(stories); + +describe('[Sidebar Default story]', () => { + it('renders without crashing', () => { + render(); + }); + it('should have no a11y violations', async () => { + const { container } = render(); + + const results = await axe(container); + expect(results).toHaveNoViolations(); + }); +}); diff --git a/packages/fuselage/src/components/SideBarV2/SideBar.stories.tsx b/packages/fuselage/src/components/SideBarV2/SideBar.stories.tsx new file mode 100644 index 0000000000..c9b0f14ed5 --- /dev/null +++ b/packages/fuselage/src/components/SideBarV2/SideBar.stories.tsx @@ -0,0 +1,184 @@ +import { action } from '@storybook/addon-actions'; +import type { Meta, StoryFn } from '@storybook/react'; + +import { + SideBar, + SideBarAccordion, + SideBarAccordionItem, + SideBarBanner, + SideBarCollapseGroup, + SideBarFooterContent, + SideBarItemAction, + SideBarLink, + SideBarItemBadge, + SideBarMedia, + SideBarMediaTitle, + SideBarMediaController, + SideBarListItem, + SideBarSection, + SideBarFooter, +} from '.'; +import { IconButton, TextInput, Icon, Box } from '../..'; +import { Condensed } from './SideBarItem/SideBarItem.stories'; +import { GenericNoAvatarItem, MenuTemplate } from './helpers'; + +export default { + title: 'Navigation/SideBar', + component: SideBar, +} as Meta; + +export const Default: StoryFn = (props) => ( + + + } + /> + + } + small + placeholder='Search' + /> + + + + + } + defaultExpanded + > + + } + menu={} + > + All + + + } + menu={} + > + Assigned to me + + + } + menu={} + > + Unassigned + + }> + On hold + + + + } + > + + } + > + {Array.from({ length: 4 }).map((_, i) => ( + + ))} + + + } + > + + + + Add team + + + + + } + > + + + + Add discussion + + + + + + + 3 calls in queue + + + + + + {/* */} + + + Powered by Rocket.Chat + + Free edition + + + + +); diff --git a/packages/fuselage/src/components/SideBarV2/SideBar.styles.scss b/packages/fuselage/src/components/SideBarV2/SideBar.styles.scss new file mode 100644 index 0000000000..1b3c0a26d0 --- /dev/null +++ b/packages/fuselage/src/components/SideBarV2/SideBar.styles.scss @@ -0,0 +1,318 @@ +@use '../../styles/colors.scss'; +@use '../../styles/lengths.scss'; +@use '../../styles/typography.scss'; +@import '../../styles/mixins/all.scss'; + +@import './SideBarFooter/SideBarFooter.styles.scss'; +@import './SideBarItem/SideBarItem.styles.scss'; +@import './SideBarMedia/SideBarMedia.styles.scss'; + +$sidebar-color-surface-default: theme( + 'sidebar-color-surface-default', + colors.surface(sidebar) +); +$sidebar-color-surface-hover: theme( + 'sidebar-color-surface-hover', + colors.surface(hover) +); +$sidebar-color-surface-selected: theme( + 'sidebar-color-surface-selected', + colors.surface(selected) +); + +$sidebar-color-font-default: theme( + 'sidebar-color-font-default', + colors.font(default) +); + +$sidebar-accordion-border-color: theme( + 'sidebar-accordion-border-color', + colors.stroke(light) +); + +$sidebar-link-color: theme('sidebar-link-color', colors.font(titles-labels)); + +$sidebar-banner-background-default: theme( + 'sidebar-banner-background-default', + colors.surface(sidebar) +); +$sidebar-banner-color-default: theme( + 'sidebar-banner-color-default', + colors.font(titles-labels) +); + +$sidebar-banner-background-info: theme( + 'sidebar-banner-background-info', + colors.status-background(info) +); +$sidebar-banner-color-info: theme( + 'sidebar-banner-background-info', + colors.status-font(on-info) +); + +$sidebar-banner-background-success: theme( + 'sidebar-banner-background-success', + colors.status-background(success) +); +$sidebar-banner-color-success: theme( + 'sidebar-banner-background-success', + colors.status-font(on-success) +); + +$sidebar-banner-background-warning: theme( + 'sidebar-banner-background-warning', + colors.status-background(warning) +); +$sidebar-banner-color-warning: theme( + 'sidebar-banner-background-warning', + colors.status-font(on-warning) +); + +$sidebar-banner-background-danger: theme( + 'sidebar-banner-background-danger', + colors.status-background(danger) +); +$sidebar-banner-color-danger: theme( + 'sidebar-banner-background-danger', + colors.status-font(on-danger) +); + +%highlighted { + color: $sidebar-item-color-highlighted; + + font-weight: 600; +} + +.rcx-sidebar-v2 { + position: relative; + + display: flex; + flex-direction: column; + + height: lengths.size(full); + + color: $sidebar-color-font-default; + background-color: $sidebar-color-surface-default; + + &--divider { + border-color: theme( + 'sidebar-color-stroke-extra-light', + colors.stroke(light) + ); + } + + &-section { + display: flex; + align-items: center; + + height: lengths.size(44); + + padding-inline: lengths.padding(16); + + gap: lengths.padding(8); + } + + &-accordion { + display: flex; + overflow: hidden; + flex-flow: column nowrap; + justify-content: stretch; + flex: 0 1 auto; + + height: lengths.size(full); + + &__wrapper { + display: flex; + overflow: scroll; + flex-direction: column; + } + } + + &-collapse-group, + &-accordion-item { + display: flex; + flex-flow: column nowrap; + + &__bar { + display: flex; + flex-flow: row nowrap; + align-items: center; + + min-height: lengths.size(24); + padding: lengths.padding(8) lengths.padding(16); + + text-align: start; + + color: colors.font(default); + + background-color: $sidebar-color-surface-default; + column-gap: lengths.padding(4); + + &[tabindex] { + @include clickable; + @include focus-state($shadow: false); + + &.hover, + &:hover { + background-color: colors.surface(tint); + } + } + + &--disabled { + cursor: not-allowed; + + color: colors.font(disabled); + background-color: colors.surface(disabled); + } + } + + &__title { + flex: 1 1 lengths.size(none); + + margin: lengths.margin(none); + + white-space: nowrap; + + @include typography.use-text-ellipsis; + @include typography.use-font-scale(c2); + } + + &__panel { + visibility: hidden; + overflow: hidden; + + height: lengths.size(none); + margin: lengths.margin(none); + padding: lengths.padding(none); + + list-style: none; + + &--expanded { + visibility: visible; + + flex-grow: 1; + + height: 100%; + padding-block-start: lengths.padding(4); + padding-block-end: lengths.padding(8); + } + } + } + + &-accordion-item { + flex: 0 1 0; + + border: 2px solid transparent; + border-bottom: lengths.border-width(default) solid + $sidebar-accordion-border-color; + + &__bar { + position: sticky; + + z-index: 1; + top: 0; + + padding: lengths.padding(12) lengths.padding(16) lengths.padding(12) + lengths.padding(none); + + border-radius: lengths.border-radius(small); + + background-color: colors.surface(sidebar); + + .rcx-sidebar-v2-accordion-item__chevron { + visibility: hidden; + } + + &:focus-visible, + &.hover, + &:hover { + .rcx-sidebar-v2-accordion-item__chevron { + visibility: visible; + } + } + } + + &__title { + @include typography.use-font-scale(h5); + } + } + + &-link { + @include use-link-colors($color: $sidebar-link-color); + } + + &-banner { + display: flex; + justify-content: space-between; + align-items: center; + + padding: lengths.padding(16); + + color: $sidebar-banner-color-default; + border-bottom: lengths.border-width(default) solid + $sidebar-accordion-border-color; + background-color: $sidebar-banner-background-default; + gap: lengths.padding(12); + + &__addon { + display: flex; + align-items: center; + } + + &__title { + margin: 0; + padding: 0; + + @include typography.use-font-scale(h5); + } + + &__link { + @include typography.use-font-scale(p2m); + @include clickable(); + + display: inline-block; + + text-decoration: underline; + } + + &--info { + color: $sidebar-banner-color-info; + background-color: $sidebar-banner-background-info; + } + + &--success { + color: $sidebar-banner-color-success; + background-color: $sidebar-banner-background-success; + } + + &--warning { + color: $sidebar-banner-color-warning; + background-color: $sidebar-banner-background-warning; + } + + &--danger { + color: $sidebar-banner-color-danger; + background-color: $sidebar-banner-background-danger; + } + } + + &--collapsed { + overflow: hidden; + + width: lengths.size(48); + + &:not(:hover) { + .rcx-sidebar-v2-item.rcx-sidebar-v2-link > .rcx-sidebar-v2-item__title, + .rcx-sidebar-v2-banner__content { + display: none; + } + + .rcx-sidebar-v2-media__title, + .rcx-sidebar-v2-footer { + visibility: hidden; + + white-space: nowrap; + } + } + } +} diff --git a/packages/fuselage/src/components/SideBarV2/SideBar.tsx b/packages/fuselage/src/components/SideBarV2/SideBar.tsx new file mode 100644 index 0000000000..9467ad4384 --- /dev/null +++ b/packages/fuselage/src/components/SideBarV2/SideBar.tsx @@ -0,0 +1,20 @@ +import { forwardRef, type HTMLAttributes } from 'react'; + +type SideBarProps = { collapsed?: boolean } & HTMLAttributes; + +export const SideBar = forwardRef( + ({ collapsed, className, ...props }, ref) => ( +