feat(react): add MainSidebar component

This commit is contained in:
Pavel Prichodko 2022-03-16 12:41:55 +01:00
parent 59f0198d81
commit c1fba5e633
No known key found for this signature in database
GPG Key ID: 0EB8D75C775AB6F1
5 changed files with 342 additions and 0 deletions

View File

@ -0,0 +1,64 @@
import React from 'react'
import * as Collapsible from '@radix-ui/react-collapsible'
import { BellIcon } from '~/src/icons/bell-icon'
import { ChevronDownIcon } from '~/src/icons/chevron-down-icon'
import { styled } from '~/src/styles/config'
import { ContextMenu, ContextMenuTrigger } from '~/src/system/context-menu'
import { Text } from '~/src/system/text'
interface Props {
name: string
children: React.ReactNode
}
export const ChannelGroup = (props: Props) => {
const { name, children } = props
return (
<ContextMenuTrigger>
<Collapsible.Root defaultOpen>
<CollapsibleTrigger>
<Text size="15" weight="500" color="black-70">
{name}
</Text>
<ChevronDownIcon />
</CollapsibleTrigger>
<CollapsibleContent>{children}</CollapsibleContent>
</Collapsible.Root>
<ContextMenu>
<ContextMenu.TriggerItem label="Mute Chat" icon={<BellIcon />}>
<ContextMenu.Item>For 15 min</ContextMenu.Item>
<ContextMenu.Item>For 1 hour</ContextMenu.Item>
<ContextMenu.Item>For 8 hours</ContextMenu.Item>
<ContextMenu.Item>For 24 hours</ContextMenu.Item>
<ContextMenu.Item>Until I turn it back on</ContextMenu.Item>
</ContextMenu.TriggerItem>
<ContextMenu.Item icon={<BellIcon />}>Mark as Read</ContextMenu.Item>
</ContextMenu>
</ContextMenuTrigger>
)
}
const CollapsibleTrigger = styled(Collapsible.Trigger, {
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: 8,
borderRadius: 8,
height: 34,
'&:hover': {
background: '#E9EDF1',
},
'&[aria-expanded="true"] svg': {
transform: 'rotate(180deg)',
},
})
const CollapsibleContent = styled(Collapsible.Content, {
overflow: 'hidden',
})

View File

@ -0,0 +1,37 @@
import React from 'react'
import { BellIcon } from '~/src/icons/bell-icon'
import { ContextMenu, ContextMenuTrigger } from '~/src/system/context-menu'
import { SidebarItem } from './sidebar-item'
import type { SidebarItemProps } from './sidebar-item'
interface Props extends SidebarItemProps {
children: string
}
export const ChannelItem = (props: Props) => {
const { children, ...sidebarItemProps } = props
return (
<ContextMenuTrigger>
<SidebarItem {...sidebarItemProps}>#{children}</SidebarItem>
<ContextMenu>
<ContextMenu.Item icon={<BellIcon />}>View Profile</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.TriggerItem label="Mute Chat">
<ContextMenu.Item>For 15 min</ContextMenu.Item>
<ContextMenu.Item>For 1 hour</ContextMenu.Item>
<ContextMenu.Item>For 8 hours</ContextMenu.Item>
<ContextMenu.Item>For 24 hours</ContextMenu.Item>
<ContextMenu.Item>Until I turn it back on</ContextMenu.Item>
</ContextMenu.TriggerItem>
<ContextMenu.Separator />
<ContextMenu.Item icon={<BellIcon />} danger>
Delete
</ContextMenu.Item>
</ContextMenu>
</ContextMenuTrigger>
)
}

View File

@ -0,0 +1,37 @@
import React from 'react'
import { BellIcon } from '~/src/icons/bell-icon'
import { ContextMenu, ContextMenuTrigger } from '~/src/system'
import { SidebarItem } from './sidebar-item'
import type { SidebarItemProps } from './sidebar-item'
interface Props extends SidebarItemProps {
children: string
}
export const ChatItem = (props: Props) => {
const { children, ...sidebarItemProps } = props
return (
<ContextMenuTrigger>
<SidebarItem {...sidebarItemProps}>{children}</SidebarItem>
<ContextMenu>
<ContextMenu.Item icon={<BellIcon />}>View Profile</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.TriggerItem label="Mute Chat" icon={<BellIcon />}>
<ContextMenu.Item>For 15 min</ContextMenu.Item>
<ContextMenu.Item>For 1 hour</ContextMenu.Item>
<ContextMenu.Item>For 8 hours</ContextMenu.Item>
<ContextMenu.Item>For 24 hours</ContextMenu.Item>
<ContextMenu.Item>Until I turn it back on</ContextMenu.Item>
</ContextMenu.TriggerItem>
<ContextMenu.Separator />
<ContextMenu.Item icon={<BellIcon />} danger>
Delete
</ContextMenu.Item>
</ContextMenu>
</ContextMenuTrigger>
)
}

View File

@ -0,0 +1,125 @@
import React from 'react'
import { useAppState } from '~/src/contexts/app-context'
import { EditIcon } from '~/src/icons/edit-icon'
import { styled } from '~/src/styles/config'
import { Box, Button } from '~/src/system'
import { Avatar } from '~/src/system/avatar'
import { Dialog, DialogTrigger } from '~/src/system/dialog'
import { Grid } from '~/src/system/grid'
import { Heading } from '~/src/system/heading'
import { IconButton } from '~/src/system/icon-button'
import { Text } from '~/src/system/text'
import { TextInput } from '~/src/system/text-input'
import { ChannelGroup } from './channel-group'
import { ChannelItem } from './channel-item'
import { ChatItem } from './chat-item'
const CHANNELS = {
Public: ['welcome', 'general', 'random'],
Other: ['random', 'general', 'welcome'],
}
const CHATS = ['vitalik.eth', 'pvl.eth', 'Climate Change']
export const MainSidebar = () => {
const { dispatch } = useAppState()
return (
<Wrapper>
<DialogTrigger>
<IdentityWrapper>
<Avatar size={36} />
<div>
<Text>CryptoKitties</Text>
<Text color="gray" size={12}>
186 members
</Text>
</div>
</IdentityWrapper>
<Dialog title="Crypto Kitties" actionLabel="Save">
<Text>A community of cat lovers, meow!</Text>
<TextInput placeholder="meow" />
<Text>
To access this community, paste community public key in Status
desktop or mobile app
</Text>
<Button>Download Status for Mac</Button>
</Dialog>
</DialogTrigger>
{Object.entries(CHANNELS).map(([group, channels]) => (
<ChannelGroup key={group} name={group}>
{channels.map(channel => (
<ChannelItem
key={group + channel}
unread={channel === 'general'}
muted={channel === 'random'}
active={false}
>
{channel}
</ChannelItem>
))}
</ChannelGroup>
))}
<Separator />
<Box>
<Grid
flow="column"
align="center"
justify="between"
css={{ marginBottom: 16 }}
>
<Heading>Messages</Heading>
<IconButton
label="New Chat"
onClick={() => dispatch({ type: 'NEW_CHAT' })}
>
<EditIcon />
</IconButton>
</Grid>
{CHATS.map(chat => (
<ChatItem key={chat} unread={false} muted={false} active={false}>
{chat}
</ChatItem>
))}
</Box>
</Wrapper>
)
}
const Wrapper = styled('div', {
width: 304,
flexShrink: 0,
flexDirection: 'column',
padding: '10px 16px',
display: 'none',
backgroundColor: '#F6F8FA',
overflowY: 'scroll',
'@medium': {
display: 'flex',
},
})
const Separator = styled('div', {
margin: '16px 0',
height: 1,
background: 'rgba(0, 0, 0, 0.1)',
})
const IdentityWrapper = styled('button', {
padding: '4px 6px',
display: 'inline-flex',
alignSelf: 'flex-start',
gap: '$2',
borderRadius: 8,
alignItems: 'center',
'&:hover': {
background: '#E9EDF1',
},
})

View File

@ -0,0 +1,79 @@
import React, { forwardRef } from 'react'
import { styled } from '~/src/styles/config'
import { Avatar } from '~/src/system'
import type { Ref } from 'react'
interface Props {
muted: boolean
unread: boolean
active: boolean
children: React.ReactNode
}
const SidebarItem = (props: Props, ref: Ref<HTMLButtonElement>) => {
const { muted, unread, active, children, ...buttonProps } = props
return (
<Button
ref={ref}
state={muted ? 'muted' : unread ? 'unread' : undefined}
active={active}
{...buttonProps}
>
<Avatar size={24} />
{children}
</Button>
)
}
const _SidebarItem = forwardRef(SidebarItem)
export { _SidebarItem as SidebarItem }
export type SidebarItemProps = Omit<Props, 'children'>
const Button = styled('button', {
position: 'relative',
fontFamily: '$sans',
fontWeight: '$500',
fontSize: 15,
display: 'inline-flex',
color: 'rgba(0, 0, 0, 0.7)',
alignItems: 'center',
width: '100%',
gap: '$2',
borderRadius: 8,
padding: 8,
'&:hover': {
background: '#E9EDF1',
},
variants: {
active: {
true: {
background: 'rgba(233, 237, 241, 1)',
},
},
state: {
muted: {
color: 'rgba(0, 0, 0, 0.4)',
},
unread: {
fontWeight: '$600',
'&::after': {
content: '"1"',
position: 'absolute',
right: 8,
width: 22,
height: 22,
background: '#4360DF',
borderRadius: '$full',
fontSize: 12,
color: '#fff',
},
},
},
},
})