Skip to content

Commit

Permalink
Merge pull request #150 from boostcampwm-2024/feature/fe/#145-Floatin…
Browse files Browse the repository at this point in the history
…gButton

[FE][FEAT] #145 - 플로팅 버튼 구현
  • Loading branch information
leedongyull authored Nov 13, 2024
2 parents 0432219 + b667d1a commit d1c2e3e
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

<p>
<a href="https://www.notion.so/127b1b2b649180e88f70d6a4648924a0?pvs=4">팀 노션</a> |
<a href="https://github.com/boostcampwm-2024/web28-DDara/wiki">팀 위키</a> |
<a href="https://ddara-docs.vercel.app/">팀 위키</a> |
<a href="https://www.figma.com/design/r9nl4Jcz9VXIMbrpf50wY6/PickMeUp?node-id=90-1897">기획서</a> |
<a href="https://www.figma.com/design/r9nl4Jcz9VXIMbrpf50wY6/PickMeUp?node-id=87-929">디자인</a>
<!-- <br />
Expand Down
2 changes: 1 addition & 1 deletion docs/docusaurus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

<p>
<a href="https://www.notion.so/127b1b2b649180e88f70d6a4648924a0?pvs=4">팀 노션</a> |
<a href="https://github.com/boostcampwm-2024/web28-DDara/wiki">팀 위키</a> |
<a href="https://ddara-docs.vercel.app/">팀 위키</a> |
<a href="https://www.figma.com/design/r9nl4Jcz9VXIMbrpf50wY6/PickMeUp?node-id=90-1897">기획서</a> |
<a href="https://www.figma.com/design/r9nl4Jcz9VXIMbrpf50wY6/PickMeUp?node-id=87-929">디자인</a>
<!-- <br />
Expand Down
3 changes: 2 additions & 1 deletion docs/docusaurus/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"clsx": "^2.0.0",
"prism-react-renderer": "^2.3.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
"react-dom": "^18.0.0",
"react-player": "^2.16.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "3.6.1",
Expand Down
8 changes: 7 additions & 1 deletion docs/docusaurus/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
// This file is not used in compilation. It is here just for a nice editor experience.
"extends": "@docusaurus/tsconfig",
"compilerOptions": {
"baseUrl": "."
"baseUrl": ".",
"paths": {
"@site/*": ["src/*"],
"@theme/*": ["src/theme/*"],
"@component/*": ["src/components/*"],
"@markdown/*": ["src/components/markdown/*"],
}
}
}
118 changes: 118 additions & 0 deletions frontend/src/component/common/FloatingButton/FloatingButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import classNames from 'classnames';
import React, { useState } from 'react';
import { ButtonState } from '../enums';
import { IconType, ToolCategory } from '../types';

/**
* FloatingButton 컴포넌트는 도구 선택 및 메뉴 토글 기능을 제공하는 플로팅 버튼을 렌더링합니다.
* @remarks
* 메뉴가 열리면 툴 선택과 설명 표시가 가능하며, 메뉴를 닫을 때 버튼 아이콘이 변경됩니다.
* @example
* return (
* <FloatingButton />
* )
*/
export const FloatingButton = () => {
const [toolType, setToolType] = useState<ButtonState>(ButtonState.CLOSE);
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);

/**
* @remarks
* - 메뉴를 토글하는 함수입니다.
*/
const toggleMenu = () => {
setIsMenuOpen(prev => !prev);
if (!isMenuOpen) {
setToolType(ButtonState.OPEN);
} else {
setToolType(ButtonState.CLOSE);
}
};

/**
* @remarks
* 툴을 선택하고 메뉴를 닫는 함수입니다.
* @param {ButtonState} type - 선택된 툴 타입
*/
const handleMenuClick = (type: ButtonState) => {
setToolType(type);
setIsMenuOpen(!isMenuOpen);
};

return (
<div
className={classNames('absolute', 'bottom-5', 'right-10', 'flex', 'flex-col', 'items-center')}
>
<button
type="button"
onClick={toggleMenu}
className={classNames(
'absolute',
'bottom-0',
'bg-blueGray-800',
'w-12',
'h-12',
'rounded-full',
'flex',
'justify-center',
'items-center',
'text-white',
'shadow-floatMenuButton',
'z-10',
)}
>
{React.createElement(IconType[toolType], { className: 'w-6 h-6' })}
</button>

{ToolCategory.map(({ type, description, icon }, index) => (
<button
type="button"
onClick={() => handleMenuClick(type)}
key={type}
className={classNames(
'w-10',
'h-10',
'bg-blueGray-200',
'text-white',
'rounded-full',
'flex',
'items-center',
'justify-center',
'absolute',
'transition-all',
'duration-300',
'shadow-floatButton',
{
'shadow-none': !isMenuOpen,
},
)}
style={{ bottom: toolType === ButtonState.OPEN ? `${48 * index + 64}px` : '0px' }}
>
<div className={classNames('flex', 'items-center')}>
{React.createElement(icon, { className: 'w-5 h-5' })}
{isMenuOpen && (
<div
className={classNames(
'w-20',
'h-8',
'bg-blueGray-200',
'absolute',
'right-12',
'text-white',
'text-xs',
'flex',
'items-center',
'justify-center',
'rounded-md',
'opacity-[0.5]',
)}
>
{description}
</div>
)}
</div>
</button>
))}
</div>
);
};
13 changes: 13 additions & 0 deletions frontend/src/component/common/enums.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @remarks
* ButtonState Enum은 버튼이 가질 수 있는 모든 종류를 정의합니다.
* @example
* const buttonState = ButtonState.OPEN;
*/
export enum ButtonState {
CLOSE = 'CLOSE', // 메뉴 닫기 버튼
OPEN = 'OPEN', // 메뉴 열기 버튼
START_MARKER = 'START_MARKER', // 출발지 설정 버튼
DESTINATION_MARKER = 'DESTINATION_MARKER', // 도착지 설정 버튼
LINE_DRAWING = 'LINE_DRAWING', // 경로 그리기 버튼
}
42 changes: 42 additions & 0 deletions frontend/src/component/common/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { FaPaintBrush } from 'react-icons/fa';
import { HiLocationMarker, HiOutlineDotsHorizontal, HiOutlineLocationMarker } from 'react-icons/hi';
import { SlLayers } from 'react-icons/sl';
import { ButtonState } from './enums';

/**
* IconType 객체는 각 버튼 타입에 해당하는 아이콘 컴포넌트를 매핑합니다.
* @type {Record<ButtonState, React.ComponentType>}
*/
export const IconType = {
CLOSE: SlLayers, // 닫기 버튼 아이콘
OPEN: HiOutlineDotsHorizontal, // 열기 버튼 아이콘
START_MARKER: HiLocationMarker, // 출발지 설정 아이콘
DESTINATION_MARKER: HiOutlineLocationMarker, // 도착지 설정 아이콘
LINE_DRAWING: FaPaintBrush, // 경로 그리기 아이콘
};
/**
* @remarks
* ToolCategory 배열은 각 저작도구에 대한 정보를 담고 있습니다.
* 각 툴은 버튼 타입, 설명, 아이콘을 포함합니다.
* 이 배열은 버튼의 목록을 정의하고, 이후 툴을 확장할 때 유용합니다.
* 또한, OPEN과 CLOSE 등 저작 도구가 아닌 종류는 제외합니다.
* @example
* const tool = ToolCategory[0];
*/
export const ToolCategory = [
{
type: ButtonState.LINE_DRAWING, // 경로 그리기 툴
description: '경로 그리기', // 툴 설명
icon: IconType.LINE_DRAWING, // 툴 아이콘
},
{
type: ButtonState.START_MARKER, // 출발지 설정 툴
description: '출발지 설정', // 툴 설명
icon: IconType.START_MARKER, // 툴 아이콘
},
{
type: ButtonState.DESTINATION_MARKER, // 도착지 설정 툴
description: '도착지 설정', // 툴 설명
icon: IconType.DESTINATION_MARKER, // 툴 아이콘
},
];
2 changes: 2 additions & 0 deletions frontend/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ module.exports = {
'6xl': '4rem',
},
boxShadow: {
floatButton: '0 5px 10px rgba(0,0,0,0.3)',
floatMenuButton: '0 4px 4px rgba(0,0,0,0.25)',
float: '0 4px 20px rgba(0, 0, 0, 0.13)',
basic: 'inset 0 0 3px rgba(0, 0, 0, 0.11)',
dark: '0px -6px 20px 0px rgba(0, 0, 0, 0.25)',
Expand Down
27 changes: 27 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d1c2e3e

Please sign in to comment.