About Marasi Drive Table Mobile
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"date-fns-tz": "^3.2.0",
|
||||
"eruda": "^3.4.3",
|
||||
"gsap": "^3.12.7",
|
||||
"ky": "^1.8.1",
|
||||
"motion": "^12.6.3",
|
||||
@@ -314,6 +315,8 @@
|
||||
|
||||
"enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="],
|
||||
|
||||
"eruda": ["eruda@3.4.3", "", {}, "sha512-J2TsF4dXSspOXev5bJ6mljv0dRrxj21wklrDzbvPmYaEmVoC+2psylyRi70nUPFh1mTQfIBsSusUtAMZtUN+/w=="],
|
||||
|
||||
"esbuild": ["esbuild@0.25.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.2", "@esbuild/android-arm": "0.25.2", "@esbuild/android-arm64": "0.25.2", "@esbuild/android-x64": "0.25.2", "@esbuild/darwin-arm64": "0.25.2", "@esbuild/darwin-x64": "0.25.2", "@esbuild/freebsd-arm64": "0.25.2", "@esbuild/freebsd-x64": "0.25.2", "@esbuild/linux-arm": "0.25.2", "@esbuild/linux-arm64": "0.25.2", "@esbuild/linux-ia32": "0.25.2", "@esbuild/linux-loong64": "0.25.2", "@esbuild/linux-mips64el": "0.25.2", "@esbuild/linux-ppc64": "0.25.2", "@esbuild/linux-riscv64": "0.25.2", "@esbuild/linux-s390x": "0.25.2", "@esbuild/linux-x64": "0.25.2", "@esbuild/netbsd-arm64": "0.25.2", "@esbuild/netbsd-x64": "0.25.2", "@esbuild/openbsd-arm64": "0.25.2", "@esbuild/openbsd-x64": "0.25.2", "@esbuild/sunos-x64": "0.25.2", "@esbuild/win32-arm64": "0.25.2", "@esbuild/win32-ia32": "0.25.2", "@esbuild/win32-x64": "0.25.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ=="],
|
||||
|
||||
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
||||
|
||||
@@ -5,15 +5,21 @@ import {
|
||||
} from "../data/aboutMarasiDrive";
|
||||
import MarariDriveNeighboursSliderDesktop from "./MarasiDriveNeighboursSliderDesktop";
|
||||
import MarasiDriveInteriorsSlider from "./MarasiDriveInteriorsSlider";
|
||||
import MarasiDriveInteriorsSliderMobile from "./MarasiDriveInteriorsSliderMobile";
|
||||
import MarasiDriveNeighboursSliderMobile from "./MarasiDriveNeighboursSliderMobile";
|
||||
import MarasiDriveMapMobile from "./MarasiDriveMapMobile";
|
||||
import TextBox from "./ui/TextBox";
|
||||
import { useRef } from "react";
|
||||
import { useScroll } from "motion/react";
|
||||
import MarasiDriveMapCard from "./MarasiDriveMapCard";
|
||||
import BrochureButton from "./ui/BrochureButton";
|
||||
|
||||
import MarasiDriveNeighboursSliderTablet from "./MarasiDriveNeighboursSliderTablet";
|
||||
import CustomScrollBar from "./ui/ScrollBar";
|
||||
import BrochureButton from "./ui/BrochureButton";
|
||||
|
||||
function AboutMarasiDrive() {
|
||||
const target = useRef<HTMLDivElement>(null);
|
||||
const homeSliderRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { scrollYProgress } = useScroll({
|
||||
target,
|
||||
@@ -22,7 +28,7 @@ function AboutMarasiDrive() {
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="2xl:sticky relative 2xl:top-[4.444vw]">
|
||||
<section className="w-full bg-white 2xl:h-[calc(100dvh-4.444vw)] md:max-2xl:h-[calc(100dvh-64px)] h-[calc(100dvh-56px)] 2xl:p-[2.222vw] 2xl:pt-[5vw] md:max-2xl:p-6 md:max-2xl:pt-10 p-4 pt-8 flex flex-col justify-between">
|
||||
<section className="w-full bg-white 2xl:h-[calc(100dvh-4.444vw)] md:max-2xl:h-[calc(100dvh-64px)] h-[calc(100dvh-56px)] max-md:h-[calc(100vw*1.62)] 2xl:p-[2.222vw] 2xl:pt-[5vw] md:max-2xl:p-6 md:max-2xl:pt-10 p-4 pt-8 flex flex-col justify-between">
|
||||
<div className="absolute inset-0">
|
||||
<img
|
||||
src="/images/about-complex/marasi-drive/main_c.jpg"
|
||||
@@ -37,7 +43,7 @@ function AboutMarasiDrive() {
|
||||
<img
|
||||
src="/images/about-complex/marasi-drive/main-mobile_c.jpg"
|
||||
alt=""
|
||||
className="object-cover md:hidden size-full"
|
||||
className="object-cover md:hidden max-md:w-[100%]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -67,7 +73,7 @@ function AboutMarasiDrive() {
|
||||
</section>
|
||||
<section>
|
||||
<div className="space-y-6 bg-white px-4 py-8 md:hidden">
|
||||
<h4 className="text-h4 text-[#00BED7] font-medium whitespace-pre-line">
|
||||
<h4 className="text-h4 text-[#00BED7] font-medium whitespace-pre-line ">
|
||||
{`A home for the young
|
||||
and young in heart`}
|
||||
</h4>
|
||||
@@ -86,23 +92,25 @@ function AboutMarasiDrive() {
|
||||
{`What makes
|
||||
a Rove Home?`}
|
||||
</h2>
|
||||
<p className="opacity-70 text-s whitespace-pre-line text-center">
|
||||
<p className="opacity-70 text-s whitespace-pre-line text-center max-md:whitespace-normal">
|
||||
{`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 max-2xl:flex-wrap max-2xl:justify-center 2xl:gap-[0.556vw] gap-2 md:max-2xl:w-[93.75vw]">
|
||||
<div ref={homeSliderRef} className="flex max-2xl:flex-wrap max-2xl:justify-center 2xl:gap-[0.556vw] gap-2 md:max-2xl:w-[93.75vw] max-md:flex-row max-md:flex-nowrap max-md:overflow-x-scroll max-md:overflow-y-hidden max-md:justify-start max-md:snap-x max-md:snap-mandatory [&::-webkit-scrollbar]:h-[1.111vw] [&::-webkit-scrollbar]:w-[none] [&::-webkit-scrollbar-thumb]:bg-transparent [&::-webkit-scrollbar-thumb]:w-4 [&::-webkit-scrollbar-thumb]:rounded-full max-md:-mx-4 max-md:px-4">
|
||||
{marasiDriveFeatures.map(({ image, name }) => (
|
||||
<div key={name} className="md:max-2xl:w-[30.208vw]">
|
||||
<div key={name} className="relative md:max-2xl:w-[30.208vw] max-md:w-full max-md:max-w-[530px] max-md:flex-shrink-0 max-md:snap-center">
|
||||
<img
|
||||
src={image}
|
||||
alt={name}
|
||||
className="object-cover rounded-[1.667vw]"
|
||||
className="object-cover object-center 2xl:rounded-[1.667vw] max-md:!aspect-[328/287] max-md:rounded-2xl md:max-2xl:rounded-[3.125vw]"
|
||||
/>
|
||||
<span className="md:hidden absolute bottom-[16px] text-white text-h5 left-1/2 -translate-x-1/2 text-center text-nowrap">{name}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<CustomScrollBar containerRef={homeSliderRef} inlinePadding={16} trackStyle="min-md:hidden" thumbStyle="min-md:hidden" />
|
||||
</section>
|
||||
<section className="bg-white w-full overflow-clip flex flex-col 2xl:gap-[4.444vw] gap-12 2xl:pt-[9.444vw] 2xl:px-[2.222vw] 2xl:pb-[2.222vw] md:max-2xl:pt-[104px] md:max-2xl:px-6 md:max-2xl:pb-8 pt-16 px-4 pb-8">
|
||||
<div className="flex flex-col 2xl:gap-[2.222vw] md:max-2xl:gap-8 gap-6 items-center">
|
||||
@@ -110,7 +118,7 @@ function AboutMarasiDrive() {
|
||||
{`Expandable living
|
||||
solutions`}
|
||||
</h2>
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center">
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center max-md:whitespace-normal">
|
||||
{`ORI introduces a revolutionary solution to apartment living,
|
||||
where space is not just a constraint but an opportunity.`}
|
||||
</p>
|
||||
@@ -144,12 +152,12 @@ function AboutMarasiDrive() {
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="bg-white w-full overflow-clip flex flex-col 2xl:gap-[4.444vw] gap-12 2xl:pt-[9.444vw] 2xl:pb-[15vw] 2xl:px-[2.222vw] md:max-2xl:pt-[104px] md:max-2xl:px-6 md:max-2xl:pb-8 pt-16 px-4 max-md:pb-8">
|
||||
<div className="flex flex-col 2xl:gap-[2.222vw] md:max-2xl:gap-8 gap-6 items-center">
|
||||
<section className="bg-white w-full overflow-clip flex flex-col 2xl:gap-[4.444vw] gap-12 2xl:pt-[9.444vw] 2xl:pb-[15vw] 2xl:px-[2.222vw] md:max-2xl:pt-[104px] md:max-2xl:px-6 md:max-2xl:pb-8 pt-16 px-4 max-md:pb-8 max-md:gap-0">
|
||||
<div className="flex flex-col 2xl:gap-[2.222vw] md:max-2xl:gap-8 gap-6 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">
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center max-md:whitespace-normal max-md:mb-10">
|
||||
{`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
|
||||
@@ -157,6 +165,7 @@ function AboutMarasiDrive() {
|
||||
</p>
|
||||
</div>
|
||||
<MarasiDriveInteriorsSlider />
|
||||
<MarasiDriveInteriorsSliderMobile/>
|
||||
</section>
|
||||
</div>
|
||||
<div className="2xl:sticky relative">
|
||||
@@ -166,7 +175,7 @@ function AboutMarasiDrive() {
|
||||
{`A home for the young
|
||||
and young in heart`}
|
||||
</h2>
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center">
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center max-md:whitespace-normal">
|
||||
{`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.`}
|
||||
@@ -184,10 +193,10 @@ function AboutMarasiDrive() {
|
||||
>
|
||||
<div className="flex flex-col 2xl:gap-[4.444vw] 2xl: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">
|
||||
<h2 className="font-mixcase-unmixed text-h1 text-center whitespace-pre-line max-md:mb-[24px] md:max-2xl:mb-8">
|
||||
{`Explore the neighbourhood`}
|
||||
</h2>
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center">
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center max-md:whitespace-normal max-md:mb-12 md:max-2xl:mb-16">
|
||||
{`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!`}
|
||||
@@ -197,20 +206,21 @@ function AboutMarasiDrive() {
|
||||
scrollYProgress={scrollYProgress}
|
||||
/>
|
||||
<MarasiDriveNeighboursSliderTablet />
|
||||
<MarasiDriveNeighboursSliderMobile />
|
||||
</div>
|
||||
</section>
|
||||
<section className="bg-white w-full overflow-clip flex flex-col gap-[3.333vw] 2xl:pt-[9.444vw] 2xl:px-[2.222vw] 2xl:pb-[2.222vw] md:max-2xl:pt-[104px] md:max-2xl:px-6 md:max-2xl:pb-8 pt-16 px-4 pb-8">
|
||||
<div className="flex flex-col gap-[2.222vw] items-center">
|
||||
<section className="bg-white w-full overflow-clip flex flex-col gap-[3.333vw] 2xl:pt-[9.444vw] 2xl:px-[2.222vw] 2xl:pb-[2.222vw] md:max-2xl:pt-[104px] md:max-2xl:px-6 pt-16 px-4 pb-8 md:max-2xl:pb-6 md:max-2xl:gap-[6.25vw]">
|
||||
<div className="flex flex-col gap-[2.222vw] items-center max-md:gap-[8.889vw] md:max-2xl:gap-[4.167vw]">
|
||||
<h2 className="text-h1 font-mixcase-unmixed">
|
||||
Rove around the city
|
||||
</h2>
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center">
|
||||
<p className="text-s opacity-70 whitespace-pre-line text-center max-md:mb-[48px] max-md:whitespace-normal">
|
||||
{`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 className="grid grid-cols-6 grid-rows-5 gap-x-[1.111vw] gap-y-[0.556vw] max-2xl:hidden">
|
||||
{marasiDriveMapCards.map((card) => (
|
||||
<MarasiDriveMapCard {...card} key={card.title} />
|
||||
))}
|
||||
@@ -222,29 +232,30 @@ function AboutMarasiDrive() {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<MarasiDriveMapMobile/>
|
||||
</section>
|
||||
<section className="bg-white w-full overflow-clip flex items-stretch justify-center gap-[1.111vw] 2xl:px-[10.278vw] 2xl:pt-[9.444vw] 2xl:pb-[15vw] md:max-2xl:py-[104px] md:mx-2xl:px-6 max-md:pt-20 max-md:pb-12 px-4">
|
||||
<div>
|
||||
<section className="bg-white w-full overflow-clip flex items-stretch justify-center gap-[1.111vw] 2xl:px-[10.278vw] 2xl:pt-[9.444vw] 2xl:pb-[15vw] md:max-2xl:py-[104px] md:mx-2xl:px-6 max-md:pt-20 max-md:pb-12 px-4 max-2xl:flex-col-reverse md:max-2xl:gap-[6.25vw] md:max-2xl:px-6">
|
||||
<div >
|
||||
<img
|
||||
src="/images/about-complex/marasi-drive/podium.png"
|
||||
className="object-cover size-full rounded-[1.667vw]"
|
||||
className="object-cover size-full rounded-[1.667vw] max-md:mt-[48px] max-md:aspect-[328/400] max-md:rounded-[6.667vw] md:max-2xl:rounded-[3.125vw] md:max-2xl:aspect-[720/400]"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div className="px-[2.778vw] flex flex-col gap-[3.333vw]">
|
||||
<div className="px-[2.778vw] flex flex-col gap-[3.333vw] max-2xl:px-0 md:max-2xl:gap-[6.25vw]">
|
||||
<div className="space-y-[1.111vw]">
|
||||
<h2 className="whitespace-pre-line text-h2 font-medium">
|
||||
<h2 className="whitespace-pre-line text-h2 font-medium max-2xl:mb-4">
|
||||
{`Live Different
|
||||
with Rove Home`}
|
||||
</h2>
|
||||
<p className="opacity-40 text-s">
|
||||
<p className="opacity-40 text-s max-md:mb-[32px] md:max-2xl:max-w-[57.943vw]">
|
||||
{`Experience the difference with Rove Home where modern amenities,
|
||||
trendy interiors, and smart features cater to your unique style.`}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-[1.111vw]">
|
||||
<h5 className="text-h5 font-medium">Download our brochures</h5>
|
||||
<div className="space-y-[0.833vw]">
|
||||
<h5 className="text-h5 font-medium max-md:mb-[16px] md:max-2xl:mb-[2.083vw]">Download our brochures</h5>
|
||||
<div className="space-y-[0.833vw] max-md:space-y-[3.333vw] md:max-2xl:space-y-[1.563vw]">
|
||||
<BrochureButton
|
||||
title={"Main Brochure"}
|
||||
link="/files/marasi-drive/Main Brochure.pdf"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { marasiDriveInspiredInteriors } from "../data/aboutMarasiDrive";
|
||||
import CustomScrollBar from "./ui/ScrollBar";
|
||||
import { useRef } from "react";
|
||||
|
||||
function MarasiDriveInteriorsSliderMobile(){
|
||||
const interiorsRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
|
||||
return(
|
||||
<>
|
||||
<div ref={interiorsRef} className="flex min-md:hidden max-md:flex-nowrap max-md:overflow-x-scroll max-md:gap-x-[8px] max-md:overflow-y-hidden max-md:justify-start max-md:snap-x max-md:snap-mandatory [&::-webkit-scrollbar]:h-[1.111vw] [&::-webkit-scrollbar]:w-[none] [&::-webkit-scrollbar-thumb]:bg-transparent [&::-webkit-scrollbar-thumb]:w-4 [&::-webkit-scrollbar-thumb]:rounded-full max-md:-mx-4 max-md:px-4">
|
||||
{marasiDriveInspiredInteriors.map(({ image, name }) => (
|
||||
<div key={name} className="relative md:max-2xl:w-[30.208vw] max-md:w-full max-md:max-w-[520px] max-md:flex-shrink-0 max-md:snap-center">
|
||||
<img
|
||||
src={image}
|
||||
alt={name}
|
||||
className="object-cover object-center 2xl:rounded-[1.667vw] max-md:!aspect-[328/430] max-md:rounded-2xl max-md:max-h-[690px]"
|
||||
/>
|
||||
<div className="md:hidden text-black text-h5 mx-auto text-center text-nowrap mt-4 mb-6 font-medium">{name}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<CustomScrollBar containerRef={interiorsRef} inlinePadding={16} trackStyle="min-md:hidden" thumbStyle="min-md:hidden"/>
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
export default MarasiDriveInteriorsSliderMobile;
|
||||
@@ -0,0 +1,44 @@
|
||||
import { useRef } from "react";
|
||||
import { marasiDriveMapCards } from "../data/aboutMarasiDrive";
|
||||
import CustomScrollBar from "./ui/ScrollBar";
|
||||
|
||||
function MarasiDriveMapMobile() {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
return (
|
||||
<div className="min-2xl:hidden relative flex flex-col">
|
||||
<div className="max-md:aspect-[328/544] md:max-2xl:aspect[1/1] max-2xl:mb-4">
|
||||
<img
|
||||
src="/images/about-complex/marasi-drive/map/map.png"
|
||||
alt=""
|
||||
className="object-cover size-full rounded-[6.667vw] md:max-2xl:rounded-[3.125vw]"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="flex flex-nowrap overflow-x-scroll scroll-pl-4 gap-x-[16px] overflow-y-hidden justify-start snap-x snap-mandatory [&::-webkit-scrollbar]:h-[1.111vw] [&::-webkit-scrollbar]:w-[none] [&::-webkit-scrollbar-thumb]:bg-[#FFFFFF] [&::-webkit-scrollbar-thumb]:w-4 [&::-webkit-scrollbar-thumb]:rounded-full -mx-4 px-4 "
|
||||
>
|
||||
{marasiDriveMapCards.map((card, index) => (
|
||||
<div key={index} className="snap-start">
|
||||
<div
|
||||
className={`rounded-[6.667vw] px-[4.444vw] py-[3.333vw] w-[51.111vw] aspect-[184/122] bg-[#F3F3F2] flex-shrink-0 flex flex-col justify-between relative md:max-2xl:w-[25vw] md:max-2xl:rounded-[3.125vw] md:max-2xl:px-[2.083vw] md:max-2xl:py-[1.563vw]`}
|
||||
>
|
||||
<div className="space-y-[0.278vw]">
|
||||
<p className="text-m">{card.title}</p>
|
||||
<p className="text-s text-[#73787C]">{`${card.mins} mins`}</p>
|
||||
</div>
|
||||
<img
|
||||
src={card.image}
|
||||
className="rounded-[0.278vw] size-[13.333vw] object-cover absolute bottom-[4.444vw] right-[3.333vw] md:max-2xl:size-[6.25vw] md:max-2xl:bottom-[1.563vw] md:max-2xl:right-[2.083vw]"
|
||||
alt={card.title}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<CustomScrollBar containerRef={containerRef} inlinePadding={16} trackStyle="min-2xl:hidden max-2xl:translate-y-5" thumbStyle="min-2xl:hidden"/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MarasiDriveMapMobile;
|
||||
@@ -0,0 +1,28 @@
|
||||
import { marasiDriveNeighbours } from "../data/aboutMarasiDrive";
|
||||
import { useRef } from "react";
|
||||
import CustomScrollBar from "./ui/ScrollBar";
|
||||
|
||||
function MarasiDriveNeighboursSliderMobile(){
|
||||
const neighboursRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
|
||||
return(
|
||||
<>
|
||||
<div ref={neighboursRef} className="flex min-md:hidden max-md:flex-nowrap max-md:overflow-x-scroll max-md:gap-x-[8px] max-md:overflow-y-hidden max-md:justify-start max-md:snap-x max-md:snap-mandatory [&::-webkit-scrollbar]:h-[1.111vw] [&::-webkit-scrollbar]:w-[none] [&::-webkit-scrollbar-thumb]:bg-transparent [&::-webkit-scrollbar-thumb]:w-4 [&::-webkit-scrollbar-thumb]:rounded-full max-md:-mx-4 max-md:px-4">
|
||||
{marasiDriveNeighbours.map(({ image, name }) => (
|
||||
<div key={name} className="relative md:max-2xl:w-[30.208vw] max-md:w-full max-md:max-w-[520px] max-md:flex-shrink-0 max-md:snap-center">
|
||||
<img
|
||||
src={image}
|
||||
alt={name}
|
||||
className="object-cover object-center 2xl:rounded-[1.667vw] max-md:!aspect-[328/430] max-md:rounded-2xl max-md:max-h-[690px]"
|
||||
/>
|
||||
<div className="md:hidden text-black text-h5 mx-auto text-center text-nowrap mt-4 mb-6 font-medium">{name}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<CustomScrollBar containerRef={neighboursRef} inlinePadding={16} trackStyle="min-md:hidden" thumbStyle="min-md:hidden"/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default MarasiDriveNeighboursSliderMobile
|
||||
@@ -73,7 +73,7 @@ function MarasiDriveNeighboursSliderTablet() {
|
||||
onlyIcon
|
||||
disabled={currentIndex === 0}
|
||||
onClick={() => setCurrentIndex(Math.max(currentIndex - 1, 0))}
|
||||
className="absolute left-[8.203vw] bottom-1/2"
|
||||
className="absolute left-[calc((100%-69.141vw)/2-56px)] bottom-1/2"
|
||||
>
|
||||
<span className="size-5">
|
||||
<ChevronLeftIcon />
|
||||
@@ -82,7 +82,7 @@ function MarasiDriveNeighboursSliderTablet() {
|
||||
<Button
|
||||
onlyIcon
|
||||
disabled={currentIndex === marasiDriveNeighbours.length - 1}
|
||||
className="absolute left-[83.594vw] bottom-1/2"
|
||||
className="absolute right-[calc((100%-69.141vw)/2-56px)] bottom-1/2"
|
||||
onClick={() =>
|
||||
setCurrentIndex(
|
||||
Math.min(currentIndex + 1, marasiDriveNeighbours.length - 1)
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useEffect, useState } from "react";
|
||||
import useWindowSize from "../../hooks/useWindowSize";
|
||||
|
||||
interface CustomScrollBarProps {
|
||||
containerRef: React.RefObject<HTMLElement | null>;
|
||||
inlinePadding: number;
|
||||
trackStyle?: string;
|
||||
thumbStyle?: string;
|
||||
}
|
||||
|
||||
function CustomScrollBar({
|
||||
containerRef,
|
||||
inlinePadding,
|
||||
trackStyle = "",
|
||||
thumbStyle = "",
|
||||
}: CustomScrollBarProps) {
|
||||
const [scrollLeft, setScrollLeft] = useState<number>(0);
|
||||
const [totalWidth, setTotalWidth] = useState<number>(0);
|
||||
const [containerWidth, setContainerWidth] = useState<number>(0);
|
||||
const [thumbVisible, setThumbVisible] = useState<boolean>(false);
|
||||
const windowSize = useWindowSize();
|
||||
|
||||
function GetContainer(): HTMLElement {
|
||||
if (!containerRef.current) {
|
||||
throw new Error("Container reference is not valid");
|
||||
}
|
||||
return containerRef.current;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setTotalWidth(GetContainer().scrollWidth);
|
||||
setContainerWidth(GetContainer().clientWidth);
|
||||
}, [windowSize]);
|
||||
|
||||
useEffect(() => {
|
||||
const container = GetContainer();
|
||||
let hideThumbTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
function handleContainerScroll() {
|
||||
setScrollLeft(container.scrollLeft);
|
||||
|
||||
if (!thumbVisible) setThumbVisible(true);
|
||||
if (hideThumbTimeout) clearTimeout(hideThumbTimeout);
|
||||
|
||||
hideThumbTimeout = setTimeout(() => {
|
||||
setThumbVisible(false);
|
||||
}, 750);
|
||||
}
|
||||
|
||||
container.addEventListener("scroll", handleContainerScroll);
|
||||
return () => {
|
||||
container.removeEventListener("scroll", handleContainerScroll);
|
||||
};
|
||||
}, [containerRef]);
|
||||
|
||||
const scrollPercent =
|
||||
totalWidth > containerWidth
|
||||
? (scrollLeft / (totalWidth - containerWidth)) * 100
|
||||
: 0;
|
||||
const thumbPosition =
|
||||
(scrollPercent / 100) * (containerWidth - 20 - inlinePadding * 2); // 20px - ширина ползунка
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative h-1 w-full bg-transparent rounded-full ${trackStyle}`}
|
||||
>
|
||||
<div
|
||||
className={`absolute w-5 h-1 bg-[#E2E2DC] rounded-full transition-opacity duration-250 ease-out ${
|
||||
thumbVisible ? "opacity-100" : "opacity-0"
|
||||
} ${thumbStyle}`}
|
||||
style={{ transform: `translateX(${thumbPosition}px)` }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CustomScrollBar;
|
||||
Reference in New Issue
Block a user