disclaimer + map

This commit is contained in:
2024-04-24 18:16:55 +05:00
parent cb40040c8a
commit a5a0453c93
22 changed files with 359 additions and 64 deletions
-1
View File
@@ -17,7 +17,6 @@
"react-router-dom": "^6.22.3",
"react-swipeable": "^7.0.1",
"react-zoom-pan-pinch": "^3.4.4",
"usehooks-ts": "^3.1.0",
"zustand": "^4.5.2"
},
"devDependencies": {
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

+7 -5
View File
@@ -1,8 +1,9 @@
import {
backgroundColors,
backgroundHoverColors,
textColors,
} from "../consts/buttonColors";
borders,
paddings,
} from "../consts/buttonStyles";
import { ButtonType } from "../types/button";
interface ButtonProps {
@@ -21,15 +22,16 @@ const Button = ({
onClick,
}: ButtonProps) => {
const backgroundColor = backgroundColors[buttonType];
const backgroundHoverColor = backgroundHoverColors[buttonType];
const textColor = textColors[buttonType];
const border = borders[buttonType];
const padding = paddings[buttonType];
return (
<button
onClick={onClick}
className={`min-w-[40px] ${
icon && !text ? "p-[10px]" : "py-3 px-6"
} transition-[background] duration-300 ease-in-out rounded-lg text-s ${backgroundColor} ${backgroundHoverColor} ${textColor} ${
icon && !text ? "p-[10px]" : padding
} transition-[background] duration-300 ease-in-out text-s pointer-events-auto flex gap-1 items-center h-fit ${backgroundColor} ${textColor} ${border} ${
className ? className : ""
}`}
>
@@ -4,7 +4,7 @@ import Navbar from "../Navbar/Navbar";
import Location from "../Location";
const DesktopHeader = () => (
<header className="bg-white w-full text-white sm:grid grid-cols-6 font-usual text-m">
<header className="bg-white w-full text-white sm:grid grid-cols-6 absolute left-0 top-0 z-20 font-usual text-m">
<div className="flex gap-4 col-span-2">
<Logo />
<Location />
@@ -3,6 +3,7 @@ import LogoIcon from "../../icons/LogoIcon";
import Auth from "../Auth/Auth";
import Navbar from "../Navbar/Navbar";
import Location from "../Location";
import BurgerMenuIcon from "../../icons/BurgerMenuIcon";
const MobileHeader = () => {
const [isToggled, setIsToggled] = useState(false);
@@ -25,7 +26,9 @@ const MobileHeader = () => {
<div className={`text-[#0D1922] transition-opacity duration-500`}>
<LogoIcon />
</div>
<div className="bg-black w-6 h-6" onClick={handleOnToggleClick}></div>
<div className="w-6 h-6 text-[#0D1922]" onClick={handleOnToggleClick}>
<BurgerMenuIcon isToggled={isToggled} />
</div>
</div>
<div className="flex flex-col justify-between h-full items-end w-full p-4 bg-[#F3F3F2]">
{isAuth && (
+54
View File
@@ -0,0 +1,54 @@
interface BurgerMenuIconProps {
isToggled: boolean;
}
const BurgerMenuIcon = ({ isToggled }: BurgerMenuIconProps) => {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
className="border transition-all duration-300 ease-in-out"
style={{
transform: isToggled
? "rotate(-45deg) translate(-13.5px, 0) scaleX(1.2)"
: "",
}}
d="M5 17L19 17"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
className={`border transition-all duration-300 ease-in-out ${
isToggled ? "opacity-0" : "opacity-100"
}`}
d="M5 12L19 12"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
className="border transition-all duration-300 ease-in-out"
style={{
transform: isToggled
? "rotate(45deg) translate(2.5px, -7.66px) scaleX(1.2)"
: "",
}}
d="M5 7L19 7"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
};
export default BurgerMenuIcon;
+21
View File
@@ -0,0 +1,21 @@
const CrossIcon = () => {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 11.9999L17.6569 6.34331M12 11.9999L6.34312 6.34302M12 11.9999L17.6568 17.6567M12 11.9999L6.34302 17.6568"
stroke="#73787C"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
};
export default CrossIcon;
+26
View File
@@ -0,0 +1,26 @@
const DisclaimerIcon = () => {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.1666 7.99992C14.1666 8.80974 14.0071 9.61163 13.6972 10.3598C13.3873 11.108 12.933 11.7878 12.3604 12.3604C11.7878 12.933 11.108 13.3873 10.3598 13.6972C9.61163 14.0071 8.80974 14.1666 7.99992 14.1666C7.1901 14.1666 6.38821 14.0071 5.64004 13.6972C4.89186 13.3873 4.21205 12.933 3.63943 12.3604C3.0668 11.7878 2.61257 11.108 2.30266 10.3598C1.99276 9.61163 1.83325 8.80974 1.83325 7.99992C1.83325 7.1901 1.99276 6.38821 2.30266 5.64004C2.61257 4.89186 3.0668 4.21205 3.63943 3.63943C4.21206 3.0668 4.89186 2.61257 5.64004 2.30266C6.38821 1.99276 7.1901 1.83325 7.99992 1.83325C8.80974 1.83325 9.61163 1.99276 10.3598 2.30266C11.108 2.61257 11.7878 3.0668 12.3604 3.63943C12.933 4.21206 13.3873 4.89186 13.6972 5.64004C14.0071 6.38821 14.1666 7.1901 14.1666 7.99992L14.1666 7.99992Z"
stroke="white"
/>
<path d="M8 4.66675V8.66675" stroke="white" stroke-linecap="round" />
<ellipse
cx="7.99992"
cy="11.3334"
rx="0.666667"
ry="0.666667"
fill="white"
/>
</svg>
);
};
export default DisclaimerIcon;
+32
View File
@@ -0,0 +1,32 @@
const HintIcon = () => {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17.5832 9.99984C17.5832 10.9957 17.387 11.9818 17.0059 12.9019C16.6248 13.8219 16.0662 14.6579 15.3621 15.3621C14.6579 16.0662 13.8219 16.6248 12.9019 17.0059C11.9818 17.387 10.9957 17.5832 9.99984 17.5832C9.00398 17.5832 8.01787 17.387 7.09782 17.0059C6.17777 16.6248 5.34179 16.0662 4.63761 15.3621C3.93343 14.6579 3.37485 13.8219 2.99375 12.9019C2.61265 11.9818 2.4165 10.9957 2.4165 9.99984C2.4165 9.00398 2.61265 8.01787 2.99375 7.09782C3.37485 6.17777 3.93343 5.34179 4.63761 4.63761C5.34179 3.93343 6.17777 3.37485 7.09782 2.99375C8.01787 2.61265 9.00398 2.4165 9.99984 2.4165C10.9957 2.4165 11.9818 2.61265 12.9019 2.99375C13.8219 3.37485 14.6579 3.93343 15.3621 4.63761C16.0662 5.34179 16.6248 6.17777 17.0059 7.09782C17.387 8.01788 17.5832 9.00398 17.5832 9.99984L17.5832 9.99984Z"
stroke="#0D1922"
strokeWidth="1.5"
/>
<path
d="M7.5 8.42609C7.5 6.99424 8.61929 5.8335 10 5.8335C11.3807 5.8335 12.5 6.99424 12.5 8.42609C12.5 9.79168 10.7893 10.7427 10 11.6668"
stroke="#0D1922"
strokeWidth="1.5"
strokeLinecap="round"
/>
<ellipse
cx="9.99984"
cy="14.1668"
rx="0.833333"
ry="0.833333"
fill="#0D1922"
/>
</svg>
);
};
export default HintIcon;
+21
View File
@@ -0,0 +1,21 @@
const ResizeIcon = () => {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7 17.5H2.5M2.5 17.5V13M2.5 17.5L7.375 12.625M12.625 7.375L17.5 2.5M17.5 2.5V7M17.5 2.5H13"
stroke="#0D1922"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
};
export default ResizeIcon;
@@ -0,0 +1,14 @@
import Button from "../Button";
import HintIcon from "../icons/HintIcon";
import ResizeIcon from "../icons/ResizeIcon";
const TopPanel = () => {
return (
<div className="absolute top-[62px] left-0 z-20 w-full p-4 flex justify-end gap-2">
<Button buttonType="fab" icon={<ResizeIcon />} />
<Button buttonType="fab" icon={<HintIcon />} />
</div>
);
};
export default TopPanel;
@@ -0,0 +1,29 @@
import Button from "../../Button";
import DisclaimerIcon from "../../icons/DisclaimerIcon";
import useModal from "../../../store/useModal";
import Disclaimer from "../../modals/Disclaimer";
const ButtomPanel = () => {
const { setModal } = useModal();
const handleOnDisclaimerClick = () => {
setModal(<Disclaimer />);
};
return (
<div className="absolute z-20 bottom-0 left-0 w-full p-6 select-none touch-none pointer-events-none flex gap-2 justify-between items-end">
<div className="flex flex-col gap-2">
<div className="flex gap-2 pb-6 pl-6">
<Button
text="Disclaimer"
buttonType="tertiary"
icon={<DisclaimerIcon />}
onClick={handleOnDisclaimerClick}
/>
<Button text="Privacy Policy" buttonType="tertiary" />
</div>
</div>
<img src="./images/masterplan/compass.png" alt="compass" />
</div>
);
};
export default ButtomPanel;
@@ -2,8 +2,8 @@ import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch";
import ImageMarker, { MarkerComponentProps } from "react-image-marker";
import { isMobile } from "react-device-detect";
import Marker from "./Marker";
import { markers } from "../../consts/markers";
import useMarker from "../../store/useMarker";
import { markers } from "../../../consts/markers";
import useMarker from "../../../store/useMarker";
const Map = () => {
const { hoveredMarker } = useMarker();
@@ -19,14 +19,15 @@ const Map = () => {
<TransformWrapper
initialScale={isMobile ? 2 : 1}
minScale={isMobile ? 2 : 1}
alignmentAnimation={{ sizeX: 0, sizeY: 0 }}
alignmentAnimation={{ sizeX: 50, sizeY: 50 }}
wheel={{ step: 1 }}
zoomAnimation={{
disabled: false,
size: 0,
animationType: "easeOutQuart",
animationTime: 2000,
animationTime: 500,
}}
// velocityAnimation={{
// sensitivity: 1000,
// animationTime: 1000,
@@ -34,7 +35,9 @@ const Map = () => {
// }}
>
<TransformComponent
wrapperClass={`${isMobile ? "h-screen" : "h-[calc(100vh-62.39px)]"}`}
wrapperClass={
"h-[calc(100vh+150px)] w-[calc(100vw+400px)] top-[-50px] left-[-200px]"
}
>
<ImageMarker
src="images/Map.jpg"
@@ -44,7 +47,6 @@ const Map = () => {
hoveredMarker ? "brightness-[.7]" : ""
}`}
/>
{/* <div className="bg-black brightness-[.7] absolute w-full h-full left-0 top-0 bg-black opacity-70 pointer-events-none"></div> */}
</TransformComponent>
</TransformWrapper>
);
@@ -1,9 +1,14 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { MarkerComponentProps } from "react-image-marker";
import { markers } from "../../consts/markers";
import useMarker from "../../store/useMarker";
import { useEffect, useState } from "react";
import { useTransformContext } from "react-zoom-pan-pinch";
import { markers } from "../../../consts/markers";
import useMarker from "../../../store/useMarker";
const Marker = (props: MarkerComponentProps) => {
const { setHoveredMarker, hoveredMarker } = useMarker();
const { transformState } = useTransformContext();
const [markerScale, setMarkerScale] = useState(1);
const currentMarker = markers.find(
(marker) => marker.itemNumber === props.itemNumber
);
@@ -13,12 +18,28 @@ const Marker = (props: MarkerComponentProps) => {
setHoveredMarker(hoveredMarker);
};
const handleOnScroll = () => {
const scale = 1 / transformState.scale;
setMarkerScale(scale);
};
const handleOnMouseLeave = () => {
setHoveredMarker(null);
};
useEffect(() => {
const map = document.querySelector(".react-transform-wrapper");
handleOnScroll();
if (map) map.addEventListener("wheel", handleOnScroll);
return () => map?.removeEventListener("wheel", handleOnScroll);
}, []);
return (
<div className="relative ">
<div
className="relative transition-transform"
style={{ transform: `scale(${markerScale})` }}
>
<div
className={`flex items-end absolute w-[108px] top-[22px] right-[72px] transition-all duration-300 ease-in-out ${
hoveredMarker &&
@@ -50,7 +71,13 @@ const Marker = (props: MarkerComponentProps) => {
onMouseEnter={handleOnMouseEnter}
onMouseLeave={handleOnMouseLeave}
>
<img src="/images/markers/1.png" alt="1" width={72} height={98} />
<img
id="marker"
src="/images/markers/1.png"
alt="1"
width={72}
height={98}
/>
</div>
</div>
<div
+53
View File
@@ -0,0 +1,53 @@
import useModal from "../../store/useModal";
import CrossIcon from "../icons/CrossIcon";
const Disclaimer = () => {
const { setModal } = useModal();
const handleOnCloseClick = () => {
setModal(null);
};
return (
<div className="absolute z-50 top-0 left-0 w-screen bg-[#0D192266] h-screen backdrop-blur-[6px] grid grid-cols-12 items-center">
<div className="bg-white rounded-lg col-span-4 col-start-5 py-[37px] px-8">
<div className=" w-full h-1 flex justify-between">
<div className="h-[2px] bg-[#00BED7] w-1/3 rounded-full"></div>
<button onClick={handleOnCloseClick}>
<CrossIcon />
</button>
</div>
<h2 className="text-subheadline-m font-semibold py-6">Disclaimer</h2>
<div className="flex flex-col gap-4">
<p className="text-caption-m">
This masterplan has been designed solely to provide an impression of
the Rove Home projects as well as the approximate location of
existing and proposed facilities, services, and destinations and is
not intended for any other purpose.
</p>
<p className="text-caption-m">
All elements including the interior design used in the units and
images shown in the virtual tour are only for illustration. The
pictures of the proposed residential units, furniture, landscaping,
amenities, color schemes, fixtures, and accessories among all other
items are illustrative to showcase the units.
</p>
<p className="text-caption-m">
IRTH does not make any representation or give any warranty
concerning the future developments shown, or the current or future
amenities, location, or existence of any facilities, services, and
destinations. Any indications of distance, sizes, travel times, and
any other information are approximate and for indicative purposes
only and are not to scale.
</p>
<p className="text-caption-m">
IRTH gives notice that this virtual tour (including units,
amenities, plans of the property) does not constitute any part of a
sale offer or sale and purchase contract.
</p>
</div>
</div>
</div>
);
};
export default Disclaimer;
+8 -5
View File
@@ -1,4 +1,3 @@
import { useOnClickOutside } from "usehooks-ts";
import { useEffect, useRef, useState } from "react";
import SearchPlusIcon from "../icons/SearchIcon";
import OpenFullscreenIcon from "../icons/OpenFullscreenIcon";
@@ -19,7 +18,8 @@ const ZoomHint = () => {
}, 300);
};
const handleClickOutside = () => {
const handleClick = () => {
console.log("first");
setIsTransparent(true);
const timeOut = setTimeout(() => {
@@ -29,19 +29,22 @@ const ZoomHint = () => {
};
useEffect(() => {
window.addEventListener("click", handleClick);
window.addEventListener("touchstart", handleClick);
const map = document.querySelector(".react-transform-wrapper");
if (!map) return;
map.addEventListener("wheel", handleOnScroll);
return () => {
map.removeEventListener("wheel", handleOnScroll);
window.removeEventListener("click", handleClick);
window.removeEventListener("touchstart", handleClick);
};
}, []);
useOnClickOutside(ref, handleClickOutside);
return (
<div
className={`absolute z-10 m-auto top-1/2 left-1/2 flex flex-col items-center bg-[#0D192266] p-4 text-white gap-3 rounded-lg transition-opacity duration-300 ${
className={`absolute z-10 m-auto top-1/2 left-1/2 flex flex-col items-center bg-[#0D192266] backdrop-blur-md p-4 text-white gap-3 rounded-lg transition-opacity duration-300 ${
isTransparent ? "opacity-0" : "opacity-100"
}`}
ref={ref}
-21
View File
@@ -1,21 +0,0 @@
import { ButtonColor } from "../types/button";
const backgroundColors: ButtonColor = {
cta: "bg-[#00BED7]",
primary: "bg-[#ffffff]",
tertiary: "bg-[#0D192266]",
};
const backgroundHoverColors: ButtonColor = {
cta: "hover:bg-[#00A8BE]",
primary: "hover:bg-[#F3F3F2]",
tertiary: "hover:bg-[#0D192266]",
};
const textColors: ButtonColor = {
cta: "text-[#ffffff]",
primary: "text-[#0D1922]",
tertiary: "text-[#ffffff]",
};
export { textColors, backgroundColors, backgroundHoverColors };
+31
View File
@@ -0,0 +1,31 @@
import { ButtonStyle } from "../types/button";
const backgroundColors: ButtonStyle = {
cta: "bg-[#00BED7] hover:bg-[#00A8BE]",
primary: "bg-[#ffffff] hover:bg-[#F3F3F2]",
tertiary: "bg-[#0D192266] hover:bg-[#0D1922B2]",
fab: "bg-[#ffffff] hover:bg-[#F3F3F2]",
};
const textColors: ButtonStyle = {
cta: "text-[#ffffff]",
primary: "text-[#0D1922]",
tertiary: "text-[#ffffff]",
fab: "text-[#ffffff]",
};
const borders: ButtonStyle = {
cta: "rounded-lg",
primary: "rounded-lg",
tertiary: "rounded-full",
fab: "rounded-full",
};
const paddings = {
cta: "py-3 px-6",
primary: "py-3 px-6",
tertiary: "py-1 px-3",
fab: "py-3 px-6",
};
export { textColors, backgroundColors, borders, paddings };
+10 -3
View File
@@ -2,19 +2,26 @@ import { Marker } from "../types/marker";
const markers: Marker[] = [
{
top: 37.5,
left: 50,
top: 38.2,
left: 54,
itemNumber: 0,
popup: "/images/markers/popups/1.svg",
isPopupLeft: true,
},
{
top: 40.5,
top: 39.5,
left: 56,
itemNumber: 1,
popup: "/images/markers/popups/1.svg",
isPopupLeft: false,
},
{
top: 73,
left: 22.5,
itemNumber: 2,
popup: "/images/markers/popups/1.svg",
isPopupLeft: false,
},
];
export { markers };
+6 -2
View File
@@ -1,7 +1,9 @@
import { useEffect } from "react";
import useModal from "../store/useModal";
import ZoomHint from "../components/modals/ZoomHint";
import Map from "../components/map/Map";
import Map from "../components/masterplanPage/map/Map";
import TopPanel from "../components/masterplanPage/TopPanel";
import ButtomPanel from "../components/masterplanPage/map/ButtomPanel";
const Masterplan = () => {
const { setModal } = useModal();
@@ -10,8 +12,10 @@ const Masterplan = () => {
}, []);
return (
<div>
<div className="overflow-hidden h-screen w-screen">
<TopPanel />
<Map />
<ButtomPanel />
</div>
);
};
+3 -3
View File
@@ -1,6 +1,6 @@
type ButtonType = "primary" | "tertiary" | "cta";
type ButtonColor = {
type ButtonType = "primary" | "tertiary" | "cta" | "fab";
type ButtonStyle = {
[key in ButtonType]: string;
};
export type { ButtonColor, ButtonType };
export type { ButtonStyle, ButtonType };
-12
View File
@@ -1496,11 +1496,6 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
lodash.merge@^4.6.2:
version "4.6.2"
resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz"
@@ -2130,13 +2125,6 @@ use-sync-external-store@1.2.0:
resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz"
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
usehooks-ts@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/usehooks-ts/-/usehooks-ts-3.1.0.tgz#156119f36efc85f1b1952616c02580f140950eca"
integrity sha512-bBIa7yUyPhE1BCc0GmR96VU/15l/9gP1Ch5mYdLcFBaFGQsdmXkvjV0TtOqW1yUd6VjIwDunm+flSciCQXujiw==
dependencies:
lodash.debounce "^4.0.8"
util-deprecate@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"