-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #42 from softeerbootcamp4th/feature/21-universalIs…
…landInteraction [feat] 유니버설 아일랜드 인터랙션 추가 (resolve #21)
- Loading branch information
Showing
12 changed files
with
364 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { useEffect } from "react"; | ||
import throttleRaf from "@/common/throttleRaf.js"; | ||
|
||
function useMountDragEvent(dragging, dragEnd) { | ||
useEffect(() => { | ||
const onPointerMove = throttleRaf((e) => { | ||
const { clientX, clientY } = e; | ||
dragging({ x: clientX, y: clientY }); | ||
}); | ||
const onTouchMove = throttleRaf((e) => { | ||
const { clientX, clientY } = e.touches[0]; | ||
dragging({ x: clientX, y: clientY }); | ||
}); | ||
|
||
window.addEventListener("pointermove", onPointerMove); | ||
window.addEventListener("pointerup", dragEnd); | ||
window.addEventListener("pointercancel", dragEnd); | ||
window.addEventListener("touchmove", onTouchMove); | ||
window.addEventListener("touchend", dragEnd); | ||
window.addEventListener("touchcancel", dragEnd); | ||
return () => { | ||
window.removeEventListener("pointermove", onPointerMove); | ||
window.removeEventListener("pointerup", dragEnd); | ||
window.removeEventListener("pointercancel", dragEnd); | ||
window.removeEventListener("touchmove", onTouchMove); | ||
window.removeEventListener("touchend", dragEnd); | ||
window.removeEventListener("touchcancel", dragEnd); | ||
}; | ||
}, [dragging, dragEnd]); | ||
} | ||
|
||
export default useMountDragEvent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
function Phone({ dynamicStyle, onPointerDown, isSnapped }) { | ||
const staticStyle = `absolute flex justify-center items-center | ||
left-[541px] top-[293px] w-[54px] h-[97px] | ||
lg:left-[528px] lg:top-[185px] lg:w-[66px] lg:h-[118px] | ||
xl:left-[516px] xl:top-[75px] xl:w-[77px] xl:h-[140px] | ||
touch-none | ||
`; | ||
const phoneScreenFill = isSnapped ? "fill-green-700" : "fill-neutral-900"; | ||
const lightningOpacity = isSnapped ? "opacity-100" : "opacity-0"; | ||
|
||
return ( | ||
<div | ||
className={staticStyle} | ||
style={dynamicStyle} | ||
onPointerDown={onPointerDown} | ||
> | ||
<svg | ||
className="w-full h-full absolute top-0 left-0" | ||
width="66" | ||
height="127" | ||
viewBox="0 0 63 127" | ||
fill="none" | ||
xmlns="http://www.w3.org/2000/svg" | ||
> | ||
<rect | ||
x="-1.5" | ||
y="1.5" | ||
width="66" | ||
height="124" | ||
rx="10.5" | ||
fill="#181818" | ||
stroke="#97E0FF" | ||
strokeWidth="3" | ||
className={`${phoneScreenFill} transition-colors`} | ||
/> | ||
<path | ||
d="M17 2H45V5C45 6.65685 43.6569 8 42 8H20C18.3431 8 17 6.65685 17 5V2Z" | ||
fill="#97E0FF" | ||
/> | ||
</svg> | ||
<svg | ||
width="15" | ||
height="28" | ||
viewBox="0 0 15 28" | ||
fill="none" | ||
xmlns="http://www.w3.org/2000/svg" | ||
className={`${lightningOpacity} z-10 transition-colors`} | ||
> | ||
<path | ||
d="M10.6239 13.1582C10.266 12.9321 10.0893 12.5051 10.1826 12.0922L12.5679 1.54338C12.792 0.552496 11.567 -0.102448 10.8675 0.634189L0.838941 11.1938C0.404727 11.651 0.496867 12.391 1.02993 12.7278L4.37611 14.8418C4.734 15.0679 4.91075 15.4949 4.81738 15.9078L2.43207 26.4566C2.20801 27.4475 3.43296 28.1024 4.13255 27.3658L14.1611 16.8062C14.5953 16.349 14.5031 15.609 13.9701 15.2722L10.6239 13.1582Z" | ||
fill="#BBFBF0" | ||
/> | ||
</svg> | ||
</div> | ||
); | ||
} | ||
|
||
export default Phone; |
108 changes: 108 additions & 0 deletions
108
src/interactions/univasalIsland/UnivasalIslandInteraction.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { useImperativeHandle } from "react"; | ||
import Phone from "./Phone.jsx"; | ||
import useIslandDrag from "./useIslandDrag.js"; | ||
|
||
import orderIcon from "@/assets/property3.svg"; | ||
import seat from "./assets/seat.png"; | ||
import univasalIsland1x from "./assets/[email protected]"; | ||
import univasalIsland2x from "./assets/[email protected]"; | ||
import univasalIslandLeg from "./assets/univasalIsland2.png"; | ||
|
||
function UnivasalIslandInteraction({ interactCallback, $ref }) { | ||
const { | ||
islandEventListener, | ||
phoneEventListener, | ||
islandStyle, | ||
phoneStyle, | ||
reset, | ||
phoneSnapArea, | ||
phoneIsSnapping, | ||
} = useIslandDrag(); | ||
|
||
useImperativeHandle($ref, () => ({ reset }), [reset]); | ||
|
||
const seatHullStyle = `absolute w-[1200px] h-[800px] | ||
bottom-[min(calc(100%-800px),-140px)] | ||
lg:bottom-[min(calc(100%-900px),-170px)] | ||
xl:bottom-[min(calc(100%-1000px),-200px)] | ||
flex justify-center items-end select-none`; | ||
|
||
const seatStyle = `w-[317.44px] h-[501.88px] | ||
lg:w-[385.46px] lg:h-[610.64px] | ||
xl:w-[453.48px] xl:h-[718.4px]`; | ||
|
||
const univasalIslandStaticStyle = `w-[158.2px] h-[546px] | ||
lg:w-[192.1px] lg:h-[663px] | ||
xl:w-[226px] xl:h-[780px] | ||
flex flex-col gap-2 cursor-pointer touch-none`; | ||
|
||
const snapAreaStyle = `absolute scale-50 | ||
left-[21px] top-[40px] w-[54px] h-[97px] | ||
lg:left-[25px] lg:top-[49px] lg:w-[66px] lg:h-[118px] | ||
xl:left-[30px] xl:top-[56px] xl:w-[77px] xl:h-[140px] | ||
`; | ||
|
||
return ( | ||
<article className="relative w-full h-full overflow-hidden flex items-center flex-col"> | ||
<div className="w-full max-w-[1200px] px-10 lg:px-20 flex gap-2 items-start mt-16 lg:mt-[6.25rem] "> | ||
<img src={orderIcon} alt="3" /> | ||
<div className="flex flex-col gap-3.5 font-bold"> | ||
<h3 className="text-neutral-400 text-title-m md:text-title-l"> | ||
나에게 맞게, 자유자재로 | ||
</h3> | ||
<p className="text-white text-body-m md:text-body-l"> | ||
새로워진 The new IONIQ 5의 유니버설 아일랜드는 어떤 모습일까요? | ||
</p> | ||
<p className="text-neutral-200 text-body-s"> | ||
유니버설 아일랜드를 드래그하여 이동시키고 스마트폰을 충전해보세요! | ||
</p> | ||
</div> | ||
</div> | ||
<div className={seatHullStyle}> | ||
<img | ||
className={seatStyle} | ||
src={seat} | ||
alt="left seat" | ||
draggable="false" | ||
/> | ||
<div | ||
className={univasalIslandStaticStyle} | ||
style={islandStyle} | ||
onPointerDown={(e) => { | ||
islandEventListener.onPointerDown(e); | ||
interactCallback?.(); | ||
}} | ||
> | ||
<img | ||
src={univasalIsland1x} | ||
srcSet={`${univasalIsland1x} 1x, ${univasalIsland2x} 2x`} | ||
alt="univasal island" | ||
draggable="false" | ||
/> | ||
<img | ||
src={univasalIslandLeg} | ||
alt="univasal island" | ||
draggable="false" | ||
/> | ||
<div className={snapAreaStyle} ref={phoneSnapArea}></div> | ||
</div> | ||
<img | ||
className={seatStyle} | ||
src={seat} | ||
alt="right seat" | ||
draggable="false" | ||
/> | ||
<Phone | ||
isSnapped={phoneIsSnapping} | ||
dynamicStyle={phoneStyle} | ||
onPointerDown={(e) => { | ||
phoneEventListener.onPointerDown(e); | ||
interactCallback?.(); | ||
}} | ||
/> | ||
</div> | ||
</article> | ||
); | ||
} | ||
|
||
export default UnivasalIslandInteraction; |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.