Skip to content

Commit

Permalink
Feature/#18 사이드바 구현 (#42)
Browse files Browse the repository at this point in the history
* feat: mocks 데이터 추가

#18

* design: theme 적용되도록 변경

#18

* feat: 카테고리 인터페이스 구현

#18

* feat: 사이드바 아이콘 버튼 구현

#18

* feat: 사이드바 구현 및 레이아웃 적용

#18

* refactor: mocks파일 위치 변경

#18

* design: 레이아웃 width 수정

#18
  • Loading branch information
pipisebastian authored Feb 16, 2024
1 parent 2bef2c6 commit 3c8438a
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 2 deletions.
11 changes: 10 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { Flex } from '@chakra-ui/react';

import Sidebar from '@/components/Sidebar';

import fonts from './fonts';
import Providers from './providers';

const RootLayout = ({ children }: { children: React.ReactNode }) => {
return (
<html lang="en" className={fonts.rubik.variable}>
<body>
<Providers>{children}</Providers>
<Providers>
<Flex>
<Sidebar />
<Flex w="full">{children}</Flex>
</Flex>
</Providers>
</body>
</html>
);
Expand Down
27 changes: 27 additions & 0 deletions src/components/Sidebar/Button/CategoryButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Button, Icon, Text } from '@chakra-ui/react';
import { BsCircleFill } from 'react-icons/bs';

import { CategoryButtonProps } from '../../type';

const CategoryButton = ({ path, text, isSelected, isTeam, isTeamMatch }: CategoryButtonProps) => {
return (
<Button
as="a"
justifyContent="flex-start"
p="2"
color={isSelected ? 'white' : (isTeamMatch && 'orange') || 'white'}
bg={isSelected ? 'orange' : 'transparent'}
_hover={isSelected ? { color: 'white' } : { color: 'orange' }}
_active={{ color: 'orange' }}
href={path}
rounded="full"
>
{isTeam && <Icon as={BsCircleFill} mr="2" fontSize="6" />}
<Text ml={isTeam ? '0px' : '24px'} fontSize={isTeam ? 'xl' : 'md'} fontWeight={isTeam ? 'bold' : 'md'}>
{text}
</Text>
</Button>
);
};

export default CategoryButton;
19 changes: 19 additions & 0 deletions src/components/Sidebar/Button/SidebarIconButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { IconButton } from '@chakra-ui/react';

import { SidebarIconButtonProps } from '../../type';

const SidebarIconButton = ({ icon, onClick }: SidebarIconButtonProps) => {
return (
<IconButton
color="white"
bg="green_dark"
_hover={{ bg: 'green_dark' }}
aria-label=""
icon={icon}
onClick={onClick}
size="icon_md"
/>
);
};

export default SidebarIconButton;
38 changes: 38 additions & 0 deletions src/components/Sidebar/Category/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Flex } from '@chakra-ui/react';
import { usePathname } from 'next/navigation';

import CategoryButton from '../Button/CategoryButton';
import { CategoryProps } from '../type';

const Category = ({ id, name, subCategory }: CategoryProps) => {
const currentPath = usePathname();
const teamPath = `/team/${id}`;

return (
<Flex direction="column" w="100%">
<CategoryButton
path={teamPath}
text={name}
isSelected={currentPath === teamPath}
isTeam
isTeamMatch={currentPath.includes(teamPath)}
/>
{subCategory.map((study) => {
const studyPath = `${teamPath}/study/${study.id}`;

return (
<CategoryButton
key={`study-${study.id}`}
path={studyPath}
text={`${study.name} 스터디`}
isSelected={currentPath === studyPath}
isTeam={false}
isTeamMatch={false}
/>
);
})}
</Flex>
);
};

export default Category;
76 changes: 76 additions & 0 deletions src/components/Sidebar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'use client';

import { Avatar, Button, Card, Flex, IconButton, Text } from '@chakra-ui/react';
import React, { useState } from 'react';
import { BiBell, BiUser } from 'react-icons/bi';
import { BsPlus, BsGrid } from 'react-icons/bs';
import { MdOutlineLogout } from 'react-icons/md';

import sidebarData from '@/mocks/sidebar';

import SidebarIconButton from './Button/SidebarIconButton';
import Category from './Category';

const Sidebar = () => {
const [isOpen, setIsOpen] = useState(true);

return (
<Flex
direction="column"
gap="16"
w={isOpen ? '72' : '20'}
h="100vh"
p="4"
bg="green"
transition="width 0.15s ease-in-out"
>
<Flex justify={isOpen ? 'space-between' : 'center'}>
{isOpen && (
// TODO - 추후 로고 대체
<Button as="a" p="0" bg="transparent" _hover={{ bg: 'transparent' }} href="/">
<Text color="white" fontSize="3xl" fontWeight="bold">
DOO RE
</Text>
</Button>
)}
<IconButton
color="white"
fontSize="3xl"
bg="transparent"
_hover={{ bg: 'transparent' }}
aria-label=""
icon={<BsGrid />}
onClick={() => setIsOpen((prev) => !prev)}
/>
</Flex>
<Flex align="center" direction="column" gap="4">
<Avatar size={isOpen ? 'lg' : 'md'} src="" />
{isOpen && (
<Text px="10" py="2" color="white" fontSize="2xl" fontWeight="bold" bg="green_dark" rounded="full">
두레
</Text>
)}
<Flex direction={isOpen ? 'row' : 'column'} gap="4">
<SidebarIconButton icon={<BiBell />} onClick={() => {}} />
<SidebarIconButton icon={<BiUser />} onClick={() => {}} />
<SidebarIconButton icon={<MdOutlineLogout />} onClick={() => {}} />
</Flex>
</Flex>

{isOpen && (
<Card direction="column" gap="4" h="100vh" p="4" bg="green_dark" rounded="2xl">
<Flex align="center" justify="space-between">
<Text color="white" fontSize="xl" fontWeight="bold">
TEAM & STUDY
</Text>
<IconButton color="black" bg="white" aria-label="" icon={<BsPlus />} size="icon_sm" />
</Flex>
{sidebarData.map((item) => (
<Category key={item.id} id={item.id} name={item.name} subCategory={item.studyList} />
))}
</Card>
)}
</Flex>
);
};
export default Sidebar;
18 changes: 18 additions & 0 deletions src/components/Sidebar/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export interface CategoryButtonProps {
path: string;
text: string;
isSelected: boolean;
isTeam: boolean;
isTeamMatch: boolean;
}

export interface SidebarIconButtonProps {
icon: React.ReactElement;
onClick: () => void;
}

export interface CategoryProps {
id: number;
name: string;
subCategory: { id: number; name: string }[];
}
32 changes: 32 additions & 0 deletions src/mocks/sidebar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const sidebarData = [
{
id: 1,
name: '팀1',
studyList: [
{
id: 1,
name: '스터디1',
},
{
id: 2,
name: '스터디2',
},
],
},
{
id: 2,
name: '팀2',
studyList: [
{
id: 1,
name: '스터디1',
},
{
id: 2,
name: '스터디2',
},
],
},
];

export default sidebarData;
2 changes: 1 addition & 1 deletion src/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import styles from './styles';
const theme = extendTheme({
styles,
...foundations,
...components,
components,
});

export default theme;

0 comments on commit 3c8438a

Please sign in to comment.