filters + fullscreen + components
This commit is contained in:
@@ -13,7 +13,9 @@
|
||||
"react": "^18.2.0",
|
||||
"react-device-detect": "^2.2.3",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-full-screen": "^1.1.1",
|
||||
"react-image-marker": "^1.2.0",
|
||||
"react-range-slider-input": "^3.0.7",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"react-swipeable": "^7.0.1",
|
||||
"react-zoom-pan-pinch": "^3.4.4",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Button from "../../Button";
|
||||
import DisclaimerIcon from "../../icons/DisclaimerIcon";
|
||||
import useModal from "../../../store/useModal";
|
||||
import DisclaimerModal from "../../modals/DisclaimerModal";
|
||||
import Button from "./Button";
|
||||
import DisclaimerIcon from "./icons/DisclaimerIcon";
|
||||
import useModal from "../store/useModal";
|
||||
import DisclaimerModal from "./modals/DisclaimerModal";
|
||||
|
||||
const ButtomPanel = () => {
|
||||
const { setModal } = useModal();
|
||||
@@ -29,7 +29,7 @@ const Button = ({
|
||||
return (
|
||||
<button
|
||||
onClick={onClick}
|
||||
className={`min-w-[40px] ${
|
||||
className={`min-w-10 max-h-10 ${
|
||||
icon && !text ? "p-[10px]" : padding
|
||||
} transition-all duration-300 ease-in-out text-s pointer-events-auto flex gap-1 items-center h-fit ${backgroundColor} ${textColor} ${border} ${
|
||||
className ? className : ""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import MinusIcon from "../icons/MinusIcon";
|
||||
import SelectedCheckboxIcon from "../icons/SelectedCheckboxIcon";
|
||||
import MinusIcon from "./icons/MinusIcon";
|
||||
import SelectedCheckboxIcon from "./icons/SelectedCheckboxIcon";
|
||||
|
||||
interface CheckboxProps {
|
||||
title: string;
|
||||
@@ -0,0 +1,51 @@
|
||||
import { useState, useRef } from "react";
|
||||
import RangeSlider from "react-range-slider-input";
|
||||
// import "react-range-slider-input/dist/style.css";
|
||||
import "./multiRamgeSlider.css";
|
||||
|
||||
interface MultiRangeSliderProps {
|
||||
onChange?: () => void;
|
||||
min: number;
|
||||
max: number;
|
||||
}
|
||||
|
||||
const MultiRangeSlider = ({ min, max, onChange }: MultiRangeSliderProps) => {
|
||||
const [firstValue, setFirstValue] = useState(min);
|
||||
const [secondValue, setSecondValue] = useState(max);
|
||||
|
||||
const handleOnRangeInputChange = (e: [a: number, b: number]) => {
|
||||
setFirstValue(e[0]);
|
||||
setSecondValue(e[1]);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="px-2">
|
||||
<div className="flex justify-between p-3 bg-white rounded-2xl relative flex-col">
|
||||
<div className="flex justify-between">
|
||||
<input
|
||||
key={firstValue}
|
||||
type="number"
|
||||
onChange={(e) => console.log("e", e.target.value)}
|
||||
defaultValue={firstValue}
|
||||
className="focus:outline-none input_number"
|
||||
/>
|
||||
<input
|
||||
key={secondValue}
|
||||
type="number"
|
||||
defaultValue={secondValue}
|
||||
className="focus:outline-none appearance-none input_number text-right"
|
||||
/>
|
||||
</div>
|
||||
<RangeSlider
|
||||
min={min}
|
||||
max={max}
|
||||
value={[firstValue, secondValue]}
|
||||
className="absolute bottom-0 left-2 w-[calc(100%-16px)] z-20"
|
||||
onInput={handleOnRangeInputChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MultiRangeSlider;
|
||||
@@ -0,0 +1,75 @@
|
||||
import { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import useModal from "../../store/useModal";
|
||||
import Button from "../Button";
|
||||
import FilterIcon from "../icons/FilterIcon";
|
||||
import HintIcon from "../icons/HintIcon";
|
||||
import LeftArrowSliderIcon from "../icons/LeftArrowSliderIcon";
|
||||
import ResizeIcon from "../icons/ResizeIcon";
|
||||
import HelpModal from "../modals/HelpModal";
|
||||
import MasterplanFilters from "../modals/MasterplanFilters";
|
||||
import InfoIcon from "../icons/InfoIcon";
|
||||
import useFullScreen from "../../store/useFullScreen";
|
||||
|
||||
const ComplexTopPanel = () => {
|
||||
const [isFullMode, setIsFullMode] = useState(false);
|
||||
const { setModal } = useModal();
|
||||
const { onFullscreen } = useFullScreen();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleOnHelpClick = () => {
|
||||
setModal(<HelpModal />);
|
||||
};
|
||||
|
||||
const handleOnFiltersClick = () => {
|
||||
setModal(<MasterplanFilters />);
|
||||
};
|
||||
|
||||
const handleOnBackClick = () => {
|
||||
navigate("../masterplan");
|
||||
};
|
||||
|
||||
const handleOnFullScreenClick = () => {
|
||||
if (!onFullscreen) return;
|
||||
|
||||
setIsFullMode((prev) => !prev);
|
||||
if (!isFullMode) {
|
||||
onFullscreen.enter();
|
||||
} else {
|
||||
onFullscreen.exit();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="absolute top-[62px] left-0 z-20 w-full p-4 grid grid-cols-12">
|
||||
<div className="flex gap-2 col-span-3">
|
||||
<Button
|
||||
icon={<LeftArrowSliderIcon />}
|
||||
buttonType="cta"
|
||||
onClick={handleOnBackClick}
|
||||
/>
|
||||
<Button
|
||||
icon={<FilterIcon />}
|
||||
buttonType="primary"
|
||||
text="Filters"
|
||||
onClick={handleOnFiltersClick}
|
||||
/>
|
||||
<Button icon={<InfoIcon />} buttonType="primary" text="About Complex" />
|
||||
</div>
|
||||
<div className="flex gap-2 col-span-2 col-start-11 justify-end">
|
||||
<Button
|
||||
buttonType="fab"
|
||||
icon={<ResizeIcon />}
|
||||
onClick={handleOnFullScreenClick}
|
||||
/>
|
||||
<Button
|
||||
buttonType="fab"
|
||||
icon={<HintIcon />}
|
||||
onClick={handleOnHelpClick}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ComplexTopPanel;
|
||||
@@ -1,18 +0,0 @@
|
||||
import { Outlet } from "react-router-dom";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import useModal from "../../../store/useModal";
|
||||
import DesktopHeader from "./DesktopHeader";
|
||||
import MobileHeader from "./MobileHeader";
|
||||
|
||||
const Header = () => {
|
||||
const { modal } = useModal();
|
||||
return (
|
||||
<>
|
||||
{modal}
|
||||
{isMobile ? <MobileHeader /> : <DesktopHeader />}
|
||||
<Outlet />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Outlet } from "react-router-dom";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { FullScreen, useFullScreenHandle } from "react-full-screen";
|
||||
import useModal from "../../../store/useModal";
|
||||
import DesktopHeader from "./DesktopHeader";
|
||||
import MobileHeader from "./MobileHeader";
|
||||
import useFullScreen from "../../../store/useFullScreen";
|
||||
import { useEffect } from "react";
|
||||
|
||||
const Layout = () => {
|
||||
const { modal } = useModal();
|
||||
const { setOnFullscreen } = useFullScreen();
|
||||
const onFullscreenHandle = useFullScreenHandle();
|
||||
|
||||
useEffect(() => {
|
||||
setOnFullscreen(onFullscreenHandle);
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
{isMobile ? <MobileHeader /> : <DesktopHeader />}
|
||||
<FullScreen handle={onFullscreenHandle}>
|
||||
{modal}
|
||||
<Outlet />
|
||||
</FullScreen>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
@@ -9,15 +9,19 @@ const DisclaimerIcon = () => {
|
||||
>
|
||||
<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"
|
||||
stroke="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M8 4.66675V8.66675"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<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"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
const FilterIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M2.5 15.417H17.5"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<circle cx="12.0833" cy="15.4168" r="2.08333" fill="currentColor" />
|
||||
<path
|
||||
d="M2.5 4.5835H17.5"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<ellipse
|
||||
cx="14.5833"
|
||||
cy="4.58333"
|
||||
rx="2.08333"
|
||||
ry="2.08333"
|
||||
fill="currentColor"
|
||||
// fill="#0D1922"
|
||||
/>
|
||||
<path
|
||||
d="M2.5 10H17.5"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M7.50016 9.99984C7.50016 11.1504 6.56742 12.0832 5.41683 12.0832C4.26624 12.0832 3.3335 11.1504 3.3335 9.99984C3.3335 8.84924 4.26624 7.9165 5.41683 7.9165C6.56742 7.9165 7.50016 8.84924 7.50016 9.99984Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default FilterIcon;
|
||||
@@ -0,0 +1,33 @@
|
||||
const InfoIcon = () => {
|
||||
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="currentColor"
|
||||
stroke-width="1.5"
|
||||
/>
|
||||
<path
|
||||
d="M10 14.1665V9.1665"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<ellipse
|
||||
cx="0.833333"
|
||||
cy="0.833333"
|
||||
rx="0.833333"
|
||||
ry="0.833333"
|
||||
transform="matrix(1 0 0 -1 9.1665 6.6665)"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default InfoIcon;
|
||||
@@ -1,18 +1,18 @@
|
||||
const LeftArrowSliderIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6 12L18 12M6 12L12.3636 6M6 12L12.3636 18"
|
||||
d="M5 10L15 10M5 10L10.303 5M5 10L10.303 15"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { useState } from "react";
|
||||
import useFullScreen from "../../store/useFullScreen";
|
||||
import useModal from "../../store/useModal";
|
||||
import Button from "../Button";
|
||||
import HintIcon from "../icons/HintIcon";
|
||||
@@ -5,15 +7,32 @@ import ResizeIcon from "../icons/ResizeIcon";
|
||||
import HelpModal from "../modals/HelpModal";
|
||||
|
||||
const TopPanel = () => {
|
||||
const [isFullMode, setIsFullMode] = useState(false);
|
||||
const { setModal } = useModal();
|
||||
const { onFullscreen } = useFullScreen();
|
||||
|
||||
const handleOnHelpClick = () => {
|
||||
setModal(<HelpModal />);
|
||||
};
|
||||
|
||||
const handleOnFullScreenClick = () => {
|
||||
if (!onFullscreen) return;
|
||||
|
||||
setIsFullMode((prev) => !prev);
|
||||
if (!isFullMode) {
|
||||
onFullscreen.enter();
|
||||
} else {
|
||||
onFullscreen.exit();
|
||||
}
|
||||
};
|
||||
|
||||
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={<ResizeIcon />}
|
||||
onClick={handleOnFullScreenClick}
|
||||
/>
|
||||
<Button
|
||||
buttonType="fab"
|
||||
icon={<HintIcon />}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
const WingDescription = () => {
|
||||
return (
|
||||
<div className="bg-white rounded-lg absolute left-1/2 top-1/2 z-50 p-6 flex flex-col gap-4">
|
||||
<div className="relative">
|
||||
<div className="flex justify-between border-b pb-4">
|
||||
<p className="text-[#0D1922] font-semibold text-[20px]">East Wing</p>
|
||||
<div className="py-[3px] px-2 rounded-full bg-[#00BED7] text-white">
|
||||
234 units
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between gap-8">
|
||||
<div className="flex gap-2 items-center">
|
||||
<div className="w-6 h-6 rounded-full bg-[#00BED7] text-white text-xs font-semibold">
|
||||
<p className="h-full w-full flex justify-center items-center">
|
||||
21
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-s text-[#73787C]">Studio Flex</p>
|
||||
</div>
|
||||
<p className="text-s text-[#0D1922]">AED 1,048,888</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-8">
|
||||
<div className="flex gap-2 items-center">
|
||||
<div className="w-6 h-6 rounded-full bg-[#00BED7] text-white text-xs font-semibold">
|
||||
<p className="h-full w-full flex justify-center items-center">
|
||||
56
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-s text-[#73787C]">Studio</p>
|
||||
</div>
|
||||
<p className="text-s text-[#0D1922]">AED 1,138,888</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-8">
|
||||
<div className="flex gap-2 items-center">
|
||||
<div className="w-6 h-6 rounded-full bg-[#00BED7] text-white text-xs font-semibold">
|
||||
<p className="h-full w-full flex justify-center items-center">
|
||||
89
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-s text-[#73787C]">1 Bedroom</p>
|
||||
</div>
|
||||
<p className="text-s text-[#0D1922]">AED 1,668,888</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-8">
|
||||
<div className="flex gap-2 items-center">
|
||||
<div className="w-6 h-6 rounded-full bg-[#00BED7] text-white text-xs font-semibold">
|
||||
<p className="h-full w-full flex justify-center items-center">
|
||||
10
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-s text-[#73787C]">2 Bedroom, Type A</p>
|
||||
</div>
|
||||
<p className="text-s text-[#0D1922]">AED 2,408,888</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-0 h-0 border-t-0 border-r-[7px] border-b-[12px] border-l-[7px] border-transparent border-b-white rotate-90 absolute top-0 -right-[37px]"></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WingDescription;
|
||||
@@ -4,11 +4,13 @@ import { useEffect, useState } from "react";
|
||||
import { useTransformContext } from "react-zoom-pan-pinch";
|
||||
import { markers } from "../../../consts/markers";
|
||||
import useMarker from "../../../store/useMarker";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const Marker = (props: MarkerComponentProps) => {
|
||||
const { setHoveredMarker, hoveredMarker } = useMarker();
|
||||
const { transformState } = useTransformContext();
|
||||
const [markerScale, setMarkerScale] = useState(1);
|
||||
const navigate = useNavigate();
|
||||
const currentMarker = markers.find(
|
||||
(marker) => marker.itemNumber === props.itemNumber
|
||||
);
|
||||
@@ -27,6 +29,10 @@ const Marker = (props: MarkerComponentProps) => {
|
||||
setHoveredMarker(null);
|
||||
};
|
||||
|
||||
const handleOnClick = () => {
|
||||
navigate(`../masterplan/${currentMarker?.itemNumber}`);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const map = document.querySelector(".react-transform-wrapper");
|
||||
handleOnScroll();
|
||||
@@ -39,7 +45,7 @@ const Marker = (props: MarkerComponentProps) => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative transition-transform"
|
||||
className="relative transition-transform "
|
||||
style={{ transform: `scale(${markerScale})` }}
|
||||
>
|
||||
<div
|
||||
@@ -62,7 +68,8 @@ const Marker = (props: MarkerComponentProps) => {
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`flex gap-1 transition-all duration-300 ease-in-out ${
|
||||
onClick={handleOnClick}
|
||||
className={`flex gap-1 transition-all duration-300 ease-in-out cursor-pointer ${
|
||||
hoveredMarker &&
|
||||
hoveredMarker.itemNumber !== currentMarker?.itemNumber
|
||||
? "brightness-[.7]"
|
||||
|
||||
@@ -2,8 +2,9 @@ import useModal from "../../store/useModal";
|
||||
import Button from "../Button";
|
||||
import CrossIcon from "../icons/CrossIcon";
|
||||
import ResetIcon from "../icons/ResetIcon";
|
||||
import Checkbox from "../masterplanPage/Checkbox";
|
||||
import Switch from "../masterplanPage/Switch";
|
||||
import Checkbox from "../Checkbox";
|
||||
import Switch from "../Switch";
|
||||
import MultiRangeSlider from "../MultiRangeSlider";
|
||||
|
||||
interface ICheckbox {
|
||||
title: string;
|
||||
@@ -24,8 +25,8 @@ const MasterplanFilters = () => {
|
||||
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="h-full col-span-3 bg-[#F3F3F2] flex flex-col items-center justify-between">
|
||||
<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="h-full col-span-3 bg-[#F3F3F2] flex flex-col items-center justify-between ">
|
||||
<div className="w-full py-6 px-6 flex flex-col items-center">
|
||||
<div className="flex justify-between border-b border-[#E2E2DC] w-full pb-4">
|
||||
<h2 className="text-subheadline-m font-semibold">Filters</h2>
|
||||
@@ -49,36 +50,41 @@ const MasterplanFilters = () => {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col pt-6 w-full">
|
||||
<div className="flex justify-between items-center pb-2">
|
||||
<p className="text-[#0D1922] text-m font-semibold ">Cost</p>
|
||||
<p className="text-[#73787C] text-m font-semibold">AED</p>
|
||||
<div className="flex flex-col pt-6 w-full gap-8">
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="text-[#0D1922] text-m font-semibold ">Cost</p>
|
||||
<p className="text-[#73787C] text-m font-semibold">AED</p>
|
||||
</div>
|
||||
<MultiRangeSlider min={1048888} max={2408888} />
|
||||
</div>
|
||||
<div className="flex justify-between w-full">
|
||||
<p className="text-s text-[#73787C]">Not the first floor</p>
|
||||
<Switch />
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="text-[#0D1922] text-m font-semibold ">
|
||||
Total Area
|
||||
</p>
|
||||
<p className="text-[#73787C] text-m font-semibold">Sqft</p>
|
||||
</div>
|
||||
<MultiRangeSlider min={341} max={891} />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="text-[#0D1922] text-m font-semibold ">Floor</p>
|
||||
<p className="text-[#73787C] text-m font-semibold"></p>
|
||||
</div>
|
||||
<MultiRangeSlider min={5} max={81} />
|
||||
</div>
|
||||
|
||||
{/* <div className="flex justify-between p-3 bg-white rounded-2xl relative">
|
||||
<input type="text" />
|
||||
<input type="text" />
|
||||
<input
|
||||
min="500"
|
||||
max="50000"
|
||||
step="500"
|
||||
type="range"
|
||||
className="absolute -bottom-2 left-3 right-3"
|
||||
style={{ backgroundColor: "#ced4da" }}
|
||||
/>
|
||||
<input
|
||||
min="500"
|
||||
max="50000"
|
||||
step="500"
|
||||
type="range"
|
||||
className="absolute left-3 -bottom-2 right-3"
|
||||
style={{ backgroundColor: "#ced4da" }}
|
||||
/>
|
||||
</div> */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex justify-between w-full">
|
||||
<p className="text-s text-[#73787C]">Not the first floor</p>
|
||||
<Switch />
|
||||
</div>
|
||||
<div className="flex justify-between w-full">
|
||||
<p className="text-s text-[#73787C]">Not the top floor</p>
|
||||
<Switch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ const ZoomHint = () => {
|
||||
|
||||
return (
|
||||
<div
|
||||
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 ${
|
||||
className={`absolute z-10 m-auto top-[calc(50%-60px)] left-[calc(50%-140px)] 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}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
.range-slider {
|
||||
touch-action: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
/* background: #ddd; */
|
||||
border-radius: 4px;
|
||||
}
|
||||
.range-slider[data-vertical] {
|
||||
height: 100%;
|
||||
width: 8px;
|
||||
}
|
||||
.range-slider[data-disabled] {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.range-slider .range-slider__thumb {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
top: 50%;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: 50%;
|
||||
background: #00bed7;
|
||||
}
|
||||
.range-slider .range-slider__thumb:focus-visible {
|
||||
outline: 0;
|
||||
}
|
||||
.range-slider[data-vertical] .range-slider__thumb {
|
||||
left: 50%;
|
||||
}
|
||||
.range-slider .range-slider__thumb[data-disabled] {
|
||||
z-index: 2;
|
||||
}
|
||||
.range-slider .range-slider__range {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
transform: translate(0, -50%);
|
||||
top: 50%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #00bed7;
|
||||
}
|
||||
.range-slider[data-vertical] .range-slider__range {
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
.range-slider input[type="range"] {
|
||||
-webkit-appearance: none;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
.range-slider input[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
.range-slider input[type="range"]::-moz-range-thumb {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 0;
|
||||
}
|
||||
.range-slider input[type="range"]:focus {
|
||||
outline: 0;
|
||||
}
|
||||
@@ -26,7 +26,7 @@ const borders: ButtonStyle = {
|
||||
|
||||
const paddings: ButtonStyle = {
|
||||
cta: "py-3 px-6",
|
||||
primary: "py-3 px-6",
|
||||
primary: "py-[10px] pr-6 pl-4",
|
||||
secondary: "py-3 px-6",
|
||||
tertiary: "py-1 px-3",
|
||||
fab: "py-3 px-6",
|
||||
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
declare module "react-range-slider-input";
|
||||
+99
-1
@@ -72,7 +72,105 @@ body {
|
||||
}
|
||||
|
||||
.left-slider-btn-offset {
|
||||
/* left: clamp(230px, 3.8007rem + 13.2075vw, 401px); */
|
||||
left: clamp(230px, 0.5927rem + 17.2144vw, 370px);
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.slider__track,
|
||||
.slider__range {
|
||||
border-radius: 3px;
|
||||
height: 5px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.slider__track {
|
||||
background-color: #000;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.slider__range {
|
||||
background-color: #9fe5e1;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Removing the default appearance */
|
||||
.thumb,
|
||||
.thumb::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.thumb {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
height: 0;
|
||||
width: 200px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.thumb--zindex-3 {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.thumb--zindex-4 {
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
/* For Chrome browsers */
|
||||
.thumb::-webkit-slider-thumb {
|
||||
background-color: #f1f5f7;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 1px 1px #ced4da;
|
||||
cursor: pointer;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
margin-top: 4px;
|
||||
pointer-events: all;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* For Firefox browsers */
|
||||
.thumb::-moz-range-thumb {
|
||||
background-color: #f1f5f7;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 1px 1px #ced4da;
|
||||
cursor: pointer;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
margin-top: 4px;
|
||||
pointer-events: all;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.slider__left-value,
|
||||
.slider__right-value {
|
||||
color: #dee2e6;
|
||||
font-size: 12px;
|
||||
margin-top: 20px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.slider__left-value {
|
||||
left: 6px;
|
||||
}
|
||||
|
||||
.slider__right-value {
|
||||
right: -4px;
|
||||
}
|
||||
|
||||
input[type="number"].input_number {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
input.input_number::-webkit-outer-spin-button,
|
||||
input.input_number::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -1,14 +1,15 @@
|
||||
import ReactDOM from "react-dom/client";
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
import Header from "./components/header/Header/Header";
|
||||
import Layout from "./components/header/Header/Layout";
|
||||
import Masterplan from "./pages/Masterplan";
|
||||
import Company from "./pages/Company";
|
||||
import "./index.css";
|
||||
import Complex from "./pages/Complex";
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: "/",
|
||||
element: <Header />,
|
||||
element: <Layout />,
|
||||
children: [
|
||||
{
|
||||
path: "/",
|
||||
@@ -18,6 +19,10 @@ const router = createBrowserRouter([
|
||||
path: "/masterplan",
|
||||
element: <Masterplan />,
|
||||
},
|
||||
{
|
||||
path: "/masterplan/:complexId",
|
||||
element: <Complex />,
|
||||
},
|
||||
{
|
||||
path: "/company",
|
||||
element: <Company />,
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import ButtomPanel from "../components/ButtomPanel";
|
||||
import ComplexTopPanel from "../components/complexPage/ComplexTopPanel";
|
||||
|
||||
const Complex = () => {
|
||||
return (
|
||||
<div className="overflow-hidden h-screen w-screen">
|
||||
<ComplexTopPanel />
|
||||
<div className="bg-black h-full w-full"></div>
|
||||
<ButtomPanel />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Complex;
|
||||
@@ -2,16 +2,14 @@ import { useEffect } from "react";
|
||||
import useModal from "../store/useModal";
|
||||
import Map from "../components/masterplanPage/map/Map";
|
||||
import TopPanel from "../components/masterplanPage/TopPanel";
|
||||
import ButtomPanel from "../components/masterplanPage/map/ButtomPanel";
|
||||
import MasterplanFilters from "../components/modals/MasterplanFilters";
|
||||
import ButtomPanel from "../components/ButtomPanel";
|
||||
import ZoomHint from "../components/modals/ZoomHintModal";
|
||||
|
||||
const Masterplan = () => {
|
||||
const { setModal } = useModal();
|
||||
useEffect(() => {
|
||||
setModal(<MasterplanFilters />);
|
||||
// setModal(<ZoomHint />);
|
||||
setModal(<ZoomHint />);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="overflow-hidden h-screen w-screen">
|
||||
<TopPanel />
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { create } from "zustand";
|
||||
import { FullScreenHandle } from "react-full-screen";
|
||||
|
||||
interface ModalStore {
|
||||
onFullscreen: FullScreenHandle | null;
|
||||
setOnFullscreen: (onFullscreen: FullScreenHandle) => void;
|
||||
}
|
||||
|
||||
const useFullScreen = create<ModalStore>((set) => ({
|
||||
onFullscreen: null,
|
||||
setOnFullscreen: (onFullscreen) =>
|
||||
set(() => ({ onFullscreen: onFullscreen })),
|
||||
}));
|
||||
|
||||
export default useFullScreen;
|
||||
@@ -888,6 +888,11 @@ chokidar@^3.5.3:
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
clsx@^1.1.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
|
||||
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
|
||||
|
||||
color-convert@^1.9.0:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
|
||||
@@ -927,6 +932,11 @@ convert-source-map@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz"
|
||||
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
|
||||
|
||||
core-js@^3.22.4:
|
||||
version "3.37.0"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.37.0.tgz#d8dde58e91d156b2547c19d8a4efd5c7f6c426bb"
|
||||
integrity sha512-fu5vHevQ8ZG4og+LXug8ulUtVxjOcEYvifJr7L5Bfq9GOztVqsKd9/59hUk2ZSbCrS3BqUr3EpaYGIYzq7g3Ug==
|
||||
|
||||
cross-spawn@^7.0.0, cross-spawn@^7.0.2:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
|
||||
@@ -1233,6 +1243,11 @@ fs.realpath@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||
|
||||
fscreen@^1.0.2:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/fscreen/-/fscreen-1.2.0.tgz#1a8c88e06bc16a07b473ad96196fb06d6657f59e"
|
||||
integrity sha512-hlq4+BU0hlPmwsFjwGGzZ+OZ9N/wq9Ljg/sq3pX+2CD7hrJsX9tJgWWK/wiNTFM212CLHWhicOoqwXyZGGetJg==
|
||||
|
||||
fsevents@~2.3.2, fsevents@~2.3.3:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
|
||||
@@ -1784,11 +1799,26 @@ react-dom@^18.2.0:
|
||||
loose-envify "^1.1.0"
|
||||
scheduler "^0.23.0"
|
||||
|
||||
react-full-screen@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-full-screen/-/react-full-screen-1.1.1.tgz#b707d56891015a71c503a65dbab3086d75be97d7"
|
||||
integrity sha512-xoEgkoTiN0dw9cjYYGViiMCBYbkS97BYb4bHPhQVWXj1UnOs8PZ1rPzpX+2HMhuvQV1jA5AF9GaRbO3fA5aZtg==
|
||||
dependencies:
|
||||
fscreen "^1.0.2"
|
||||
|
||||
react-image-marker@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-image-marker/-/react-image-marker-1.2.0.tgz#2f964a826aaa8c6b18c4ce7cedb0284f8eab8b6c"
|
||||
integrity sha512-HFrzKVnX/hgZqHlxwV7XQNiyMRowD1IAnbsf4dZCEuSzGlGHxAv+sCv/AU1VHHVxFxoHubNL/xYNpGQfgtX67A==
|
||||
|
||||
react-range-slider-input@^3.0.7:
|
||||
version "3.0.7"
|
||||
resolved "https://registry.yarnpkg.com/react-range-slider-input/-/react-range-slider-input-3.0.7.tgz#88ceb118b33d7eb0550cec1f77fc3e60e0f880f9"
|
||||
integrity sha512-yAJDDMUNkILOcZSCLCVbwgnoAM3v0AfdDysTCMXDwY/+ZRNRlv98TyHbVCwPFEd7qiI8Ca/stKb0GAy//NybYw==
|
||||
dependencies:
|
||||
clsx "^1.1.1"
|
||||
core-js "^3.22.4"
|
||||
|
||||
react-refresh@^0.14.0:
|
||||
version "0.14.0"
|
||||
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz"
|
||||
|
||||
Reference in New Issue
Block a user