-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 레스토랑 카드 및 마커 클릭 이벤트 변경 #198
The head ref may contain hidden characters: "192-feat-\uB808\uC2A4\uD1A0\uB791-\uCE74\uB4DC-\uBC0F-\uB9C8\uCEE4-\uD074\uB9AD-\uC774\uBCA4\uD2B8-\uBCC0\uACBD"
Changes from all commits
462bbb7
161d6fe
0838f20
d09af48
11cf5f8
8748b91
11ba021
43ca047
fdeb97a
f731c1d
b4ad157
d9bd80d
dbb297f
a6ae8ef
5b69f96
3df8276
c3a5c15
e8e9e31
ab9e38d
9141668
34b12a6
750fe7f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,102 @@ | ||
import styled from 'styled-components'; | ||
import styled, { css, keyframes } from 'styled-components'; | ||
import { useRef, useState } from 'react'; | ||
import ProfileImage from '../ProfileImage'; | ||
import Overlay from './Overlay/Overlay'; | ||
import RestaurantCard from '~/components/RestaurantCard'; | ||
import useOnClickOutside from '~/hooks/useOnClickOutside'; | ||
|
||
import type { Quadrant } from '~/utils/getQuadrant'; | ||
import type { Restaurant } from '~/@types/restaurant.types'; | ||
import type { Celeb } from '~/@types/celeb.types'; | ||
import type { Coordinate } from '~/@types/map.types'; | ||
|
||
interface OverlayMarkerProps { | ||
celeb: Celeb; | ||
position: Coordinate; | ||
onClick: ({ lat, lng }: Coordinate) => void; | ||
map?: google.maps.Map; | ||
restaurant: Restaurant; | ||
quadrant: Quadrant; | ||
isRestaurantHovered: boolean; | ||
} | ||
|
||
function OverlayMarker({ celeb, position, map, onClick }: OverlayMarkerProps) { | ||
function OverlayMarker({ celeb, restaurant, map, quadrant, isRestaurantHovered }: OverlayMarkerProps) { | ||
const { lat, lng } = restaurant; | ||
const [isClicked, setIsClicked] = useState(false); | ||
const ref = useRef(); | ||
useOnClickOutside(ref, () => setIsClicked(false)); | ||
|
||
const clickMarker = () => setIsClicked(true); | ||
|
||
return ( | ||
map && ( | ||
<Overlay position={position} map={map}> | ||
<StyledMarker type="button" onClick={() => onClick(position)}> | ||
<ProfileImage name={celeb.name} imageUrl={celeb.profileImageUrl} size={32} border /> | ||
<Overlay position={{ lat, lng }} map={map} zIndex={isClicked || isRestaurantHovered ? 18 : 0}> | ||
<StyledMarker onClick={clickMarker} isClicked={isClicked} isRestaurantHovered={isRestaurantHovered} ref={ref}> | ||
<ProfileImage name={celeb.name} imageUrl={celeb.profileImageUrl} border size="100%" /> | ||
</StyledMarker> | ||
{isClicked && ( | ||
<StyledModal quadrant={quadrant}> | ||
<RestaurantCard restaurant={restaurant} type="map" /> | ||
</StyledModal> | ||
)} | ||
</Overlay> | ||
) | ||
); | ||
} | ||
|
||
const StyledMarker = styled.button` | ||
border: none; | ||
background-color: transparent; | ||
const scaleUp = keyframes` | ||
0% { | ||
transform: scale(1); | ||
} | ||
100% { | ||
transform: scale(1.5); | ||
} | ||
`; | ||
|
||
const StyledMarker = styled.div<{ isClicked: boolean; isRestaurantHovered: boolean }>` | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
|
||
width: 36px; | ||
height: 36px; | ||
|
||
transition: all 0.2s ease-in-out; | ||
border: ${({ isClicked, isRestaurantHovered }) => | ||
isClicked || isRestaurantHovered ? '3px solid var(--orange-2)' : '3px solid transparent'}; | ||
border-radius: 50%; | ||
|
||
transition: transform 0.2s ease-in-out; | ||
transform: ${({ isClicked }) => (isClicked ? 'scale(1.5)' : 'scale(1)')}; | ||
|
||
&:hover { | ||
transform: scale(1.1); | ||
transform: scale(1.5); | ||
} | ||
|
||
${({ isRestaurantHovered }) => | ||
isRestaurantHovered && | ||
css` | ||
animation: ${scaleUp} 0.2s ease-in-out forwards; | ||
`} | ||
`; | ||
|
||
const fadeInAnimation = keyframes` | ||
from { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요 애니메이션은 많이 쓰일거 같네용 ~~ 공통 css로 빼도 좋을 거 같아여!! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 다른 컴포넌트에서 위와 같은 애니메이션을 쓰게되면 그때 분리해도 늦진 않을 것 같아요. |
||
opacity: 0; | ||
} | ||
to { | ||
opacity: 1; | ||
} | ||
`; | ||
|
||
const StyledModal = styled.div<{ quadrant: Quadrant }>` | ||
position: absolute; | ||
top: ${({ quadrant }) => (quadrant === 1 || quadrant === 2 ? '40px' : '-280px')}; | ||
right: ${({ quadrant }) => (quadrant === 1 || quadrant === 4 ? '45px' : '-210px')}; | ||
|
||
width: 200px; | ||
|
||
border-radius: 12px; | ||
background-color: #fff; | ||
|
||
animation: ${fadeInAnimation} 100ms ease-in; | ||
box-shadow: 0 4px 6px rgb(0 0 0 / 20%); | ||
`; | ||
|
||
export default OverlayMarker; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
quadrant가 사분면을 뜻하는 군요 ㅋㅋㅋㅋ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
맞습니다ㅋㅋ 저도 이번에 구현하면서 처음 알게된 단어입니다ㅋㅋ