Skip to content

Commit

Permalink
Merge pull request #153 from boostcampwm-2024/feature/fe/#108-drawer
Browse files Browse the repository at this point in the history
[FE][Feat] #108 : Dropdown ๋ฒ„ํŠผ ๊ตฌํ˜„
  • Loading branch information
effozen authored Nov 13, 2024
2 parents ca9080e + 0b7f080 commit 2afef59
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 75 deletions.
2 changes: 1 addition & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ export const App = () => (
<Route path="/add-channel/:user/draw" element={<DrawRoute />} />
<Route path="/channel/:channelId/*" element={<ChannelRoutes />} />
</Routes>
);
);
35 changes: 35 additions & 0 deletions frontend/src/component/common/dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { createContext, ReactNode, useMemo, useState } from 'react';
import { DropdownTrigger } from '@/component/common/dropdown/DropdownTrigger.tsx';
import { DropdownItem } from '@/component/common/dropdown/DropdownItem.tsx';
import { DropdownMenu } from '@/component/common/dropdown/DropdownMenu.tsx';

interface IDropdownProps {
children: ReactNode;
}

export interface IToggleContext {
isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
}

export const ToggleContext = createContext<IToggleContext>({
isOpen: false,
setIsOpen: () => {},
});

// Todo : ๋“œ๋ž๋‹ค์šด ์™ธ๋ถ€์—์„œ ํด๋ฆญ์‹œ ์ฐฝ ๋‹ซํžˆ๊ฒŒ ์„ค์ •
export const Dropdown = (props: IDropdownProps) => {
const [isOpen, setIsOpen] = useState(false);

const toggleContextValue = useMemo(() => ({ isOpen, setIsOpen }), [isOpen, setIsOpen]);

return (
<aside className="relative flex w-fit flex-col">
<ToggleContext.Provider value={toggleContextValue}>{props.children}</ToggleContext.Provider>
</aside>
);
};

Dropdown.Trigger = DropdownTrigger;
Dropdown.Item = DropdownItem;
Dropdown.Menu = DropdownMenu;
27 changes: 0 additions & 27 deletions frontend/src/component/common/dropdown/DropdownButton.tsx

This file was deleted.

21 changes: 21 additions & 0 deletions frontend/src/component/common/dropdown/DropdownItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ReactNode } from 'react';

interface IDropdownItemProps {
children: ReactNode;
onClick?: React.MouseEventHandler<HTMLButtonElement>;
}

export const DropdownItem = (props: IDropdownItemProps) => {
// undefined๋Š” react์—์„œ ๋žœ๋”๋ง ํ•˜์ง€ ์•Š์Œ
return (
<li className="px-3 py-1.5 text-base">
<button
type="button"
className="flex w-full items-center justify-between whitespace-nowrap bg-transparent"
onClick={props.onClick}
>
{props.children}
</button>
</li>
);
};
63 changes: 63 additions & 0 deletions frontend/src/component/common/dropdown/DropdownMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { ReactNode, useContext, useRef, useEffect } from 'react';
import classNames from 'classnames';
import { ToggleContext } from '@/component/common/dropdown/Dropdown.tsx';

interface IDropdownMenuProps {
children: ReactNode | ReactNode[];
}

export const DropdownMenu = (props: IDropdownMenuProps) => {
const { isOpen, setIsOpen } = useContext(ToggleContext);
const ref = useRef<HTMLUListElement | null>(null);

const handleOutSideClick = (event: MouseEvent) => {
const { target } = event;

if (!(target instanceof HTMLElement)) {
return;
}

if (
ref.current &&
target &&
!ref.current.contains(target) &&
target.dataset.component !== 'DropdownTrigger'
) {
setIsOpen(false);
}
};

useEffect(() => {
document.addEventListener('click', handleOutSideClick);
return () => {
document.removeEventListener('click', handleOutSideClick);
};
}, []);

return (
isOpen && (
<ul
ref={ref}
className={classNames(
// ์ถ”ํ›„ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์กฐ๊ฑด๋ถ€ ์ ์šฉ์„ ์œ„ํ•ด์„œ classNames ์‚ฌ์šฉ
'align-center',
'animate-smoothAppear',
'absolute',
'right-0',
'top-8',
'z-10',
'flex',
'flex-col',
'justify-center',
'gap-2.5',
'rounded-xl',
'p-2.5',
'shadow-2xl',
'w-fit',
)}
>
{props.children}
</ul>
)
);
};
33 changes: 33 additions & 0 deletions frontend/src/component/common/dropdown/DropdownTrigger.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { ReactNode, useContext } from 'react';
import classNames from 'classnames';
import { ToggleContext } from '@/component/common/dropdown/Dropdown.tsx';

interface IDropdownTriggerProps {
children: ReactNode;
}

export const DropdownTrigger = (props: IDropdownTriggerProps) => {
const { setIsOpen } = useContext(ToggleContext);

const handleOnClick = () => {
setIsOpen(prevIsOpen => !prevIsOpen);
};

return (
<button
type="button"
className={classNames(
'flex',
'justify-center',
'items-center',
'bg-transparent',
'w-fit',
'h-fit',
)}
data-component="DropdownTrigger"
onClick={handleOnClick}
>
{props.children}
</button>
);
};
38 changes: 38 additions & 0 deletions frontend/src/component/header/HeaderDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Dropdown } from '@/component/common/dropdown/Dropdown.tsx';
import { MdMenu, MdLocationOn } from 'react-icons/md';
import { DropdownItem } from '@/component/common/dropdown/DropdownItem.tsx';
import classNames from 'classnames';

// interface IDropdownContainerProps {}

// TDDO : props๋กœ ์ „๋‹ฌ๋˜๋ฉด ํ•ด์„๋˜๋„๋ก ๋กœ์ง ๋ณ€๊ฒฝ (props:props: IDropdownContainerProps)
export const HeaderDropdown = () => {
return (
<div>
<Dropdown>
<Dropdown.Trigger>
<MdMenu className="h-6 w-6" />
</Dropdown.Trigger>
<Dropdown.Menu>
{[
'์‚ฌ์šฉ์ž 1 ๋ณด๊ธฐ',
'์‚ฌ์šฉ์ž 2 ๋ณด๊ธฐ',
'์‚ฌ์šฉ์ž 3 ๋ณด๊ธฐ',
'์‚ฌ์šฉ์ž 4 ๋ณด๊ธฐ',
'์‚ฌ์šฉ์ž 5 ๋ณด๊ธฐ',
].map((e, i) => {
return (
<DropdownItem key={e}>
{e}
<MdLocationOn
className={classNames('w-5', 'h-5', `text-marker-user${i + 1}`, 'fill-current')}
/>
{/* ์•„์ด์ฝ˜ ์ƒ‰ ๋ณ€๊ฒฝ ๋กœ์ง ์ฐพ๊ธฐ, ํ˜„์žฌ๋Š” ์•„์ด์ฝ˜์ƒ‰์ด ๋ฐ˜์˜์ด ์•ˆ๋จ ์ˆ˜์ •ํ•  ์‚ฌ */}
</DropdownItem>
);
})}
</Dropdown.Menu>
</Dropdown>
</div>
);
};
2 changes: 1 addition & 1 deletion frontend/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import './index.css';
import { App } from './App';
import { App } from './App2';
// ์šฐ์„ ์€ ํฐํŠธ ๋‹ค ํฌํ•จ์‹œ์ผฐ๋Š”๋ฐ, ๋‚˜์ค‘์— ์‚ฌ์šฉํ•  ๊ฒƒ๋“ค๋งŒ ๋”ฐ๋กœ ๋บด์ž.
import '@fontsource/pretendard/100.css';
import '@fontsource/pretendard/200.css';
Expand Down
46 changes: 0 additions & 46 deletions frontend/src/stories/DropdownButton.stories.tsx

This file was deleted.

10 changes: 10 additions & 0 deletions frontend/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ module.exports = {
float: '0 4px 20px rgba(0, 0, 0, 0.13)',
basic: 'inset 0 0 3px rgba(0, 0, 0, 0.11)',
},
keyframes: {
smoothAppear: {
'0%': { opacity: '0', transform: 'translateY(-5%)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
},
animation: {
smoothAppear: 'smoothAppear 0.5s ease-out', // 0.5s๋Š” ์›ํ•˜๋Š” ์ง€์† ์‹œ๊ฐ„
smoothDisappear: 'smoothAppear 0.5s reverse ease-out', // 0.5s๋Š” ์›ํ•˜๋Š” ์ง€์† ์‹œ๊ฐ„
},
}, // ํ•„์š”ํ•œ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•์„ ์—ฌ๊ธฐ์„œ ์„ค์ • ๊ฐ€๋Šฅ
},
plugins: [],
Expand Down

0 comments on commit 2afef59

Please sign in to comment.