upd
This commit is contained in:
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 117 KiB |
@@ -3,15 +3,15 @@ import { ISwitchLabel } from "../types/switchLabel";
|
||||
interface ISwitchToggleProps {
|
||||
labels: ISwitchLabel[];
|
||||
currentLabel: ISwitchLabel;
|
||||
onClick: (label: ISwitchLabel) => void;
|
||||
isDisabled?: boolean;
|
||||
onClick: (label: ISwitchLabel) => void;
|
||||
}
|
||||
|
||||
function SwitchToggle({
|
||||
labels,
|
||||
currentLabel,
|
||||
onClick,
|
||||
isDisabled = false,
|
||||
onClick,
|
||||
}: ISwitchToggleProps) {
|
||||
return (
|
||||
<div className="flex bg-[#F3F3F2] rounded-lg">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
interface Props {
|
||||
floor: string;
|
||||
@@ -8,23 +9,11 @@ interface Props {
|
||||
|
||||
function FloorItem({ floor, onSelected }: Props) {
|
||||
const [selected, setSelected] = useState(false);
|
||||
// const [ref, entry] = useIntersectionObserver({
|
||||
// threshold: 0,
|
||||
// root: document.querySelector("#test"),
|
||||
// rootMargin: "0px",
|
||||
// });
|
||||
|
||||
// console.log(document.querySelector("#test"));
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!entry?.isIntersecting) return;
|
||||
|
||||
// onSelected();
|
||||
// }, [entry?.isIntersecting]);
|
||||
|
||||
const ref = useRef<HTMLParagraphElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isMobile) return;
|
||||
|
||||
const test = document.querySelector("#test")!.getBoundingClientRect();
|
||||
|
||||
setInterval(() => {
|
||||
@@ -37,13 +26,13 @@ function FloorItem({ floor, onSelected }: Props) {
|
||||
} else {
|
||||
setSelected(false);
|
||||
}
|
||||
}, 0);
|
||||
}, 50);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<p
|
||||
ref={ref}
|
||||
className={`snap-center w-4 h-4 flex items-center justify-center text-xs font-semibold transition-[color,transform] ${
|
||||
className={`snap-center min-w-[68px] w-[68px] h-4 flex items-center justify-center text-xs font-semibold transition-[color,transform] whitespace-nowrap ${
|
||||
selected ? "text-[#00BED7] scale-125" : ""
|
||||
}`}
|
||||
>
|
||||
|
||||
@@ -2437,7 +2437,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}16`}
|
||||
{`E-${floor}16`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"1BR"}
|
||||
@@ -2464,7 +2464,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}15`}
|
||||
{`E-${floor}15`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"1BR"}
|
||||
@@ -2491,7 +2491,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}14`}
|
||||
{`E-${floor}14`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"ST"}
|
||||
@@ -2518,7 +2518,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}13`}
|
||||
{`E-${floor}13`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"ST"}
|
||||
@@ -2545,7 +2545,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}12`}
|
||||
{`E-${floor}12`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"ST"}
|
||||
@@ -2572,7 +2572,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}11`}
|
||||
{`E-${floor}11`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"ST"}
|
||||
@@ -2599,7 +2599,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}10`}
|
||||
{`E-${floor}10`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"1BR"}
|
||||
@@ -2626,7 +2626,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}09`}
|
||||
{`E-${floor}09`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"1BR"}
|
||||
@@ -2653,7 +2653,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}08`}
|
||||
{`E-${floor}08`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"1BR"}
|
||||
@@ -2680,7 +2680,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}07`}
|
||||
{`E-${floor}07`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"1BR"}
|
||||
@@ -2708,7 +2708,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}06`}
|
||||
{`E-${floor}06`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"1BR"}
|
||||
@@ -2735,7 +2735,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}05`}
|
||||
{`E-${floor}05`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"ST"}
|
||||
@@ -2762,7 +2762,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}04`}
|
||||
{`E-${floor}04`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"ST"}
|
||||
@@ -2789,7 +2789,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}03`}
|
||||
{`E-${floor}03`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"1BR"}
|
||||
@@ -2816,7 +2816,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}02`}
|
||||
{`E-${floor}02`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"ST"}
|
||||
@@ -2843,7 +2843,7 @@ function EastWingFloorPlan({
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{`E-${floor.padStart(2, "0")}01`}
|
||||
{`E-${floor}01`}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{"2BR"}
|
||||
|
||||
@@ -11,19 +11,49 @@ import { isMobile } from "react-device-detect";
|
||||
import WestWingFloorPlanLower from "./WestWingFloorPlanLower";
|
||||
import WestWingFloorPlanUpper from "./WestWingFloorPlanUpper";
|
||||
import EastWingFloorPlan from "./EastWingFloorPlan";
|
||||
import PlayIcon from "../../icons/PlayIcon";
|
||||
import SwitchToggle from "../../SwitchToggle";
|
||||
import AmphitheatreIcon from "../../icons/activities/AmphitheatreIcon";
|
||||
import BoulderingWallIcon from "../../icons/activities/BoulderingWallIcon";
|
||||
import ChangingRoomsIcon from "../../icons/activities/ChangingRoomsIcon";
|
||||
import ChessTablesIcon from "../../icons/activities/ChessTablesIcon";
|
||||
import ClimbingRoomIcon from "../../icons/activities/ClimbingRoomIcon";
|
||||
import CommunalDiningTablesIcon from "../../icons/activities/CommunalDiningTablesIcon";
|
||||
import IndoorLapPoolIcon from "../../icons/activities/IndoorLapPoolIcon";
|
||||
import LushLandscapeIcon from "../../icons/activities/LushLandscapeIcon";
|
||||
import MultiPurposeCourtIcon from "../../icons/activities/MultiPurposeCourtIcon";
|
||||
import OutdoorCinemaIcon from "../../icons/activities/OutdoorCinemaIcon";
|
||||
import OutdoorCoworkingSpaceIcon from "../../icons/activities/OutdoorCoworkingSpaceIcon";
|
||||
import PadelPongIcon from "../../icons/activities/PadelPongIcon";
|
||||
import PingPongInATableIcon from "../../icons/activities/PingPongInATableIcon";
|
||||
import RunningWheelIcon from "../../icons/activities/RunningWheelIcon";
|
||||
import SunLoungingDeckIcon from "../../icons/activities/SunLoungingDeckIcon";
|
||||
import SuspendedLoungingNetsIcon from "../../icons/activities/SuspendedLoungingNetsIcon";
|
||||
import WellnessFeaturesIcon from "../../icons/activities/WellnessFeaturesIcon";
|
||||
import ActivityCard from "../SkygardenSidebar/ActivityCard";
|
||||
import SkyGardenSlider from "../SkygardenSidebar/SkyGardenSlider";
|
||||
import VirtualTourVideoModal from "../../modals/VirtualTourVideoModal";
|
||||
|
||||
interface Props {
|
||||
floor: number;
|
||||
floor: string;
|
||||
wing: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const skyGardenImages = {
|
||||
indoor: "/images/skyGarden/sky-garden-indoor.jpg",
|
||||
outdoor: "/images/skyGarden/sky-garden-outdoor.jpg",
|
||||
};
|
||||
|
||||
function FloorPlanSidebar({ floor, wing, onClose }: Props) {
|
||||
const { setModal } = useModal();
|
||||
const [hoveredUnit, setHoveredUnit] = useState<IUnit | undefined>();
|
||||
const [showPopup, setShowPopup] = useState(false);
|
||||
const [mousePos, setMousePos] = useState<[number, number]>([0, 0]);
|
||||
const [type, setType] = useState<string | null>(null);
|
||||
const [selectedSkyGardenImage, setSelectedSkyGardenImage] = useState<
|
||||
"indoor" | "outdoor"
|
||||
>("indoor");
|
||||
|
||||
function handleMouseEnter(e: React.MouseEvent<SVGPathElement>) {
|
||||
const unitNumber = e.currentTarget.dataset.number;
|
||||
@@ -46,14 +76,12 @@ function FloorPlanSidebar({ floor, wing, onClose }: Props) {
|
||||
const x = e.clientX - e.currentTarget.getBoundingClientRect().left;
|
||||
const y = e.clientY - e.currentTarget.getBoundingClientRect().top;
|
||||
|
||||
console.log(x, y);
|
||||
|
||||
setMousePos([x, y]);
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
console.log("hoveredUnit", hoveredUnit);
|
||||
console.log("type", type);
|
||||
// console.log("hoveredUnit", hoveredUnit);
|
||||
// console.log("type", type);
|
||||
|
||||
if (!hoveredUnit || !type) return;
|
||||
|
||||
@@ -79,7 +107,7 @@ function FloorPlanSidebar({ floor, wing, onClose }: Props) {
|
||||
}, [hoveredUnit]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col flex-1 gap-4 p-4 select-none sm:p-6 mt-14">
|
||||
<div className="flex flex-col flex-1 gap-4 p-4 overflow-y-auto select-none sm:p-6 mt-14">
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<p
|
||||
@@ -87,9 +115,11 @@ function FloorPlanSidebar({ floor, wing, onClose }: Props) {
|
||||
floor ? "opacity-100" : "opacity-0"
|
||||
}`}
|
||||
>
|
||||
{floor} floor
|
||||
{floor === "Sky Garden" ? "Sky Garden" : `${floor} floor`}
|
||||
</p>
|
||||
<p className="text-sm">
|
||||
{floor === "Sky Garden" ? `22-23 floor` : `${wing} Wing`}
|
||||
</p>
|
||||
<p className="text-sm">{wing} Wing</p>
|
||||
</div>
|
||||
<Button3
|
||||
icon={<CloseIcon className="w-5 h-5" />}
|
||||
@@ -97,68 +127,205 @@ function FloorPlanSidebar({ floor, wing, onClose }: Props) {
|
||||
onClick={onClose}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col flex-1 space-y-2 max-sm:w-screen max-sm:-m-4">
|
||||
<div className="flex items-center justify-end p-4 bg-white xl:justify-between rounded-2xl max-xl:hidden">
|
||||
<div className="flex gap-6 max-xl:hidden">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-5 h-5 text-white rounded-full bg-[#A19E9E] text-xs flex items-center justify-center"></div>
|
||||
<p className="text-xs font-semibold">Studio Flex</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-5 h-5 text-white rounded-full bg-[#8299AD] text-xs flex items-center justify-center"></div>
|
||||
<p className="text-xs font-semibold">Studio²</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-5 h-5 text-white rounded-full bg-[#BFC9D1] text-xs flex items-center justify-center"></div>
|
||||
<p className="text-xs font-semibold">1 Bedroom²</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-5 h-5 text-white rounded-full bg-[#878FA3] text-xs flex items-center justify-center"></div>
|
||||
<p className="text-xs font-semibold">2 Bedroom²</p>
|
||||
{floor === "Sky Garden" ? (
|
||||
<div className="space-y-6">
|
||||
<div className="pb-6 border-b border-[#E2E2DC]">
|
||||
<div className="relative flex flex-col p-6 bg-white rounded-2xl">
|
||||
<Button3
|
||||
variant="secondary"
|
||||
icon={<PlayIcon />}
|
||||
className="absolute self-end max-sm:hidden"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<VirtualTourVideoModal videoHref="/videos/SkyGarden.mp4" />
|
||||
)
|
||||
}
|
||||
>
|
||||
Play video
|
||||
</Button3>
|
||||
<Button3
|
||||
variant="secondary"
|
||||
icon={<PlayIcon />}
|
||||
onlyIcon
|
||||
size="small"
|
||||
className="absolute self-end sm:hidden"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<VirtualTourVideoModal videoHref="/videos/SkyGarden.mp4" />
|
||||
)
|
||||
}
|
||||
/>
|
||||
<div className="flex flex-col gap-10">
|
||||
<div className="px-4">
|
||||
<img
|
||||
src={skyGardenImages[selectedSkyGardenImage]}
|
||||
alt=""
|
||||
className="pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
<div className="self-center">
|
||||
<SwitchToggle
|
||||
labels={[
|
||||
{ id: "indoor", label: "Indoor" },
|
||||
{ id: "outdoor", label: "Outdoor" },
|
||||
]}
|
||||
currentLabel={
|
||||
selectedSkyGardenImage === "indoor"
|
||||
? { id: "indoor", label: "Indoor" }
|
||||
: { id: "outdoor", label: "Outdoor" }
|
||||
}
|
||||
onClick={(label) =>
|
||||
setSelectedSkyGardenImage(
|
||||
label.id as "indoor" | "outdoor"
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className="text-xs text-white rounded-full bg-[#00BED7] px-2 py-[3px] ">
|
||||
<div className="pb-6 space-y-6 border-b border-[#E2E2DC]">
|
||||
<p className="sm:text-xl text-[#0D1922] font-semibold">
|
||||
Indoor Amenities
|
||||
</p>
|
||||
<div className="grid grid-cols-3 gap-4 sm:grid-cols-4">
|
||||
<ActivityCard
|
||||
title={"Indoor Lap Pool"}
|
||||
icon={<IndoorLapPoolIcon />}
|
||||
/>
|
||||
<ActivityCard
|
||||
title={"Wellness Features"}
|
||||
icon={<WellnessFeaturesIcon />}
|
||||
/>
|
||||
<ActivityCard
|
||||
title={"Changing Rooms"}
|
||||
icon={<ChangingRoomsIcon />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pb-6 space-y-6 border-b border-[#E2E2DC]">
|
||||
<p className="sm:text-xl text-[#0D1922] font-semibold">
|
||||
Outdoor Amenities
|
||||
</p>
|
||||
<div className="grid grid-cols-3 sm:grid-cols-4 gap-x-4 gap-y-6">
|
||||
<ActivityCard title={"Padel Pong"} icon={<PadelPongIcon />} />
|
||||
<ActivityCard
|
||||
title={"Sun Lounging Deck"}
|
||||
icon={<SunLoungingDeckIcon />}
|
||||
/>
|
||||
<ActivityCard
|
||||
title={"Outdoor Cinema"}
|
||||
icon={<OutdoorCinemaIcon />}
|
||||
/>
|
||||
<ActivityCard
|
||||
title={"Bouldering Wall"}
|
||||
icon={<BoulderingWallIcon />}
|
||||
/>
|
||||
<ActivityCard
|
||||
title={"Ping Pong in a Tube"}
|
||||
icon={<PingPongInATableIcon />}
|
||||
/>
|
||||
<ActivityCard
|
||||
title={"Amphitheatre"}
|
||||
icon={<AmphitheatreIcon />}
|
||||
/>
|
||||
<ActivityCard
|
||||
title={"Communal Dining Tables"}
|
||||
icon={<CommunalDiningTablesIcon />}
|
||||
/>
|
||||
<ActivityCard
|
||||
title={"Suspended Lounging Nets "}
|
||||
icon={<SuspendedLoungingNetsIcon />}
|
||||
/>
|
||||
<ActivityCard
|
||||
title={"Lush Landscape"}
|
||||
icon={<LushLandscapeIcon />}
|
||||
/>
|
||||
<ActivityCard
|
||||
title={"Running Wheel"}
|
||||
icon={<RunningWheelIcon />}
|
||||
/>
|
||||
<ActivityCard title={"Chess Tables"} icon={<ChessTablesIcon />} />
|
||||
<ActivityCard
|
||||
title={"Climbing Wall"}
|
||||
icon={<ClimbingRoomIcon />}
|
||||
/>
|
||||
<ActivityCard
|
||||
title={"Outdoor Coworking Space"}
|
||||
icon={<OutdoorCoworkingSpaceIcon />}
|
||||
/>
|
||||
<ActivityCard
|
||||
title={"Multi-purpose Court"}
|
||||
icon={<MultiPurposeCourtIcon />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<SkyGardenSlider />
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col flex-1 space-y-2 max-sm:w-screen max-sm:-m-4">
|
||||
<div className="flex items-center justify-end p-4 bg-white xl:justify-between rounded-2xl max-xl:hidden">
|
||||
<div className="flex gap-6 max-xl:hidden">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-5 h-5 text-white rounded-full bg-[#A19E9E] text-xs flex items-center justify-center"></div>
|
||||
<p className="text-xs font-semibold">Studio Flex</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-5 h-5 text-white rounded-full bg-[#8299AD] text-xs flex items-center justify-center"></div>
|
||||
<p className="text-xs font-semibold">Studio²</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-5 h-5 text-white rounded-full bg-[#BFC9D1] text-xs flex items-center justify-center"></div>
|
||||
<p className="text-xs font-semibold">1 Bedroom²</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-5 h-5 text-white rounded-full bg-[#878FA3] text-xs flex items-center justify-center"></div>
|
||||
<p className="text-xs font-semibold">2 Bedroom²</p>
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className="text-xs text-white rounded-full bg-[#00BED7] px-2 py-[3px] ">
|
||||
0 units
|
||||
</div> */}
|
||||
</div>
|
||||
<div className="relative flex flex-1 sm:bg-white rounded-2xl">
|
||||
<svg className="flex-1 p-2 sm:p-10" onMouseMove={handleMouseMove}>
|
||||
{wing === "West" ? (
|
||||
floor <= 21 ? (
|
||||
<WestWingFloorPlanLower
|
||||
floor={floor.toString().padStart(2, "0")}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
</div>
|
||||
<div className="relative flex flex-1 sm:bg-white rounded-2xl">
|
||||
<svg className="flex-1 p-2 sm:p-10" onMouseMove={handleMouseMove}>
|
||||
{wing === "West" ? (
|
||||
+floor <= 21 ? (
|
||||
<WestWingFloorPlanLower
|
||||
floor={floor}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
) : (
|
||||
<WestWingFloorPlanUpper
|
||||
floor={floor}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<WestWingFloorPlanUpper
|
||||
floor={floor.toString().padStart(2, "0")}
|
||||
<EastWingFloorPlan
|
||||
floor={floor}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<EastWingFloorPlan
|
||||
floor={floor.toString()}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={handleClick}
|
||||
)}
|
||||
</svg>
|
||||
|
||||
{!isMobile && (
|
||||
<UnitPopup
|
||||
unit={hoveredUnit}
|
||||
type={type}
|
||||
show={showPopup}
|
||||
mousePos={mousePos}
|
||||
/>
|
||||
)}
|
||||
</svg>
|
||||
|
||||
{!isMobile && (
|
||||
<UnitPopup
|
||||
unit={hoveredUnit}
|
||||
type={type}
|
||||
show={showPopup}
|
||||
mousePos={mousePos}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ interface ActivityCardProps {
|
||||
|
||||
const ActivityCard = ({ icon, title }: ActivityCardProps) => {
|
||||
return (
|
||||
// <div className="bg-white rounded-2xl flex flex-col gap-9 p-3">
|
||||
// <div className="flex gap-2 items-center">
|
||||
// <div className="flex flex-col p-3 bg-white rounded-2xl gap-9">
|
||||
// <div className="flex items-center gap-2">
|
||||
// <div className="w-3 h-3 bg-[#E2E2DC] rounded-full"></div>
|
||||
// <p className="text-m text-[#0D1922]">{title}</p>
|
||||
// </div>
|
||||
@@ -18,7 +18,7 @@ const ActivityCard = ({ icon, title }: ActivityCardProps) => {
|
||||
<div className="w-10 h-10 rounded-full text-[#00BED7] overflow-hidden border border-[#00BED7]">
|
||||
{icon}
|
||||
</div>
|
||||
<p className="text-sm font-semibold">{title}</p>
|
||||
<p className="lg:text-sm sm:text-xs text-[10px] font-semibold">{title}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -39,23 +39,37 @@ function SkyGardenSlider() {
|
||||
}, [currentSlideIndex]);
|
||||
|
||||
return (
|
||||
<div ref={ref} className="relative py-8 overflow-x-clip">
|
||||
<div ref={ref} className="relative pb-4 overflow-x-clip">
|
||||
{ref.current?.clientWidth && (
|
||||
<div
|
||||
className="flex gap-4 px-6 transition-transform duration-300"
|
||||
style={{
|
||||
transform: `translateX(calc(-${
|
||||
ref.current.clientWidth * currentSlideIndex
|
||||
}px + ${currentSlideIndex * 32}px))`,
|
||||
}}
|
||||
>
|
||||
{images.map((image, index) => (
|
||||
<img key={index} src={image} alt="" className="rounded-2xl" />
|
||||
))}
|
||||
</div>
|
||||
<>
|
||||
<div
|
||||
className="flex gap-4 px-6 transition-transform duration-300 max-sm:hidden"
|
||||
style={{
|
||||
transform: `translateX(calc(-${
|
||||
ref.current.clientWidth * currentSlideIndex
|
||||
}px + ${currentSlideIndex * 32}px))`,
|
||||
}}
|
||||
>
|
||||
{images.map((image, index) => (
|
||||
<img key={index} src={image} alt="" className="rounded-2xl" />
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className="flex gap-2 transition-transform duration-300 sm:hidden"
|
||||
style={{
|
||||
transform: `translateX(calc(-${
|
||||
ref.current.clientWidth * currentSlideIndex
|
||||
}px + ${currentSlideIndex * -8}px))`,
|
||||
}}
|
||||
>
|
||||
{images.map((image, index) => (
|
||||
<img key={index} src={image} alt="" className="rounded-2xl" />
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="absolute top-0 w-full h-full flex items-center justify-between px-4">
|
||||
<div className="absolute top-0 flex items-center justify-between w-full h-full px-4">
|
||||
<button
|
||||
className={`p-2.5 bg-[#FFFFFFCC] hover:bg-white hover:text-[#0D1922] rounded-full transition-all ${
|
||||
isShowPrevButton ? "opacity-100" : "opacity-0 pointer-events-none"
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
interface Props {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function PlayIcon({ className = "" }: Props) {
|
||||
return (
|
||||
<svg
|
||||
width={24}
|
||||
height={24}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
d="M19.185 11.7856C19.3468 11.8827 19.3468 12.1173 19.185 12.2144L7.12863 19.4482C6.96199 19.5482 6.75 19.4281 6.75 19.2338L6.75 4.76619C6.75 4.57187 6.96199 4.45184 7.12862 4.55182L19.185 11.7856Z"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default PlayIcon;
|
||||
@@ -22,8 +22,8 @@ const Map = () => {
|
||||
return (
|
||||
<div className="relative">
|
||||
<TransformWrapper
|
||||
initialScale={isMobile ? 2 : 1}
|
||||
minScale={isMobile ? 2 : 1}
|
||||
initialScale={isMobile ? 1 : 1}
|
||||
minScale={isMobile ? 1 : 1}
|
||||
maxScale={2}
|
||||
alignmentAnimation={{ sizeX: 50, sizeY: 50 }}
|
||||
wheel={{ step: 10000, smoothStep: 0.0005 }}
|
||||
@@ -32,6 +32,7 @@ const Map = () => {
|
||||
animationType: "easeOutQuart",
|
||||
animationTime: 500,
|
||||
}}
|
||||
centerOnInit
|
||||
>
|
||||
<WeatherWidget />
|
||||
{!isMobile && <ZoomControlls />}
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
},
|
||||
{
|
||||
"data-wing": "West",
|
||||
"data-floor": "Sky Garden",
|
||||
"data-name": "Sky Garden",
|
||||
"d": "M2450.23,1803.6v55.16c0,2.21,1.79,4,4,4h10.05c2.21,0,4,1.79,4,4v54.89c0,2.18-1.74,3.96-3.92,4l-186.91,3.6-38.36-3.29-271.8-9.8c-2.15-.08-3.85-1.84-3.85-4v-109.83c0-2.21,1.79-4,4-4h59.25l220.63,1.42h53.38l145.49-.15c2.23-.02,4.04,1.78,4.04,4Z"
|
||||
},
|
||||
@@ -216,6 +217,7 @@
|
||||
},
|
||||
{
|
||||
"data-wing": "East",
|
||||
"data-floor": "Sky Garden",
|
||||
"data-name": "Sky Garden",
|
||||
"d": "M1440.88,1803.85v115.81c0,2.11,1.63,3.85,3.74,3.99l151.21,9.86,305.4-17.52,58.2.03c2.21,0,4.01-1.79,4.01-4v-109.69c0-2.21-1.79-4-4-4h-58.21l-318,2.8-138.31-1.28c-2.23-.02-4.04,1.78-4.04,4Z"
|
||||
},
|
||||
|
||||
@@ -14,7 +14,6 @@ import AboutProjectsPage from "./pages/AboutProjectsPage";
|
||||
import SearchPage from "./pages/SearchPage";
|
||||
import FavoritesPage from "./pages/FavoritesPage";
|
||||
import TestPage from "./pages/TestPage";
|
||||
import Test2Page from "./pages/Test2Page";
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
@@ -82,10 +81,6 @@ const router = createBrowserRouter([
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/test2",
|
||||
element: <Test2Page />,
|
||||
},
|
||||
]);
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
|
||||
@@ -15,12 +15,20 @@ function AboutProjectsPage() {
|
||||
return (
|
||||
<div className="mt-[58px] sm:py-16 py-10 sm:space-y-[100px] space-y-20 select-none">
|
||||
<div className="px-4 space-y-16 lg:px-6">
|
||||
<p className="lg:text-[56px] sm:text-[40px] text-[28px] text-[#0D1922] font-mixcase -tracking-[1.68px] leading-none">
|
||||
Rove Home this residence a complete ecosystem that has everything
|
||||
you’ll ever need. This isn’t just where you’ll live.
|
||||
<br />
|
||||
It’s where you’ll thrive.
|
||||
</p>
|
||||
<div className="space-y-4 lg:space-y-6 sm:space-y-5">
|
||||
<Button2
|
||||
icon={<ArrowLeftIcon />}
|
||||
onClick={() => navigate("/masterplan/1/wing")}
|
||||
>
|
||||
Masterplan
|
||||
</Button2>
|
||||
<p className="lg:text-[56px] sm:text-[40px] text-[28px] text-[#0D1922] font-mixcase -tracking-[1.68px] leading-none">
|
||||
Rove Home this residence a complete ecosystem that has everything
|
||||
you’ll ever need. This isn’t just where you’ll live.
|
||||
<br />
|
||||
It’s where you’ll thrive.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex gap-6 max-lg:flex-col">
|
||||
<div className="max-lg:order-last lg:min-w-[25%] lg:w-[25%] flex flex-col justify-between gap-6">
|
||||
<div className="space-y-3 lg:space-y-6">
|
||||
@@ -33,12 +41,6 @@ function AboutProjectsPage() {
|
||||
exceptional location and an extended playlist of life-enhancing{" "}
|
||||
</p>
|
||||
</div>
|
||||
<Button2
|
||||
icon={<ArrowLeftIcon />}
|
||||
onClick={() => navigate("/masterplan/1/wing")}
|
||||
>
|
||||
Masterplan
|
||||
</Button2>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<img
|
||||
|
||||
@@ -32,6 +32,7 @@ const floors = [
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"Sky Garden",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
@@ -55,7 +56,6 @@ function ComplexWingPage() {
|
||||
const [hoveredFloor, setHoveredFloor] = useState<string>();
|
||||
const navigate = useNavigate();
|
||||
const [hoveredWing, setHoveredWing] = useState<string>();
|
||||
const [selectedIndex] = useState<number>(0);
|
||||
const [selectedFloor, setSelectedFloor] = useState<string>();
|
||||
// const [showFloorPlanSidebar, setShowFloorPlanSidebar] = useState(false);
|
||||
const refFloors = useRef<HTMLDivElement>(null);
|
||||
@@ -92,16 +92,6 @@ function ComplexWingPage() {
|
||||
setSelectedFloor(e.currentTarget.dataset["floor"]);
|
||||
}
|
||||
|
||||
// function prev() {
|
||||
// if (selectedIndex === 0) return;
|
||||
// setSelectedIndex((prev) => prev - 1);
|
||||
// }
|
||||
|
||||
// function next() {
|
||||
// if (selectedIndex === floors.length - 1) return;
|
||||
// setSelectedIndex((prev) => prev + 1);
|
||||
// }
|
||||
|
||||
function handleLoadedData() {
|
||||
setImageWidth(ref.current!.naturalWidth);
|
||||
setImageHeight(ref.current!.naturalHeight);
|
||||
@@ -117,10 +107,6 @@ function ComplexWingPage() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setHoveredFloor(floors[selectedIndex]);
|
||||
}, [selectedIndex]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative overflow-hidden h-dvh"
|
||||
@@ -139,12 +125,12 @@ function ComplexWingPage() {
|
||||
<div className="flex items-start justify-between pb-4 border-b border-[#E2E2DC]">
|
||||
<div className="space-y-1">
|
||||
<p className="text-xl text-[#0D1922] font-semibold">
|
||||
{selectedFloorPath?.dataset["name"] === "Sky Garden"
|
||||
? selectedFloorPath?.dataset["name"]
|
||||
{selectedFloorPath?.dataset["floor"] === "Sky Garden"
|
||||
? selectedFloorPath?.dataset["floor"]
|
||||
: `${selectedFloorPath?.dataset["floor"]} floor`}
|
||||
</p>
|
||||
<p className="text-xs font-semibold">
|
||||
{selectedFloorPath?.dataset["name"] !== "Sky Garden" &&
|
||||
{selectedFloorPath?.dataset["floor"] !== "Sky Garden" &&
|
||||
`${selectedFloorPath?.dataset["wing"]} Wing`}
|
||||
</p>
|
||||
</div>
|
||||
@@ -152,7 +138,7 @@ function ComplexWingPage() {
|
||||
<p className="text-xs font-semibold text-white">0 units</p>
|
||||
</div>
|
||||
</div>
|
||||
{selectedFloorPath?.dataset["name"] !== "Sky Garden" ? (
|
||||
{selectedFloorPath?.dataset["floor"] !== "Sky Garden" ? (
|
||||
<div className="grid grid-cols-2">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -522,9 +508,13 @@ function ComplexWingPage() {
|
||||
>
|
||||
<div className="relative px-4 pt-2 pb-4 space-y-3 bg-white rounded-lg">
|
||||
<div className="relative overflow-hidden">
|
||||
<div
|
||||
{/* <div
|
||||
id="test"
|
||||
className="absolute top-[calc(50%-16px)] left-[calc(50%-16px)] w-8 h-6"
|
||||
></div> */}
|
||||
<div
|
||||
id="test"
|
||||
className="absolute h-6 w-[68px] top-[calc(50%-16px)] left-[calc(50%-68px)]"
|
||||
></div>
|
||||
<div
|
||||
ref={refFloors}
|
||||
@@ -600,7 +590,7 @@ function ComplexWingPage() {
|
||||
className={`absolute top-0 h-dvh bg-[#F3F3F2] right-0 lg:w-1/2 w-full z-10 transition-all duration-300 flex flex-col ${state}`}
|
||||
>
|
||||
<FloorPlanSidebar
|
||||
floor={+selectedFloor!}
|
||||
floor={selectedFloor!}
|
||||
wing={selectedWing!}
|
||||
onClose={() => setSelectedFloor(undefined)}
|
||||
/>
|
||||
|
||||
@@ -1,555 +0,0 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Transition } from "react-transition-group";
|
||||
import FloorPath from "../components/FloorPath";
|
||||
import paths from "../data/floorPaths.json";
|
||||
import ArrowLeftIcon from "../components/icons/ArrowLeftIcon";
|
||||
import Button3 from "../components/Button3";
|
||||
import InfoIcon from "../components/icons/InfoIcon";
|
||||
import Header from "../components/Header";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import ArrowRightIcon from "../components/icons/ArrowRightIcon";
|
||||
import FloorItem from "../components/Test/FloorItem";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import FloorPlanSidebar from "../components/complexWingPage/FloorSidebar/FloorPlanSidebar";
|
||||
import useModal from "../store/useModal";
|
||||
|
||||
const floors = [
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"10",
|
||||
"11",
|
||||
"12",
|
||||
"13",
|
||||
"14",
|
||||
"15",
|
||||
"16",
|
||||
"17",
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28",
|
||||
"29",
|
||||
"30",
|
||||
"31",
|
||||
];
|
||||
|
||||
function Test2Page() {
|
||||
const { modal } = useModal();
|
||||
const ref = useRef<HTMLImageElement>(null);
|
||||
const [imageWidth, setImageWidth] = useState(0);
|
||||
const [imageHeight, setImageHeight] = useState(0);
|
||||
const [scaled, setScaled] = useState(false);
|
||||
const [selectedWing, setSelectedWing] = useState<string>();
|
||||
const [mousePos, setMousePos] = useState<[number, number]>([0, 0]);
|
||||
const [showPopup, setShowPopup] = useState<boolean>(false);
|
||||
const [selectedFloorPath, setSelectedFloorPath] = useState<SVGPathElement>();
|
||||
const [hoveredFloor, setHoveredFloor] = useState<string>();
|
||||
const navigate = useNavigate();
|
||||
const [hoveredWing, setHoveredWing] = useState<string>();
|
||||
const [selectedIndex] = useState<number>(0);
|
||||
const [selectedFloor, setSelectedFloor] = useState<string>();
|
||||
// const [showFloorPlanSidebar, setShowFloorPlanSidebar] = useState(false);
|
||||
|
||||
function handleResize() {
|
||||
if (window.innerHeight > window.innerWidth) {
|
||||
setScaled(true);
|
||||
} else {
|
||||
setScaled(false);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseMove(e: React.MouseEvent<HTMLDivElement>) {
|
||||
const x = e.clientX - e.currentTarget.getBoundingClientRect().left;
|
||||
const y = e.clientY - e.currentTarget.getBoundingClientRect().top;
|
||||
|
||||
setMousePos([x, y]);
|
||||
}
|
||||
|
||||
function handleMouseEnter(e: React.MouseEvent<SVGPathElement>) {
|
||||
if (!e.currentTarget.dataset["wing"]) return;
|
||||
|
||||
setSelectedFloorPath(e.currentTarget);
|
||||
setHoveredWing(e.currentTarget.dataset["wing"]);
|
||||
setShowPopup(true);
|
||||
}
|
||||
|
||||
function handleMouseLeave() {
|
||||
setShowPopup(false);
|
||||
}
|
||||
|
||||
function handleClick(e: React.MouseEvent<SVGPathElement>) {
|
||||
setSelectedWing(e.currentTarget.dataset["wing"]);
|
||||
setSelectedFloor(e.currentTarget.dataset["floor"]);
|
||||
}
|
||||
|
||||
// function prev() {
|
||||
// if (selectedIndex === 0) return;
|
||||
// setSelectedIndex((prev) => prev - 1);
|
||||
// }
|
||||
|
||||
// function next() {
|
||||
// if (selectedIndex === floors.length - 1) return;
|
||||
// setSelectedIndex((prev) => prev + 1);
|
||||
// }
|
||||
|
||||
function handleLoadedData() {
|
||||
setImageWidth(ref.current!.naturalWidth);
|
||||
setImageHeight(ref.current!.naturalHeight);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
handleResize();
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleResize);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setHoveredFloor(floors[selectedIndex]);
|
||||
}, [selectedIndex]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative overflow-hidden h-dvh"
|
||||
onMouseMove={handleMouseMove}
|
||||
>
|
||||
<Header />
|
||||
|
||||
<div
|
||||
className={`absolute z-10 bg-white rounded-2xl w-[344px] transition-[opacity,transform] duration-300 p-6 space-y-4 pointer-events-none select-none ${
|
||||
selectedFloorPath?.dataset["wing"] === "West"
|
||||
? "-translate-x-[calc(100%+16px)]"
|
||||
: "translate-x-4"
|
||||
} -translate-y-[50%] ${showPopup ? "opacity-100" : "opacity-0"}`}
|
||||
style={{ top: `${mousePos[1]}px`, left: `${mousePos[0]}px` }}
|
||||
>
|
||||
<div className="flex items-start justify-between pb-4 border-b border-[#E2E2DC]">
|
||||
<div className="space-y-1">
|
||||
<p className="text-xl text-[#0D1922] font-semibold">
|
||||
{selectedFloorPath?.dataset["name"] === "Sky Garden"
|
||||
? selectedFloorPath?.dataset["name"]
|
||||
: `${selectedFloorPath?.dataset["floor"]} floor`}
|
||||
</p>
|
||||
<p className="text-xs font-semibold">
|
||||
{selectedFloorPath?.dataset["name"] !== "Sky Garden" &&
|
||||
`${selectedFloorPath?.dataset["wing"]} Wing`}
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-[#00BED7] rounded-full px-2 py-[3px]">
|
||||
<p className="text-xs font-semibold text-white">0 units</p>
|
||||
</div>
|
||||
</div>
|
||||
{selectedFloorPath?.dataset["name"] !== "Sky Garden" ? (
|
||||
<div className="grid grid-cols-2">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-4 h-4 bg-[#00BED7] px-[4.5px] py-px rounded-full">
|
||||
<p className="text-[10px] text-white font-semibold leading-[13.5px]">
|
||||
0
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-sm">Studio Flex</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-4 h-4 bg-[#00BED7] px-[4.5px] py-px rounded-full">
|
||||
<p className="text-[10px] text-white font-semibold leading-[13.5px]">
|
||||
0
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-sm">Studio²</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-4 h-4 bg-[#00BED7] px-[4.5px] py-px rounded-full">
|
||||
<p className="text-[10px] text-white font-semibold leading-[13.5px]">
|
||||
0
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-sm">1 Bedroom²</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-4 h-4 bg-[#00BED7] px-[4.5px] py-px rounded-full">
|
||||
<p className="text-[10px] text-white font-semibold leading-[13.5px]">
|
||||
0
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-sm">2 Bedroom²</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-4 h-4 bg-[#00BED7] px-[4.5px] py-px rounded-full">
|
||||
<p className="text-[10px] text-white font-semibold leading-[13.5px]">
|
||||
0
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-sm">Indoor</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-4 h-4 bg-[#00BED7] px-[4.5px] py-px rounded-full">
|
||||
<p className="text-[10px] text-white font-semibold leading-[13.5px]">
|
||||
0
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-sm">Outdoor</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="absolute top-0 left-0 z-10">
|
||||
<div className="p-4 mt-14">
|
||||
<div className="flex gap-2">
|
||||
<Button3
|
||||
icon={<ArrowLeftIcon />}
|
||||
onlyIcon
|
||||
onClick={() => navigate("..")}
|
||||
/>
|
||||
<Button3
|
||||
variant="secondary"
|
||||
icon={<InfoIcon />}
|
||||
onClick={() => navigate("/about-projects")}
|
||||
>
|
||||
About Projects
|
||||
</Button3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="transition-all duration-300"
|
||||
style={{
|
||||
transform: `translateX(${selectedFloor ? -25 : 0}%)`,
|
||||
}}
|
||||
>
|
||||
<div className={`h-dvh ${scaled ? "scale-150 -translate-x-[1%]" : ""}`}>
|
||||
<img
|
||||
ref={ref}
|
||||
src="/images/sequenceWing.jpg"
|
||||
alt=""
|
||||
className="object-cover w-full h-full"
|
||||
onLoad={() => handleLoadedData()}
|
||||
/>
|
||||
|
||||
<svg
|
||||
viewBox={`0 0 ${imageWidth} ${imageHeight}`}
|
||||
preserveAspectRatio="xMidYMid slice"
|
||||
className="absolute top-0 left-0 w-full h-full"
|
||||
>
|
||||
{!isMobile ? (
|
||||
paths.map((path, index) => (
|
||||
<FloorPath
|
||||
key={index}
|
||||
{...path}
|
||||
selected={
|
||||
path["data-wing"] && path["data-floor"]
|
||||
? path["data-wing"] === hoveredWing &&
|
||||
path["data-floor"] === hoveredFloor
|
||||
: false
|
||||
}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<>
|
||||
<g
|
||||
className={`transition-opacity duration-300 ${
|
||||
selectedWing
|
||||
? "opacity-100"
|
||||
: "opacity-0 pointer-events-none"
|
||||
}`}
|
||||
>
|
||||
{paths
|
||||
.filter((path) => path["data-wing"] === selectedWing)
|
||||
.map((path, index) => (
|
||||
<FloorPath
|
||||
key={index}
|
||||
{...path}
|
||||
selected={
|
||||
path["data-wing"] && path["data-floor"]
|
||||
? path["data-wing"] === selectedWing &&
|
||||
path["data-floor"] === hoveredFloor
|
||||
: false
|
||||
}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
))}
|
||||
</g>
|
||||
<g
|
||||
className={`transition-opacity duration-300 ${
|
||||
selectedWing
|
||||
? "opacity-0 pointer-events-none"
|
||||
: "opacity-100"
|
||||
}`}
|
||||
>
|
||||
<path
|
||||
d="M1441.29,1493.16v23.81l-.29,1034.35h0v24.45c0,1.73,1.11,3.26,2.76,3.8l138.35,45.23c.76.25,1.57.27,2.34.04l316.3-90.81c.23-.06.46-.11.7-.13l58.15-5.9,3.6-.53.29-1015.83c0-2.21-1.79-4-4-4h-58.11l-321.31-34.62c-.3-.03-.6-.03-.9.01l-134.36,16.16c-2.01.24-3.52,1.94-3.52,3.97Z"
|
||||
className={`fill-[#00bed7]/20`}
|
||||
onClick={() => setSelectedWing("East")}
|
||||
/>
|
||||
<path
|
||||
d="M2446,1515.51v-25.79c0-2.13-1.68-3.89-3.81-3.99l-136.64-6.53c-.32-.02-.64.01-.96.07l-28.81,5.68-249.29,22.69h-59c-2.21,0-4,1.79-4,4l-.29,1015.83,3.81.34,58.82,2.71c.25.01.5.04.74.1l248.44,59.2c.36.09.71.23,1.04.41l23.43,13.25c.75.43,1.62.6,2.48.49l140.27-18.21c1.99-.26,3.48-1.96,3.48-3.97v-24.64l.29-1041.64Z"
|
||||
className={`fill-[#00bed7]/20`}
|
||||
onClick={() => setSelectedWing("West")}
|
||||
/>
|
||||
</g>
|
||||
</>
|
||||
)}
|
||||
<g>
|
||||
<rect
|
||||
x={2068}
|
||||
y={1234}
|
||||
width={224}
|
||||
height={56}
|
||||
rx={24}
|
||||
ry={24}
|
||||
style={{
|
||||
fill: "#000",
|
||||
opacity: 0.4,
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<g>
|
||||
<path
|
||||
d="M2105.55,1273.23l-6.47-22.91h4.46l4.13,16.83h.21l4.41-16.83h4.06l4.42,16.85h.2l4.13-16.85h4.46l-6.47,22.91h-4.09l-4.59-16.07h-.18l-4.6,16.07h-4.09Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M2145.74,1264.51c0-1.51-.21-2.81-.63-3.9-.42-1.09-.99-1.99-1.72-2.7s-1.56-1.23-2.51-1.57c-.94-.34-1.94-.51-3-.51-1.64,0-3.07.37-4.28,1.12-1.22.75-2.16,1.79-2.84,3.13-.68,1.34-1.01,2.89-1.01,4.66s.34,3.36,1.01,4.68c.67,1.32,1.63,2.35,2.88,3.07,1.25.72,2.74,1.08,4.46,1.08,1.33,0,2.52-.2,3.56-.61,1.04-.41,1.89-.98,2.56-1.72s1.12-1.61,1.36-2.61l-3.78-.43c-.18.48-.44.89-.79,1.22s-.76.58-1.24.74c-.48.17-1.01.25-1.6.25-.88,0-1.65-.19-2.3-.56-.66-.38-1.17-.92-1.53-1.63-.35-.69-.53-1.51-.54-2.47h11.96v-1.24ZM2133.79,1263.02c.04-.67.21-1.3.51-1.87.35-.65.83-1.17,1.46-1.57.63-.4,1.35-.6,2.18-.6.78,0,1.46.18,2.04.53.59.35,1.04.83,1.37,1.44.33.61.5,1.3.5,2.08h-8.07Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M2162.75,1260.59l-3.69.4c-.1-.37-.29-.72-.54-1.05s-.6-.59-1.03-.79c-.43-.2-.96-.3-1.59-.3-.84,0-1.55.18-2.12.55-.57.37-.85.84-.85,1.42,0,.5.18.91.55,1.22.38.31,1,.57,1.87.77l2.93.63c1.63.35,2.84.91,3.63,1.67.79.76,1.19,1.76,1.2,2.99,0,1.08-.32,2.03-.95,2.86s-1.49,1.47-2.59,1.93c-1.1.46-2.37.69-3.8.69-2.1,0-3.8-.44-5.08-1.33s-2.05-2.12-2.29-3.7l3.95-.38c.18.78.56,1.36,1.14,1.76.58.4,1.34.59,2.27.59s1.74-.2,2.32-.59c.59-.4.88-.88.88-1.47,0-.49-.19-.9-.57-1.22-.38-.32-.96-.57-1.75-.74l-2.93-.62c-1.65-.34-2.87-.92-3.66-1.74-.79-.82-1.18-1.85-1.17-3.1,0-1.06.28-1.98.87-2.76s1.4-1.38,2.45-1.81c1.05-.43,2.26-.64,3.63-.64,2.01,0,3.6.43,4.76,1.29s1.88,2.02,2.15,3.48Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M2174.67,1269.9c-.11.03-.27.06-.49.1-.21.04-.45.06-.7.06-.34,0-.64-.05-.92-.16-.28-.1-.5-.3-.67-.59-.17-.29-.25-.7-.25-1.25v-8.88h3.39v-3.13h-3.39v-4.12h-4.05v4.12h-2.44v3.13h2.44v9.55c0,1.07.23,1.97.7,2.68.47.72,1.12,1.24,1.93,1.58.81.34,1.73.49,2.74.46.57-.01,1.06-.07,1.46-.16.4-.09.71-.17.92-.25l-.68-3.17Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M2191.25,1273.23l-6.47-22.91h4.46l4.13,16.83h.21l4.41-16.83h4.06l4.42,16.85h.2l4.13-16.85h4.46l-6.47,22.91h-4.09l-4.59-16.07h-.18l-4.6,16.07h-4.09Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M2220,1253.61c-.64,0-1.19-.21-1.66-.64s-.69-.95-.69-1.55.23-1.13.69-1.56c.46-.43,1.01-.64,1.66-.64s1.2.21,1.66.64c.46.43.69.95.69,1.56s-.23,1.12-.69,1.55c-.46.43-1.01.64-1.66.64ZM2217.96,1273.23v-17.18h4.05v17.18h-4.05Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M2230.22,1263.16v10.07h-4.05v-17.18h3.87v2.92h.2c.39-.96,1.03-1.73,1.9-2.29.87-.57,1.94-.85,3.23-.85,1.19,0,2.22.25,3.1.76.88.51,1.57,1.24,2.06,2.2.49.96.73,2.13.72,3.5v10.94h-4.05v-10.31c0-1.15-.3-2.05-.89-2.7-.59-.65-1.41-.97-2.46-.97-.71,0-1.34.15-1.88.46-.55.31-.98.76-1.29,1.34s-.46,1.29-.46,2.11Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M2252.85,1280.03c-1.45,0-2.7-.2-3.75-.59s-1.88-.92-2.52-1.57c-.63-.66-1.07-1.38-1.32-2.18l3.65-.88c.16.34.4.67.72,1,.31.33.74.61,1.27.83s1.21.33,2.02.33c1.15,0,2.1-.28,2.85-.83.75-.56,1.13-1.47,1.13-2.73v-3.26h-.2c-.21.42-.51.85-.91,1.29s-.92.81-1.58,1.11-1.47.45-2.45.45c-1.32,0-2.52-.31-3.59-.93s-1.92-1.55-2.55-2.8c-.63-1.24-.95-2.8-.95-4.67s.32-3.48.95-4.78c.63-1.3,1.48-2.29,2.56-2.96,1.07-.68,2.27-1.01,3.59-1.01,1.01,0,1.84.17,2.49.51.65.34,1.17.75,1.56,1.22.39.47.68.92.88,1.34h.22v-2.84h3.99v17.46c0,1.47-.35,2.68-1.05,3.65-.7.96-1.66,1.68-2.88,2.16-1.22.48-2.6.72-4.14.72ZM2252.88,1269.81c.86,0,1.59-.21,2.19-.63.6-.42,1.06-1.02,1.38-1.8.31-.78.47-1.72.47-2.82s-.15-2.03-.46-2.84c-.31-.81-.76-1.44-1.36-1.9-.6-.45-1.34-.68-2.21-.68s-1.66.23-2.26.7c-.6.47-1.06,1.11-1.37,1.93-.31.82-.46,1.74-.46,2.78s.15,1.97.46,2.76c.31.79.77,1.4,1.38,1.83s1.36.65,2.24.65Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<rect
|
||||
x={1618}
|
||||
y={1234}
|
||||
width={224}
|
||||
height={56}
|
||||
rx={24}
|
||||
ry={24}
|
||||
style={{
|
||||
fill: "#000",
|
||||
opacity: 0.4,
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<g>
|
||||
<path
|
||||
d="M1655.6,1273.23v-22.91h14.9v3.48h-10.75v6.22h9.98v3.48h-9.98v6.25h10.84v3.48h-14.99Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M1679.5,1273.58c-1.09,0-2.07-.2-2.94-.59-.87-.39-1.55-.97-2.06-1.74s-.75-1.72-.75-2.84c0-.97.18-1.77.54-2.4.36-.63.85-1.14,1.47-1.52s1.32-.67,2.1-.87c.78-.2,1.59-.34,2.42-.43,1.01-.1,1.82-.2,2.45-.29.63-.09,1.08-.22,1.37-.4.29-.18.43-.47.43-.86v-.07c0-.84-.25-1.5-.75-1.96-.5-.46-1.22-.69-2.16-.69-.99,0-1.78.22-2.35.65s-.97.94-1.17,1.53l-3.78-.54c.3-1.04.79-1.92,1.48-2.62.69-.7,1.52-1.23,2.52-1.59.99-.35,2.09-.53,3.29-.53.83,0,1.65.1,2.47.29s1.57.51,2.25.96c.68.44,1.22,1.05,1.64,1.81.41.76.62,1.71.62,2.85v11.5h-3.89v-2.36h-.13c-.25.48-.59.92-1.03,1.34-.44.41-1,.75-1.67,1-.67.25-1.45.37-2.34.37ZM1680.55,1270.6c.81,0,1.52-.16,2.11-.49.6-.32,1.06-.75,1.38-1.29.32-.54.49-1.12.49-1.76v-2.02c-.13.1-.34.2-.64.29-.3.09-.64.17-1.01.23-.37.07-.74.13-1.11.18-.37.05-.68.1-.95.13-.6.08-1.15.22-1.62.4-.48.19-.85.45-1.13.78-.28.33-.41.76-.41,1.28,0,.75.27,1.31.82,1.69s1.24.57,2.08.57Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M1706.24,1260.59l-3.69.4c-.1-.37-.29-.72-.54-1.05s-.6-.59-1.03-.79c-.43-.2-.96-.3-1.59-.3-.84,0-1.55.18-2.12.55-.57.37-.85.84-.84,1.42,0,.5.18.91.55,1.22.38.31,1,.57,1.87.77l2.93.63c1.63.35,2.84.91,3.63,1.67.79.76,1.2,1.76,1.2,2.99,0,1.08-.32,2.03-.95,2.86s-1.49,1.47-2.59,1.93-2.37.69-3.8.69c-2.1,0-3.8-.44-5.08-1.33-1.28-.88-2.05-2.12-2.29-3.7l3.95-.38c.18.78.56,1.36,1.14,1.76.58.4,1.34.59,2.27.59s1.74-.2,2.32-.59c.59-.4.88-.88.88-1.47,0-.49-.19-.9-.56-1.22-.38-.32-.96-.57-1.75-.74l-2.93-.62c-1.65-.34-2.87-.92-3.66-1.74-.79-.82-1.18-1.85-1.17-3.1,0-1.06.28-1.98.87-2.76s1.4-1.38,2.45-1.81c1.05-.43,2.26-.64,3.63-.64,2.01,0,3.6.43,4.76,1.29,1.16.86,1.88,2.02,2.15,3.48Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M1718.16,1269.9c-.11.03-.27.06-.49.1-.21.04-.45.06-.7.06-.34,0-.64-.05-.92-.16s-.5-.3-.67-.59c-.17-.29-.25-.7-.25-1.25v-8.88h3.39v-3.13h-3.39v-4.12h-4.05v4.12h-2.44v3.13h2.44v9.55c0,1.07.23,1.97.7,2.68.47.72,1.12,1.24,1.93,1.58.81.34,1.73.49,2.74.46.57-.01,1.06-.07,1.46-.16.4-.09.71-.17.92-.25l-.68-3.17Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M1734.74,1273.23l-6.47-22.91h4.46l4.13,16.83h.21l4.41-16.83h4.06l4.42,16.85h.2l4.13-16.85h4.46l-6.47,22.91h-4.09l-4.59-16.07h-.18l-4.6,16.07h-4.09Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M1763.48,1253.61c-.64,0-1.19-.21-1.66-.64s-.69-.95-.69-1.55.23-1.13.69-1.56c.46-.43,1.01-.64,1.66-.64s1.2.21,1.66.64c.46.43.69.95.69,1.56s-.23,1.12-.69,1.55c-.46.43-1.01.64-1.66.64ZM1761.45,1273.23v-17.18h4.05v17.18h-4.05Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M1773.71,1263.16v10.07h-4.05v-17.18h3.87v2.92h.2c.4-.96,1.03-1.73,1.9-2.29.87-.57,1.94-.85,3.23-.85,1.19,0,2.22.25,3.1.76.88.51,1.57,1.24,2.06,2.2.49.96.73,2.13.72,3.5v10.94h-4.05v-10.31c0-1.15-.3-2.05-.89-2.7-.59-.65-1.41-.97-2.46-.97-.71,0-1.34.15-1.89.46-.55.31-.98.76-1.29,1.34s-.46,1.29-.46,2.11Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
d="M1796.34,1280.03c-1.45,0-2.7-.2-3.75-.59s-1.88-.92-2.52-1.57c-.63-.66-1.07-1.38-1.32-2.18l3.65-.88c.16.34.4.67.72,1,.31.33.74.61,1.27.83.53.22,1.21.33,2.02.33,1.15,0,2.1-.28,2.85-.83s1.13-1.47,1.13-2.73v-3.26h-.2c-.21.42-.51.85-.91,1.29s-.92.81-1.58,1.11c-.65.3-1.47.45-2.46.45-1.32,0-2.51-.31-3.59-.93s-1.92-1.55-2.55-2.8c-.63-1.24-.95-2.8-.95-4.67s.32-3.48.95-4.78,1.48-2.29,2.56-2.96c1.07-.68,2.27-1.01,3.59-1.01,1.01,0,1.84.17,2.49.51.65.34,1.17.75,1.56,1.22.39.47.68.92.88,1.34h.22v-2.84h3.99v17.46c0,1.47-.35,2.68-1.05,3.65-.7.96-1.66,1.68-2.87,2.16-1.22.48-2.6.72-4.14.72ZM1796.37,1269.81c.86,0,1.59-.21,2.19-.63.6-.42,1.06-1.02,1.38-1.8s.47-1.72.47-2.82-.15-2.03-.46-2.84c-.31-.81-.76-1.44-1.36-1.9s-1.34-.68-2.21-.68-1.66.23-2.26.7c-.6.47-1.06,1.11-1.36,1.93-.31.82-.46,1.74-.46,2.78s.16,1.97.46,2.76c.31.79.77,1.4,1.38,1.83.61.44,1.36.65,2.24.65Z"
|
||||
style={{
|
||||
fill: "#fff",
|
||||
strokeWidth: 0,
|
||||
}}
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={`sm:hidden absolute bottom-0 w-full p-3 transition-opacity duration-300 ${
|
||||
selectedWing ? "opacity-100" : "opacity-0 pointer-events-none"
|
||||
}`}
|
||||
>
|
||||
<div className="relative px-4 pt-2 pb-4 space-y-3 bg-white rounded-lg">
|
||||
<div className="relative overflow-hidden">
|
||||
<div
|
||||
id="test"
|
||||
className="absolute top-[calc(50%-16px)] left-[calc(50%-16px)] w-8 h-6"
|
||||
></div>
|
||||
<div
|
||||
id="floors"
|
||||
className="relative flex gap-4 overflow-x-auto px-[calc(50%)] pt-2.5 pb-[18px] snap-x snap-mandatory"
|
||||
>
|
||||
{floors.map((floor) => (
|
||||
<FloorItem
|
||||
floor={floor}
|
||||
onSelected={() => setHoveredFloor(floor)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="absolute top-0 left-0 w-full h-full pointer-events-none bg-gradient-to-r from-white via-transparent to-white"></div>
|
||||
<div className="absolute top-0 left-0 flex justify-between w-full pointer-events-none">
|
||||
<Button3
|
||||
variant="secondary"
|
||||
icon={<ArrowLeftIcon className="w-4 h-4" />}
|
||||
onlyIcon
|
||||
className="ring-0 w-9 h-9"
|
||||
/>
|
||||
<Button3
|
||||
variant="secondary"
|
||||
icon={<ArrowRightIcon className="w-4 h-4" />}
|
||||
onlyIcon
|
||||
className="ring-0 w-9 h-9"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button3
|
||||
variant="secondary"
|
||||
size="small"
|
||||
icon={<ArrowLeftIcon className="w-4 h-4" />}
|
||||
className="w-full"
|
||||
onClick={() => setSelectedWing(undefined)}
|
||||
>
|
||||
Back
|
||||
</Button3>
|
||||
<Button3
|
||||
size="small"
|
||||
icon={<ArrowRightIcon className="w-4 h-4" />}
|
||||
className="flex-row-reverse w-full"
|
||||
onClick={() => setSelectedFloor(hoveredFloor)}
|
||||
>
|
||||
Explore
|
||||
</Button3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Transition
|
||||
in={!!selectedFloor && !!selectedWing}
|
||||
timeout={300}
|
||||
mountOnEnter
|
||||
unmountOnExit
|
||||
>
|
||||
{(state) => (
|
||||
<div
|
||||
className={`absolute top-0 h-dvh bg-[#F3F3F2] right-0 lg:w-1/2 w-full z-10 transition-all duration-300 flex flex-col ${state}`}
|
||||
>
|
||||
<FloorPlanSidebar
|
||||
floor={+selectedFloor!}
|
||||
wing={selectedWing!}
|
||||
onClose={() => setSelectedFloor(undefined)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Transition>
|
||||
|
||||
{modal}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Test2Page;
|
||||
Reference in New Issue
Block a user