From 0a2595503a9e7944953bd90ba37bbd65c461c7e3 Mon Sep 17 00:00:00 2001 From: soonki-98 Date: Sun, 27 Nov 2022 18:06:09 +0900 Subject: [PATCH] =?UTF-8?q?[Feat]=20=ED=95=84=ED=84=B0=20=EB=A9=94?= =?UTF-8?q?=EB=89=B4=20UI=20=EA=B5=AC=ED=98=84=20#32?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/close.svg | 4 + src/components/pages/map/FilterMenu.tsx | 134 +++++++++++++++++++-- src/components/pages/map/FilterSection.tsx | 66 ++++++++++ 3 files changed, 197 insertions(+), 7 deletions(-) create mode 100644 src/assets/icons/close.svg create mode 100644 src/components/pages/map/FilterSection.tsx diff --git a/src/assets/icons/close.svg b/src/assets/icons/close.svg new file mode 100644 index 0000000..15a00b5 --- /dev/null +++ b/src/assets/icons/close.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/pages/map/FilterMenu.tsx b/src/components/pages/map/FilterMenu.tsx index b80b042..9c9ed08 100644 --- a/src/components/pages/map/FilterMenu.tsx +++ b/src/components/pages/map/FilterMenu.tsx @@ -1,24 +1,64 @@ import { filterAtom } from '@recoil/map'; +import Image from 'next/image'; import { useEffect, useRef } from 'react'; import { useRecoilState } from 'recoil'; import styled, { css } from 'styled-components'; +import closeImg from '../../../assets/icons/close.svg'; +import FilterSection from './FilterSection'; function FilterMenu() { const [filterState, setFilterState] = useRecoilState(filterAtom); const filterRef = useRef(null); - const closeFilter = (e: MouseEvent) => { + const closeClickOutSide = (e: MouseEvent) => { if (!filterRef.current) return; if (filterState.isOpen && !filterRef.current.contains(e.target as HTMLElement)) { - setFilterState({ ...filterState, isOpen: false }); + closeFilter(); } }; + const closeFilter = () => { + setFilterState({ ...filterState, isOpen: false }); + }; + useEffect(() => { - document.addEventListener('click', closeFilter); - return () => document.removeEventListener('click', closeFilter); + document.addEventListener('click', closeClickOutSide); + return () => document.removeEventListener('click', closeClickOutSide); }, [filterState.isOpen]); - return ; + return ( + + + <LogoBox onClick={closeFilter}> + <Image src={closeImg} className="close-icon" /> + </LogoBox> + <h1>필터</h1> + + + + 시끌벅적한 + 고급스러운 + 격식있는 + 이색적인 + 깔끔한 + 조용한 + 뷰가 예쁜 + + + + + + + + + + + + + + + ); } export default FilterMenu; @@ -27,12 +67,12 @@ const Wrapper = styled.div<{ isOpen: boolean }>` position: fixed; bottom: 0; width: 100%; - height: 80vh; - background-color: #fff; + background: #fafafa; z-index: 500; transition: 0.5s; box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.15); border-radius: 16px 16px 0px 0px; + max-height: 80vh; ${({ isOpen }) => { if (isOpen) { return css` @@ -45,3 +85,83 @@ const Wrapper = styled.div<{ isOpen: boolean }>` } }} `; + +const Title = styled.header` + position: relative; + padding: 12px; + box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.15); + color: #000; + text-align: center; + background: #fff; + border-radius: 16px 16px 0px 0px; + h1 { + font-size: 18px; + line-height: 24px; + margin: 0; + } + + .close-icon { + position: absolute; + top: 50%; + left: 16px; + z-index: 400; + width: 18px; + height: 18px; + } +`; + +const LogoBox = styled.button` + position: absolute; + top: 50%; + transform: translateY(-50%); + background: #fff; + left: 16px; + border: 1px solid; + cursor: pointer; +`; + +const SectionWrapper = styled.div` + padding: 16px; +`; + +const DrinkFilter = styled.li` + aspect-ratio: 1/1; + background-color: #fff; + border: 1px solid #f0f0f0; + border-radius: 50%; +`; + +const MoodFilter = styled.li` + padding: 8px 16px; + border: 1px solid #f0f0f0; + background-color: #fff; + border-radius: 24px; + color: #000; + font-weight: 500; + font-size: 12px; + line-height: 16px; +`; + +const ButtonWrapper = styled.div` + display: flex; + gap: 16px; + justify-content: center; + align-items: center; + padding: 16px; +`; + +const Button = styled.button` + width: 100%; + padding: 14px 0; + border-radius: 26px; + border: 1px solid #f0f0f0; + cursor: pointer; + &.cancel { + background: #f0f0f0; + color: #000; + } + &.submit { + background: #715ae4; + color: #f0f0f0; + } +`; diff --git a/src/components/pages/map/FilterSection.tsx b/src/components/pages/map/FilterSection.tsx new file mode 100644 index 0000000..9e86634 --- /dev/null +++ b/src/components/pages/map/FilterSection.tsx @@ -0,0 +1,66 @@ +import styled, { css } from 'styled-components'; + +interface IFilterSectionProps { + filterType: 'mood' | 'drink'; + children: React.ReactNode; +} + +function FilterSection({ filterType, children }: IFilterSectionProps) { + return ( + + {filterType === 'mood' ? '술집 분위기' : '술 종류'} + {children} + + ); +} + +export default FilterSection; + +const Wrapper = styled.section` + padding: 8px 0 24px 0; + border-bottom: 0.5px solid #d9d9d9; +`; + +const FilterName = styled.h2` + margin: 0; + color: #000; + font-weight: 400; + font-size: 16px; + line-height: 24px; +`; + +const FilterList = styled.ul<{ filterType: 'mood' | 'drink' }>` + margin-top: 16px; + ${({ filterType }) => { + switch (filterType) { + case 'drink': + return css` + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 26px; + `; + case 'mood': + return css` + display: flex; + flex-wrap: wrap; + gap: 12px; + `; + default: + return css` + gap: 12px; + `; + } + }} +`; + +const ButtonWrapper = styled.div` + display: flex; + gap: 16px; + justify-content: center; + align-items: center; +`; + +const Button = styled.button` + width: 100%; + padding: 14px 0; +`;