Skip to content

Commit

Permalink
feat: add harmony sidebar
Browse files Browse the repository at this point in the history
  • Loading branch information
IgorGoryany committed Jul 24, 2024
1 parent 9b16456 commit 7bdea07
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/harmony/NavigationSidebar/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React, { FC, HTMLAttributes } from 'react';
import cn from 'classnames';

import s from './NavigationSidebar.module.css';

export const Navigation: FC<HTMLAttributes<HTMLDivElement>> = ({ children, className, ...rest }) => (
<div className={cn(s.Navigation, className)} {...rest}>
{children}
</div>
);
33 changes: 33 additions & 0 deletions src/harmony/NavigationSidebar/NavigationItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { FC, HTMLAttributes } from 'react';
import cn from 'classnames';

import { ListViewItem } from '../ListView/ListView';
import { Link } from '../Link/Link';
import { MenuItem } from '../MenuItem/MenuItem';

import s from './NavigationSidebar.module.css';

interface NavigationItemProps extends HTMLAttributes<HTMLDivElement> {
href: string;
selected?: boolean;
}

export const NavigationItem: FC<NavigationItemProps> = ({ selected, href, children, ...rest }) => (
<ListViewItem
value={href}
renderItem={({ hovered, active, ...props }) => (
<Link view="primary" className={s.NavigationItemLink}>
<MenuItem
hovered={active || hovered}
className={cn({
[s.MenuItem_active]: selected,
})}
{...props}
{...rest}
>
{children}
</MenuItem>
</Link>
)}
/>
);
41 changes: 41 additions & 0 deletions src/harmony/NavigationSidebar/NavigationSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { FC, HTMLAttributes, ReactNode, useState } from 'react';
import cn from 'classnames';
import { IconDownSmallOutline, IconUpSmallOutline } from '@taskany/icons';

import { nullable } from '../../utils';
import { Text } from '../Text/Text';
import { ListView } from '../ListView/ListView';

import s from './NavigationSidebar.module.css';

interface NavigationSectionProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
title: ReactNode;
collapsed?: boolean;
}

export const NavigationSection: FC<NavigationSectionProps> = ({
collapsed: defaultState = false,
title,
children,
className,
...rest
}) => {
const [collapsed, setCollapsed] = useState(defaultState);
return (
<div className={cn(s.NavigationSection, className)} {...rest}>
<div className={s.NavigationSectionTitle} onClick={() => setCollapsed((val) => !val)}>
<Text size="xs">{title}</Text>
{nullable(
collapsed,
() => (
<IconUpSmallOutline size="s" />
),
<IconDownSmallOutline size="s" />,
)}
</div>
{nullable(!collapsed, () => (
<ListView>{children}</ListView>
))}
</div>
);
};
68 changes: 68 additions & 0 deletions src/harmony/NavigationSidebar/NavigationSidebar.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
.NavigationSidebarContainer {
display: flex;
flex-direction: column;
height: 100%;
background: var(--layer);
border-right: 1px solid var(--layer-border);
}

.NavigationSidebarHeader {
display: flex;
padding: var(--gap-sm);
border-bottom: 1px solid var(--gray-900);
align-items: center;
gap: var(--gap-s);
}

.NavigationSidebarLogo{
display: flex;
}

.NavigationSidebarTitle {
flex: 1;
}

.NavigationSidebarContent {
display: flex;
flex-direction: column;
padding: var(--gap-sm);
gap: var(--gap-sm);
flex: 1;
overflow: auto;
}

.Navigation {
display: flex;
flex-direction: column;
gap: var(--gap-s);
flex: 1;
overflow: auto;
padding-right: var(--gap-sm);
margin-right: calc(var(--gap-sm)* -1);
}

.NavigationSection {
padding-bottom: var(--gap-s);
border-bottom: 1px solid var(--gray-900);
}

.NavigationSection:last-child {
border: 0;
}

.NavigationSectionTitle {
display: flex;
align-items: center;
padding: var(--gap-s) 0;
color: var(--text-secondary);
cursor: pointer;
user-select: none;
}

.NavigationItemLink:hover {
color: inherit;
}

.MenuItem_active {
background-color: var(--layer-above);
}
65 changes: 65 additions & 0 deletions src/harmony/NavigationSidebar/NavigationSidebar.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Meta, StoryObj } from '@storybook/react';
import { IconBellOutline } from '@taskany/icons';

import { Link } from '../Link/Link';
import { TaskanyLogo } from '../TaskanyLogo/TaskanyLogo';

import { NavigationSidebar } from './NavigationSidebar';
import { Navigation } from './Navigation';
import { NavigationItem } from './NavigationItem';
import { NavigationSection } from './NavigationSection';
import { NavigationSidebarContent } from './NavigationSidebarContent';
import { NavigationSidebarHeader } from './NavigationSidebarHeader';
import { NavigationSidebarTitle } from './NavigationSidebarTitle';

const meta: Meta = {
title: '@harmony/NavigationSidebar',
component: NavigationSidebar,
};

export default meta;

const routes = new Array(3).fill(0).map((item, index) => ({ title: `item ${index + 1}`, href: '#' }));

export const Default: StoryObj<typeof NavigationSidebar> = {
render: () => {
return (
<NavigationSidebar>
<NavigationSidebarHeader>
<Link>
<TaskanyLogo />
</Link>
<NavigationSidebarTitle>Title</NavigationSidebarTitle>
<IconBellOutline size="s" />
</NavigationSidebarHeader>
<NavigationSidebarContent>
<Navigation>
<NavigationSection title="Section 1">
{routes.map(({ title, href }) => (
<NavigationItem key={title} href={href}>
{title}
</NavigationItem>
))}
</NavigationSection>

<NavigationSection title="Section 2">
{routes.map(({ title, href }) => (
<NavigationItem key={title} href={href}>
{title}
</NavigationItem>
))}
</NavigationSection>

<NavigationSection title="Section 3">
{routes.map(({ title, href }) => (
<NavigationItem key={title} href={href}>
{title}
</NavigationItem>
))}
</NavigationSection>
</Navigation>
</NavigationSidebarContent>
</NavigationSidebar>
);
},
};
12 changes: 12 additions & 0 deletions src/harmony/NavigationSidebar/NavigationSidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React, { FC, HTMLAttributes } from 'react';
import cn from 'classnames';

import s from './NavigationSidebar.module.css';

export const NavigationSidebar: FC<HTMLAttributes<HTMLDivElement>> = ({ children, className, ...rest }) => {
return (
<div className={cn(s.NavigationSidebarContainer, className)} {...rest}>
{children}
</div>
);
};
10 changes: 10 additions & 0 deletions src/harmony/NavigationSidebar/NavigationSidebarContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React, { FC, HTMLAttributes } from 'react';
import cn from 'classnames';

import s from './NavigationSidebar.module.css';

export const NavigationSidebarContent: FC<HTMLAttributes<HTMLDivElement>> = ({ children, className, ...rest }) => (
<div className={cn(s.NavigationSidebarContent, className)} {...rest}>
{children}
</div>
);
10 changes: 10 additions & 0 deletions src/harmony/NavigationSidebar/NavigationSidebarHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React, { FC, HTMLAttributes } from 'react';
import cn from 'classnames';

import s from './NavigationSidebar.module.css';

export const NavigationSidebarHeader: FC<HTMLAttributes<HTMLDivElement>> = ({ children, className, ...rest }) => (
<div className={cn(s.NavigationSidebarHeader, className)} {...rest}>
{children}
</div>
);
12 changes: 12 additions & 0 deletions src/harmony/NavigationSidebar/NavigationSidebarTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React, { ComponentProps, FC } from 'react';
import cn from 'classnames';

import { Text } from '../Text/Text';

import s from './NavigationSidebar.module.css';

export const NavigationSidebarTitle: FC<ComponentProps<typeof Text>> = ({ children, className, ...rest }) => (
<Text className={cn(s.NavigationSidebarTitle, className)} weight="bold" size="l" {...rest}>
{children}
</Text>
);
7 changes: 7 additions & 0 deletions src/harmony/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ export * from './ListView/ListView';
export * from './MenuItem/MenuItem';
export * from './Modal/Modal';
export * from './ModalPreview/ModalPreview';
export * from './NavigationSidebar/Navigation';
export * from './NavigationSidebar/NavigationItem';
export * from './NavigationSidebar/NavigationSection';
export * from './NavigationSidebar/NavigationSidebar';
export * from './NavigationSidebar/NavigationSidebarContent';
export * from './NavigationSidebar/NavigationSidebarHeader';
export * from './NavigationSidebar/NavigationSidebarTitle';
export * from './OfflineBanner/OfflineBanner';
export * from './PageLoadProgress/PageLoadProgress';
export * from './Popup/Popup';
Expand Down

0 comments on commit 7bdea07

Please sign in to comment.