about marasi drive in process
@@ -1,2 +1,2 @@
|
||||
VITE_API_URL=http://192.168.1.170:4002
|
||||
VITE_API_URL=http://192.168.1.122:4002
|
||||
# VITE_API_URL=http://194.26.138.94:4002
|
||||
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 520 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 191 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 769 KiB |
|
Before Width: | Height: | Size: 454 KiB After Width: | Height: | Size: 454 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 822 KiB |
|
After Width: | Height: | Size: 207 KiB |
@@ -0,0 +1,382 @@
|
||||
import { useRef, useState } from "react";
|
||||
import {
|
||||
dubaiMarinaDescription,
|
||||
dubaiMarinaFeatures,
|
||||
dubaiMarinaSlider,
|
||||
dubaiMarinaDescriptionBadges,
|
||||
sliderBadgesCategory,
|
||||
} from "../data/aboutDubaiMarina";
|
||||
import {
|
||||
AnimatePresence,
|
||||
motion,
|
||||
useInView,
|
||||
useScroll,
|
||||
useTransform,
|
||||
} from "motion/react";
|
||||
import useWindowSize from "../hooks/useWindowSize";
|
||||
import TextBox from "./ui/TextBox";
|
||||
import SliderMobile from "./SliderMobile";
|
||||
import clsx from "clsx";
|
||||
import Slider from "./Slider";
|
||||
import PlusIcon from "./icons/map/PlusIcon";
|
||||
import EqualIcon from "./icons/EqualIcon";
|
||||
import FullScreenButton from "./FullScreenButton";
|
||||
|
||||
function AboutDubaiMarina() {
|
||||
const containerRef = useRef(null);
|
||||
const sliderRef = useRef(null);
|
||||
const mapRef = useRef(null);
|
||||
const { width } = useWindowSize();
|
||||
|
||||
const [selectedCategorySlider, setSelectedCategorySlider] =
|
||||
useState<keyof typeof dubaiMarinaSlider>("Wellness");
|
||||
|
||||
const { scrollYProgress } = useScroll({
|
||||
target: containerRef,
|
||||
offset: ["start start", "end start"],
|
||||
});
|
||||
|
||||
const firstSectionOpacity = useTransform(scrollYProgress, [0, 0.2], [1, 0]);
|
||||
|
||||
const secondSectionY = useTransform(
|
||||
scrollYProgress,
|
||||
[0, 0.4],
|
||||
["100dvh", "0dvh"]
|
||||
);
|
||||
|
||||
const isSliderInView = useInView(sliderRef, {
|
||||
once: true,
|
||||
amount: 0.1,
|
||||
});
|
||||
const isMapInView = useInView(mapRef, {
|
||||
once: true,
|
||||
margin: `0px 0px ${-window.innerHeight / 2}px 0px`,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="relative bg-white" ref={containerRef}>
|
||||
<motion.section
|
||||
className="2xl:h-[calc(100dvh-4.444vw)] w-full bg-white text-black 2xl:fixed top-[4.444vw] left-0 right-0 z-0 max-md:top-[15.556vw]]
|
||||
max-md:bg-[url(/images/about-complex/dubai-marina/tower-mobile.png)] max-md:bg-cover max-md:bg-top max-md:bg-no-repeat max-md:aspect-[360/584]
|
||||
max-2xl:bg-[url(/images/about-complex/dubai-marina/tower-tablet.png)] max-2xl:bg-cover max-2xl:bg-top max-2xl:bg-no-repeat max-2xl:aspect-[768/960]
|
||||
"
|
||||
style={{
|
||||
opacity: width > 1439 ? firstSectionOpacity : 1,
|
||||
}}
|
||||
>
|
||||
<div className="absolute inset-0 2xl:">
|
||||
<img
|
||||
src="/images/about-complex/dubai-marina/tower.jpg"
|
||||
alt="dubai marina about"
|
||||
className="h-full w-full object-contain object-bottom max-2xl:hidden"
|
||||
/>
|
||||
<img
|
||||
src="/images/about-complex/dubai-marina/logo.png"
|
||||
alt="dubai marina about"
|
||||
className="absolute top-[5vw] right-[2.778vw] w-[9.931vw] h-[4.444vw] max-md:top-[6.667vw] max-md:right-[4.444vw] max-md:w-[21.389vw] max-md:h-[9.444vw] max-2xl:w-[18.62vw] max-2xl:h-[8.333vw]"
|
||||
/>
|
||||
</div>
|
||||
<div className="relative h-full flex flex-col justify-between 2xl:gap-[4.444vw] flex-1 w-full pt-[5vw] pb-[2.5vw] pl-[2.222vw] max-md:px-[4.444vw] max-md:block ">
|
||||
<div className="font-bold whitespace-pre-line space-y-8 max-md:space-y-4">
|
||||
<h1 className="text-[5vw] leading-none tracking-[-0.07em] font-mixcase-unmixed font-[500] max-md:text-[8.889vw] max-2xl:text-[9.375vw]">
|
||||
{`Rove Home
|
||||
Dubai Marina`}
|
||||
</h1>
|
||||
<div className="space-y-2 font-[400]">
|
||||
{dubaiMarinaDescriptionBadges.map((description) => (
|
||||
<TextBox text={description} key={description} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-8 max-md:hidden">
|
||||
<h4 className="text-h4 text-[#00BED7] font-[500] whitespace-pre-line">
|
||||
{`Own the last slice of
|
||||
Dubai Marina, ROVE Style`}
|
||||
</h4>
|
||||
<p className="text-s text-[#0D1922B2] max-md:whitespace-pre-line min-2xl:whitespace-pre-line max-2xl:w-[34vw]">
|
||||
{`With an extended playlist of life-enhancing
|
||||
amenities, Rove Home is a complete ecosystem
|
||||
that has everything you'll ever need.`}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.section>
|
||||
<motion.section
|
||||
className="w-full text-white bg-white flex justify-center max-md:top-0 max-md:overflow-x-clip"
|
||||
style={{
|
||||
y: width > 1439 ? secondSectionY : 0,
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<div className="w-full min-md:overflow-x-hidden">
|
||||
<div className="flex flex-col items-center gap-[2.222vw] w-full max-md:py-[8.889vw] max-md:px-[4.444vw] max-2xl:p-6">
|
||||
<div className="space-y-8 min-md:hidden self-start">
|
||||
<h4 className="text-h4 text-[#00BED7] font-[500] whitespace-pre-line">
|
||||
{`Own the last slice of Dubai
|
||||
Marina, ROVE Style`}
|
||||
</h4>
|
||||
<p className="text-s text-[#0D1922B2] whitespace-pre-line ">
|
||||
{`With an extended playlist of life-enhancing
|
||||
amenities, Rove Home is a complete ecosystem
|
||||
that has everything you'll ever need.`}
|
||||
</p>
|
||||
</div>
|
||||
<div className="2xl:px-[2.222vw] flex pt-[7.222vw] flex-col items-center gap-[2.222vw] max-md:pt-[17.778vw]">
|
||||
<h1 className="text-[3.889vw] text-[#0D1922] font-mixcase-unmixed max-md:text-[6.667vw] max-2xl:text-[7.682vw]">
|
||||
Rove Home has it all
|
||||
</h1>
|
||||
<p className="text-s text-[#0D1922B2] text-center tracking-[-0.02em] whitespace-pre-line">
|
||||
{`Rove Home Dubai Marina features modern-day
|
||||
conveniences, carefully curated for an active
|
||||
and social lifestyle.`}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className="flex gap-[0.556vw] mt-[0.833vw] 2xl:h-[26.667vw] max-md:pl-[4.444vw] max-md:pr-[2vw] max-md:gap-[2.222vw] max-md:snap-x max-md:snap-mandatory max-md:py-[6.667vw] max-md:overflow-x-auto max-md:self-start max-md:w-screen max-md:-ml-[4.444vw] max-md:flex-nowrap max-md:justify-start
|
||||
max-2xl:flex-wrap max-2xl:justify-center"
|
||||
>
|
||||
{dubaiMarinaFeatures.map((feature) => (
|
||||
<div
|
||||
key={feature.name}
|
||||
className={`rounded-3xl 2xl:flex-1 2xl:h-[26.667vw] w-full flex flex-col items-center py-[1.667vw] justify-end bg-cover bg-center bg-no-repeat relative before:absolute before:inset-0 before:bg-[#0D1922]/10 before:z-1 before:rounded-3xl
|
||||
max-2xl:w-[30.208vw] max-2xl:h-[41.146vw] max-2xl:flex-wrap
|
||||
max-md:w-[91.111vw] max-md:h-[79.722vw] max-md:flex-none aspect-[268/384] max-md:aspect-[328/287] max-md:snap-alwaysa max-md:snap-center max-md:py-[4.444vw]
|
||||
`}
|
||||
style={{
|
||||
backgroundImage: `url(${feature.image})`,
|
||||
}}
|
||||
>
|
||||
<h5 className="text-h5 text-white tracking-[-0.02em] z-2">
|
||||
{feature.name}
|
||||
</h5>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center pt-[4.444vw] px-8 gap-[4.444vw] max-md:px-[4.444vw] max-2xl:pr-[3.125vw] max-2xl:-mr-[3.125vw] max-2xl:p-6 max-2xl:items-start max-2xl:gap-[4.167vw]">
|
||||
<h1 className="font-mixcase-unmixed 2xl:text-[3.889vw] text-[#0D1922] tracking-[-0.05em] max-md:text-2xl max-2xl:text-[7.292vw] max-2xl:self-center">
|
||||
Dubai, <span className="text-[#0D192266]">within reach</span>
|
||||
</h1>
|
||||
<SliderMobile />
|
||||
<div
|
||||
className="z-1 flex w-full text-[#0D1922]/40 gap-[1.111vw] max-md:hidden
|
||||
max-2xl:overflow-x-auto max-2xl:self-start max-2xl:snap-x max-2xl:snap-mandatory
|
||||
max-2xl:[scrollbar-width:none] max-2xl:mt-[4.167vw]"
|
||||
>
|
||||
{dubaiMarinaDescription.map((descriptionItem) => (
|
||||
<div
|
||||
key={descriptionItem.title}
|
||||
className="2xl:flex-1 text-center flex flex-col gap-[1.111vw] cursor-pointer hover:text-[#0D1922B2] transition-all duration-200
|
||||
max-2xl:w-[45.833vw] max-2xl:h-[12.76vw] max-2xl:shrink-0"
|
||||
onClick={() =>
|
||||
setSelectedCategorySlider(descriptionItem.title)
|
||||
}
|
||||
>
|
||||
<div className="h-[2px] bg-gray-300 w-full"></div>
|
||||
<h5
|
||||
className={clsx(
|
||||
"text-h5 tracking-[-0.02em] mt-[0.556vw] font-[500]",
|
||||
descriptionItem.title === selectedCategorySlider &&
|
||||
"text-[#00BED7]"
|
||||
)}
|
||||
>
|
||||
{descriptionItem.title}
|
||||
</h5>
|
||||
<p
|
||||
className={clsx(
|
||||
"text-s leading-[125%] tracking-[-0.02em] w-[16.389vw] self-center max-2xl:w-[30.729vw] ",
|
||||
descriptionItem.title === selectedCategorySlider &&
|
||||
"text-[#0D1922]"
|
||||
)}
|
||||
>
|
||||
{descriptionItem.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<AnimatePresence mode="wait">
|
||||
<div
|
||||
ref={sliderRef}
|
||||
className="flex flex-col gap-8 max-md:hidden"
|
||||
>
|
||||
<motion.div
|
||||
key={`slider-${selectedCategorySlider}`}
|
||||
initial={{ opacity: 0, y: 40 }}
|
||||
animate={
|
||||
isSliderInView
|
||||
? { opacity: 1, y: 0 }
|
||||
: { opacity: 0, y: 140 }
|
||||
}
|
||||
exit={{ opacity: 0, y: -40 }}
|
||||
transition={{ duration: 0.6, ease: "easeIn" }}
|
||||
>
|
||||
<Slider categoryName={selectedCategorySlider} />
|
||||
</motion.div>
|
||||
<motion.div
|
||||
key={`badges-${selectedCategorySlider}`}
|
||||
className="flex gap-[0.556vw] w-[63.333vw] flex-wrap justify-center max-2xl:w-[93.75vw]"
|
||||
>
|
||||
{sliderBadgesCategory[selectedCategorySlider].map(
|
||||
(badgeItem, index) => (
|
||||
<motion.div
|
||||
key={badgeItem}
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{
|
||||
duration: 0.3,
|
||||
delay: index * 0.1,
|
||||
ease: "easeOut",
|
||||
}}
|
||||
>
|
||||
<TextBox text={badgeItem} />
|
||||
</motion.div>
|
||||
)
|
||||
)}
|
||||
</motion.div>
|
||||
</div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
<div className="text-center w-full flex flex-col items-center gap-[2.222vw] bg-white max-md:gap-[6.667vw] max-2xl:gap-[3.125vw]">
|
||||
<h1 className="font-mixcase-unmixed text-[3.889vw] text-[#0D1922] w-[44.861vw] leading-[100%] tracking-[-0.05em] pt-[8.056vw] max-md:text-[6.667vw] max-md:w-full max-2xl:text-[7.292vw] max-2xl:w-[84.115vw]">
|
||||
Dubai's first-ever combinable Apartments
|
||||
</h1>
|
||||
<span className="max-2xl:mt-[1.042vw]">
|
||||
<TextBox text="On-demand" />
|
||||
</span>
|
||||
<p className="text-s text-[#0D1922B2] leading-[140%] tracking-[-0.02em] whitespace-pre-line">
|
||||
{`Enjoy the option to combine 2 apartments and create
|
||||
a larger space and configuration.`}
|
||||
</p>
|
||||
<div className="flex gap-4 relative max-md:flex-col max-md:gap-[2.222vw] max-md:w-full max-md:px-[4.444vw] max-2xl:mt-[7.292vw]">
|
||||
<div
|
||||
className="w-[19.028vw] text-[#0D1922] h-[27.778vw] p-[1.667vw] rounded-2xl bg-[#F3F3F2] text-left bg-[url(/images/about-complex/dubai-marina/studio.png)] bg-[length:7.778vw_17.847vw] bg-no-repeat bg-center
|
||||
max-md:w-full max-md:h-[75.556vw] max-md:bg-[length:25.556vw_58.333vw] max-md:p-[4.444vw] max-2xl:w-[25.521vw] max-2xl:h-[34.375vw]"
|
||||
>
|
||||
<h4 className="text-h4 tracking-[-0.02em] font-[500] max-md:text-h5">
|
||||
Studio²
|
||||
</h4>
|
||||
</div>
|
||||
<div
|
||||
className="w-10 h-10 rounded-full bg-[#0D1922] flex items-center justify-center absolute left-[18.500vw] self-center
|
||||
max-md:top-[71.111vw] max-md:left-[45vw] max-2xl:top-[14.583vw] max-2xl:left-[24vw]"
|
||||
>
|
||||
<span className="w-5 h-5">
|
||||
<PlusIcon />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="w-[19.028vw] text-[#0D1922] h-[27.778vw] p-6 rounded-2xl bg-[#F3F3F2] text-left bg-[url(/images/about-complex/dubai-marina/studio.png)] bg-[length:7.778vw_17.847vw] bg-no-repeat bg-center
|
||||
max-md:w-full max-md:h-[75.556vw] max-md:bg-[length:25.556vw_58.333vw] max-md:p-[4.444vw] max-2xl:w-[25.521vw] max-2xl:h-[34.375vw]"
|
||||
>
|
||||
<h4 className="text-h4 tracking-[-0.02em] font-[500] max-md:text-h5">
|
||||
Studio²
|
||||
</h4>
|
||||
</div>
|
||||
<div
|
||||
className="w-10 h-10 rounded-full bg-[#0D1922] flex items-center justify-center absolute left-[38.333vw] self-center
|
||||
max-md:top-[148.611vw] max-md:left-[45vw] max-2xl:top-[14.583vw] max-2xl:left-[52vw]"
|
||||
>
|
||||
<span className="w-5 h-5">
|
||||
<EqualIcon />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="w-[30.972vw] text-[#0D1922] h-[27.778vw] p-6 rounded-2xl bg-[#F3F3F2] text-left bg-[url(/images/about-complex/dubai-marina/1_bedroom.png)] bg-[length:15.972vw_17.847vw] bg-no-repeat bg-center
|
||||
max-md:w-full max-md:h-[111.111vw] max-md:bg-[length:63.889vw_71.389vw] max-md:p-[4.444vw] max-2xl:w-[40.625vw] max-2xl:h-[34.375vw]"
|
||||
>
|
||||
<h4 className="text-h4 tracking-[-0.02em] font-[500] max-md:text-h5">
|
||||
1 Bedroom²
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
<h5 className="2xl:hidden text-h5 text-[#0D1922B2] max-2xl:hidden">
|
||||
or
|
||||
</h5>
|
||||
<div className="flex gap-4 relative max-md:flex-col max-md:gap-[2.222vw] max-md:w-full max-md:px-[4.444vw]">
|
||||
<div
|
||||
className="w-[19.028vw] text-[#0D1922] h-[27.778vw] p-6 rounded-2xl bg-[#F3F3F2] text-left bg-[url(/images/about-complex/dubai-marina/2_studio.png)] bg-[length:13.125vw_17.847vw] bg-no-repeat bg-center
|
||||
max-md:w-full max-md:h-[75.556vw] max-md:bg-[length:38.889vw_52.5vw] max-md:p-[4.444vw] max-2xl:w-[25.521vw] max-2xl:h-[34.375vw]"
|
||||
>
|
||||
<h4 className="text-h4 tracking-[-0.02em] font-[500] max-md:text-h5">
|
||||
Studio²
|
||||
</h4>
|
||||
</div>
|
||||
<div
|
||||
className="w-10 h-10 rounded-full bg-[#0D1922] flex items-center justify-center absolute left-[18.500vw] self-center
|
||||
max-md:top-[71.111vw] max-md:left-[45vw] max-2xl:top-[14.583vw] max-2xl:left-[24vw]"
|
||||
>
|
||||
<span className="w-5 h-5">
|
||||
<PlusIcon />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="w-[30.972vw] text-[#0D1922] h-[27.778vw] p-6 rounded-2xl bg-[#F3F3F2] text-left bg-[url(/images/about-complex/dubai-marina/1_bedroom_rotated.png)] bg-[length:17.847vw_13.681vw] bg-no-repeat bg-center
|
||||
max-md:w-full max-md:h-[75.556vw] max-md:bg-[length:56.111vw_43.056vw] max-md:p-[4.444vw] max-2xl:w-[33.073vw] max-2xl:h-[34.375vw]"
|
||||
>
|
||||
<h4 className="text-h4 tracking-[-0.02em] font-[500] max-md:text-h5">
|
||||
1 Bedroom²
|
||||
</h4>
|
||||
</div>
|
||||
<div
|
||||
className="w-10 h-10 rounded-full bg-[#0D1922] flex items-center justify-center absolute left-[50.300vw] self-center
|
||||
max-md:top-[148.611vw] max-md:left-[45vw] max-2xl:top-[14.583vw] max-2xl:left-[59vw]"
|
||||
>
|
||||
<span className="w-5 h-5">
|
||||
<EqualIcon />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="w-[30.972vw] text-[#0D1922] h-[27.778vw] p-6 rounded-2xl bg-[#F3F3F2] text-left bg-[url(/images/about-complex/dubai-marina/2_bedroom.png)] bg-[length:19.028vw_17.847vw] bg-no-repeat bg-center
|
||||
max-md:w-full max-md:h-[111.111vw] max-md:bg-[length:76.267vw_71.389vw] max-md:p-[4.444vw] max-2xl:w-[33.073vw] max-2xl:h-[34.375vw]"
|
||||
>
|
||||
<h4 className="text-h4 tracking-[-0.02em] font-[500] max-md:text-h5">
|
||||
2 Bedroom²
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-[2.222vw] bg-white px-[2.222vw] pb-[8.333vw] max-md:gap-[6.667vw] max-md:px-[4.444vw] max-2xl:gap-[4.167vw]">
|
||||
<h1
|
||||
className="font-mixcase-unmixed text-[3.889vw] text-[#0D1922] w-[44.861vw] leading-[100%] tracking-[-0.05em] pt-[7.222vw] text-center
|
||||
max-md:text-[6.667vw] max-md:w-full max-2xl:text-[7.292vw] max-2xl:w-[84.115vw]"
|
||||
>
|
||||
Live central. Live centred
|
||||
</h1>
|
||||
<p className="text-s text-[#0D1922B2] leading-[140%] tracking-[-0.02em] text-center 2xl:whitespace-pre-line max-2xl:w-[66.146vw]">
|
||||
{`Located in the heart of Dubai Marina, Rove Home Dubai Marina is where active
|
||||
living meets modern convenience. Enjoy an energetic lifestyle surrounded by
|
||||
trendy cafés, shops, and entertainment options – all within reach.`}
|
||||
</p>
|
||||
<motion.img
|
||||
ref={mapRef}
|
||||
src="/images/about-complex/dubai-marina/central_map.png"
|
||||
alt="central map"
|
||||
className="rounded-3xl object-cover object-center aspect-[1376/609] max-md:hidden max-2xl:w-[93.75vw] max-2xl:h-[89.583vw] max-2xl:aspect-[720/688] max-2xl:mt-[1.563vw]"
|
||||
initial={{ width: "47.083vw" }}
|
||||
animate={
|
||||
isMapInView ? { width: "95.556vw" } : { width: "47.083vw" }
|
||||
}
|
||||
transition={{ duration: 0.6, ease: "easeInOut" }}
|
||||
/>
|
||||
<div className="min-md:hidden relative w-[89.167vw] aspect-square overflow-hidden rounded-2xl">
|
||||
<img
|
||||
src="/images/about-complex/dubai-marina/central_map.png"
|
||||
alt="central map"
|
||||
className="w-full h-full object-cover object-center scale-120"
|
||||
/>
|
||||
<div className="absolute bottom-[1.111vw] right-[1.111vw] w-[11.111vw] h-[11.111vw]">
|
||||
<FullScreenButton
|
||||
isFullScreen={false}
|
||||
onClick={() => {}}
|
||||
onFullScreenChange={() => {}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AboutDubaiMarina;
|
||||
@@ -0,0 +1,165 @@
|
||||
import {
|
||||
marasiDriveFeatures,
|
||||
marasiDriveDescriptionBadges,
|
||||
marasiDriveExpandable,
|
||||
} from "../data/aboutMarasiDrive";
|
||||
import MarariDriveNeighboursSlider from "./MarasiDriveNeighboursSlider";
|
||||
import MarasiDriveInteriorsSlider from "./MarasiDriveInteriorsSlider";
|
||||
import TextBox from "./ui/TextBox";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useScroll } from "motion/react";
|
||||
|
||||
function AboutMarasiDrive() {
|
||||
const target = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { scrollYProgress } = useScroll({
|
||||
target,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
scrollYProgress.on("change", (latest) => {
|
||||
console.log(latest);
|
||||
});
|
||||
}, [scrollYProgress]);
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<section className="sticky top-[4.444vw] w-full bg-white bg-[url(/images/about-complex/marasi-drive/tower.png)] bg-cover h-[calc(100dvh-4.444vw)] bg-no-repeat bg-[position:left_13.264vw_top] pl-[2.222vw] pt-[5vw] pb-[2.222vw] flex flex-col justify-between">
|
||||
<div className="space-y-[1.667vw]">
|
||||
<h1 className="text-[5vw] leading-none tracking-[-0.07em] font-mixcase-unmixed font-medium max-md:text-[8.889vw] whitespace-pre-line">
|
||||
{`Rove Home
|
||||
Marasi Drive`}
|
||||
</h1>
|
||||
<div className="space-y-[0.556vw]">
|
||||
{marasiDriveDescriptionBadges.map((description) => (
|
||||
<TextBox text={description} key={description} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-[2.222vw] max-md:hidden">
|
||||
<h4 className="text-h4 text-[#00BED7] font-medium whitespace-pre-line">
|
||||
{`A home for the young
|
||||
and young in heart`}
|
||||
</h4>
|
||||
<p className="text-s text-[#0D1922B2] max-md:whitespace-pre-line min-2xl:whitespace-pre-line">
|
||||
{`The dynamic essence of Rove comes to life at our
|
||||
new location in Marasi Drive, Business Bay. Enjoy
|
||||
an urban living experience beyond the ordinary.`}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<section className="sticky pt-[9.444vw] px-[2.222vw] pb-[5.347vw] flex flex-col gap-[11.667vw] bg-white w-full overflow-clip">
|
||||
<div className="flex flex-col gap-[4.444vw]">
|
||||
<div className="flex flex-col gap-[2.222vw] items-center">
|
||||
<h2 className="font-mixcase-unmixed text-h1 text-center">
|
||||
What makes a Rove Home?
|
||||
</h2>
|
||||
<p className="opacity-70 text-s whitespace-pre-line text-center">
|
||||
{`Experience the difference with Rove Home where modern amenities, trendy
|
||||
interiors, and smart features cater to your unique style. Rove Home is your
|
||||
destination for artful inspiration and cleverly activated spaces.`}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex gap-[0.556vw]">
|
||||
{marasiDriveFeatures.map(({ image, name }) => (
|
||||
<div key={name}>
|
||||
<img
|
||||
src={image}
|
||||
alt={name}
|
||||
className="object-cover rounded-[1.667vw]"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-[4.444vw]">
|
||||
<div className="flex flex-col gap-[2.222vw] items-center">
|
||||
<h2 className="font-mixcase-unmixed text-h1 text-center">
|
||||
Expandable Living Solutions
|
||||
</h2>
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center">
|
||||
{`ORI introduces a revolutionary solution to apartment living,
|
||||
where space is not just a constraint but an opportunity.`}
|
||||
</p>
|
||||
<div className="flex gap-[0.556vw]">
|
||||
{["Simple", "Safe", "Effortless"].map((text) => (
|
||||
<TextBox key={text} text={text} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-[1.111vw]">
|
||||
{marasiDriveExpandable.map((image) => (
|
||||
<div key={image}>
|
||||
<img src={image} alt="Expandable Living Solutions" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col 2xl:gap-[4.444vw]">
|
||||
<div className="flex flex-col 2xl:gap-[2.222vw] items-center">
|
||||
<h2 className="font-mixcase-unmixed text-h1 text-center">
|
||||
Inspired interiors
|
||||
</h2>
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center">
|
||||
{`Smart, flexible designs maximize every inch. The ORI Cloud Bed
|
||||
expands space by 33%, while the Flexibed transforms living areas
|
||||
into bedrooms. Multipurpose layouts adapt effortlessly—blending
|
||||
innovation with modern urban living.`}
|
||||
</p>
|
||||
</div>
|
||||
<MarasiDriveInteriorsSlider />
|
||||
</div>
|
||||
<div className="flex flex-col 2xl:gap-[4.444vw]">
|
||||
<div className="flex flex-col items-center 2xl:gap-[2.222vw]">
|
||||
<h2 className="font-mixcase-unmixed text-h1 text-center whitespace-pre-line">
|
||||
{`A home for the young
|
||||
and young in heart`}
|
||||
</h2>
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center">
|
||||
{`The dynamic essence of Rove comes to life at our new
|
||||
location in Marasi Drive, Business Bay. Enjoy an urban
|
||||
living experience beyond the ordinary.`}
|
||||
</p>
|
||||
</div>
|
||||
<img
|
||||
className="rounded-[1.667vw]"
|
||||
src="/images/about-complex/marasi-drive/buisness_bay.jpg"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div className="h-[calc(27.639vw*3)]" ref={target}>
|
||||
<div className="flex flex-col 2xl:gap-[4.444vw] sticky top-[5vw]">
|
||||
<div className="flex flex-col items-center 2xl:gap-[2.222vw]">
|
||||
<h2 className="font-mixcase-unmixed text-h1 text-center whitespace-pre-line">
|
||||
{`Explore the neighbourhood`}
|
||||
</h2>
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center">
|
||||
{`With Dubai's trendiest spots right at your doorstep, explore nearby
|
||||
entertainment and dining experiences in just 15 minutes. Live your best life
|
||||
at Rove Home Marasi Drive!`}
|
||||
</p>
|
||||
</div>
|
||||
<MarariDriveNeighboursSlider scrollYProgress={scrollYProgress} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-[3.333vw]">
|
||||
<div className="flex flex-col gap-[2.222vw] items-center">
|
||||
<h2 className="text-h1 font-mixcase-unmixed">
|
||||
Rove around the city
|
||||
</h2>
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center">
|
||||
Located in the heart of Dubai Marina, Rove Home Dubai Marina is
|
||||
where active living meets modern convenience. Enjoy an energetic
|
||||
lifestyle surrounded by trendy cafés, shops, and entertainment
|
||||
options – all within reach.
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-6 grid-rows-5 gap-x-[1.111vw] gap-y-[0.556vw]"></div>
|
||||
</div>
|
||||
</section>
|
||||
<section></section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AboutMarasiDrive;
|
||||
@@ -4,8 +4,11 @@ import MoreIcon from "./icons/MoreIcon";
|
||||
import PrivacyPolicyButton from "./PrivacyPolicyButton";
|
||||
import FullScreenButton from "./FullScreenButton";
|
||||
import { useState } from "react";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import CloseIcon from "./icons/CloseIcon";
|
||||
|
||||
function ButtonGroup() {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [isFullScreen, setIsFullScreen] = useState(false);
|
||||
|
||||
async function handleFullScreenClick() {
|
||||
@@ -27,22 +30,35 @@ function ButtonGroup() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="absolute 2xl:bottom-[2.222vw] 2xl:right-[2.222vw] max-w-full flex justify-end items-center 2xl:gap-[0.556vw] gap-2 md:max-2xl:bottom-6 md:max-2xl:right-6 max-md:hidden">
|
||||
<DisclaimerButton />
|
||||
<PrivacyPolicyButton />
|
||||
<FullScreenButton
|
||||
isFullScreen={isFullScreen}
|
||||
onFullScreenChange={setIsFullScreen}
|
||||
onClick={handleFullScreenClick}
|
||||
/>
|
||||
<div className="absolute 2xl:bottom-[2.222vw] 2xl:right-[2.222vw] md:max-2xl:bottom-6 md:max-2xl:right-6 bottom-8 max-md:pb-8 right-4 max-md:overflow-hidden">
|
||||
<AnimatePresence>
|
||||
{(innerWidth >= 768 || expanded) && (
|
||||
<motion.div
|
||||
initial={innerWidth < 768 ? { y: "100%", opacity: 0 } : {}}
|
||||
animate={innerWidth < 768 ? { y: "0%", opacity: 1 } : {}}
|
||||
exit={innerWidth < 768 ? { y: "100%", opacity: 0 } : {}}
|
||||
transition={{ bounce: 0 }}
|
||||
className="max-w-full flex justify-end items-center 2xl:gap-[0.556vw] gap-2 max-md:flex-col"
|
||||
>
|
||||
<DisclaimerButton />
|
||||
<PrivacyPolicyButton />
|
||||
<FullScreenButton
|
||||
isFullScreen={isFullScreen}
|
||||
onFullScreenChange={setIsFullScreen}
|
||||
onClick={handleFullScreenClick}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
<Button
|
||||
onlyIcon
|
||||
variant="secondary"
|
||||
className="absolute md:hidden right-4 bottom-4"
|
||||
onClick={() => setExpanded((prev) => !prev)}
|
||||
>
|
||||
<span className="size-5">
|
||||
<MoreIcon />
|
||||
{expanded ? <CloseIcon /> : <MoreIcon />}
|
||||
</span>
|
||||
</Button>
|
||||
</>
|
||||
|
||||
@@ -8,14 +8,15 @@ export default function BottomButton() {
|
||||
|
||||
return (
|
||||
<Button
|
||||
size="small"
|
||||
onlyIcon={innerWidth < 768}
|
||||
size={innerWidth >= 768 ? "small" : "medium"}
|
||||
variant="secondary"
|
||||
onClick={() => setModal(<DisclaimerModal />)}
|
||||
>
|
||||
<span className="2xl:size-[1.111vw] size-4">
|
||||
<span className="2xl:size-[1.389vw] size-5">
|
||||
<DisclaimerIcon />
|
||||
</span>
|
||||
<span>Disclaimer</span>
|
||||
<span className="max-md:hidden">Disclaimer</span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -36,31 +36,51 @@ function Footer() {
|
||||
<div className="2xl:space-y-[0.833vw] space-y-3 md:max-2xl:col-start-3 max-2xl:col-span-3 md:max-2xl:row-start-3 max-md:row-start-4 max-md:mt-6">
|
||||
<p className="text-s text-[#0D1922]/40">Follow us for more:</p>
|
||||
<div className="flex 2xl:gap-[0.278vw] gap-1">
|
||||
<div className="2xl:p-[0.417vw] p-1.5 bg-[#E2E2DC] 2xl:rounded-[0.278vw] rounded">
|
||||
<Link
|
||||
to={"https://www.youtube.com/@IRTHgroup"}
|
||||
target="_blank"
|
||||
className="2xl:p-[0.417vw] p-1.5 bg-[#E2E2DC] 2xl:rounded-[0.278vw] rounded"
|
||||
>
|
||||
<div className="2xl:w-[2.222vw] 2xl:h-[2.222vw] md:max-2xl:w-8 md:max-2xl:h-8 w-9 h-9 text-[#0D1922]/70">
|
||||
<YoutubeIcon />
|
||||
</div>
|
||||
</div>
|
||||
<div className="2xl:p-[0.417vw] p-1.5 bg-[#E2E2DC] 2xl:rounded-[0.278vw] rounded">
|
||||
</Link>
|
||||
<Link
|
||||
to={"https://www.instagram.com/irth.group"}
|
||||
target="_blank"
|
||||
className="2xl:p-[0.417vw] p-1.5 bg-[#E2E2DC] 2xl:rounded-[0.278vw] rounded"
|
||||
>
|
||||
<div className="2xl:w-[2.222vw] 2xl:h-[2.222vw] md:max-2xl:w-8 md:max-2xl:h-8 w-9 h-9 text-[#0D1922]/70">
|
||||
<InstagramIcon />
|
||||
</div>
|
||||
</div>
|
||||
<div className="2xl:p-[0.417vw] p-1.5 bg-[#E2E2DC] 2xl:rounded-[0.278vw] rounded">
|
||||
</Link>
|
||||
<Link
|
||||
to={"https://www.facebook.com/irth.group"}
|
||||
target="_blank"
|
||||
className="2xl:p-[0.417vw] p-1.5 bg-[#E2E2DC] 2xl:rounded-[0.278vw] rounded"
|
||||
>
|
||||
<div className="2xl:w-[2.222vw] 2xl:h-[2.222vw] md:max-2xl:w-8 md:max-2xl:h-8 w-9 h-9 text-[#0D1922]/70">
|
||||
<FacebookIcon />
|
||||
</div>
|
||||
</div>
|
||||
<div className="2xl:p-[0.417vw] p-1.5 bg-[#E2E2DC] 2xl:rounded-[0.278vw] rounded">
|
||||
</Link>
|
||||
<Link
|
||||
to={"https://www.linkedin.com/company/irth-group-uae"}
|
||||
target="_blank"
|
||||
className="2xl:p-[0.417vw] p-1.5 bg-[#E2E2DC] 2xl:rounded-[0.278vw] rounded"
|
||||
>
|
||||
<div className="2xl:w-[2.222vw] 2xl:h-[2.222vw] md:max-2xl:w-8 md:max-2xl:h-8 w-9 h-9 text-[#0D1922]/70">
|
||||
<LinkedInIcon />
|
||||
</div>
|
||||
</div>
|
||||
<div className="2xl:p-[0.417vw] p-1.5 bg-[#E2E2DC] 2xl:rounded-[0.278vw] rounded">
|
||||
</Link>
|
||||
<Link
|
||||
to={"https://twitter.com/IRTHGroup"}
|
||||
target="_blank"
|
||||
className="2xl:p-[0.417vw] p-1.5 bg-[#E2E2DC] 2xl:rounded-[0.278vw] rounded"
|
||||
>
|
||||
<div className="2xl:w-[2.222vw] 2xl:h-[2.222vw] md:max-2xl:w-8 md:max-2xl:h-8 w-9 h-9 text-[#0D1922]/70">
|
||||
<TwitterIcon />
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -78,7 +98,7 @@ function Footer() {
|
||||
Unit Types
|
||||
</Link>
|
||||
<Link
|
||||
to={"/about-irth"}
|
||||
to={"/about"}
|
||||
className="md:text-btn-l text-btn-m flex-1 content-center md:my-4 my-[13px] text-[#0D1922]/70"
|
||||
>
|
||||
About IRTH
|
||||
@@ -92,7 +112,7 @@ function Footer() {
|
||||
>
|
||||
Favorites
|
||||
{!!favoriteUnits.length && (
|
||||
<div className="absolute top-0 right-0 translate-x-full max-2xl:-translate-y-full rounded-full w-5 flex items-center justify-center aspect-square bg-[#00BED7] text-white text-caption-s font-mono">
|
||||
<div className="absolute top-0 right-0 translate-x-full max-2xl:-translate-y-full rounded-full w-4 flex items-center justify-center aspect-square bg-[#00BED7] text-white text-caption-s font-mono">
|
||||
{favoriteUnits.length}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -30,8 +30,13 @@ function FullScreenButton({
|
||||
if (isMobileSafari) return null;
|
||||
|
||||
return (
|
||||
<Button onlyIcon size="small" variant="secondary" onClick={handleClick}>
|
||||
<span className="2xl:size-[1.111vw] size-4">
|
||||
<Button
|
||||
onlyIcon
|
||||
size={innerWidth >= 768 ? "small" : "medium"}
|
||||
variant="secondary"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<span className="2xl:size-[1.389vw] size-5">
|
||||
{isFullScreen ? <CloseFullscreenIcon /> : <FullScreenIcon />}
|
||||
</span>
|
||||
</Button>
|
||||
|
||||
@@ -249,7 +249,7 @@ function NavItem({ href, title }: { href: string; title: string }) {
|
||||
>
|
||||
{title}
|
||||
{title === "Favorites" && !!favoriteUnits.length && (
|
||||
<div className="absolute 2xl:top-1.5 2xl:right-1.5 top-1.5 right-1.5 rounded-full min-w-5 min-h-5 flex items-center justify-center aspect-square bg-[#00BED7] text-white text-caption-s text-center font-mono">
|
||||
<div className="absolute top-1 right-1 rounded-full min-w-4 min-h-4 flex items-center justify-center aspect-square bg-[#00BED7] text-white text-caption-s text-center font-mono">
|
||||
{favoriteUnits.length}
|
||||
</div>
|
||||
)}
|
||||
@@ -257,17 +257,6 @@ function NavItem({ href, title }: { href: string; title: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
// function ProfileBar() {
|
||||
// return (
|
||||
// <Button
|
||||
// variant="secondary"
|
||||
// className="2xl:mr-[2.222vw] mr-4 text-[#0D1922]/70 !bg-[#F3F3F2]"
|
||||
// >
|
||||
// Login
|
||||
// </Button>
|
||||
// );
|
||||
// }
|
||||
|
||||
function BrochuresDropdown() {
|
||||
const [opened, setOpened] = useState(false);
|
||||
|
||||
@@ -293,6 +282,7 @@ function BrochuresDropdown() {
|
||||
<AnimatePresence>
|
||||
{opened && (
|
||||
<motion.div
|
||||
key={"menu"}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
|
||||
@@ -13,7 +13,6 @@ import Compass from "./Compass";
|
||||
import { getWeather } from "../api/weather";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import useWindowSize from "../hooks/useWindowSize";
|
||||
import TouchIcon from "./icons/map/TouchIcon";
|
||||
import SelectedComplexCard from "./SelectedComplexCard";
|
||||
import ButtonGroup from "./ButtonGroup";
|
||||
|
||||
@@ -181,8 +180,8 @@ function Map({ maxZoom = 1 }: MapProps) {
|
||||
|
||||
setZoom(newMinZoom);
|
||||
|
||||
const scaledWidth = originalSize.width * zoom;
|
||||
const scaledHeight = originalSize.height * zoom;
|
||||
const scaledWidth = originalSize.width * newMinZoom;
|
||||
const scaledHeight = originalSize.height * newMinZoom;
|
||||
|
||||
const maxOffsetX = Math.max(0, scaledWidth - width);
|
||||
const maxOffsetY = Math.max(0, scaledHeight - height);
|
||||
@@ -199,11 +198,23 @@ function Map({ maxZoom = 1 }: MapProps) {
|
||||
});
|
||||
};
|
||||
|
||||
// Обработчик изменения полноэкранного режима
|
||||
const handleFullscreenChange = () => {
|
||||
// Увеличенная задержка для полного применения изменений размера экрана на мобильных
|
||||
setTimeout(() => {
|
||||
updateContainerSize();
|
||||
}, 200);
|
||||
};
|
||||
|
||||
updateContainerSize();
|
||||
|
||||
window.addEventListener("resize", updateContainerSize);
|
||||
document.addEventListener("fullscreenchange", handleFullscreenChange);
|
||||
|
||||
return () => window.removeEventListener("resize", updateContainerSize);
|
||||
return () => {
|
||||
window.removeEventListener("resize", updateContainerSize);
|
||||
document.removeEventListener("fullscreenchange", handleFullscreenChange);
|
||||
};
|
||||
}, [originalSize, zoom]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -524,7 +535,8 @@ function Map({ maxZoom = 1 }: MapProps) {
|
||||
lastTimestamp = now;
|
||||
setCloudOffset((prev) => {
|
||||
let next = prev + windSpeed * delta;
|
||||
if (cloudImageWidth > 0 && next > 0) next -= cloudImageWidth;
|
||||
if (cloudImageWidth > 0 && (next > 0 || prev > 0))
|
||||
next -= cloudImageWidth;
|
||||
return next;
|
||||
});
|
||||
cloudAnimationRef.current = requestAnimationFrame(animateClouds);
|
||||
@@ -557,7 +569,7 @@ function Map({ maxZoom = 1 }: MapProps) {
|
||||
<img
|
||||
ref={mapRef}
|
||||
src={`/images/map/map-new-${
|
||||
containerRef.current.clientWidth < 1440 ? "mobile" : "desktop"
|
||||
containerRef.current.clientWidth < 1440 ? "mobile-fhd" : "desktop"
|
||||
}.jpg`}
|
||||
alt="map"
|
||||
className={clsx(
|
||||
@@ -572,7 +584,7 @@ function Map({ maxZoom = 1 }: MapProps) {
|
||||
)}
|
||||
<div
|
||||
className={clsx(
|
||||
"pointer-events-none absolute max-w-none transition-opacity duration-300 bg-black",
|
||||
"pointer-events-none absolute max-w-none transition-opacity duration-300 bg-black will-change-[transform,opacity]",
|
||||
hoveredMarker ? "opacity-20" : "opacity-0"
|
||||
)}
|
||||
style={imageStyle}
|
||||
@@ -581,7 +593,7 @@ function Map({ maxZoom = 1 }: MapProps) {
|
||||
style={cloudStyle}
|
||||
ref={cloudsRef}
|
||||
className={clsx(
|
||||
`absolute inset-0 pointer-events-none transition-[opacity] will-change-[opacity,scale,transform]`,
|
||||
`absolute inset-0 pointer-events-none transition-[opacity] will-change-[opacity,scale,transform,opacity]`,
|
||||
hoveredMarker && "opacity-80"
|
||||
)}
|
||||
>
|
||||
@@ -590,18 +602,20 @@ function Map({ maxZoom = 1 }: MapProps) {
|
||||
style={{
|
||||
rotate: `${90 + windDirection}deg`,
|
||||
transform: `translateX(${cloudOffset}px) translateZ(0px)`,
|
||||
transformOrigin: "0 0",
|
||||
// transformOrigin: "0 0",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
className="flex-1 w-full"
|
||||
ref={cloudImgRef}
|
||||
src={`/images/map/clouds-${
|
||||
windowWidth < 1440 ? "mobile" : "desktop"
|
||||
windowWidth < 1440 ? "mobile-fhd" : "desktop"
|
||||
}.png`}
|
||||
/>
|
||||
<img
|
||||
className="flex-1 w-full"
|
||||
src={`/images/map/clouds-${
|
||||
windowWidth < 1440 ? "mobile" : "desktop"
|
||||
windowWidth < 1440 ? "mobile-fhd" : "desktop"
|
||||
}.png`}
|
||||
/>
|
||||
</div>
|
||||
@@ -621,46 +635,30 @@ function Map({ maxZoom = 1 }: MapProps) {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<WeatherWidget temperature={temperature} />
|
||||
{!!temperature && <WeatherWidget temperature={temperature} />}
|
||||
<AnimatePresence>
|
||||
{isShowInstruction &&
|
||||
(isMobile ? (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="absolute left-1/2 -translate-x-1/2 top-1/2 backdrop-blur-sm -translate-y-1/2 pointer-events-none will-change-[opacity] bg-[#0D1922]/40 2xl:rounded-[0.556vw] rounded-lg 2xl:space-y-[0.833vw] space-y-3 2xl:p-[1.111vw] p-4 text-white"
|
||||
>
|
||||
<div className="flex items-center justify-center gap-4">
|
||||
<span className="2xl:size-[3.333vw] size-12">
|
||||
<MoveIcon />
|
||||
</span>
|
||||
<div className="w-px 2xl:h-[1.111vw] h-4 bg-white" />
|
||||
<span className="2xl:size-[3.333vw] size-12">
|
||||
<TouchIcon />
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-s text-center">Tap to move</p>
|
||||
</motion.div>
|
||||
) : (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="absolute pointer-events-none left-1/2 -translate-x-1/2 top-1/2 -translate-y-1/2 backdrop-blur-sm bg-[#0D1922]/40 2xl:rounded-[0.556vw] rounded-lg 2xl:space-y-[0.833vw] space-y-3 2xl:p-[1.111vw] p-4 text-white"
|
||||
>
|
||||
<div className="flex items-center justify-center gap-4">
|
||||
<span className="2xl:size-[3.333vw] size-12">
|
||||
<SearchIcon />
|
||||
</span>
|
||||
<div className="w-px 2xl:h-[1.111vw] h-4 bg-white" />
|
||||
<span className="2xl:size-[3.333vw] size-12">
|
||||
<MoveIcon />
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-s">Zoom and Move to select a location</p>
|
||||
</motion.div>
|
||||
))}
|
||||
{isShowInstruction && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="absolute pointer-events-none left-1/2 -translate-x-1/2 top-1/2 -translate-y-1/2 backdrop-blur-md bg-[#0D1922]/40 2xl:rounded-[1.111vw] rounded-2xl 2xl:space-y-[0.833vw] space-y-3 2xl:px-[1.667vw] 2xl:py-[1.111vw] px-6 py-4 text-white 2xl:max-w-[13.611vw] max-w-[196px] w-full"
|
||||
>
|
||||
<div className="flex items-center justify-center 2xl:gap-[1.111vw] gap-4">
|
||||
<span className="2xl:size-[3.333vw] size-12">
|
||||
<SearchIcon />
|
||||
</span>
|
||||
<span className="2xl:size-[3.333vw] size-12">
|
||||
<MoveIcon />
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-s text-center">
|
||||
<span>Zoom and Move to</span>
|
||||
<br />
|
||||
<span>select a location</span>
|
||||
</p>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
<ButtonGroup />
|
||||
<Compass />
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import { useState } from "react";
|
||||
import { marasiDriveInspiredInteriors } from "../data/aboutMarasiDrive";
|
||||
import clsx from "clsx";
|
||||
import Button from "./ui/Button";
|
||||
import ChevronLeftIcon from "./icons/ChevronLeftIcon";
|
||||
import ChevronRightIcon from "./icons/ChevronRightIcon";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import { useSwipeable } from "react-swipeable";
|
||||
|
||||
function MarasiDriveInteriorsSlider() {
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
|
||||
const handlers = useSwipeable({
|
||||
onSwipedLeft: () =>
|
||||
setCurrentIndex(
|
||||
Math.min(currentIndex + 1, marasiDriveInspiredInteriors.length - 1)
|
||||
),
|
||||
onSwipedRight: () => setCurrentIndex(Math.max(currentIndex - 1, 0)),
|
||||
preventScrollOnSwipe: true,
|
||||
touchEventOptions: {
|
||||
passive: false,
|
||||
},
|
||||
trackMouse: true,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="relative" {...handlers}>
|
||||
<motion.div
|
||||
className="flex items-center gap-[6.667vw] min-h-[38.333vw]"
|
||||
animate={{
|
||||
transform: `translateX(calc(5vw - ${currentIndex - 1} * 27.222vw))`,
|
||||
}}
|
||||
>
|
||||
<AnimatePresence>
|
||||
{marasiDriveInspiredInteriors.map(({ image, name }, index) => (
|
||||
<motion.div
|
||||
animate={{
|
||||
width: index === currentIndex ? "31.111vw" : "20.556vw",
|
||||
}}
|
||||
exit={{
|
||||
width: index !== currentIndex ? "31.111vw" : "20.556vw",
|
||||
}}
|
||||
key={name}
|
||||
className="shrink-0"
|
||||
>
|
||||
<motion.img
|
||||
src={image}
|
||||
alt={name}
|
||||
className="object-cover rounded-[1.667vw] pointer-events-none"
|
||||
animate={{
|
||||
marginBottom: index !== currentIndex ? "1.667vw" : "2.222vw",
|
||||
}}
|
||||
onClick={() => setCurrentIndex(index)}
|
||||
/>
|
||||
<p
|
||||
className={clsx(
|
||||
"text-h4 text-center font-medium",
|
||||
index !== currentIndex && "opacity-40"
|
||||
)}
|
||||
>
|
||||
{name}
|
||||
</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
</motion.div>
|
||||
<Button
|
||||
onlyIcon
|
||||
disabled={currentIndex === 0}
|
||||
onClick={() => setCurrentIndex(Math.max(currentIndex - 1, 0))}
|
||||
className="!bg-[#F3F3F2] absolute 2xl:left-[27.778vw] top-1/2 -translate-y-1/2"
|
||||
>
|
||||
<span className="2xl:size-[1.389vw] size-5 text-[#0D1922]">
|
||||
<ChevronLeftIcon />
|
||||
</span>
|
||||
</Button>
|
||||
<Button
|
||||
onlyIcon
|
||||
disabled={currentIndex === marasiDriveInspiredInteriors.length - 1}
|
||||
className="!bg-[#F3F3F2] absolute 2xl:right-[27.778vw] top-1/2 -translate-y-1/2"
|
||||
onClick={() =>
|
||||
setCurrentIndex(
|
||||
Math.min(currentIndex + 1, marasiDriveInspiredInteriors.length - 1)
|
||||
)
|
||||
}
|
||||
>
|
||||
<span className="2xl:size-[1.389vw] size-5 text-[#0D1922]">
|
||||
<ChevronRightIcon />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default MarasiDriveInteriorsSlider;
|
||||
@@ -0,0 +1,31 @@
|
||||
function MarasiDriveMapCard({
|
||||
title,
|
||||
mins,
|
||||
image,
|
||||
className,
|
||||
}: {
|
||||
title: string;
|
||||
mins: number;
|
||||
image: string;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={`rounded-[1.667vw] px-[0.833vw] py-[1.111vw] bg-[#F3F3F2] flex flex-col gap-[0.556vw]${
|
||||
className ? " " + className : ""
|
||||
}`}
|
||||
>
|
||||
<div className="space-y-[0.278vw]">
|
||||
<p className="text-m">{title}</p>
|
||||
<p className="text-s text-[#73787C]">{`${mins} mins`}</p>
|
||||
</div>
|
||||
<img
|
||||
src={image}
|
||||
className="rounded-[0.278vw] size-[3.333vw] object-cover self-end"
|
||||
alt={title}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MarasiDriveMapCard;
|
||||
@@ -0,0 +1,69 @@
|
||||
import {
|
||||
AnimatePresence,
|
||||
motion,
|
||||
MotionValue,
|
||||
useTransform,
|
||||
} from "motion/react";
|
||||
import { marasiDriveNeighbours } from "../data/aboutMarasiDrive";
|
||||
|
||||
function MarariDriveNeighboursSlider({
|
||||
scrollYProgress,
|
||||
}: {
|
||||
scrollYProgress: MotionValue<number>;
|
||||
}) {
|
||||
const x = useTransform(
|
||||
scrollYProgress,
|
||||
[0, 1 / 3, 2 / 3],
|
||||
["4.236vw", "-20.868vw", "-45.972vw"]
|
||||
);
|
||||
|
||||
const width1 = useTransform(
|
||||
scrollYProgress,
|
||||
[0, 1 / 3, 2 / 3],
|
||||
["20.139vw", "20.139vw", "20.139vw"]
|
||||
);
|
||||
|
||||
const width2 = useTransform(
|
||||
scrollYProgress,
|
||||
[0, 1 / 3, 2 / 3],
|
||||
["36.944vw", "20.139vw", "20.139vw"]
|
||||
);
|
||||
|
||||
const width3 = useTransform(
|
||||
scrollYProgress,
|
||||
[0, 1 / 3, 2 / 3],
|
||||
["20.139vw", "36.944vw", "20.139vw"]
|
||||
);
|
||||
|
||||
const width4 = useTransform(
|
||||
scrollYProgress,
|
||||
[0, 1 / 3, 2 / 3],
|
||||
["20.139vw", "20.139vw", "36.944vw"]
|
||||
);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className="flex items-center 2xl:gap-[4.965vw] min-h-[27.639vw]"
|
||||
style={{ x }}
|
||||
>
|
||||
<AnimatePresence>
|
||||
{marasiDriveNeighbours.map(({ name, image }, index) => (
|
||||
<motion.div
|
||||
key={name}
|
||||
className="flex flex-col shrink-0 items-center gap-[1.667vw]"
|
||||
style={{ width: [width1, width2, width3, width4][index] }}
|
||||
>
|
||||
<img
|
||||
src={image}
|
||||
alt={name}
|
||||
className="2xl:rounded-[1.667vw] aspect-[290/205] object-cover w-full pointer-events-none"
|
||||
/>
|
||||
<p className={"text-h4 text-center font-medium"}>{name}</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MarariDriveNeighboursSlider;
|
||||
@@ -42,19 +42,20 @@ function ModalContainer() {
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{modal && (
|
||||
<motion.div
|
||||
ref={rootRef}
|
||||
// initial={{ opacity: 0 }}
|
||||
// animate={{ opacity: 1 }}
|
||||
// exit={{ opacity: 0 }}
|
||||
className="h-full"
|
||||
>
|
||||
<div ref={rootRef} key={"modal"} className="h-full">
|
||||
<div
|
||||
ref={popoverRef}
|
||||
className="bg-black/70 fixed inset-0 max-md:top-14a flex flex-col items-center justify-center amax-md:justify-start overflow-y-auto z-2"
|
||||
className="bg-black/70 fixed inset-0 max-md:top-14 flex flex-col items-center justify-center overflow-y-auto z-10"
|
||||
>
|
||||
<div className="max-h-full">
|
||||
<div ref={divRef} className="md:p-[1.08vw]">
|
||||
<motion.div
|
||||
ref={divRef}
|
||||
className="md:p-[1.08vw]"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.3, bounce: 0 }}
|
||||
>
|
||||
<div
|
||||
ref={backdropRef}
|
||||
className="absolute inset-0 cursor-pointer"
|
||||
@@ -62,7 +63,7 @@ function ModalContainer() {
|
||||
/>
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="relative w-full max-md:border-tmax-md:border-[#E2E2DC]"
|
||||
className="relative w-full max-md:border-t border-[#E2E2DC]"
|
||||
>
|
||||
{modal}
|
||||
<Button
|
||||
@@ -77,10 +78,10 @@ function ModalContainer() {
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
|
||||
@@ -8,12 +8,12 @@ export default function PrivacyPolicyButton() {
|
||||
|
||||
return (
|
||||
<Button
|
||||
size="small"
|
||||
size={innerWidth >= 768 ? "small" : "medium"}
|
||||
variant="secondary"
|
||||
onlyIcon
|
||||
onClick={() => setModal(<PrivacyPolicyModal />)}
|
||||
>
|
||||
<span className="2xl:size-[1.111vw] size-4">
|
||||
<span className="2xl:size-[1.389vw] size-5">
|
||||
<QuestionIcon />
|
||||
</span>
|
||||
</Button>
|
||||
|
||||
@@ -234,8 +234,8 @@ function SequenceSlider({ complexName }: SequenceSliderProps) {
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
size="small"
|
||||
className="absolute left-1/2 -translate-x-1/2 md:bottom-6 bottom-4 2xl:hidden"
|
||||
size={innerWidth < 768 ? "medium" : "small"}
|
||||
className="absolute left-1/2 -translate-x-1/2 md:bottom-6 bottom-4 2xl:hidden w"
|
||||
onClick={() => navigate("floors")}
|
||||
>
|
||||
Select a Floor
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
function FilledPlayIcon() {
|
||||
return (
|
||||
<svg viewBox="0 0 48 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M48 28 0 55.713V.287z" fill="currentColor" />
|
||||
<svg viewBox="0 0 24 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M24 14 0 27.857V.143z" fill="currentColor" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,158 +1,158 @@
|
||||
export const roveHomeDescription = [
|
||||
'Fullyfurnished apartments',
|
||||
'Vibrant art installations',
|
||||
'Inspiring design',
|
||||
export const dubaiMarinaDescriptionBadges = [
|
||||
"Fullyfurnished apartments",
|
||||
"Vibrant art installations",
|
||||
"Inspiring design",
|
||||
] as const;
|
||||
|
||||
export const dubaiMarinaFeatures = [
|
||||
{
|
||||
name: 'Life-enhancing Amenties',
|
||||
image: '/images/about-complex/dubai-marina/amenties.jpg',
|
||||
name: "Life-enhancing Amenties",
|
||||
image: "/images/about-complex/dubai-marina/amenties.jpg",
|
||||
},
|
||||
{
|
||||
name: 'Community',
|
||||
image: '/images/about-complex/dubai-marina/community.jpg',
|
||||
name: "Community",
|
||||
image: "/images/about-complex/dubai-marina/community.jpg",
|
||||
},
|
||||
{
|
||||
name: 'Wellness Focus',
|
||||
image: '/images/about-complex/dubai-marina/wellness.jpg',
|
||||
name: "Wellness Focus",
|
||||
image: "/images/about-complex/dubai-marina/wellness.jpg",
|
||||
},
|
||||
{
|
||||
name: 'Rove-Style Design',
|
||||
image: '/images/about-complex/dubai-marina/design.jpg',
|
||||
name: "Rove-Style Design",
|
||||
image: "/images/about-complex/dubai-marina/design.jpg",
|
||||
},
|
||||
{
|
||||
name: 'Fully-Furnished Apartments',
|
||||
image: '/images/about-complex/dubai-marina/furnished.jpg',
|
||||
name: "Fully-Furnished Apartments",
|
||||
image: "/images/about-complex/dubai-marina/furnished.jpg",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const dubaiMarinaDescription = [
|
||||
{
|
||||
title: 'Wellness',
|
||||
description: 'Unlock your inner zen in our wellness playground',
|
||||
title: "Wellness",
|
||||
description: "Unlock your inner zen in our wellness playground",
|
||||
},
|
||||
{
|
||||
title: 'Fitness',
|
||||
description: 'Cancel all your membership. Your new home has it all',
|
||||
title: "Fitness",
|
||||
description: "Cancel all your membership. Your new home has it all",
|
||||
},
|
||||
{
|
||||
title: 'Community',
|
||||
description: 'Connect. Engage. Thrive.',
|
||||
title: "Community",
|
||||
description: "Connect. Engage. Thrive.",
|
||||
},
|
||||
{
|
||||
title: 'Convenience',
|
||||
description: 'Your smart living hub',
|
||||
title: "Convenience",
|
||||
description: "Your smart living hub",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const dubaiMarinaSlider = {
|
||||
Wellness: [
|
||||
{
|
||||
title: 'Indoor Infinity Pool',
|
||||
title: "Indoor Infinity Pool",
|
||||
description:
|
||||
'Breezy and open in winter and closed in summer – this one-of-a-kind convertible pool takes relaxation to new heights, 165 meters to be precise!',
|
||||
image: '/images/about-complex/dubai-marina/pool1.jpg',
|
||||
"Breezy and open in winter and closed in summer – this one-of-a-kind convertible pool takes relaxation to new heights, 165 meters to be precise!",
|
||||
image: "/images/about-complex/dubai-marina/pool1.jpg",
|
||||
},
|
||||
{
|
||||
title: 'Multi-sensory wellness pods',
|
||||
title: "Multi-sensory wellness pods",
|
||||
description:
|
||||
'Set against a backdrop of dream-worthy views, immerse yourself in diverse wellness experiences including ultrashield oxygen, cold bucket showers and more.',
|
||||
image: '/images/about-complex/dubai-marina/pool2.jpg',
|
||||
"Set against a backdrop of dream-worthy views, immerse yourself in diverse wellness experiences including ultrashield oxygen, cold bucket showers and more.",
|
||||
image: "/images/about-complex/dubai-marina/pool2.jpg",
|
||||
},
|
||||
],
|
||||
Fitness: [
|
||||
{
|
||||
title: 'Semi-Olympic Leisure Pool',
|
||||
title: "Semi-Olympic Leisure Pool",
|
||||
description:
|
||||
'Overlooking the city, enjoy a leisurely swim, do your daily 25-meter laps or just unwind at one of the cozy cabanas,',
|
||||
image: '/images/about-complex/dubai-marina/fitness1.jpg',
|
||||
"Overlooking the city, enjoy a leisurely swim, do your daily 25-meter laps or just unwind at one of the cozy cabanas,",
|
||||
image: "/images/about-complex/dubai-marina/fitness1.jpg",
|
||||
},
|
||||
{
|
||||
title: 'Boutique Fitness Studio',
|
||||
title: "Boutique Fitness Studio",
|
||||
description:
|
||||
'Elevate your fitness regime at flagship Crank Ride & Shape studios – blending fitness, fun, and thrill vibes.',
|
||||
image: '/images/about-complex/dubai-marina/fitness2.jpg',
|
||||
"Elevate your fitness regime at flagship Crank Ride & Shape studios – blending fitness, fun, and thrill vibes.",
|
||||
image: "/images/about-complex/dubai-marina/fitness2.jpg",
|
||||
},
|
||||
],
|
||||
Community: [
|
||||
{
|
||||
title: 'Multi-Purpose Hall',
|
||||
title: "Multi-Purpose Hall",
|
||||
description:
|
||||
'Designed for gatherings, gamings, and entertainment, step into a vibrant multi-functional indoor and outdoor space that can be rented for special events.',
|
||||
image: '/images/about-complex/dubai-marina/community.jpg',
|
||||
"Designed for gatherings, gamings, and entertainment, step into a vibrant multi-functional indoor and outdoor space that can be rented for special events.",
|
||||
image: "/images/about-complex/dubai-marina/community.jpg",
|
||||
},
|
||||
{
|
||||
title: 'Lobby Lounge',
|
||||
title: "Lobby Lounge",
|
||||
description:
|
||||
'Enjoy multi-level seating, reading nooks, co-working spaces, Rove Café and more, for an unforgettable welcome, every time you come home.',
|
||||
image: '/images/about-complex/dubai-marina/community2.jpg',
|
||||
"Enjoy multi-level seating, reading nooks, co-working spaces, Rove Café and more, for an unforgettable welcome, every time you come home.",
|
||||
image: "/images/about-complex/dubai-marina/community2.jpg",
|
||||
},
|
||||
],
|
||||
Convenience: [
|
||||
{
|
||||
title: 'Rentable Guest Room',
|
||||
title: "Rentable Guest Room",
|
||||
description:
|
||||
'A private space for guests to relax and unwind, complete with a comfortable seating area, a flat-screen TV, and a private bathroom.',
|
||||
image: '/images/about-complex/dubai-marina/convenience1.jpg',
|
||||
"A private space for guests to relax and unwind, complete with a comfortable seating area, a flat-screen TV, and a private bathroom.",
|
||||
image: "/images/about-complex/dubai-marina/convenience1.jpg",
|
||||
},
|
||||
{
|
||||
title: 'Entrance & Concierge',
|
||||
description: 'An unforgettable welcome, every time you come home.',
|
||||
image: '/images/about-complex/dubai-marina/design.jpg',
|
||||
title: "Entrance & Concierge",
|
||||
description: "An unforgettable welcome, every time you come home.",
|
||||
image: "/images/about-complex/dubai-marina/design.jpg",
|
||||
},
|
||||
],
|
||||
} as const;
|
||||
|
||||
export const sliderBadgesCategory = {
|
||||
Wellness: [
|
||||
'Vitality Pool',
|
||||
'Reflexology Pool',
|
||||
'Cold Plunge Pool',
|
||||
'Convertible Indoor Infinity Pool',
|
||||
'Zen Library Area',
|
||||
'Finnish Sauna Pod',
|
||||
'Aroma Steam Pod',
|
||||
'Salt Steam Pod',
|
||||
'Ultra Shield Oxygen Pod',
|
||||
'Experience Shower Pods',
|
||||
"Vitality Pool",
|
||||
"Reflexology Pool",
|
||||
"Cold Plunge Pool",
|
||||
"Convertible Indoor Infinity Pool",
|
||||
"Zen Library Area",
|
||||
"Finnish Sauna Pod",
|
||||
"Aroma Steam Pod",
|
||||
"Salt Steam Pod",
|
||||
"Ultra Shield Oxygen Pod",
|
||||
"Experience Shower Pods",
|
||||
],
|
||||
Fitness: [
|
||||
'State-of-the-Art Gym',
|
||||
'Crank Fitness Studios – Bike & Shape',
|
||||
'Counter-current Pool',
|
||||
'Rowing Workout',
|
||||
'Aqua Cycling',
|
||||
'Outdoor Semi-olympic Leisure Pool',
|
||||
'Outdoor Gym Park',
|
||||
'Pedal-powered Workstations',
|
||||
"State-of-the-Art Gym",
|
||||
"Crank Fitness Studios – Bike & Shape",
|
||||
"Counter-current Pool",
|
||||
"Rowing Workout",
|
||||
"Aqua Cycling",
|
||||
"Outdoor Semi-olympic Leisure Pool",
|
||||
"Outdoor Gym Park",
|
||||
"Pedal-powered Workstations",
|
||||
],
|
||||
Community: [
|
||||
'Multipurpose Area',
|
||||
'Rentable Kitchen',
|
||||
'Gaming Lounge',
|
||||
'Arcade Zone and PlayStation',
|
||||
'Indoor Cinema',
|
||||
'Suspended Net Lounge',
|
||||
'Karaoke Studios',
|
||||
'Outdoor Cinema & Ampitheatre',
|
||||
'Rove Café and Energise Bar',
|
||||
'Co-working Spaces',
|
||||
'Meeting Rooms & Pods',
|
||||
'Lobby Lounge',
|
||||
'Marina Views Chill Zone',
|
||||
'Allotment Gardens',
|
||||
"Multipurpose Area",
|
||||
"Rentable Kitchen",
|
||||
"Gaming Lounge",
|
||||
"Arcade Zone and PlayStation",
|
||||
"Indoor Cinema",
|
||||
"Suspended Net Lounge",
|
||||
"Karaoke Studios",
|
||||
"Outdoor Cinema & Ampitheatre",
|
||||
"Rove Café and Energise Bar",
|
||||
"Co-working Spaces",
|
||||
"Meeting Rooms & Pods",
|
||||
"Lobby Lounge",
|
||||
"Marina Views Chill Zone",
|
||||
"Allotment Gardens",
|
||||
],
|
||||
Convenience: [
|
||||
'Smart Home Digital Features',
|
||||
'Organic Smart Gardens',
|
||||
'Electric Vehicle Charging Stations',
|
||||
'Bike/Scooter Rental and Storage',
|
||||
'Free Wi-fi',
|
||||
'24x7 Convenience Store',
|
||||
'Rentable Guest Rooms',
|
||||
'Changing Rooms',
|
||||
'Rentable Storage',
|
||||
'Concierge',
|
||||
"Smart Home Digital Features",
|
||||
"Organic Smart Gardens",
|
||||
"Electric Vehicle Charging Stations",
|
||||
"Bike/Scooter Rental and Storage",
|
||||
"Free Wi-fi",
|
||||
"24x7 Convenience Store",
|
||||
"Rentable Guest Rooms",
|
||||
"Changing Rooms",
|
||||
"Rentable Storage",
|
||||
"Concierge",
|
||||
],
|
||||
};
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
export const marasiDriveDescriptionBadges = [
|
||||
"Expandable Living Solutions",
|
||||
"Heartbeat Location",
|
||||
"Inspired Interiors",
|
||||
] as const;
|
||||
|
||||
export const marasiDriveFeatures = [
|
||||
{
|
||||
name: "Community",
|
||||
image: "/images/about-complex/marasi-drive/community.jpg",
|
||||
},
|
||||
{
|
||||
name: "Central Urban Locations",
|
||||
image: "/images/about-complex/marasi-drive/location.jpg",
|
||||
},
|
||||
{
|
||||
name: "Fully Loaded Amenties",
|
||||
image: "/images/about-complex/marasi-drive/amenties.jpg",
|
||||
},
|
||||
{
|
||||
name: "Rove-Inspired Design",
|
||||
image: "/images/about-complex/marasi-drive/design.jpg",
|
||||
},
|
||||
{
|
||||
name: "Add-on Services",
|
||||
image: "/images/about-complex/marasi-drive/services.jpg",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const marasiDriveExpandable = [
|
||||
"/images/about-complex/marasi-drive/living_solution1.jpg",
|
||||
"/images/about-complex/marasi-drive/living_solution2.jpg",
|
||||
"/images/about-complex/marasi-drive/living_solution3.jpg",
|
||||
] as const;
|
||||
|
||||
export const marasiDriveInspiredInteriors = [
|
||||
{
|
||||
name: "Studio flex",
|
||||
image: "/images/about-complex/marasi-drive/studio_flex.jpg",
|
||||
},
|
||||
{
|
||||
name: "Studio²",
|
||||
image: "/images/about-complex/marasi-drive/studio2.jpg",
|
||||
},
|
||||
{
|
||||
name: "1 Bedroom²",
|
||||
image: "/images/about-complex/marasi-drive/1bedroom2.jpg",
|
||||
},
|
||||
{
|
||||
name: "2 Bedroom²",
|
||||
image: "/images/about-complex/marasi-drive/2bedroom2.jpg",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const marasiDriveNeighbours = [
|
||||
{
|
||||
name: "City Walk",
|
||||
image: "/images/about-complex/marasi-drive/city_walk.jpg",
|
||||
},
|
||||
{
|
||||
name: "Downtown Dubai",
|
||||
image: "/images/about-complex/marasi-drive/downtown.jpg",
|
||||
},
|
||||
{
|
||||
name: "Marasi promenade",
|
||||
image: "/images/about-complex/marasi-drive/promenade.jpg",
|
||||
},
|
||||
{
|
||||
name: "Dubai Mall",
|
||||
image: "/images/about-complex/marasi-drive/mall.jpg",
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const marasiDriveMapCards = [
|
||||
{
|
||||
title: "Burj Khalifa",
|
||||
mins: 10,
|
||||
image: "/images/about-complex/marasi-drive/burj_khalifa.jpg",
|
||||
},
|
||||
{
|
||||
title: "Dubai Fountain",
|
||||
mins: 15,
|
||||
image: "/images/about-complex/marasi-drive/fountain.jpg",
|
||||
},
|
||||
{
|
||||
title: "Dubai Mall",
|
||||
mins: 15,
|
||||
image: "/images/about-complex/marasi-drive/mall.jpg",
|
||||
},
|
||||
{
|
||||
title: "Dubai Opera",
|
||||
mins: 15,
|
||||
image: "/images/about-complex/marasi-drive/opera.jpg",
|
||||
},
|
||||
{
|
||||
title: "Marasi Promenade",
|
||||
mins: 15,
|
||||
image: "/images/about-complex/marasi-drive/promenade.jpg",
|
||||
},
|
||||
{
|
||||
title: "Rove Downtown Hotel",
|
||||
mins: 15,
|
||||
image: "/images/about-complex/marasi-drive/rovedowntown.jpg",
|
||||
},
|
||||
{
|
||||
title: "Rove City Walk Hotel",
|
||||
mins: 15,
|
||||
image: "/images/about-complex/marasi-drive/rovecitywalk.jpg",
|
||||
},
|
||||
{
|
||||
title: "Coca-Cola Arena",
|
||||
mins: 15,
|
||||
image: "/images/about-complex/marasi-drive/arena.jpg",
|
||||
},
|
||||
{
|
||||
title: "Dubai International Airport",
|
||||
mins: 15,
|
||||
image: "/images/about-complex/marasi-drive/airport.jpg",
|
||||
},
|
||||
] as const;
|
||||
@@ -9,7 +9,7 @@ function DefaultLayout() {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"min-h-dvh flex flex-col select-none bg-white",
|
||||
"min-h-dvh flex flex-col select-none",
|
||||
pathname.endsWith("/about") ? "bg-white" : "bg-[#F3F3F2]"
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -1,382 +1,15 @@
|
||||
import {
|
||||
useScroll,
|
||||
useTransform,
|
||||
motion,
|
||||
useInView,
|
||||
AnimatePresence,
|
||||
} from "motion/react";
|
||||
import { useRef, useState } from "react";
|
||||
import {
|
||||
dubaiMarinaFeatures,
|
||||
dubaiMarinaDescription,
|
||||
roveHomeDescription,
|
||||
dubaiMarinaSlider,
|
||||
sliderBadgesCategory,
|
||||
} from "../data/aboutDubaiMarina";
|
||||
import EqualIcon from "../components/icons/EqualIcon";
|
||||
import TextBox from "../components/ui/TextBox";
|
||||
import clsx from "clsx";
|
||||
import Slider from "../components/Slider";
|
||||
import PlusIcon from "../components/icons/map/PlusIcon";
|
||||
import useWindowSize from "../hooks/useWindowSize";
|
||||
import FullScreenButton from "../components/FullScreenButton";
|
||||
import SliderMobile from "../components/SliderMobile";
|
||||
import { useParams } from "react-router";
|
||||
import AboutDubaiMarina from "../components/AboutDubaiMarina";
|
||||
import AboutMarasiDrive from "../components/AboutMarasiDrive";
|
||||
|
||||
function AboutComplexPage() {
|
||||
const containerRef = useRef(null);
|
||||
const sliderRef = useRef(null);
|
||||
const mapRef = useRef(null);
|
||||
const { width } = useWindowSize();
|
||||
const { complexName } = useParams();
|
||||
|
||||
const [selectedCategorySlider, setSelectedCategorySlider] =
|
||||
useState<keyof typeof dubaiMarinaSlider>("Wellness");
|
||||
|
||||
const { scrollYProgress } = useScroll({
|
||||
target: containerRef,
|
||||
offset: ["start start", "end start"],
|
||||
});
|
||||
|
||||
const firstSectionOpacity = useTransform(scrollYProgress, [0, 0.2], [1, 0]);
|
||||
|
||||
const secondSectionY = useTransform(
|
||||
scrollYProgress,
|
||||
[0, 0.4],
|
||||
["100dvh", "0dvh"]
|
||||
);
|
||||
|
||||
const isSliderInView = useInView(sliderRef, {
|
||||
once: true,
|
||||
amount: 0.1,
|
||||
});
|
||||
const isMapInView = useInView(mapRef, {
|
||||
once: true,
|
||||
margin: `0px 0px ${-window.innerHeight / 2}px 0px`,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="relative bg-white" ref={containerRef}>
|
||||
<motion.section
|
||||
className="2xl:h-[calc(100dvh-4.444vw)] w-full bg-white text-black 2xl:fixed top-[4.444vw] left-0 right-0 z-0 max-md:top-[15.556vw]]
|
||||
max-md:bg-[url(/images/about-complex/dubai-marina/tower-mobile.png)] max-md:bg-cover max-md:bg-top max-md:bg-no-repeat max-md:aspect-[360/584]
|
||||
max-2xl:bg-[url(/images/about-complex/dubai-marina/tower-tablet.png)] max-2xl:bg-cover max-2xl:bg-top max-2xl:bg-no-repeat max-2xl:aspect-[768/960]
|
||||
"
|
||||
style={{
|
||||
opacity: width > 1439 ? firstSectionOpacity : 1,
|
||||
}}
|
||||
>
|
||||
<div className="absolute inset-0 2xl:">
|
||||
<img
|
||||
src="/images/about-complex/dubai-marina/tower.jpg"
|
||||
alt="dubai marina about"
|
||||
className="h-full w-full object-contain object-bottom max-2xl:hidden"
|
||||
/>
|
||||
<img
|
||||
src="/images/about-complex/dubai-marina/logo.png"
|
||||
alt="dubai marina about"
|
||||
className="absolute top-[5vw] right-[2.778vw] w-[9.931vw] h-[4.444vw] max-md:top-[6.667vw] max-md:right-[4.444vw] max-md:w-[21.389vw] max-md:h-[9.444vw] max-2xl:w-[18.62vw] max-2xl:h-[8.333vw]"
|
||||
/>
|
||||
</div>
|
||||
<div className="relative h-full flex flex-col justify-between 2xl:gap-[4.444vw] flex-1 w-full pt-[5vw] pb-[2.5vw] pl-[2.222vw] max-md:px-[4.444vw] max-md:block ">
|
||||
<div className="font-bold whitespace-pre-line space-y-8 max-md:space-y-4">
|
||||
<h1 className="text-[5vw] leading-none tracking-[-0.07em] font-mixcase-unmixed font-[500] max-md:text-[8.889vw] max-2xl:text-[9.375vw]">
|
||||
{`Rove Home
|
||||
Dubai Marina`}
|
||||
</h1>
|
||||
<div className="space-y-2 font-[400]">
|
||||
{roveHomeDescription.map((description) => (
|
||||
<TextBox text={description} key={description} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-8 max-md:hidden">
|
||||
<h4 className="text-h4 text-[#00BED7] font-[500] whitespace-pre-line">
|
||||
{`Own the last slice of
|
||||
Dubai Marina, ROVE Style`}
|
||||
</h4>
|
||||
<p className="text-s text-[#0D1922B2] max-md:whitespace-pre-line min-2xl:whitespace-pre-line max-2xl:w-[34vw]">
|
||||
{`With an extended playlist of life-enhancing
|
||||
amenities, Rove Home is a complete ecosystem
|
||||
that has everything you'll ever need.`}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.section>
|
||||
<motion.section
|
||||
className="w-full text-white bg-white flex justify-center max-md:top-0 max-md:overflow-x-clip"
|
||||
style={{
|
||||
y: width > 1439 ? secondSectionY : 0,
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<div className="w-full min-md:overflow-x-hidden">
|
||||
<div className="flex flex-col items-center gap-[2.222vw] w-full max-md:py-[8.889vw] max-md:px-[4.444vw] max-2xl:p-6">
|
||||
<div className="space-y-8 min-md:hidden self-start">
|
||||
<h4 className="text-h4 text-[#00BED7] font-[500] whitespace-pre-line">
|
||||
{`Own the last slice of Dubai
|
||||
Marina, ROVE Style`}
|
||||
</h4>
|
||||
<p className="text-s text-[#0D1922B2] whitespace-pre-line ">
|
||||
{`With an extended playlist of life-enhancing
|
||||
amenities, Rove Home is a complete ecosystem
|
||||
that has everything you'll ever need.`}
|
||||
</p>
|
||||
</div>
|
||||
<div className="2xl:px-[2.222vw] flex pt-[7.222vw] flex-col items-center gap-[2.222vw] max-md:pt-[17.778vw]">
|
||||
<h1 className="text-[3.889vw] text-[#0D1922] font-mixcase-unmixed max-md:text-[6.667vw] max-2xl:text-[7.682vw]">
|
||||
Rove Home has it all
|
||||
</h1>
|
||||
<p className="text-s text-[#0D1922B2] text-center tracking-[-0.02em] whitespace-pre-line">
|
||||
{`Rove Home Dubai Marina features modern-day
|
||||
conveniences, carefully curated for an active
|
||||
and social lifestyle.`}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className="flex gap-[0.556vw] mt-[0.833vw] 2xl:h-[26.667vw] max-md:pl-[4.444vw] max-md:pr-[2vw] max-md:gap-[2.222vw] max-md:snap-x max-md:snap-mandatory max-md:py-[6.667vw] max-md:overflow-x-auto max-md:self-start max-md:w-screen max-md:-ml-[4.444vw] max-md:flex-nowrap max-md:justify-start
|
||||
max-2xl:flex-wrap max-2xl:justify-center"
|
||||
>
|
||||
{dubaiMarinaFeatures.map((feature) => (
|
||||
<div
|
||||
key={feature.name}
|
||||
className={`rounded-3xl 2xl:flex-1 2xl:h-[26.667vw] w-full flex flex-col items-center py-[1.667vw] justify-end bg-cover bg-center bg-no-repeat relative before:absolute before:inset-0 before:bg-[#0D1922]/10 before:z-1 before:rounded-3xl
|
||||
max-2xl:w-[30.208vw] max-2xl:h-[41.146vw] max-2xl:flex-wrap
|
||||
max-md:w-[91.111vw] max-md:h-[79.722vw] max-md:flex-none aspect-[268/384] max-md:aspect-[328/287] max-md:snap-alwaysa max-md:snap-center max-md:py-[4.444vw]
|
||||
`}
|
||||
style={{
|
||||
backgroundImage: `url(${feature.image})`,
|
||||
}}
|
||||
>
|
||||
<h5 className="text-h5 text-white tracking-[-0.02em] z-2">
|
||||
{feature.name}
|
||||
</h5>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center pt-[4.444vw] px-8 gap-[4.444vw] max-md:px-[4.444vw] max-2xl:pr-[3.125vw] max-2xl:-mr-[3.125vw] max-2xl:p-6 max-2xl:items-start max-2xl:gap-[4.167vw]">
|
||||
<h1 className="font-mixcase-unmixed 2xl:text-[3.889vw] text-[#0D1922] tracking-[-0.05em] max-md:text-2xl max-2xl:text-[7.292vw] max-2xl:self-center">
|
||||
Dubai, <span className="text-[#0D192266]">within reach</span>
|
||||
</h1>
|
||||
<SliderMobile />
|
||||
<div
|
||||
className="z-1 flex w-full text-[#0D1922]/40 gap-[1.111vw] max-md:hidden
|
||||
max-2xl:overflow-x-auto max-2xl:self-start max-2xl:snap-x max-2xl:snap-mandatory
|
||||
max-2xl:[scrollbar-width:none] max-2xl:mt-[4.167vw]"
|
||||
>
|
||||
{dubaiMarinaDescription.map((descriptionItem) => (
|
||||
<div
|
||||
key={descriptionItem.title}
|
||||
className="2xl:flex-1 text-center flex flex-col gap-[1.111vw] cursor-pointer hover:text-[#0D1922B2] transition-all duration-200
|
||||
max-2xl:w-[45.833vw] max-2xl:h-[12.76vw] max-2xl:shrink-0"
|
||||
onClick={() =>
|
||||
setSelectedCategorySlider(descriptionItem.title)
|
||||
}
|
||||
>
|
||||
<div className="h-[2px] bg-gray-300 w-full"></div>
|
||||
<h5
|
||||
className={clsx(
|
||||
"text-h5 tracking-[-0.02em] mt-[0.556vw] font-[500]",
|
||||
descriptionItem.title === selectedCategorySlider &&
|
||||
"text-[#00BED7]"
|
||||
)}
|
||||
>
|
||||
{descriptionItem.title}
|
||||
</h5>
|
||||
<p
|
||||
className={clsx(
|
||||
"text-s leading-[125%] tracking-[-0.02em] w-[16.389vw] self-center max-2xl:w-[30.729vw] ",
|
||||
descriptionItem.title === selectedCategorySlider &&
|
||||
"text-[#0D1922]"
|
||||
)}
|
||||
>
|
||||
{descriptionItem.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<AnimatePresence mode="wait">
|
||||
<div
|
||||
ref={sliderRef}
|
||||
className="flex flex-col gap-8 max-md:hidden"
|
||||
>
|
||||
<motion.div
|
||||
key={`slider-${selectedCategorySlider}`}
|
||||
initial={{ opacity: 0, y: 40 }}
|
||||
animate={
|
||||
isSliderInView
|
||||
? { opacity: 1, y: 0 }
|
||||
: { opacity: 0, y: 140 }
|
||||
}
|
||||
exit={{ opacity: 0, y: -40 }}
|
||||
transition={{ duration: 0.6, ease: "easeIn" }}
|
||||
>
|
||||
<Slider categoryName={selectedCategorySlider} />
|
||||
</motion.div>
|
||||
<motion.div
|
||||
key={`badges-${selectedCategorySlider}`}
|
||||
className="flex gap-[0.556vw] w-[63.333vw] flex-wrap justify-center max-2xl:w-[93.75vw]"
|
||||
>
|
||||
{sliderBadgesCategory[selectedCategorySlider].map(
|
||||
(badgeItem, index) => (
|
||||
<motion.div
|
||||
key={badgeItem}
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{
|
||||
duration: 0.3,
|
||||
delay: index * 0.1,
|
||||
ease: "easeOut",
|
||||
}}
|
||||
>
|
||||
<TextBox text={badgeItem} />
|
||||
</motion.div>
|
||||
)
|
||||
)}
|
||||
</motion.div>
|
||||
</div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
<div className="text-center w-full flex flex-col items-center gap-[2.222vw] bg-white max-md:gap-[6.667vw] max-2xl:gap-[3.125vw]">
|
||||
<h1 className="font-mixcase-unmixed text-[3.889vw] text-[#0D1922] w-[44.861vw] leading-[100%] tracking-[-0.05em] pt-[8.056vw] max-md:text-[6.667vw] max-md:w-full max-2xl:text-[7.292vw] max-2xl:w-[84.115vw]">
|
||||
Dubai's first-ever combinable Apartments
|
||||
</h1>
|
||||
<span className="max-2xl:mt-[1.042vw]">
|
||||
<TextBox text="On-demand" />
|
||||
</span>
|
||||
<p className="text-s text-[#0D1922B2] leading-[140%] tracking-[-0.02em] whitespace-pre-line">
|
||||
{`Enjoy the option to combine 2 apartments and create
|
||||
a larger space and configuration.`}
|
||||
</p>
|
||||
<div className="flex gap-4 relative max-md:flex-col max-md:gap-[2.222vw] max-md:w-full max-md:px-[4.444vw] max-2xl:mt-[7.292vw]">
|
||||
<div
|
||||
className="w-[19.028vw] text-[#0D1922] h-[27.778vw] p-[1.667vw] rounded-2xl bg-[#F3F3F2] text-left bg-[url(/images/about-complex/dubai-marina/studio.png)] bg-[length:7.778vw_17.847vw] bg-no-repeat bg-center
|
||||
max-md:w-full max-md:h-[75.556vw] max-md:bg-[length:25.556vw_58.333vw] max-md:p-[4.444vw] max-2xl:w-[25.521vw] max-2xl:h-[34.375vw]"
|
||||
>
|
||||
<h4 className="text-h4 tracking-[-0.02em] font-[500] max-md:text-h5">
|
||||
Studio²
|
||||
</h4>
|
||||
</div>
|
||||
<div
|
||||
className="w-10 h-10 rounded-full bg-[#0D1922] flex items-center justify-center absolute left-[18.500vw] self-center
|
||||
max-md:top-[71.111vw] max-md:left-[45vw] max-2xl:top-[14.583vw] max-2xl:left-[24vw]"
|
||||
>
|
||||
<span className="w-5 h-5">
|
||||
<PlusIcon />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="w-[19.028vw] text-[#0D1922] h-[27.778vw] p-6 rounded-2xl bg-[#F3F3F2] text-left bg-[url(/images/about-complex/dubai-marina/studio.png)] bg-[length:7.778vw_17.847vw] bg-no-repeat bg-center
|
||||
max-md:w-full max-md:h-[75.556vw] max-md:bg-[length:25.556vw_58.333vw] max-md:p-[4.444vw] max-2xl:w-[25.521vw] max-2xl:h-[34.375vw]"
|
||||
>
|
||||
<h4 className="text-h4 tracking-[-0.02em] font-[500] max-md:text-h5">
|
||||
Studio²
|
||||
</h4>
|
||||
</div>
|
||||
<div
|
||||
className="w-10 h-10 rounded-full bg-[#0D1922] flex items-center justify-center absolute left-[38.333vw] self-center
|
||||
max-md:top-[148.611vw] max-md:left-[45vw] max-2xl:top-[14.583vw] max-2xl:left-[52vw]"
|
||||
>
|
||||
<span className="w-5 h-5">
|
||||
<EqualIcon />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="w-[30.972vw] text-[#0D1922] h-[27.778vw] p-6 rounded-2xl bg-[#F3F3F2] text-left bg-[url(/images/about-complex/dubai-marina/1_bedroom.png)] bg-[length:15.972vw_17.847vw] bg-no-repeat bg-center
|
||||
max-md:w-full max-md:h-[111.111vw] max-md:bg-[length:63.889vw_71.389vw] max-md:p-[4.444vw] max-2xl:w-[40.625vw] max-2xl:h-[34.375vw]"
|
||||
>
|
||||
<h4 className="text-h4 tracking-[-0.02em] font-[500] max-md:text-h5">
|
||||
1 Bedroom²
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
<h5 className="2xl:hidden text-h5 text-[#0D1922B2] max-2xl:hidden">
|
||||
or
|
||||
</h5>
|
||||
<div className="flex gap-4 relative max-md:flex-col max-md:gap-[2.222vw] max-md:w-full max-md:px-[4.444vw]">
|
||||
<div
|
||||
className="w-[19.028vw] text-[#0D1922] h-[27.778vw] p-6 rounded-2xl bg-[#F3F3F2] text-left bg-[url(/images/about-complex/dubai-marina/2_studio.png)] bg-[length:13.125vw_17.847vw] bg-no-repeat bg-center
|
||||
max-md:w-full max-md:h-[75.556vw] max-md:bg-[length:38.889vw_52.5vw] max-md:p-[4.444vw] max-2xl:w-[25.521vw] max-2xl:h-[34.375vw]"
|
||||
>
|
||||
<h4 className="text-h4 tracking-[-0.02em] font-[500] max-md:text-h5">
|
||||
Studio²
|
||||
</h4>
|
||||
</div>
|
||||
<div
|
||||
className="w-10 h-10 rounded-full bg-[#0D1922] flex items-center justify-center absolute left-[18.500vw] self-center
|
||||
max-md:top-[71.111vw] max-md:left-[45vw] max-2xl:top-[14.583vw] max-2xl:left-[24vw]"
|
||||
>
|
||||
<span className="w-5 h-5">
|
||||
<PlusIcon />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="w-[30.972vw] text-[#0D1922] h-[27.778vw] p-6 rounded-2xl bg-[#F3F3F2] text-left bg-[url(/images/about-complex/dubai-marina/1_bedroom_rotated.png)] bg-[length:17.847vw_13.681vw] bg-no-repeat bg-center
|
||||
max-md:w-full max-md:h-[75.556vw] max-md:bg-[length:56.111vw_43.056vw] max-md:p-[4.444vw] max-2xl:w-[33.073vw] max-2xl:h-[34.375vw]"
|
||||
>
|
||||
<h4 className="text-h4 tracking-[-0.02em] font-[500] max-md:text-h5">
|
||||
1 Bedroom²
|
||||
</h4>
|
||||
</div>
|
||||
<div
|
||||
className="w-10 h-10 rounded-full bg-[#0D1922] flex items-center justify-center absolute left-[50.300vw] self-center
|
||||
max-md:top-[148.611vw] max-md:left-[45vw] max-2xl:top-[14.583vw] max-2xl:left-[59vw]"
|
||||
>
|
||||
<span className="w-5 h-5">
|
||||
<EqualIcon />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="w-[30.972vw] text-[#0D1922] h-[27.778vw] p-6 rounded-2xl bg-[#F3F3F2] text-left bg-[url(/images/about-complex/dubai-marina/2_bedroom.png)] bg-[length:19.028vw_17.847vw] bg-no-repeat bg-center
|
||||
max-md:w-full max-md:h-[111.111vw] max-md:bg-[length:76.267vw_71.389vw] max-md:p-[4.444vw] max-2xl:w-[33.073vw] max-2xl:h-[34.375vw]"
|
||||
>
|
||||
<h4 className="text-h4 tracking-[-0.02em] font-[500] max-md:text-h5">
|
||||
2 Bedroom²
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-[2.222vw] bg-white px-[2.222vw] pb-[8.333vw] max-md:gap-[6.667vw] max-md:px-[4.444vw] max-2xl:gap-[4.167vw]">
|
||||
<h1
|
||||
className="font-mixcase-unmixed text-[3.889vw] text-[#0D1922] w-[44.861vw] leading-[100%] tracking-[-0.05em] pt-[7.222vw] text-center
|
||||
max-md:text-[6.667vw] max-md:w-full max-2xl:text-[7.292vw] max-2xl:w-[84.115vw]"
|
||||
>
|
||||
Live central. Live centred
|
||||
</h1>
|
||||
<p className="text-s text-[#0D1922B2] leading-[140%] tracking-[-0.02em] text-center 2xl:whitespace-pre-line max-2xl:w-[66.146vw]">
|
||||
{`Located in the heart of Dubai Marina, Rove Home Dubai Marina is where active
|
||||
living meets modern convenience. Enjoy an energetic lifestyle surrounded by
|
||||
trendy cafés, shops, and entertainment options – all within reach.`}
|
||||
</p>
|
||||
<motion.img
|
||||
ref={mapRef}
|
||||
src="/images/about-complex/dubai-marina/central_map.png"
|
||||
alt="central map"
|
||||
className="rounded-3xl object-cover object-center aspect-[1376/609] max-md:hidden max-2xl:w-[93.75vw] max-2xl:h-[89.583vw] max-2xl:aspect-[720/688] max-2xl:mt-[1.563vw]"
|
||||
initial={{ width: "47.083vw" }}
|
||||
animate={
|
||||
isMapInView ? { width: "95.556vw" } : { width: "47.083vw" }
|
||||
}
|
||||
transition={{ duration: 0.6, ease: "easeInOut" }}
|
||||
/>
|
||||
<div className="min-md:hidden relative w-[89.167vw] aspect-square overflow-hidden rounded-2xl">
|
||||
<img
|
||||
src="/images/about-complex/dubai-marina/central_map.png"
|
||||
alt="central map"
|
||||
className="w-full h-full object-cover object-center scale-120"
|
||||
/>
|
||||
<div className="absolute bottom-[1.111vw] right-[1.111vw] w-[11.111vw] h-[11.111vw]">
|
||||
<FullScreenButton
|
||||
isFullScreen={false}
|
||||
onClick={() => {}}
|
||||
onFullScreenChange={() => {}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.section>
|
||||
</div>
|
||||
);
|
||||
if (complexName === "dubai-marina") {
|
||||
return <AboutDubaiMarina />;
|
||||
} else if (complexName === "marasi-drive") {
|
||||
return <AboutMarasiDrive />;
|
||||
} else return null;
|
||||
}
|
||||
|
||||
export default AboutComplexPage;
|
||||
|
||||
@@ -54,6 +54,7 @@ function AboutIRTHPage() {
|
||||
<video
|
||||
src="/videos/About/IRTH 1_HIGHRES.mp4"
|
||||
className="object-cover w-full h-full"
|
||||
poster="/images/video-posters/about.jpg"
|
||||
ref={videoRef}
|
||||
muted
|
||||
autoPlay
|
||||
|
||||
@@ -42,7 +42,7 @@ function UnitPage() {
|
||||
if (!unit) return null;
|
||||
|
||||
return (
|
||||
<div className="2xl:p-[2.222vw] md:max-2xl:p-[3.125vw] p-4 max-2xl:pb-0 bg-white flex 2xl:gap-[2.222vw] md:max-2xl:gap-8 gap-6 max-2xl:flex-col">
|
||||
<div className="2xl:p-[2.222vw] md:max-2xl:p-6 p-4 max-2xl:pb-0 bg-white flex 2xl:gap-[2.222vw] md:max-2xl:gap-8 gap-6 max-2xl:flex-col">
|
||||
<div className="bg-[#F3F3F2] 2xl:aspect-[1028/664] md:max-2xl:aspect-[720/616] aspect-square 2xl:w-[71.389vw] w-full 2xl:rounded-[1.111vw] md:max-2xl:rounded-2xl rounded-xl" />
|
||||
<div className="flex flex-col justify-between md:max-2xl:gap-6 gap-4 flex-1">
|
||||
<div className="2xl:space-y-[1.667vw] space-y-6">
|
||||
|
||||