diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 9a691368..f516c490 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,4 +1,4 @@ -import { Providers, ThemeButton } from '@/components' +import { Providers } from '@/components' import Header from '@/components/common/Header/Header' import type { Metadata } from 'next' import './globals.css' @@ -17,11 +17,12 @@ export default function RootLayout({ -
+
-
{children}
+
{children}
- diff --git a/src/components/common/Header/Header.tsx b/src/components/common/Header/Header.tsx index ca05711d..00e8a184 100644 --- a/src/components/common/Header/Header.tsx +++ b/src/components/common/Header/Header.tsx @@ -1,5 +1,6 @@ 'use client' +import { useState } from 'react' import { LinkIcon } from '@heroicons/react/20/solid' import { BellIcon } from '@heroicons/react/24/outline' import { MagnifyingGlassCircleIcon } from '@heroicons/react/24/outline' @@ -7,39 +8,46 @@ import { Bars3Icon } from '@heroicons/react/24/solid' import Link from 'next/link' import { usePathname } from 'next/navigation' import Button from '../Button/Button' +import Sidebar from '../Sidebar/Sidebar' const Header = () => { + const [isSidebarOpen, setIsSidebarOpen] = useState(false) const pathName = usePathname() const currentPage = pathName .split(/[^a-zA-Z]/)[1] // 라우터명 .replace(/^[a-z]/, (char) => char.toUpperCase()) // 첫글자 대문자 치환 return ( -
-
- + <> +
+
+ +
+
+ {currentPage || 'Home'} +
+
+ + + +
-
- {currentPage || 'Home'} -
-
- - - -
-
+ {isSidebarOpen && setIsSidebarOpen(false)} />} + ) } diff --git a/src/components/common/Sidebar/Sidebar.tsx b/src/components/common/Sidebar/Sidebar.tsx new file mode 100644 index 00000000..5244ec92 --- /dev/null +++ b/src/components/common/Sidebar/Sidebar.tsx @@ -0,0 +1,134 @@ +'use client' + +import { useRef } from 'react' +import { mock_userData } from '@/data' +import { XMarkIcon } from '@heroicons/react/24/outline' +import { ArchiveBoxIcon, StarIcon } from '@heroicons/react/24/solid' +import Link from 'next/link' +import Avatar from '../Avatar/Avatar' +import Button from '../Button/Button' +import ThemeButton from '../ThemeButton/ThemeButton' +import useSidebar from './hooks/useSidebar' + +export interface SidebarProps { + onClose: () => void +} + +const Sidebar = ({ onClose }: SidebarProps) => { + const user = mock_userData + const sidebarRef = useRef(null) + const { spaceType, handleSpaceType, handleOverlayClick, logout } = useSidebar( + { + sidebarRef, + onClose, + }, + ) + + return ( +
+
+
+ {user ? ( + <> +
+ +

+ {user.name} +

+ +
+ + 프로필 + +
+
+ {spaceType} + {spaceType === '내 스페이스' ? ( + + ) : ( + + )} +
+
    + {user[ + spaceType === '내 스페이스' ? 'mySpaces' : 'favoriteSpaces' + ].map(({ name, id }) => ( +
  • + + {name} + +
  • + ))} +
+ + 스페이스 전체보기 + +
+ + 스페이스 생성 + + + ) : ( +
+ + + 로그인 + +
+ )} +
+
+ + {user && ( + + )} +
+
+
+ ) +} + +export default Sidebar diff --git a/src/components/common/Sidebar/hooks/useSidebar.ts b/src/components/common/Sidebar/hooks/useSidebar.ts new file mode 100644 index 00000000..a15e1835 --- /dev/null +++ b/src/components/common/Sidebar/hooks/useSidebar.ts @@ -0,0 +1,36 @@ +import { useState } from 'react' + +type SpaceType = '내 스페이스' | '즐겨찾기' + +export interface useSidebarProps { + sidebarRef: React.RefObject + onClose: () => void +} + +const useSidebar = ({ sidebarRef, onClose }: useSidebarProps) => { + const [spaceType, setSpaceType] = useState('내 스페이스') + + const logout = () => { + // TODO: 로그아웃 + onClose() + } + + const handleSpaceType = (e?: React.MouseEvent) => { + setSpaceType(spaceType === '내 스페이스' ? '즐겨찾기' : '내 스페이스') + } + + const handleOverlayClick = (e: React.MouseEvent) => { + if (e.target === sidebarRef.current) { + onClose() + } + } + + return { + spaceType, + handleSpaceType, + handleOverlayClick, + logout, + } +} + +export default useSidebar diff --git a/src/components/common/ThemeButton/ThemeButton.tsx b/src/components/common/ThemeButton/ThemeButton.tsx index 5ff40269..67014f10 100644 --- a/src/components/common/ThemeButton/ThemeButton.tsx +++ b/src/components/common/ThemeButton/ThemeButton.tsx @@ -7,7 +7,7 @@ const ThemeButton = () => { return ( diff --git a/src/components/index.ts b/src/components/index.ts index 83af2a67..f0bd59c6 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -14,4 +14,5 @@ export { default as CategoryList } from './common/CategoryList/CategoryList' export { default as DropdownItem } from './common/Dropdown/DropdownItem' export { default as Dropdown } from './common/Dropdown/Dropdown' export { default as SpaceMemberList } from './common/SpaceMemberList/SpaceMemberList' +export { default as Sidebar } from './common/Sidebar/Sidebar' export { default as Comment } from './Comment/Comment' diff --git a/src/data/index.ts b/src/data/index.ts index c25abd04..cf712344 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -95,6 +95,56 @@ export const mock_memberData = [ }, ] +export const mock_userData = { + id: 'frong', + name: '프롱이', + profile: '/duck.jpg', + mySpaces: [ + { + name: 'My Space 1', + id: 'my-space-1', + }, + { + name: 'My Space 2', + id: 'my-space-2', + }, + { + name: 'My Space 3', + id: 'my-space-3', + }, + { + name: 'My Space 4', + id: 'my-space-4', + }, + { + name: 'My Space 5', + id: 'my-space-5', + }, + ], + favoriteSpaces: [ + { + name: 'Favorite Space 1', + id: 'favorite-space-1', + }, + { + name: 'Favorite Space 2', + id: 'favorite-space-2', + }, + { + name: 'Favorite Space 3', + id: 'favorite-space-3', + }, + { + name: 'Favorite Space 4', + id: 'favorite-space-4', + }, + { + name: 'Favorite Space 5', + id: 'favorite-space-5', + }, + ], +} + export const mock_spaceData = { userName: 'dudwns', spaceId: 123,