-
-
{intl.formatMessage({ id: "Where to" })}
-
- {parsedLocation
- ? parsedLocation.name
- : intl.formatMessage({ id: "Destination" })}
-
-
-
-
-
- {intl.formatMessage(
- { id: "booking.nights" },
- { totalNights: nights }
- )}
-
-
- {selectedFromDate} - {selectedToDate}
-
-
-
-
-
+
+ {!locationAndDateIsSet && (
+ <>
+
+
+ {intl.formatMessage({ id: "Where to" })}
+
+
+ {parsedLocation
+ ? parsedLocation.name
+ : intl.formatMessage({ id: "Destination" })}
+
+
+
+
+
+ {intl.formatMessage(
+ { id: "booking.nights" },
+ { totalNights: nights }
+ )}
+
+
+ {selectedFromDate} - {selectedToDate}
+
+
+
+
+
+ >
+ )}
+
+ {locationAndDateIsSet && (
+ <>
+
+
{parsedLocation?.name}
+
+ {`${selectedFromDate} - ${selectedToDate} (${intl.formatMessage(
+ { id: "booking.nights" },
+ { totalNights: nights }
+ )}) ${intl.formatMessage({ id: "booking.adults" }, { totalAdults })}, ${
+ totalChildren > 0
+ ? intl.formatMessage(
+ { id: "booking.children" },
+ { totalChildren }
+ ) + ", "
+ : ""
+ }${intl.formatMessage({ id: "booking.rooms" }, { totalRooms })}`}
+
+
+
+
+
+ >
+ )}
)
}
diff --git a/components/BookingWidget/bookingWidget.module.css b/components/BookingWidget/bookingWidget.module.css
index d8235bae8..f0dec979d 100644
--- a/components/BookingWidget/bookingWidget.module.css
+++ b/components/BookingWidget/bookingWidget.module.css
@@ -1,5 +1,11 @@
+.containerDesktop,
+.containerMobile,
+.close {
+ display: none;
+}
+
@media screen and (max-width: 767px) {
- .container {
+ .containerMobile {
background-color: var(--UI-Input-Controls-Surface-Normal);
bottom: -100%;
display: grid;
@@ -14,7 +20,7 @@
border-radius: var(--Corner-radius-Large) var(--Corner-radius-Large) 0 0;
}
- .container[data-open="true"] {
+ .containerMobile[data-open="true"] {
bottom: 0;
}
@@ -25,7 +31,7 @@
justify-self: flex-end;
}
- .container[data-open="true"] + .backdrop {
+ .containerMobile[data-open="true"] + .backdrop {
background-color: rgba(0, 0, 0, 0.4);
height: 100%;
left: 0;
@@ -37,7 +43,7 @@
}
@media screen and (min-width: 768px) {
- .container {
+ .containerDesktop {
display: block;
box-shadow: 0px 4px 24px 0px rgba(0, 0, 0, 0.05);
position: sticky;
@@ -45,10 +51,6 @@
z-index: 10;
background-color: var(--Base-Surface-Primary-light-Normal);
}
-
- .close {
- display: none;
- }
}
@media screen and (min-width: 1367px) {
diff --git a/components/Breadcrumbs/breadcrumbs.module.css b/components/Breadcrumbs/breadcrumbs.module.css
index 9523fd4c9..93bedd5a6 100644
--- a/components/Breadcrumbs/breadcrumbs.module.css
+++ b/components/Breadcrumbs/breadcrumbs.module.css
@@ -19,6 +19,7 @@
.listItem {
align-items: center;
display: flex;
+ gap: var(--Spacing-x-quarter);
}
.homeLink {
diff --git a/components/Breadcrumbs/index.tsx b/components/Breadcrumbs/index.tsx
index 1939e47fa..adf892011 100644
--- a/components/Breadcrumbs/index.tsx
+++ b/components/Breadcrumbs/index.tsx
@@ -1,6 +1,6 @@
import { serverClient } from "@/lib/trpc/server"
-import { ChevronRightIcon, HouseIcon } from "@/components/Icons"
+import { ChevronRightSmallIcon, HouseIcon } from "@/components/Icons"
import Link from "@/components/TempDesignSystem/Link"
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
@@ -24,9 +24,9 @@ export default async function Breadcrumbs() {
href={homeBreadcrumb.href!}
variant="breadcrumb"
>
-
+
-
+
) : null}
@@ -41,7 +41,7 @@ export default async function Breadcrumbs() {
>
{breadcrumb.title}
-
+
)
}
diff --git a/components/ContentType/HotelPage/AmenitiesList/amenitiesList.module.css b/components/ContentType/HotelPage/AmenitiesList/amenitiesList.module.css
index e35dc13a6..d3e5d9d91 100644
--- a/components/ContentType/HotelPage/AmenitiesList/amenitiesList.module.css
+++ b/components/ContentType/HotelPage/AmenitiesList/amenitiesList.module.css
@@ -18,6 +18,7 @@
.amenityItem {
display: inline-flex;
gap: var(--Spacing-x1);
+ align-items: center;
}
.icon {
diff --git a/components/ContentType/HotelPage/AmenitiesList/index.tsx b/components/ContentType/HotelPage/AmenitiesList/index.tsx
index 8c90f19c2..03244ea7a 100644
--- a/components/ContentType/HotelPage/AmenitiesList/index.tsx
+++ b/components/ContentType/HotelPage/AmenitiesList/index.tsx
@@ -1,7 +1,7 @@
import { amenities } from "@/constants/routes/hotelPageParams"
import { mapFacilityToIcon } from "@/components/ContentType/HotelPage/data"
-import { ChevronRightIcon } from "@/components/Icons"
+import { ChevronRightSmallIcon } from "@/components/Icons"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
@@ -29,7 +29,12 @@ export default async function AmenitiesList({
return (
{IconComponent && (
-
+
)}
{facility.name}
@@ -44,7 +49,7 @@ export default async function AmenitiesList({
className={styles.showAllAmenities}
>
{intl.formatMessage({ id: "Show all amenities" })}
-
+
)
diff --git a/components/ContentType/HotelPage/IntroSection/index.tsx b/components/ContentType/HotelPage/IntroSection/index.tsx
index 360d0f8df..010530f74 100644
--- a/components/ContentType/HotelPage/IntroSection/index.tsx
+++ b/components/ContentType/HotelPage/IntroSection/index.tsx
@@ -1,7 +1,6 @@
import { about } from "@/constants/routes/hotelPageParams"
-import { ChevronRightIcon } from "@/components/Icons"
-import ArrowRight from "@/components/Icons/ArrowRight"
+import { ChevronRightSmallIcon } from "@/components/Icons"
import TripAdvisorIcon from "@/components/Icons/TripAdvisor"
import Link from "@/components/TempDesignSystem/Link"
import BiroScript from "@/components/TempDesignSystem/Text/BiroScript"
@@ -48,7 +47,7 @@ export default async function IntroSection({
- {intl.formatMessage({ id: "Welcome to" })}:
+ {intl.formatMessage({ id: "Welcome to" })}
{hotelName}
@@ -77,7 +76,7 @@ export default async function IntroSection({
scroll={false}
>
{intl.formatMessage({ id: "Read more about the hotel" })}
-
+
diff --git a/components/ContentType/HotelPage/Map/DynamicMap/Sidebar/index.tsx b/components/ContentType/HotelPage/Map/DynamicMap/Sidebar/index.tsx
index 5ed761081..db979bf47 100644
--- a/components/ContentType/HotelPage/Map/DynamicMap/Sidebar/index.tsx
+++ b/components/ContentType/HotelPage/Map/DynamicMap/Sidebar/index.tsx
@@ -37,21 +37,26 @@ export default function Sidebar({
function moveToPoi(poiCoordinates: Coordinates) {
if (map) {
+ const hotelLatLng = new google.maps.LatLng(
+ coordinates.lat,
+ coordinates.lng
+ )
+ const poiLatLng = new google.maps.LatLng(
+ poiCoordinates.lat,
+ poiCoordinates.lng
+ )
+
const bounds = new google.maps.LatLngBounds()
- const boundPadding = 0.02
+ bounds.extend(hotelLatLng)
+ bounds.extend(poiLatLng)
- const minLat = Math.min(coordinates.lat, poiCoordinates.lat)
- const maxLat = Math.max(coordinates.lat, poiCoordinates.lat)
- const minLng = Math.min(coordinates.lng, poiCoordinates.lng)
- const maxLng = Math.max(coordinates.lng, poiCoordinates.lng)
-
- bounds.extend(
- new google.maps.LatLng(minLat - boundPadding, minLng - boundPadding)
- )
- bounds.extend(
- new google.maps.LatLng(maxLat + boundPadding, maxLng + boundPadding)
- )
map.fitBounds(bounds)
+
+ const currentZoomLevel = map.getZoom()
+
+ if (currentZoomLevel) {
+ map.setZoom(currentZoomLevel - 1)
+ }
}
}
@@ -61,12 +66,6 @@ export default function Sidebar({
}
}
- function handleMouseLeave() {
- if (!isClicking) {
- onActivePoiChange(null)
- }
- }
-
function handlePoiClick(poiName: string, poiCoordinates: Coordinates) {
setIsClicking(true)
toggleFullScreenSidebar()
@@ -78,66 +77,71 @@ export default function Sidebar({
}
return (
-
+
+ >
)
}
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/MapWithCard/index.tsx b/components/ContentType/HotelPage/Map/MapWithCard/index.tsx
new file mode 100644
index 000000000..b544e39d3
--- /dev/null
+++ b/components/ContentType/HotelPage/Map/MapWithCard/index.tsx
@@ -0,0 +1,24 @@
+"use client"
+
+import { PropsWithChildren, useRef } from "react"
+
+import { StickyElementNameEnum } from "@/stores/sticky-position"
+
+import useStickyPosition from "@/hooks/useStickyPosition"
+
+import styles from "./mapWithCard.module.css"
+
+export default function MapWithCard({ children }: PropsWithChildren) {
+ const mapWithCardRef = useRef