diff --git a/components/ContentType/HotelPage/Map/DynamicMap/Sidebar/index.tsx b/components/ContentType/HotelPage/Map/DynamicMap/Sidebar/index.tsx index 5ed761081..e73c2c6b4 100644 --- a/components/ContentType/HotelPage/Map/DynamicMap/Sidebar/index.tsx +++ b/components/ContentType/HotelPage/Map/DynamicMap/Sidebar/index.tsx @@ -78,66 +78,72 @@ export default function Sidebar({ } return ( - + {poisInGroups.map(({ group, pois }) => + pois.length ? ( +
+ +

+ + {intl.formatMessage({ id: group })} +

+ + +
+ ) : null + )} + + +
+ ) } diff --git a/components/ContentType/HotelPage/Map/DynamicMap/Sidebar/sidebar.module.css b/components/ContentType/HotelPage/Map/DynamicMap/Sidebar/sidebar.module.css index 11f26b822..4bab124e7 100644 --- a/components/ContentType/HotelPage/Map/DynamicMap/Sidebar/sidebar.module.css +++ b/components/ContentType/HotelPage/Map/DynamicMap/Sidebar/sidebar.module.css @@ -1,50 +1,12 @@ .sidebar { - --sidebar-max-width: 26.25rem; - --sidebar-mobile-toggle-height: 91px; - --sidebar-mobile-fullscreen-height: calc( - 100vh - var(--main-menu-mobile-height) - var(--sidebar-mobile-toggle-height) - ); - - position: absolute; - top: var(--sidebar-mobile-fullscreen-height); - height: 100%; - right: 0; - left: 0; background-color: var(--Base-Surface-Primary-light-Normal); - z-index: 1; - transition: top 0.3s; -} - -.sidebar:not(.fullscreen) { - border-radius: var(--Corner-radius-Large) var(--Corner-radius-Large) 0 0; -} - -.sidebar.fullscreen { - top: 0; -} - -.sidebarToggle { - position: relative; - margin: var(--Spacing-x4) 0 var(--Spacing-x2); - width: 100%; -} - -.sidebarToggle::before { - content: ""; - position: absolute; - display: block; - top: -0.5rem; - width: 100px; - height: 3px; - background-color: var(--UI-Text-High-contrast); + z-index: 2; } .sidebarContent { display: grid; gap: var(--Spacing-x5); align-content: start; - padding: var(--Spacing-x3) var(--Spacing-x2); - height: var(--sidebar-mobile-fullscreen-height); overflow-y: auto; } @@ -90,12 +52,65 @@ background-color: var(--Base-Surface-Primary-light-Hover); } +@media screen and (max-width: 767px) { + .sidebar { + --sidebar-mobile-toggle-height: 84px; + --sidebar-mobile-top-space: 40px; + --sidebar-mobile-content-height: calc( + var(--hotel-map-height) - var(--sidebar-mobile-toggle-height) - + var(--sidebar-mobile-top-space) + ); + + position: absolute; + bottom: calc(-1 * var(--sidebar-mobile-content-height)); + width: 100%; + transition: + bottom 0.3s, + top 0.3s; + border-radius: var(--Corner-radius-Large) var(--Corner-radius-Large) 0 0; + } + + .sidebar.fullscreen + .backdrop { + position: absolute; + top: 0; + left: 0; + right: 0; + height: 100%; + background-color: rgba(0, 0, 0, 0.4); + z-index: 1; + } + + .sidebar.fullscreen { + bottom: 0; + } + + .sidebarToggle { + position: relative; + margin-top: var(--Spacing-x4); + } + + .sidebarToggle::before { + content: ""; + position: absolute; + display: block; + top: -0.5rem; + width: 100px; + height: 3px; + background-color: var(--UI-Text-High-contrast); + } + + .sidebarContent { + padding: var(--Spacing-x3) var(--Spacing-x2); + height: var(--sidebar-mobile-content-height); + } +} + @media screen and (min-width: 768px) { .sidebar { position: static; width: 40vw; min-width: 10rem; - max-width: var(--sidebar-max-width); + max-width: 26.25rem; background-color: var(--Base-Surface-Primary-light-Normal); } diff --git a/components/ContentType/HotelPage/Map/DynamicMap/dynamicMap.module.css b/components/ContentType/HotelPage/Map/DynamicMap/dynamicMap.module.css index 32df5b502..7cdd02371 100644 --- a/components/ContentType/HotelPage/Map/DynamicMap/dynamicMap.module.css +++ b/components/ContentType/HotelPage/Map/DynamicMap/dynamicMap.module.css @@ -1,18 +1,19 @@ .dynamicMap { - position: fixed; - top: var(--main-menu-mobile-height); - right: 0; - bottom: 0; + --hotel-map-height: 100dvh; + + position: absolute; + top: 0; left: 0; - z-index: var(--dialog-z-index); + height: var(--hotel-map-height); + width: 100dvw; + z-index: var(--hotel-dynamic-map-z-index); display: flex; background-color: var(--Base-Surface-Primary-light-Normal); } - -@media screen and (min-width: 768px) { - .dynamicMap { - top: var(--main-menu-desktop-height); - } +.wrapper { + position: absolute; + top: 0; + left: 0; } .closeButton { diff --git a/components/ContentType/HotelPage/Map/DynamicMap/index.tsx b/components/ContentType/HotelPage/Map/DynamicMap/index.tsx index f539d7614..969b24588 100644 --- a/components/ContentType/HotelPage/Map/DynamicMap/index.tsx +++ b/components/ContentType/HotelPage/Map/DynamicMap/index.tsx @@ -1,6 +1,6 @@ "use client" import { APIProvider } from "@vis.gl/react-google-maps" -import { useEffect, useRef, useState } from "react" +import { useCallback, useEffect, useRef, useState } from "react" import { Dialog, Modal } from "react-aria-components" import { useIntl } from "react-intl" @@ -10,6 +10,7 @@ import CloseLargeIcon from "@/components/Icons/CloseLarge" import InteractiveMap from "@/components/Maps/InteractiveMap" import Button from "@/components/TempDesignSystem/Button" import { useHandleKeyUp } from "@/hooks/useHandleKeyUp" +import { debounce } from "@/utils/debounce" import Sidebar from "./Sidebar" @@ -25,9 +26,10 @@ export default function DynamicMap({ mapId, }: DynamicMapProps) { const intl = useIntl() + const rootDiv = useRef(null) + const [mapHeight, setMapHeight] = useState("0px") const { isDynamicMapOpen, closeDynamicMap } = useHotelPageStore() const [scrollHeightWhenOpened, setScrollHeightWhenOpened] = useState(0) - const hasMounted = useRef(false) const [activePoi, setActivePoi] = useState(null) useHandleKeyUp((event: KeyboardEvent) => { @@ -36,23 +38,47 @@ export default function DynamicMap({ } }) - // Making sure the map is always opened at the top of the page, just below the header. + // Calculate the height of the map based on the viewport height from the start-point (below the header and booking widget) + const handleMapHeight = useCallback(() => { + const topPosition = rootDiv.current?.getBoundingClientRect().top ?? 0 + const scrollY = window.scrollY + setMapHeight(`calc(100dvh - ${topPosition + scrollY}px)`) + }, []) + + // Making sure the map is always opened at the top of the page, + // just below the header and booking widget as these should stay visible. // When closing, the page should scroll back to the position it was before opening the map. useEffect(() => { // Skip the first render - if (!hasMounted.current) { - hasMounted.current = true + if (!rootDiv.current) { return } if (isDynamicMapOpen && scrollHeightWhenOpened === 0) { - setScrollHeightWhenOpened(window.scrollY) + const scrollY = window.scrollY + setScrollHeightWhenOpened(scrollY) window.scrollTo({ top: 0, behavior: "instant" }) } else if (!isDynamicMapOpen && scrollHeightWhenOpened !== 0) { window.scrollTo({ top: scrollHeightWhenOpened, behavior: "instant" }) setScrollHeightWhenOpened(0) } - }, [isDynamicMapOpen, scrollHeightWhenOpened]) + }, [isDynamicMapOpen, scrollHeightWhenOpened, rootDiv]) + + useEffect(() => { + const debouncedResizeHandler = debounce(function () { + handleMapHeight() + }) + + const observer = new ResizeObserver(debouncedResizeHandler) + + observer.observe(document.documentElement) + + return () => { + if (observer) { + observer.unobserve(document.documentElement) + } + } + }, [rootDiv, isDynamicMapOpen, handleMapHeight]) const closeButton = (
) } diff --git a/components/ContentType/HotelPage/Map/MobileMapToggle/mobileToggle.module.css b/components/ContentType/HotelPage/Map/MobileMapToggle/mobileToggle.module.css index e5bb3b75b..b2edd97a0 100644 --- a/components/ContentType/HotelPage/Map/MobileMapToggle/mobileToggle.module.css +++ b/components/ContentType/HotelPage/Map/MobileMapToggle/mobileToggle.module.css @@ -1,7 +1,7 @@ .mobileToggle { position: sticky; bottom: var(--Spacing-x5); - z-index: 1; + z-index: var(--hotel-mobile-map-toggle-button-z-index); margin: 0 auto; display: grid; grid-template-columns: repeat(2, 1fr); diff --git a/components/ContentType/HotelPage/PreviewImages/previewImages.module.css b/components/ContentType/HotelPage/PreviewImages/previewImages.module.css index 7a1818557..064d99dce 100644 --- a/components/ContentType/HotelPage/PreviewImages/previewImages.module.css +++ b/components/ContentType/HotelPage/PreviewImages/previewImages.module.css @@ -4,6 +4,7 @@ position: relative; width: 100%; padding: var(--Spacing-x2) var(--Spacing-x2) 0; + z-index: 0; } .image { diff --git a/components/ContentType/HotelPage/TabNavigation/tabNavigation.module.css b/components/ContentType/HotelPage/TabNavigation/tabNavigation.module.css index 702f7d1fc..4c8cbaca1 100644 --- a/components/ContentType/HotelPage/TabNavigation/tabNavigation.module.css +++ b/components/ContentType/HotelPage/TabNavigation/tabNavigation.module.css @@ -1,7 +1,7 @@ .stickyWrapper { position: sticky; top: var(--booking-widget-mobile-height); - z-index: 2; + z-index: var(--hotel-tab-navigation-z-index); background-color: var(--Base-Surface-Subtle-Normal); border-bottom: 1px solid var(--Base-Border-Subtle); overflow-x: auto; diff --git a/components/ContentType/HotelPage/hotelPage.module.css b/components/ContentType/HotelPage/hotelPage.module.css index 091444fe2..87d0e8a3f 100644 --- a/components/ContentType/HotelPage/hotelPage.module.css +++ b/components/ContentType/HotelPage/hotelPage.module.css @@ -1,4 +1,8 @@ .pageContainer { + --hotel-tab-navigation-z-index: 2; + --hotel-mobile-map-toggle-button-z-index: 1; + --hotel-dynamic-map-z-index: 2; + --hotel-page-navigation-height: 59px; --hotel-page-scroll-margin-top: calc( var(--hotel-page-navigation-height) + var(--Spacing-x2)