feat: add about page for dubai-marina
@@ -0,0 +1,221 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="noindex, noarchive">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<title>Transfonter demo</title>
|
||||
<link href="stylesheet.css" rel="stylesheet">
|
||||
<style>
|
||||
/*
|
||||
http://meyerweb.com/eric/tools/css/reset/
|
||||
v2.0 | 20110126
|
||||
License: none (public domain)
|
||||
*/
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, embed,
|
||||
figure, figcaption, footer, header, hgroup,
|
||||
menu, nav, output, ruby, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article, aside, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote, q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
/* demo styles */
|
||||
body {
|
||||
background: #f0f0f0;
|
||||
color: #000;
|
||||
}
|
||||
.page {
|
||||
background: #fff;
|
||||
width: 920px;
|
||||
margin: 0 auto;
|
||||
padding: 20px 20px 0 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.font-container {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
margin-bottom: 40px;
|
||||
line-height: 1.3;
|
||||
white-space: nowrap;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
h1 {
|
||||
position: relative;
|
||||
background: #444;
|
||||
font-size: 32px;
|
||||
color: #fff;
|
||||
padding: 10px 20px;
|
||||
margin: 0 -20px 12px -20px;
|
||||
}
|
||||
.letters {
|
||||
font-size: 25px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.s10:before {
|
||||
content: '10px';
|
||||
}
|
||||
.s11:before {
|
||||
content: '11px';
|
||||
}
|
||||
.s12:before {
|
||||
content: '12px';
|
||||
}
|
||||
.s14:before {
|
||||
content: '14px';
|
||||
}
|
||||
.s18:before {
|
||||
content: '18px';
|
||||
}
|
||||
.s24:before {
|
||||
content: '24px';
|
||||
}
|
||||
.s30:before {
|
||||
content: '30px';
|
||||
}
|
||||
.s36:before {
|
||||
content: '36px';
|
||||
}
|
||||
.s48:before {
|
||||
content: '48px';
|
||||
}
|
||||
.s60:before {
|
||||
content: '60px';
|
||||
}
|
||||
.s72:before {
|
||||
content: '72px';
|
||||
}
|
||||
.s10:before, .s11:before, .s12:before, .s14:before,
|
||||
.s18:before, .s24:before, .s30:before, .s36:before,
|
||||
.s48:before, .s60:before, .s72:before {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 10px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
color: #999;
|
||||
padding-right: 6px;
|
||||
}
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9px;
|
||||
margin: 0 0 12px;
|
||||
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.428571429;
|
||||
color: #333;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #ccc;
|
||||
overflow-x: auto;
|
||||
border-radius: 4px;
|
||||
}
|
||||
/* responsive */
|
||||
@media (max-width: 959px) {
|
||||
.page {
|
||||
width: auto;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<div class="demo">
|
||||
<h1 style="font-family: 'Mixcase Mixed'; font-weight: normal; font-style: normal;">Mixcase Mixed</h1>
|
||||
<pre title="Usage">.your-style {
|
||||
font-family: 'Mixcase Mixed';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}</pre>
|
||||
<pre title="Preload (optional)">
|
||||
<link rel="preload" href="MixcaseMixed.woff2" as="font" type="font/woff2" crossorigin></pre>
|
||||
<div class="font-container" style="font-family: 'Mixcase Mixed'; font-weight: normal; font-style: normal;">
|
||||
<p class="letters">
|
||||
abcdefghijklmnopqrstuvwxyz<br>
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
|
||||
0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||
</p>
|
||||
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo">
|
||||
<h1 style="font-family: 'Mixcase Unmixed'; font-weight: normal; font-style: normal;">Mixcase Unmixed</h1>
|
||||
<pre title="Usage">.your-style {
|
||||
font-family: 'Mixcase Unmixed';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}</pre>
|
||||
<pre title="Preload (optional)">
|
||||
<link rel="preload" href="MixcaseUnmixed.woff2" as="font" type="font/woff2" crossorigin></pre>
|
||||
<div class="font-container" style="font-family: 'Mixcase Unmixed'; font-weight: normal; font-style: normal;">
|
||||
<p class="letters">
|
||||
abcdefghijklmnopqrstuvwxyz<br>
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
|
||||
0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||
</p>
|
||||
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,26 @@
|
||||
@font-face {
|
||||
font-family: 'Mixcase Mixed';
|
||||
src: url('MixcaseMixed.eot');
|
||||
src: local('Mixcase Mixed'), local('MixcaseMixed'),
|
||||
url('MixcaseMixed.eot?#iefix') format('embedded-opentype'),
|
||||
url('MixcaseMixed.woff2') format('woff2'),
|
||||
url('MixcaseMixed.woff') format('woff'),
|
||||
url('MixcaseMixed.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Mixcase Unmixed';
|
||||
src: url('MixcaseUnmixed.eot');
|
||||
src: local('Mixcase Unmixed'), local('MixcaseUnmixed'),
|
||||
url('MixcaseUnmixed.eot?#iefix') format('embedded-opentype'),
|
||||
url('MixcaseUnmixed.woff2') format('woff2'),
|
||||
url('MixcaseUnmixed.woff') format('woff'),
|
||||
url('MixcaseUnmixed.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 209 KiB |
|
After Width: | Height: | Size: 140 KiB |
|
After Width: | Height: | Size: 252 KiB |
|
After Width: | Height: | Size: 107 KiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 323 KiB |
|
After Width: | Height: | Size: 2.1 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 924 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 936 KiB |
|
After Width: | Height: | Size: 990 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 208 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
@@ -7,7 +7,7 @@ import TwitterIcon from './icons/TwitterIcon';
|
||||
|
||||
function Footer() {
|
||||
return (
|
||||
<footer className='2xl:px-[2.222vw] 2xl:pb-[2.222vw] 2xl:pt-[2.778vw] md:max-2xl:p-6 px-4 py-6 grid 2xl:grid-cols-6 md:max-2xl:grid-cols-4 grid-cols-2 2xl:grid-rows-2 2xl:gap-x-[1.667vw] 2xl:gap-y-[1.111vw] max-2xl:gap-y-6 2xl:rounded-t-[1.667vw] rounded-t-3xl outline outline-[#E2E2DC] bg-white'>
|
||||
<footer className='z-1 2xl:px-[2.222vw] 2xl:pb-[2.222vw] 2xl:pt-[2.778vw] md:max-2xl:p-6 px-4 py-6 grid 2xl:grid-cols-6 md:max-2xl:grid-cols-4 grid-cols-2 2xl:grid-rows-2 2xl:gap-x-[1.667vw] 2xl:gap-y-[1.111vw] max-2xl:gap-y-6 2xl:rounded-t-[1.667vw] rounded-t-3xl outline outline-[#E2E2DC] bg-white'>
|
||||
<img
|
||||
src='/images/logo.svg'
|
||||
className='2xl:w-[5.972vw] w-[86px] cursor-pointer'
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
// import { sequenceVideos } from "../data/sequenceVideos";
|
||||
import { useState, useRef } from "react";
|
||||
import gsap from "gsap";
|
||||
import { useSwipeable } from "react-swipeable";
|
||||
import { motion, AnimatePresence } from "motion/react";
|
||||
import Button from "./ui/Button";
|
||||
import ArrowRightIcon from "./icons/map/ArrowRightIcon";
|
||||
import ArrowLeftIcon from "./icons/ArrowLeftIcon";
|
||||
import Compass from "./Compass";
|
||||
import { useNavigate } from "react-router";
|
||||
import InfoIcon from "./icons/InfoIcon";
|
||||
import FullScreenButton from "./FullScreenButton";
|
||||
import PrivacyPolicyButton from "./PrivacyPolicyButton";
|
||||
import DisclaimerButton from "./DisclaimerButton";
|
||||
import { useState, useRef } from 'react';
|
||||
import gsap from 'gsap';
|
||||
import { useSwipeable } from 'react-swipeable';
|
||||
import { motion, AnimatePresence } from 'motion/react';
|
||||
import Button from './ui/Button';
|
||||
import ArrowRightIcon from './icons/map/ArrowRightIcon';
|
||||
import ArrowLeftIcon from './icons/ArrowLeftIcon';
|
||||
import Compass from './Compass';
|
||||
import { useNavigate } from 'react-router';
|
||||
import InfoIcon from './icons/InfoIcon';
|
||||
import FullScreenButton from './FullScreenButton';
|
||||
import PrivacyPolicyButton from './PrivacyPolicyButton';
|
||||
import DisclaimerButton from './DisclaimerButton';
|
||||
|
||||
interface SequenceSliderProps {
|
||||
complexName: string;
|
||||
@@ -25,8 +25,8 @@ function SequenceSlider({ complexName }: SequenceSliderProps) {
|
||||
const [isAnimating, setIsAnimating] = useState(false);
|
||||
|
||||
const handlers = useSwipeable({
|
||||
onSwipedLeft: () => handleSwipe("next"),
|
||||
onSwipedRight: () => handleSwipe("prev"),
|
||||
onSwipedLeft: () => handleSwipe('next'),
|
||||
onSwipedRight: () => handleSwipe('prev'),
|
||||
preventScrollOnSwipe: true,
|
||||
touchEventOptions: {
|
||||
passive: false,
|
||||
@@ -37,7 +37,7 @@ function SequenceSlider({ complexName }: SequenceSliderProps) {
|
||||
const [imageLoaded, setImageLoaded] = useState(0);
|
||||
const [isShowVideo, setIsShowVideo] = useState(true);
|
||||
|
||||
const directionRef = useRef<"next" | "prev">("next");
|
||||
const directionRef = useRef<'next' | 'prev'>('next');
|
||||
|
||||
const [isFullScreen, setIsFullScreen] = useState(false);
|
||||
|
||||
@@ -45,7 +45,7 @@ function SequenceSlider({ complexName }: SequenceSliderProps) {
|
||||
setImageLoaded((prev) => prev + 1);
|
||||
}
|
||||
|
||||
function handleSwipe(direction: "next" | "prev") {
|
||||
function handleSwipe(direction: 'next' | 'prev') {
|
||||
if (imageLoaded < FRAME_COUNT) return;
|
||||
directionRef.current = direction;
|
||||
setIsShowVideo(false);
|
||||
@@ -53,18 +53,18 @@ function SequenceSlider({ complexName }: SequenceSliderProps) {
|
||||
|
||||
function handleLoadVideo() {}
|
||||
|
||||
function animate(direction: "next" | "prev") {
|
||||
function animate(direction: 'next' | 'prev') {
|
||||
setIsAnimating(true);
|
||||
|
||||
const targetIndex =
|
||||
currentIndex + (direction === "next" ? FRAME_STEP : -FRAME_STEP); // -1, -2
|
||||
currentIndex + (direction === 'next' ? FRAME_STEP : -FRAME_STEP); // -1, -2
|
||||
|
||||
gsap.to(
|
||||
{ value: currentIndex },
|
||||
{
|
||||
value: targetIndex,
|
||||
duration: 1,
|
||||
ease: "power2.inOut",
|
||||
ease: 'power2.inOut',
|
||||
onUpdate: function () {
|
||||
const currentValue = Math.round(this.targets()[0].value);
|
||||
|
||||
@@ -103,21 +103,21 @@ function SequenceSlider({ complexName }: SequenceSliderProps) {
|
||||
handlers.ref(el);
|
||||
rootRef.current = el;
|
||||
}}
|
||||
className="relative h-full overflow-hidden"
|
||||
className='relative h-full overflow-hidden'
|
||||
>
|
||||
<AnimatePresence>
|
||||
{imageLoaded < FRAME_COUNT && (
|
||||
<motion.div
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="absolute inset-0 z-10 flex flex-col items-center justify-center gap-2 bg-white"
|
||||
className='absolute inset-0 z-10 flex flex-col items-center justify-center gap-2 bg-white'
|
||||
>
|
||||
<img
|
||||
src={`/images/loader.png`}
|
||||
alt=""
|
||||
className="w-16 h-16 animate-spin"
|
||||
alt=''
|
||||
className='w-16 h-16 animate-spin'
|
||||
/>
|
||||
<p className="text-[#00BED7] text-m">
|
||||
<p className='text-[#00BED7] text-m'>
|
||||
{Math.round((imageLoaded / FRAME_COUNT) * 100)}%
|
||||
</p>
|
||||
</motion.div>
|
||||
@@ -128,10 +128,10 @@ function SequenceSlider({ complexName }: SequenceSliderProps) {
|
||||
<img
|
||||
key={index}
|
||||
src={`/images/sequence/compressed-${
|
||||
window.innerWidth < 768 ? "mobile" : "desktop"
|
||||
window.innerWidth < 768 ? 'mobile' : 'desktop'
|
||||
}/${index}.jpg`}
|
||||
alt=""
|
||||
className="absolute object-cover w-full h-full pointer-events-none"
|
||||
alt=''
|
||||
className='absolute object-cover w-full h-full pointer-events-none'
|
||||
style={{
|
||||
opacity: index === currentIndex ? 1 : 0,
|
||||
}}
|
||||
@@ -144,13 +144,13 @@ function SequenceSlider({ complexName }: SequenceSliderProps) {
|
||||
<motion.video
|
||||
key={currentIndex}
|
||||
src={`/videos/sequence/${
|
||||
window.innerWidth < 768 ? "mobile" : "desktop"
|
||||
window.innerWidth < 768 ? 'mobile' : 'desktop'
|
||||
}/${Math.floor(currentIndex / FRAME_STEP) + 1}.mp4`}
|
||||
autoPlay
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
className="absolute object-cover w-full h-full"
|
||||
className='absolute object-cover w-full h-full'
|
||||
onLoad={handleLoadVideo}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
@@ -166,54 +166,59 @@ function SequenceSlider({ complexName }: SequenceSliderProps) {
|
||||
</AnimatePresence>
|
||||
{imageLoaded === FRAME_COUNT && (
|
||||
<>
|
||||
<div className="absolute flex 2xl:gap-[0.556vw] justify-between gap-2 2xl:left-[2.222vw] 2xl:right-[2.222vw] 2xl:top-[2.222vw] max-w-full md:max-2xl:left-6 md:max-2xl:right-6 md:max-2xl:top-6 left-4 right-4 top-4">
|
||||
<div className='absolute flex 2xl:gap-[0.556vw] justify-between gap-2 2xl:left-[2.222vw] 2xl:right-[2.222vw] 2xl:top-[2.222vw] max-w-full md:max-2xl:left-6 md:max-2xl:right-6 md:max-2xl:top-6 left-4 right-4 top-4'>
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="!bg-white"
|
||||
onClick={() => navigate("/")}
|
||||
variant='secondary'
|
||||
className='!bg-white'
|
||||
onClick={() => navigate('/')}
|
||||
>
|
||||
<span className="2xl:w-[1.389vw] 2xl:h-[1.389vw] w-5 h-5">
|
||||
<span className='2xl:w-[1.389vw] 2xl:h-[1.389vw] w-5 h-5'>
|
||||
<ArrowLeftIcon />
|
||||
</span>
|
||||
<span className="max-md:hidden">Map</span>
|
||||
<span className='max-md:hidden'>Map</span>
|
||||
</Button>
|
||||
<Button variant="secondary" size="small" className="max-md:hidden">
|
||||
<span className="2xl:w-[1.389vw] 2xl:h-[1.389vw] w-5 h-5">
|
||||
<Button
|
||||
variant='secondary'
|
||||
size='small'
|
||||
className='max-md:hidden'
|
||||
onClick={() => navigate('./about')}
|
||||
>
|
||||
<span className='2xl:w-[1.389vw] 2xl:h-[1.389vw] w-5 h-5'>
|
||||
<InfoIcon />
|
||||
</span>
|
||||
<span>About</span>
|
||||
</Button>
|
||||
</div>
|
||||
<p className="absolute text-xl font-bold text-white -translate-x-1/2 select-none left-1/2 top-9 max-md:hidden">
|
||||
<p className='absolute text-xl font-bold text-white -translate-x-1/2 select-none left-1/2 top-9 max-md:hidden'>
|
||||
ROVE Home Marasi Drive
|
||||
</p>
|
||||
|
||||
<Button
|
||||
onlyIcon
|
||||
variant="secondary"
|
||||
className="absolute top-1/2 -translate-y-1/2 2xl:left-[31.111vw] md:max-2xl:left-[8.854vw] left-4 !bg-[#0D1922]/40 backdrop-blur-md"
|
||||
variant='secondary'
|
||||
className='absolute top-1/2 -translate-y-1/2 2xl:left-[31.111vw] md:max-2xl:left-[8.854vw] left-4 !bg-[#0D1922]/40 backdrop-blur-md'
|
||||
roundedFull
|
||||
disabled={isAnimating || !isShowVideo}
|
||||
onClick={() => handleSwipe("prev")}
|
||||
onClick={() => handleSwipe('prev')}
|
||||
>
|
||||
<span className="2xl:w-[1.111vw] 2xl:h-[1.111vw] w-4 h-4 text-white">
|
||||
<span className='2xl:w-[1.111vw] 2xl:h-[1.111vw] w-4 h-4 text-white'>
|
||||
<ArrowLeftIcon />
|
||||
</span>
|
||||
</Button>
|
||||
<Button
|
||||
onlyIcon
|
||||
variant="secondary"
|
||||
className="absolute top-1/2 -translate-y-1/2 2xl:right-[31.111vw] md:max-2xl:right-[8.854vw] right-4 !bg-[#0D1922]/40 backdrop-blur-md"
|
||||
variant='secondary'
|
||||
className='absolute top-1/2 -translate-y-1/2 2xl:right-[31.111vw] md:max-2xl:right-[8.854vw] right-4 !bg-[#0D1922]/40 backdrop-blur-md'
|
||||
roundedFull
|
||||
disabled={isAnimating || !isShowVideo}
|
||||
onClick={() => handleSwipe("next")}
|
||||
onClick={() => handleSwipe('next')}
|
||||
>
|
||||
<span className="2xl:w-[1.111vw] 2xl:h-[1.111vw] w-4 h-4 text-white">
|
||||
<span className='2xl:w-[1.111vw] 2xl:h-[1.111vw] w-4 h-4 text-white'>
|
||||
<ArrowRightIcon />
|
||||
</span>
|
||||
</Button>
|
||||
<Compass imgStyle={{ transform: `rotate(${currentIndex}deg)` }} />
|
||||
<div className="absolute 2xl:bottom-[2.222vw] 2xl:right-[2.222vw] 2xl:left-[2.222vw] max-w-full flex justify-end items-center 2xl:gap-[0.556vw] gap-2 md:max-2xl:bottom-6 md:max-2xl:left-6 md:max-2xl:right-6 bottom-4 left-4 right-4">
|
||||
<div className='absolute 2xl:bottom-[2.222vw] 2xl:right-[2.222vw] 2xl:left-[2.222vw] max-w-full flex justify-end items-center 2xl:gap-[0.556vw] gap-2 md:max-2xl:bottom-6 md:max-2xl:left-6 md:max-2xl:right-6 bottom-4 left-4 right-4'>
|
||||
<DisclaimerButton />
|
||||
<PrivacyPolicyButton />
|
||||
<FullScreenButton
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import { useState } from 'react';
|
||||
import ArrowLeftIcon from './icons/ArrowLeftIcon';
|
||||
import ArrowRightIcon from './icons/map/ArrowRightIcon';
|
||||
import { dubaiMarinaWellnessSlides } from '../data/aboutDubaiMarina';
|
||||
import { AnimatePresence, motion } from 'motion/react';
|
||||
|
||||
function Slider() {
|
||||
const [currentSlide, setCurrentSlide] = useState(0);
|
||||
const [direction, setDirection] = useState(-1);
|
||||
|
||||
const handleNextSlide = () => {
|
||||
if (currentSlide < dubaiMarinaWellnessSlides.length - 1) {
|
||||
setDirection(1);
|
||||
setCurrentSlide(currentSlide + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePreviousSlide = () => {
|
||||
if (currentSlide > 0) {
|
||||
setDirection(-1);
|
||||
setCurrentSlide(currentSlide - 1);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='relative w-[63.333vw] h-[27.639vw] rounded-3xl overflow-hidden'>
|
||||
<AnimatePresence custom={direction}>
|
||||
<motion.div
|
||||
key={currentSlide}
|
||||
className='absolute inset-0 bg-cover bg-no-repeat bg-center'
|
||||
style={{
|
||||
backgroundImage: `url(${dubaiMarinaWellnessSlides[currentSlide].image})`,
|
||||
}}
|
||||
custom={direction}
|
||||
initial={{ x: direction > 0 ? '100%' : '-100%' }}
|
||||
animate={{ x: 0, transition: { duration: 0.5, ease: 'easeInOut' } }}
|
||||
exit={{
|
||||
x: direction > 0 ? '100%' : '-100%',
|
||||
transition: { duration: 0.8, ease: 'easeInOut' },
|
||||
}}
|
||||
/>
|
||||
</AnimatePresence>
|
||||
<div className='relative z-10 w-full h-full flex flex-col justify-between p-6'>
|
||||
<div className='flex flex-col gap-4'>
|
||||
<AnimatePresence mode='wait'>
|
||||
<motion.h3
|
||||
key={`title-${currentSlide}`}
|
||||
className='text-subheadline-m'
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
{dubaiMarinaWellnessSlides[currentSlide].title}
|
||||
</motion.h3>
|
||||
</AnimatePresence>
|
||||
<AnimatePresence mode='wait'>
|
||||
<motion.p
|
||||
key={`desc-${currentSlide}`}
|
||||
className='text-s w-[19.861vw] tracking-[-0.07em] leading-[140%]'
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
{dubaiMarinaWellnessSlides[currentSlide].description}
|
||||
</motion.p>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
<div className='flex items-center gap-[0.556vw] relative'>
|
||||
<div
|
||||
className='w-10 h-10 rounded-xl text-[#0D1922] bg-white flex items-center justify-center cursor-pointer hover:bg-[#F3F3F2] transition-all duration-200'
|
||||
onClick={handlePreviousSlide}
|
||||
>
|
||||
<span className='w-5 h-5'>
|
||||
<ArrowLeftIcon />
|
||||
</span>
|
||||
</div>
|
||||
<div className='text-s'>
|
||||
{currentSlide + 1}/{dubaiMarinaWellnessSlides.length}
|
||||
</div>
|
||||
<div
|
||||
className='w-10 h-10 rounded-xl text-[#0D1922] bg-white flex items-center justify-center cursor-pointer hover:bg-[#F3F3F2] transition-all duration-200'
|
||||
onClick={handleNextSlide}
|
||||
>
|
||||
<span className='w-5 h-5'>
|
||||
<ArrowRightIcon />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Slider;
|
||||
@@ -0,0 +1,9 @@
|
||||
function TextBox({ text }: { text: string }) {
|
||||
return (
|
||||
<div className='text-caption-m px-4 py-1.5 border border-[#E2E2DC] rounded-[40px] w-fit text-[#0D1922]'>
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TextBox;
|
||||
@@ -0,0 +1,20 @@
|
||||
function EqualIcon() {
|
||||
return (
|
||||
<svg
|
||||
viewBox='0 0 20 20'
|
||||
fill='currentColor'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
>
|
||||
<path
|
||||
d='M16.6654 7.64815C16.6654 7.29019 16.3752 7 16.0172 7H10.647H3.98018C3.62222 7 3.33203 7.29019 3.33203 7.64815C3.33203 8.00611 3.62222 8.2963 3.98018 8.2963H10.647H16.0172C16.3752 8.2963 16.6654 8.00611 16.6654 7.64815Z'
|
||||
fill='currentColor'
|
||||
/>
|
||||
<path
|
||||
d='M16.6654 12.2966C16.6654 11.9386 16.3752 11.6484 16.0172 11.6484H10.647H3.98018C3.62222 11.6484 3.33203 11.9386 3.33203 12.2966C3.33203 12.6545 3.62222 12.9447 3.98018 12.9447H10.647H16.0172C16.3752 12.9447 16.6654 12.6545 16.6654 12.2966Z'
|
||||
fill='currentColor'
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default EqualIcon;
|
||||
@@ -0,0 +1,75 @@
|
||||
export const roveHomeDescription = [
|
||||
'Fullyfurnished apartments',
|
||||
'Vibrant art installations',
|
||||
'Inspiring design',
|
||||
] as const;
|
||||
|
||||
export const wellnessDescription = [
|
||||
'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',
|
||||
] as const;
|
||||
|
||||
export const dubaiMarinaFeatures = [
|
||||
{
|
||||
name: 'Life-enhancing Amenties',
|
||||
image: '/images/about-complex/dubai-marina/amenties.jpg',
|
||||
},
|
||||
{
|
||||
name: 'Community',
|
||||
image: '/images/about-complex/dubai-marina/community.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: '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: 'Fitness',
|
||||
description: 'Cancel all your membership. Your new home has it all',
|
||||
},
|
||||
{
|
||||
title: 'Community',
|
||||
description: 'Connect. Engage. Thrive.',
|
||||
},
|
||||
{
|
||||
title: 'Convenience',
|
||||
description: 'Your smart living hub',
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const dubaiMarinaWellnessSlides = [
|
||||
{
|
||||
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',
|
||||
},
|
||||
{
|
||||
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',
|
||||
},
|
||||
] as const;
|
||||
@@ -1,12 +1,13 @@
|
||||
@import url("/fonts/Usual/stylesheet.css");
|
||||
@import "tailwindcss";
|
||||
@import url('/fonts/Usual/stylesheet.css');
|
||||
@import url('/fonts/Mixcase/stylesheet.css');
|
||||
@import 'tailwindcss';
|
||||
|
||||
@theme {
|
||||
--breakpoint-2xl: 1440px;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Usual", sans-serif;
|
||||
font-family: 'Usual', sans-serif;
|
||||
color: #0d1922;
|
||||
}
|
||||
|
||||
@@ -20,6 +21,14 @@ button {
|
||||
@apply 2xl:text-[clamp(56px,3.889vw,68px)] md:max-2xl:text-[clamp(44px,6.366vw,56px)] text-[44px] leading-none;
|
||||
}
|
||||
|
||||
.text-h4 {
|
||||
@apply 2xl:text-[clamp(20px,1.389vw,28px)] text-[20px] leading-[120%];
|
||||
}
|
||||
|
||||
.text-h5 {
|
||||
@apply 2xl:text-[clamp(14px,0.972vw,20px)] text-[14px] leading-[125%];
|
||||
}
|
||||
|
||||
.text-subheadline-l {
|
||||
@apply 2xl:text-[clamp(40px,2.778vw,48px)] md:max-2xl:text-[clamp(32px,4.63vw,40px)] text-[32px] leading-[135%];
|
||||
}
|
||||
@@ -48,3 +57,7 @@ button {
|
||||
@apply 2xl:text-[clamp(10px,0.694vw,12px)] text-[10px] leading-[135%];
|
||||
}
|
||||
}
|
||||
|
||||
@utility font-mixcase-unmixed {
|
||||
font-family: 'Mixcase Unmixed', sans-serif;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
import Header from "../components/Header";
|
||||
import { Outlet } from "react-router";
|
||||
import Footer from "../components/Footer";
|
||||
import Header from '../components/Header';
|
||||
import { Outlet, useLocation } from 'react-router';
|
||||
import Footer from '../components/Footer';
|
||||
import clsx from 'clsx';
|
||||
|
||||
function DefaultLayout() {
|
||||
const { pathname } = useLocation();
|
||||
console.log(pathname);
|
||||
return (
|
||||
<div className="min-h-dvh flex flex-col select-none bg-[#F3F3F2]">
|
||||
<div
|
||||
className={clsx(
|
||||
'min-h-dvh flex flex-col select-none',
|
||||
pathname.endsWith('/about') ? 'bg-white' : 'bg-[#F3F3F2]'
|
||||
)}
|
||||
>
|
||||
<Header />
|
||||
<div className="flex-1 flex flex-col justify-between">
|
||||
<div className='flex-1 flex flex-col justify-between'>
|
||||
<Outlet />
|
||||
</div>
|
||||
<Footer />
|
||||
|
||||
@@ -1,66 +1,66 @@
|
||||
import "./index.css";
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { createBrowserRouter, RouterProvider } from "react-router";
|
||||
import DefaultLayout from "./layout/DefaultLayout.tsx";
|
||||
import MainPage from "./pages/MainPage.tsx";
|
||||
import ModalContainer from "./components/ModalContainer.tsx";
|
||||
import ComplexPage from "./pages/ComplexPage.tsx";
|
||||
import FloorsPage from "./pages/FloorsPage.tsx";
|
||||
import UnitTypesPage from "./pages/UnitTypesPage.tsx";
|
||||
import AboutPage from "./pages/AboutPages.tsx";
|
||||
import FavoritesPage from "./pages/FavouritesPage.tsx";
|
||||
import SearchPage from "./pages/SearchPage.tsx";
|
||||
import LayoutWithoutFooter from "./layout/LayoutWithoutFooter.tsx";
|
||||
import { queryClient } from "./lib/queryClient.ts";
|
||||
import AboutComplexPage from "./pages/AboutComplexPage.tsx";
|
||||
import './index.css';
|
||||
import { QueryClientProvider } from '@tanstack/react-query';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { createBrowserRouter, RouterProvider } from 'react-router';
|
||||
import DefaultLayout from './layout/DefaultLayout.tsx';
|
||||
import MainPage from './pages/MainPage.tsx';
|
||||
import ModalContainer from './components/ModalContainer.tsx';
|
||||
import ComplexPage from './pages/ComplexPage.tsx';
|
||||
import FloorsPage from './pages/FloorsPage.tsx';
|
||||
import UnitTypesPage from './pages/UnitTypesPage.tsx';
|
||||
import AboutPage from './pages/AboutPages.tsx';
|
||||
import FavoritesPage from './pages/FavouritesPage.tsx';
|
||||
import SearchPage from './pages/SearchPage.tsx';
|
||||
import LayoutWithoutFooter from './layout/LayoutWithoutFooter.tsx';
|
||||
import { queryClient } from './lib/queryClient.ts';
|
||||
import AboutComplexPage from './pages/AboutComplexPage.tsx';
|
||||
|
||||
const route = createBrowserRouter([
|
||||
{
|
||||
element: <DefaultLayout />,
|
||||
children: [
|
||||
{
|
||||
path: "/unit-types",
|
||||
path: '/unit-types',
|
||||
element: <UnitTypesPage />,
|
||||
},
|
||||
{
|
||||
path: "/about",
|
||||
path: '/about',
|
||||
element: <AboutPage />,
|
||||
},
|
||||
{
|
||||
path: "/favorites",
|
||||
path: '/favorites',
|
||||
element: <FavoritesPage />,
|
||||
},
|
||||
{
|
||||
path: "/search",
|
||||
path: '/search',
|
||||
element: <SearchPage />,
|
||||
},
|
||||
{
|
||||
path: '/complex/:complexName/about',
|
||||
element: <AboutComplexPage />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
element: <LayoutWithoutFooter />,
|
||||
children: [
|
||||
{
|
||||
path: "/",
|
||||
path: '/',
|
||||
element: <MainPage />,
|
||||
},
|
||||
{
|
||||
path: "/complex/:complexName",
|
||||
path: '/complex/:complexName',
|
||||
element: <ComplexPage />,
|
||||
},
|
||||
{
|
||||
path: "/complex/:complexName/floors",
|
||||
path: '/complex/:complexName/floors',
|
||||
element: <FloorsPage />,
|
||||
},
|
||||
{
|
||||
path: "/complex/:complexName/about",
|
||||
element: <AboutComplexPage />,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<RouterProvider router={route} />
|
||||
|
||||
@@ -1,5 +1,258 @@
|
||||
import { useScroll, useTransform, motion, useInView } from 'motion/react';
|
||||
import { useRef } from 'react';
|
||||
import {
|
||||
dubaiMarinaFeatures,
|
||||
dubaiMarinaDescription,
|
||||
roveHomeDescription,
|
||||
wellnessDescription,
|
||||
} from '../data/aboutDubaiMarina';
|
||||
|
||||
import EqualIcon from '../components/icons/EqualIcon';
|
||||
import TextBox from '../components/TextBox';
|
||||
import clsx from 'clsx';
|
||||
import Slider from '../components/Slider';
|
||||
import PlusIcon from '../components/icons/map/PlusIcon';
|
||||
|
||||
function AboutComplexPage() {
|
||||
return <div></div>;
|
||||
const containerRef = useRef(null);
|
||||
const sliderRef = useRef(null);
|
||||
const mapRef = useRef(null);
|
||||
|
||||
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='h-[calc(100dvh-4.444vw)] w-full bg-white text-black fixed top-[4.444vw] left-0 right-0 z-0'
|
||||
style={{
|
||||
opacity: firstSectionOpacity,
|
||||
}}
|
||||
>
|
||||
<div className='absolute inset-0'>
|
||||
<img
|
||||
src='/images/about-complex/dubai-marina/tower.jpg'
|
||||
alt='dubai marina about'
|
||||
className='h-full w-full object-contain object-top'
|
||||
/>
|
||||
<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]'
|
||||
/>
|
||||
</div>
|
||||
<div className='relative flex flex-col justify-between gap-[4.444vw] flex-1 w-full h-full pt-[5vw] pb-[2.5vw] pl-[2.222vw]'>
|
||||
<div className='text-2xl font-bold whitespace-pre-line space-y-8'>
|
||||
<h1 className='text-[5vw] leading-none tracking-[-0.07em] font-mixcase-unmixed font-[500]'>
|
||||
{`Rove Home
|
||||
Dubai Marina`}
|
||||
</h1>
|
||||
<div className='space-y-2 font-[400]'>
|
||||
{roveHomeDescription.map((description) => (
|
||||
<TextBox text={description} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className='space-y-8'>
|
||||
<h4 className='text-h4 text-[#00BED7] w-[20.486vw] font-[500] '>
|
||||
{`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>
|
||||
</motion.section>
|
||||
<motion.section
|
||||
className='w-full text-white bg-white flex justify-center top-[4.444vw] left-0 right-0'
|
||||
style={{
|
||||
y: secondSectionY,
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<div className='w-full'>
|
||||
<div className='flex flex-col items-center gap-[2.222vw] w-full pb-[3.75vw]'>
|
||||
<div className='px-8 flex pt-[7.222vw] flex-col items-center gap-[2.222vw]'>
|
||||
<h1 className='text-[3.889vw] text-[#0D1922] font-mixcase-unmixed'>
|
||||
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] h-[26.667vw] w-full px-[2.222vw]'>
|
||||
{dubaiMarinaFeatures.map((feature) => (
|
||||
<div
|
||||
key={feature.name}
|
||||
className={`rounded-3xl flex-1 h-[26.667vw] w-full flex flex-col items-center py-[1.667vw] justify-end bg-cover bg-center bg-no-repeat`}
|
||||
style={{
|
||||
backgroundImage: `url(${feature.image})`,
|
||||
}}
|
||||
>
|
||||
<h5 className='text-h5 text-white tracking-[-0.02em]'>
|
||||
{feature.name}
|
||||
</h5>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col items-center pt-[4.444vw] h-auto px-8 gap-[4.444vw]'>
|
||||
<h1 className='font-mixcase-unmixed text-[3.889vw] text-[#0D1922]'>
|
||||
Dubai, <span className='text-[#0D192266]'>within reach</span>
|
||||
</h1>
|
||||
<div className='flex w-full text-[#0D192266] gap-[1.111vw]'>
|
||||
{dubaiMarinaDescription.map((descriptionItem) => (
|
||||
<div className='flex-1 text-center flex flex-col gap-[1.111vw]'>
|
||||
<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 === 'Wellness' && 'text-[#00BED7]'
|
||||
)}
|
||||
>
|
||||
{descriptionItem.title}
|
||||
</h5>
|
||||
<p
|
||||
className={clsx(
|
||||
'text-s leading-[125%] tracking-[-0.02em]',
|
||||
descriptionItem.title === 'Wellness' && 'text-[#0D1922] '
|
||||
)}
|
||||
>
|
||||
{descriptionItem.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<motion.div
|
||||
ref={sliderRef}
|
||||
initial={{ opacity: 0, y: 40 }}
|
||||
animate={
|
||||
isSliderInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 140 }
|
||||
}
|
||||
transition={{ duration: 0.6, ease: 'easeOut' }}
|
||||
className='flex flex-col gap-8'
|
||||
>
|
||||
<Slider />
|
||||
<div className='flex gap-[0.556vw] w-[63.333vw] flex-wrap justify-center'>
|
||||
{wellnessDescription.map((wellnessItem) => (
|
||||
<TextBox text={wellnessItem} />
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
<div className='text-center w-full flex flex-col items-center gap-[2.222vw] bg-white'>
|
||||
<h1 className='font-mixcase-unmixed text-[3.889vw] text-[#0D1922] w-[44.861vw] leading-[100%] tracking-[-0.05em] pt-[8.056vw]'>
|
||||
Dubai's first-ever combinable Apartments
|
||||
</h1>
|
||||
<TextBox text='On-demand' />
|
||||
<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'>
|
||||
<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'>
|
||||
<h4 className='text-h4 tracking-[-0.02em] font-[500]'>
|
||||
Studio²
|
||||
</h4>
|
||||
</div>
|
||||
<div className='w-10 h-10 rounded-full bg-[#0D1922] flex items-center justify-center absolute left-[18.500vw] self-center'>
|
||||
<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'>
|
||||
<h4 className='text-h4 tracking-[-0.02em] font-[500]'>
|
||||
Studio²
|
||||
</h4>
|
||||
</div>
|
||||
<div className='w-10 h-10 rounded-full bg-[#0D1922] flex items-center justify-center absolute left-[38.333vw] self-center'>
|
||||
<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'>
|
||||
<h4 className='text-h4 tracking-[-0.02em] font-[500]'>
|
||||
1 Bedroom²
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex gap-4 relative'>
|
||||
<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'>
|
||||
<h4 className='text-h4 tracking-[-0.02em] font-[500]'>
|
||||
Studio²
|
||||
</h4>
|
||||
</div>
|
||||
<div className='w-10 h-10 rounded-full bg-[#0D1922] flex items-center justify-center absolute left-[18.500vw] self-center'>
|
||||
<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'>
|
||||
<h4 className='text-h4 tracking-[-0.02em] font-[500]'>
|
||||
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'>
|
||||
<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'>
|
||||
<h4 className='text-h4 tracking-[-0.02em] font-[500]'>
|
||||
2 Bedroom²
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col items-center gap-[2.222vw] bg-white px-[2.222vw] pb-[8.333vw]'>
|
||||
<h1 className='font-mixcase-unmixed text-[3.889vw] text-[#0D1922] w-[44.861vw] leading-[100%] tracking-[-0.05em] pt-[7.222vw]'>
|
||||
Live central. Live centred
|
||||
</h1>
|
||||
<p className='text-s w-[35.278vw] text-[#0D1922B2] leading-[140%] tracking-[-0.02em] text-center whitespace-pre-line'>
|
||||
{`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.jpg'
|
||||
alt=''
|
||||
className='rounded-3xl object-cover object-center aspect-[1376/609]'
|
||||
initial={{ width: '47.083vw' }}
|
||||
animate={
|
||||
isMapInView ? { width: '95.556vw' } : { width: '47.083vw' }
|
||||
}
|
||||
transition={{ duration: 0.6, ease: 'easeInOut' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AboutComplexPage;
|
||||
|
||||