navbar, desktop, responsive element, fixes

This commit is contained in:
2025-04-21 20:15:13 +05:00
parent 0ef6009b57
commit 7905481033
25 changed files with 492 additions and 70 deletions
+96
View File
@@ -0,0 +1,96 @@
import clsx from "clsx";
import { Link, useLocation } from "react-router";
import YoutubeIcon from "./icons/YoutubeIcon";
import InstagramIcon from "./icons/InstagramIcon";
import FacebookIcon from "./icons/FacebookIcon";
import LinkedInIcon from "./icons/LinkedInIcon";
import TwitterIcon from "./icons/TwitterIcon";
function Footer() {
const { pathname } = useLocation();
return (
<div
className={clsx(
"lg:px-[2.222vw] lg:pb-[2.222vw] lg:pt-[2.778vw] md:max-lg:p-6 px-4 py-6 flex lg:gap-[1.667vw] gap-6 lg:rounded-[1.667vw] rounded-3xl border border-[#E2E2DC] max-lg:hidden",
(pathname === "/" || pathname.startsWith("/complex")) && "hidden"
)}
>
<div className="space-y-14 flex-1">
<img src="/images/logo.svg" className="lg:w-[5.972vw]" alt="" />
<div className="flex lg:gap-[2.778vw] gap-10">
<p className="lg:max-w-[17.083vw] text-s text-[#0D1922]/40">
For more information, visit our website: 
<Link
className="text-[#00BED7] underline"
to={"https://www.irth.ae"}
>
www.irth.ae
</Link>
</p>
<div className="lg:space-y-[0.833vw] space-y-3">
<p className="text-s text-[#0D1922]/40">Follow us for more:</p>
<div className="flex lg:gap-[0.278vw] gap-1">
<div className="lg:p-[0.417vw] p-1.5 bg-[#E2E2DC] lg:rounded-[0.278vw] rounded">
<div className="lg:w-[1.389vw] lg:h-[1.389vw] w-5 h-5 text-[#0D1922]/70">
<YoutubeIcon />
</div>
</div>
<div className="lg:p-[0.417vw] p-1.5 bg-[#E2E2DC] lg:rounded-[0.278vw] rounded">
<div className="lg:w-[1.389vw] lg:h-[1.389vw] w-5 h-5 text-[#0D1922]/70">
<InstagramIcon />
</div>
</div>
<div className="lg:p-[0.417vw] p-1.5 bg-[#E2E2DC] lg:rounded-[0.278vw] rounded">
<div className="lg:w-[1.389vw] lg:h-[1.389vw] w-5 h-5 text-[#0D1922]/70">
<FacebookIcon />
</div>
</div>
<div className="lg:p-[0.417vw] p-1.5 bg-[#E2E2DC] lg:rounded-[0.278vw] rounded">
<div className="lg:w-[1.389vw] lg:h-[1.389vw] w-5 h-5 text-[#0D1922]/70">
<LinkedInIcon />
</div>
</div>
<div className="lg:p-[0.417vw] p-1.5 bg-[#E2E2DC] lg:rounded-[0.278vw] rounded">
<div className="lg:w-[1.389vw] lg:h-[1.389vw] w-5 h-5 text-[#0D1922]/70">
<TwitterIcon />
</div>
</div>
</div>
</div>
</div>
</div>
<div className="grid grid-cols-3 lg:gap-[1.667vw] gap-6 flex-1">
<div className="lg:border-l-[0.069vw] border-l border-[#E2E2DC] lg:pl-[1.111vw] pl-4 flex flex-col">
<Link to={"/"} className="text-m flex-1 content-center">
Map
</Link>
<Link to={"/unit-types"} className="text-m flex-1 content-center">
Unit Types
</Link>
<Link to={"/about-irth"} className="text-m flex-1 content-center">
About IRTH
</Link>
</div>
<div className="lg:border-l-[0.069vw] border-l border-[#E2E2DC] lg:pl-[1.111vw] pl-4 flex flex-col">
<Link to={"/favorites"} className="text-m flex-1 content-center">
Favorites
</Link>
<Link to={"/search"} className="text-m flex-1 content-center">
Search
</Link>
<Link to={"/"} className="text-m flex-1 content-center">
Brochures
</Link>
</div>
<div className="content-end text-right">
<Link to={"/"} className="text-m">
Privacy Policy
</Link>
</div>
</div>
</div>
);
}
export default Footer;
+1 -1
View File
@@ -34,7 +34,7 @@ function FullScreenButton({
onlyIcon
size="small"
variant="secondary"
className="absolute lg:top-[1.667vw] lg:right-[1.667vw] top-4 right-4 z-10"
className="absolute lg:top-[1.667vw] lg:right-[1.667vw] top-4 right-4"
onClick={handleClick}
>
<span className="lg:w-[1.389vw] lg:h-[1.389vw] w-5 h-5">
+65 -5
View File
@@ -1,4 +1,8 @@
import { NavLink } from "react-router";
import LocationIcon from "./icons/LocationIcon";
import clsx from "clsx";
import ArrowDownIcon from "./icons/ArrowDownIcon";
import { useState } from "react";
function Header() {
function handleLogoClick() {
@@ -6,10 +10,10 @@ function Header() {
}
return (
<div className="sticky top-0 left-0 w-full h-[3.889vw] max-lg:h-14 max-md:h-16 flex items-center justify-between bg-white">
<div className="flex lg:gap-[1.111vw] gap-4">
<div className="sticky top-0 left-0 w-full h-[3.889vw] max-lg:h-14 max-md:h-16 flex items-center justify-center bg-white">
<div className="flex lg:gap-[1.111vw] gap-4 flex-1">
<div
className="lg:px-[1.667vw] lg:py-[1.111vw] md:max-lg:p-4 max-md:px-4 max-md:py-5 self-stretch lg:border-r-[0.07vw] border-r border-[#E2E2DC] cursor-pointer"
className="lg:px-[1.667vw] lg:py-[1.111vw] md:max-lg:p-4 max-md:px-4 max-md:py-5 cursor-pointer"
onClick={handleLogoClick}
>
<img
@@ -25,10 +29,66 @@ function Header() {
<p className="text-s text-[#0D1922]/40">Dubai</p>
</div>
</div>
<div className=""></div>
<div className=""></div>
<NavBar />
<div className="flex-1"></div>
</div>
);
}
export default Header;
function NavBar() {
return (
<>
<nav className="flex lg:gap-[0.556vw] gap-2 items-center max-lg:hidden">
<NavItem href={"/"} title={"Map"} />
<NavItem href={"/unit-types"} title={"Unit Types"} />
<NavItem href={"/about"} title={"About IRTH"} />
<NavItem href={"/favourites"} title={"Favourites"} />
<BrochuresDropdown />
<NavItem href={"/search"} title={"Search"} />
</nav>
</>
);
}
function NavItem({ href, title }: { href: string; title: string }) {
return (
<NavLink
to={href}
className={({ isActive }) =>
clsx(
"text-m lg:px-[1.25vw] lg:py-[0.903vw] px-4.5 py-[13px] lg:rounded-[0.833vw] rounded-xl transition-colors duration-300",
isActive && "bg-[#00BED7] text-[#FFFFFF]"
)
}
>
{title}
</NavLink>
);
}
function BrochuresDropdown() {
const [opened, setOpened] = useState(false);
return (
<div>
<button
className="lg:px-[0.972vw] lg:py-[0.694vw] px-3.5 py-2.5 flex items-center"
onClick={() => setOpened((prev) => !prev)}
>
<p className="lg:px-[0.278vw] lg:py-[0.208vw] px-1 py-[3px]">
<span className="text-m">Brochures</span>
</p>
<span
className={clsx(
"text-[#0D1922] lg:w-[1.389vw] lg:h-[1.389vw] w-5 h-5 transition-transform duration-300",
opened && "rotate-180"
)}
>
<ArrowDownIcon />
</span>
</button>
</div>
);
}
+42 -27
View File
@@ -17,6 +17,7 @@ import { isMobile } from "react-device-detect";
import SelectedComplexCard from "./SelectedComplexCard";
import FullScreenButton from "./FullScreenButton";
import useWindowSize from "../hooks/useWindowSize";
import TouchIcon from "./icons/TouchIcon";
interface Position {
x: number;
@@ -589,7 +590,6 @@ function Map({ maxZoom = 1 }: MapProps) {
onLoad={handleLoad}
/>
)}
<div
className={clsx(
"pointer-events-none absolute max-w-none transition-opacity duration-300 bg-black",
@@ -597,17 +597,16 @@ function Map({ maxZoom = 1 }: MapProps) {
)}
style={imageStyle}
/>
<div
style={cloudStyle}
ref={cloudsRef}
className={clsx(
`absolute w-full h-full pointer-events-none transition-opacity duration-300 will-change-[opacity,scale,translate,transform]`,
`absolute w-full h-full pointer-events-none transition-[opacity] duration-300 will-change-[opacity,scale,translate,transform]`,
hoveredMarker && "opacity-80"
)}
>
<div
className="h-full flex"
className="h-full flex transition-transformduration-300"
style={{
rotate: `${90 + windDirection}deg`,
transform: `translateX(${Math.round(
@@ -628,7 +627,6 @@ function Map({ maxZoom = 1 }: MapProps) {
/>
</div>
</div>
<div ref={markersContainerRef} className="absolute" style={imageStyle}>
<div className="relative h-full">
{markers.map((marker) => (
@@ -644,44 +642,61 @@ function Map({ maxZoom = 1 }: MapProps) {
))}
</div>
</div>
<WeatherWidget temperature={temperature} />
<AnimatePresence>
{isShowInstruction && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="absolute inset-0 flex items-center justify-center pointer-events-none"
>
<div className="w-fit bg-[#0D1922]/40 rounded-lg backdrop-blur-sm space-y-3 p-4 text-white">
<div className="flex items-center justify-center gap-4">
<SearchIcon />
<div className="w-px h-4 bg-white"></div>
<MoveIcon />
{isShowInstruction &&
(isMobile ? (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="absolute inset-0 flex items-center justify-center pointer-events-none"
>
<div className="w-fit bg-[#0D1922]/40 lg:rounded-[0.556vw] rounded-lg backdrop-blur-sm lg:space-y-[0.833vw] space-y-3 lg:p-[1.111vw] p-4 text-white">
<div className="flex items-center justify-center gap-4">
<span className="lg:w-[3.333vw] lg:h-[3.333vw] w-12 h-12">
<MoveIcon />
</span>
<div className="w-px lg:h-[1.111vw] h-4 bg-white" />
<span className="lg:w-[3.333vw] lg:h-[3.333vw] w-12 h-12">
<TouchIcon />
</span>
</div>
<p className="text-sm text-center">Tap to move</p>
</div>
<div className="">
</motion.div>
) : (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="absolute inset-0 flex items-center justify-center pointer-events-none"
>
<div className="w-fit bg-[#0D1922]/40 lg:rounded-[0.556vw] rounded-lg backdrop-blur-sm lg:space-y-[0.833vw] space-y-3 lg:p-[1.111vw] p-4 text-white">
<div className="flex items-center justify-center gap-4">
<span className="lg:w-[3.333vw] lg:h-[3.333vw] w-12 h-12">
<SearchIcon />
</span>
<div className="w-px lg:h-[1.111vw] h-4 bg-white" />
<span className="lg:w-[3.333vw] lg:h-[3.333vw] w-12 h-12">
<MoveIcon />
</span>
</div>
<p className="text-sm">Zoom and Move to select a location</p>
</div>
</div>
</motion.div>
)}
</motion.div>
))}
</AnimatePresence>
<FullScreenButton
isFullScreen={isFullScreen}
onFullScreenChange={setIsFullScreen}
onClick={handleFullScreenClick}
/>
<div className="absolute lg:right-[1.667vw] lg:bottom-[1.667vw] right-4 bottom-4 flex lg:gap-[0.556vw] gap-2">
<DisclaimerButton />
<PrivacyPolicyButton />
</div>
<Compass />
<AnimatePresence>
{isMobile && hoveredMarker && (
<SelectedComplexCard marker={hoveredMarker} />
+1 -8
View File
@@ -29,13 +29,6 @@ function ModalContainer() {
const rootRef = useRef<HTMLDivElement>(null);
// useEffect(() => {
// if (!rootRef.current || !modal) return;
// if (document.fullscreenElement) {
// rootRef.current?.requestFullscreen();
// }
// }, [modal]);
useEffect(() => {
window.addEventListener("resize", handleResize);
window.addEventListener("keydown", handleKeydown);
@@ -77,7 +70,7 @@ function ModalContainer() {
{modal}
<Button
onlyIcon
variant="tertiary"
variant="secondary"
className="absolute top-[1.111vw] right-[1.111vw]"
onClick={() => setModal(null)}
>
+11 -2
View File
@@ -1,10 +1,19 @@
import useModalStore from "../stores/useModalStore";
import QuestionIcon from "./icons/QuestionIcon";
import PrivacyPolicyModal from "./modals/PrivacyPolicyModal";
import Button from "./ui/Button";
export default function PrivacyPolicyButton() {
const { setModal } = useModalStore();
return (
<Button size="small" variant="secondary" onlyIcon>
<span className="lg:w-[1.389vw] lg:h-[1.389vw] w-5 h-5">
<Button
size="small"
variant="secondary"
onlyIcon
onClick={() => setModal(<PrivacyPolicyModal />)}
>
<span className="lg:w-[1.389vw] lg:h-[1.389vw] w-5 h-5 text-[#0D1922]">
<QuestionIcon />
</span>
</Button>
-1
View File
@@ -59,7 +59,6 @@ export default function SelectedComplexCard({ marker }: { marker: IMarker }) {
variant="tertiary"
size="small"
className="w-fit"
// onClick={() => navigate(`/complex/${marker.name}`)}
onTouchStart={() => navigate(`/complex/${marker.name}`)}
>
Explore
+10 -9
View File
@@ -12,6 +12,7 @@ import InfoIcon from "./icons/InfoIcon";
import FullScreenButton from "./FullScreenButton";
import BottomButton from "./DisclaimerButton";
import PrivacyPolicyButton from "./PrivacyPolicyButton";
import DisclaimerButton from "./DisclaimerButton";
interface SequenceSliderProps {
complexName: string;
@@ -198,7 +199,7 @@ function SequenceSlider({ complexName }: SequenceSliderProps) {
<Button
onlyIcon
variant="secondary"
className="absolute top-1/2 -translate-y-1/2 z-100 lg:left-[1.111vw] left-4"
className="absolute top-1/2 -translate-y-1/2 lg:left-[1.111vw] left-4"
roundedFull
disabled={isAnimating || !isShowVideo}
onClick={() => handleSwipe("prev")}
@@ -210,7 +211,7 @@ function SequenceSlider({ complexName }: SequenceSliderProps) {
<Button
onlyIcon
variant="secondary"
className="absolute top-1/2 -translate-y-1/2 z-100 lg:right-[1.111vw] right-4"
className="absolute top-1/2 -translate-y-1/2 lg:right-[1.111vw] right-4"
roundedFull
disabled={isAnimating || !isShowVideo}
onClick={() => handleSwipe("next")}
@@ -219,15 +220,15 @@ function SequenceSlider({ complexName }: SequenceSliderProps) {
<ArrowRightIcon />
</span>
</Button>
<div className="max-md:hidden">
<Compass imgStyle={{ transform: `rotate(${currentIndex}deg)` }} />
<div className="absolute right-[28px] bottom-[32px] flex gap-2">
<DisclaimerButton />
<PrivacyPolicyButton />
</div>
</div>
</>
)}
<div className="max-md:hidden">
<Compass imgStyle={{ transform: `rotate(${currentIndex}deg)` }} />
<div className="absolute right-[28px] bottom-[32px] flex gap-2">
<BottomButton />
<PrivacyPolicyButton />
</div>
</div>
</div>
);
}
+1 -1
View File
@@ -18,7 +18,7 @@ export default function WeatherWidget({
const formattedTime = `${hours}:${minutes}`;
return (
<div className="absolute left-[1.667vw] top-[1.667vw] z-10 rounded-2xl space-y-4 min-w-50 w-[8.333vw] p-4 font-medium text-white bg-black/40 pointer-events-none max-[1440px]:hidden backdrop-blur-2xl">
<div className="absolute left-[1.667vw] top-[1.667vw] rounded-2xl space-y-4 min-w-50 w-[8.333vw] p-4 font-medium text-white bg-black/40 pointer-events-none max-[1440px]:hidden backdrop-blur-2xl">
<div>
<div className="flex justify-between">
<p>{day}</p>
+14
View File
@@ -0,0 +1,14 @@
function ArrowDownIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M11.47 16.53a.75.75 0 0 0 1.06 0l7-7a.75.75 0 1 0-1.06-1.06L12 14.94 5.53 8.47a.75.75 0 0 0-1.06 1.06z"
fill="currentColor"
/>
</svg>
);
}
export default ArrowDownIcon;
+12
View File
@@ -0,0 +1,12 @@
function FacebookIcon() {
return (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M11.834 2.396A3.854 3.854 0 0 0 7.979 6.25v2.146H5.917a.19.19 0 0 0-.188.187v2.834c0 .103.084.187.188.187h2.062v5.813c0 .103.084.187.188.187H11a.19.19 0 0 0 .188-.187v-5.813h2.08a.19.19 0 0 0 .182-.142l.709-2.833a.187.187 0 0 0-.182-.233h-2.79V6.25a.646.646 0 0 1 .647-.646H14a.187.187 0 0 0 .188-.187V2.583A.187.187 0 0 0 14 2.396z"
fill="currentColor"
/>
</svg>
);
}
export default FacebookIcon;
+12
View File
@@ -0,0 +1,12 @@
function InstagramIcon() {
return (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M13.75 1.875h-7.5A4.38 4.38 0 0 0 1.875 6.25v7.5a4.38 4.38 0 0 0 4.375 4.375h7.5a4.38 4.38 0 0 0 4.375-4.375v-7.5a4.38 4.38 0 0 0-4.375-4.375M10 13.75a3.75 3.75 0 1 1 0-7.5 3.75 3.75 0 0 1 0 7.5m4.688-7.5a.937.937 0 1 1 0-1.874.937.937 0 0 1 0 1.874M12.5 10a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0"
fill="currentColor"
/>
</svg>
);
}
export default InstagramIcon;
+12
View File
@@ -0,0 +1,12 @@
function LinkedInIcon() {
return (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M3.958 1.563a1.77 1.77 0 1 0 0 3.541 1.77 1.77 0 0 0 0-3.541m-1.666 5a.104.104 0 0 0-.104.104V17.5c0 .058.046.104.104.104h3.333a.104.104 0 0 0 .104-.104V6.667a.104.104 0 0 0-.104-.104zm5.416 0a.104.104 0 0 0-.104.104V17.5c0 .058.047.104.104.104h3.334a.104.104 0 0 0 .104-.104v-5.833a1.563 1.563 0 0 1 3.125 0V17.5c0 .058.046.104.104.104h3.333a.104.104 0 0 0 .105-.104v-7.183c0-2.022-1.76-3.604-3.771-3.422a6 6 0 0 0-1.807.457l-1.09.466V6.667a.104.104 0 0 0-.103-.104z"
fill="currentColor"
/>
</svg>
);
}
export default LinkedInIcon;
+20
View File
@@ -0,0 +1,20 @@
function TouchIcon() {
return (
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M19.83 12.87c.77-.757 1.87-1.37 3.157-1.37 1.189 0 2.334.464 3.182 1.298a4.44 4.44 0 0 1 1.33 3.165v5.269a4.56 4.56 0 0 1 4.67 1.049c.297.291.549.62.75.975a4.55 4.55 0 0 1 5.25.802 4.44 4.44 0 0 1 1.331 3.164v5.926c0 1.757-.352 3.496-1.035 5.118a13.3 13.3 0 0 1-2.943 4.332 13.6 13.6 0 0 1-4.395 2.889A13.7 13.7 0 0 1 25.95 46.5c-3.665 0-6.472-1.007-8.982-3.482-2.39-2.358-4.453-5.998-6.89-11.052a4.43 4.43 0 0 1-.423-3.344c.155-.57.422-1.102.784-1.567a4.5 4.5 0 0 1 1.326-1.144 4.55 4.55 0 0 1 3.411-.442 4.5 4.5 0 0 1 2.739 2.071l.002.004.583.983V16.035c0-1.192.482-2.33 1.33-3.165M33.5 27.221v1.08h-3v-2.856c0-.38-.153-.75-.434-1.025a1.54 1.54 0 0 0-1.078-.438c-.41 0-.797.16-1.079.438a1.4 1.4 0 0 0-.409 1.025v1.77h-3V15.963c0-.38-.154-.75-.435-1.026a1.54 1.54 0 0 0-1.078-.437c-.31 0-.692.154-1.053.509a1.44 1.44 0 0 0-.434 1.026V34l-2.79.765-3.382-5.705a1.5 1.5 0 0 0-.385-.432 1.56 1.56 0 0 0-1.697-.109 1.5 1.5 0 0 0-.441.381 1.42 1.42 0 0 0-.107 1.604l.058.11c2.457 5.099 4.334 8.31 6.319 10.268 1.873 1.847 3.886 2.618 6.875 2.618 1.39 0 2.764-.27 4.046-.791a10.6 10.6 0 0 0 3.423-2.25 10.3 10.3 0 0 0 2.281-3.358c.528-1.254.8-2.597.8-3.953v-5.926c0-.38-.153-.75-.434-1.026a1.54 1.54 0 0 0-1.078-.437c-.41 0-.797.16-1.079.438-.258.254-.41.612-.41 1.024"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M26.699 6.173A10.5 10.5 0 0 0 13.907 21.25l-2.598 1.5a13.5 13.5 0 1 1 24.731-3.256l-2.898-.776A10.5 10.5 0 0 0 26.7 6.173"
fill="currentColor"
/>
</svg>
);
}
export default TouchIcon;
+16
View File
@@ -0,0 +1,16 @@
function TwitterIcon() {
return (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="m16.82 16.683-5.498-7.988-.621-.904-3.934-5.714-.326-.473H1.608l1.18 1.713 5.229 7.598.621.903 4.202 6.105.326.473H18zm-3.08.62L9.376 10.96l-.621-.903-5.066-7.36h2.18L9.963 8.65l.621.903 5.335 7.75z"
fill="currentColor"
/>
<path
d="m8.754 10.057.622.903-.737.857-5.655 6.579H1.59l6.427-7.481zm8.664-8.453-6.095 7.09-.738.858-.621-.903.737-.858 4.129-4.805 1.193-1.382z"
fill="currentColor"
/>
</svg>
);
}
export default TwitterIcon;
+14
View File
@@ -0,0 +1,14 @@
function YoutubeIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M19.814 5.423a2.52 2.52 0 0 1 1.768 1.79C22 8.79 22 12.082 22 12.082s0 3.293-.418 4.871a2.52 2.52 0 0 1-1.768 1.79c-1.56.423-7.814.423-7.814.423s-6.254 0-7.814-.423a2.52 2.52 0 0 1-1.768-1.79C2 15.377 2 12.084 2 12.084s0-3.294.418-4.872a2.52 2.52 0 0 1 1.768-1.79C5.746 5 12 5 12 5s6.254 0 7.814.423m-9.48 3.744V15l5-2.917z"
fill="currentColor"
/>
</svg>
);
}
export default YoutubeIcon;
+4 -8
View File
@@ -1,15 +1,11 @@
function MoveIcon() {
return (
<svg
width={49}
height={48}
viewBox="0 0 49 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<svg viewBox="0 0 49 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="m11.9 29-5.4-5m0 0 5.4-5m-5.4 5h11.7m12.6 0h11.7m0 0-5.4 5m5.4-5-5.4-5m-7.6 17.6-5 5.4m0 0-5-5.4m5 5.4V30.3m0-12.6V6m0 0 5 5.4m-5-5.4-5 5.4"
stroke="#fff"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={3}
/>
</svg>
+2 -8
View File
@@ -1,18 +1,12 @@
function SearchIcon() {
return (
<svg
width={49}
height={48}
viewBox="0 0 49 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<svg viewBox="0 0 49 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="m41.5 41-7.686-7.686m0 0A15.95 15.95 0 0 0 38.5 22c0-8.837-7.163-16-16-16s-16 7.163-16 16 7.163 16 16 16a15.95 15.95 0 0 0 11.306-4.678zM16.5 22h12m-6-6v12"
stroke="currentColor"
strokeWidth={3}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={3}
/>
</svg>
);
@@ -0,0 +1,117 @@
function PrivacyPolicyModal() {
return (
<div className="lg:rounded-[1.111vw] bg-white rounded-2xl lg:p-[2.222vw] lg:w-[38.889vw] p-8">
<div className="bg-[#00BED7] lg:h-[0.139vw] h-0.5 lg:w-[8.646vw] lg:rounded-[0.208vw] rounded-[3px]" />
<h2 className="text-subheadline-m font-semibold py-6">
Privacy Policy for IRTH Group and its companies:
</h2>
<div className="space-y-4">
<p className="text-caption-s">
At IRTH Group and its companies, we are committed to protecting the
privacy and security of your personal information. This Privacy Policy
explains how we collect, use, disclose, and safeguard your information
when you visit our website or use our services.
</p>
<div className="space-y-2">
<p className="text-caption-m">Information We Collect:</p>
<ul className="text-caption-s list-disc ml-5">
<li>
Personal Information: We may collect personal information such as
your name, contact details, and address when you voluntarily
provide it to us, such as when you register through a form or
request information
</li>
<li>
Usage Information: We automatically collect certain information
about your device and usage of our website, such as your IP
address, browser type, operating system, pages visited, and time
spent on each page. This information helps us analyze trends,
administer the website, and improve our services.
</li>
</ul>
</div>
<div className="space-y-2">
<p className="text-caption-m">How We Use Your Information:</p>
<ul className="text-caption-s list-disc ml-5">
<li>
To Provide Services:We use your personal information to deliver
the services you request, such as facilitating property
transactions, responding to inquiries, and sending you relevant
updates and notifications
</li>
<li>
To Improve Our Services: We analyze usage data to understand how
our website is accessed and used, identify areas for improvement,
and enhance the user experience.
</li>
<li>
To Communicate with You: We may use your contact information to
communicate with you about properties, services, promotions, and
updates. You can opt out of receiving marketing communications at
any time by following the unsubscribe instructions provided in our
emails or contacting us directly.
</li>
<li>
To Protect Our Rights: We may use your information to enforce our
terms of service, protect our rights, or comply with legal
obligations.
</li>
</ul>
</div>
<div className="space-y-2">
<p className="text-caption-m">Information Sharing and Disclosure:</p>
<p className="text-caption-s">
We may share your personal information with trusted third-party
service providers who assist us in operating our website, conducting
business, or servicing you, as long as those parties agree to keep
this information confidential. We may also disclose your information
when required by law, to enforce our site policies, or to protect
our or others' rights, property, or safety.
</p>
</div>
<div className="space-y-2">
<p className="text-caption-m">Data Security:</p>
<p className="text-caption-s">
We implement a variety of security measures to safeguard your
personal information and protect it from unauthorized access,
alteration, disclosure, or destruction. However, no method of
transmission over the Internet or electronic storage is 100% secure,
so we cannot guarantee absolute security.
</p>
</div>
<div className="space-y-2">
<p className="text-caption-m">Your Rights:</p>
<p className="text-caption-s">
You have the right to access, update, or delete your personal
information at any time. You can do this by contacting us directly.
We will make reasonable efforts to accommodate your request, subject
to any legal or contractual obligations.
</p>
</div>
<div className="space-y-2">
<p className="text-caption-m">Contact Us:</p>
<p className="text-caption-s">
If you have any questions or concerns about this Privacy Policy or
our privacy practices, please contact us at info@irth.ae
</p>
</div>
<div className="space-y-2">
<p className="text-caption-m">Effective Date:</p>
<p className="text-caption-s">
This Privacy Policy is effective as of 07/03/2024 and supersedes any
prior versions
</p>
</div>
</div>
</div>
);
}
export default PrivacyPolicyModal;
+2
View File
@@ -1,5 +1,6 @@
import Header from "../components/Header";
import { Outlet } from "react-router";
import Footer from "../components/Footer";
function DefaultLayout() {
return (
@@ -8,6 +9,7 @@ function DefaultLayout() {
<div className="h-[calc(100dvh-3.889vw)] max-lg:h-[calc(100dvh-56px)] max-md:h-[calc(100dvh-64px)]">
<Outlet />
</div>
<Footer />
</div>
);
}
+20
View File
@@ -7,6 +7,10 @@ import MainPage from "./pages/MainPage.tsx";
import ModalContainer from "./components/ModalContainer.tsx";
import ComplexPage from "./pages/ComplexPage.tsx";
import FloorsPage from "./pages/FloorsPage.tsx";
import UnitTypesPage from "./pages/UnitTypesPages.tsx";
import AboutPage from "./pages/AboutPages.tsx";
import FavouritesPage from "./pages/FavouritesPage.tsx";
import SearchPage from "./pages/SearchPage.tsx";
const route = createBrowserRouter([
{
@@ -24,6 +28,22 @@ const route = createBrowserRouter([
path: "/complex/:complexName/floors",
element: <FloorsPage />,
},
{
path: "/unit-types",
element: <UnitTypesPage />,
},
{
path: "/about",
element: <AboutPage />,
},
{
path: "/favourites",
element: <FavouritesPage />,
},
{
path: "/search",
element: <SearchPage />,
},
],
},
]);
+5
View File
@@ -0,0 +1,5 @@
function AboutPage() {
return <div>AboutPage</div>;
}
export default AboutPage;
+5
View File
@@ -0,0 +1,5 @@
function FavouritesPage() {
return <div>FavouritesPage</div>;
}
export default FavouritesPage;
+5
View File
@@ -0,0 +1,5 @@
function SearchPage() {
return <div>SearchPage</div>;
}
export default SearchPage;
+5
View File
@@ -0,0 +1,5 @@
function UnitTypesPage() {
return <div>UnitTypesPage</div>;
}
export default UnitTypesPage;