mirror of
https://github.com/ershisan99/flashcards-example-project.git
synced 2025-12-19 20:59:26 +00:00
feat: header component
feat: dropdown component feat: avatar component
This commit is contained in:
18
src/components/layout/header/header.module.scss
Normal file
18
src/components/layout/header/header.module.scss
Normal file
@@ -0,0 +1,18 @@
|
||||
.root {
|
||||
width: 100%;
|
||||
height: var(--header-height);
|
||||
padding: 12px var(--horizontal-padding);
|
||||
|
||||
background: var(--color-dark-700);
|
||||
border-bottom: 1px solid var(--color-dark-500);
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
width: 100%;
|
||||
max-width: var(--max-width);
|
||||
margin: 0 auto;
|
||||
}
|
||||
34
src/components/layout/header/header.stories.tsx
Normal file
34
src/components/layout/header/header.stories.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import { Header } from './'
|
||||
|
||||
const meta = {
|
||||
argTypes: {
|
||||
onLogout: { action: 'logout' },
|
||||
},
|
||||
component: Header,
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
title: 'Components/Header',
|
||||
} satisfies Meta<typeof Header>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const LoggedIn: Story = {
|
||||
// @ts-expect-error onLogout is required but it is provided through argTypes
|
||||
args: {
|
||||
avatar: 'https://avatars.githubusercontent.com/u/1196870?v=4',
|
||||
email: 'johndoe@gmail.com',
|
||||
isLoggedIn: true,
|
||||
userName: 'John Doe',
|
||||
},
|
||||
}
|
||||
|
||||
export const LoggedOut: Story = {
|
||||
args: {
|
||||
isLoggedIn: false,
|
||||
},
|
||||
}
|
||||
37
src/components/layout/header/header.tsx
Normal file
37
src/components/layout/header/header.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { memo } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
import { Logo } from '@/assets'
|
||||
import { UserDropdown, UserDropdownProps } from '@/components/layout/header/user-dropdown'
|
||||
|
||||
import s from './header.module.scss'
|
||||
|
||||
import { Button } from '../../ui'
|
||||
|
||||
export type HeaderProps =
|
||||
| (Partial<UserDropdownProps> & {
|
||||
isLoggedIn: false
|
||||
})
|
||||
| (UserDropdownProps & {
|
||||
isLoggedIn: true
|
||||
})
|
||||
|
||||
export const Header = memo(({ avatar, email, isLoggedIn, onLogout, userName }: HeaderProps) => {
|
||||
return (
|
||||
<header className={s.root}>
|
||||
<div className={s.content}>
|
||||
<Link to={'/'}>
|
||||
<Logo />
|
||||
</Link>
|
||||
{isLoggedIn && (
|
||||
<UserDropdown avatar={avatar} email={email} onLogout={onLogout} userName={userName} />
|
||||
)}
|
||||
{!isLoggedIn && (
|
||||
<Button as={Link} to={'/sign-in'}>
|
||||
Sign In
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
})
|
||||
1
src/components/layout/header/index.ts
Normal file
1
src/components/layout/header/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './header'
|
||||
1
src/components/layout/header/user-dropdown/index.ts
Normal file
1
src/components/layout/header/user-dropdown/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './user-dropdown'
|
||||
@@ -0,0 +1,3 @@
|
||||
.email {
|
||||
color: var(--color-dark-100);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import { UserDropdown } from './'
|
||||
|
||||
const meta = {
|
||||
argTypes: {
|
||||
onLogout: { action: 'logout' },
|
||||
},
|
||||
component: UserDropdown,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
title: 'Components/UserDropdown',
|
||||
} satisfies Meta<typeof UserDropdown>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
// @ts-expect-error onLogout is required but it is provided through argTypes
|
||||
args: {
|
||||
avatar: 'https://avatars.githubusercontent.com/u/1196870?v=4',
|
||||
email: 'johndoe@gmail.com',
|
||||
userName: 'John Doe',
|
||||
},
|
||||
}
|
||||
59
src/components/layout/header/user-dropdown/user-dropdown.tsx
Normal file
59
src/components/layout/header/user-dropdown/user-dropdown.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { ComponentPropsWithoutRef } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
import { Logout, PersonOutline } from '@/assets'
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
Typography,
|
||||
} from '@/components'
|
||||
|
||||
import s from './user-dropdown.module.scss'
|
||||
|
||||
export type UserDropdownProps = {
|
||||
avatar: string
|
||||
email: string
|
||||
onLogout: ComponentPropsWithoutRef<typeof DropdownMenuItem>['onSelect']
|
||||
userName: string
|
||||
}
|
||||
|
||||
export const UserDropdown = ({ avatar, email, onLogout, userName }: UserDropdownProps) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button rounded variant={'icon'}>
|
||||
<Avatar src={avatar} />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuLabel>
|
||||
<Avatar src={avatar} />
|
||||
<div>
|
||||
<Typography variant={'subtitle2'}>{userName}</Typography>
|
||||
<Typography className={s.email} variant={'caption'}>
|
||||
{email}
|
||||
</Typography>
|
||||
</div>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem asChild>
|
||||
<Link to={'/profile'}>
|
||||
<PersonOutline />
|
||||
My profile
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onSelect={onLogout}>
|
||||
<Logout />
|
||||
Sign out
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user