fix(SW-2759): Sticky position for mobile map toggle button on hotel pages

Approved-by: Christian Andolf
Approved-by: Matilda Landström
This commit is contained in:
Erik Tiekstra
2025-06-02 09:37:59 +00:00
parent 5d6776c383
commit 9aa5c294a3
2 changed files with 44 additions and 59 deletions

View File

@@ -1,7 +1,8 @@
"use client" "use client"
import Link from "next/link" import { cx } from "class-variance-authority"
import { useParams, useSearchParams } from "next/navigation" import NextLink from "next/link"
import { useEffect, useMemo, useState } from "react" import { useParams } from "next/navigation"
import { useEffect, useState } from "react"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
@@ -13,12 +14,7 @@ import styles from "./mobileToggle.module.css"
export default function MobileMapToggle() { export default function MobileMapToggle() {
const intl = useIntl() const intl = useIntl()
const searchParams = useSearchParams()
const params = useParams() const params = useParams()
const isMapView = useMemo(
() => searchParams.get("view") === "map",
[searchParams]
)
const [mapUrl, setMapUrl] = useState<string | null>(null) const [mapUrl, setMapUrl] = useState<string | null>(null)
useEffect(() => { useEffect(() => {
@@ -33,41 +29,34 @@ export default function MobileMapToggle() {
return ( return (
<div className={styles.mobileToggle}> <div className={styles.mobileToggle}>
<span <Typography variant="Body/Supporting text (caption)/smBold">
className={`${styles.iconWrapper} ${!isMapView ? styles.active : ""}`} <span className={cx(styles.iconWrapper, styles.active)}>
> <MaterialIcon icon="home" color="CurrentColor" />
<MaterialIcon
icon="home"
color={!isMapView ? "Icon/Inverted" : "Icon/Accent"}
/>
<Typography variant="Body/Supporting text (caption)/smBold">
<span> <span>
{intl.formatMessage({ {intl.formatMessage({
defaultMessage: "Hotel", defaultMessage: "Hotel",
})} })}
</span> </span>
</Typography> </span>
</span> </Typography>
<span <span className={styles.iconWrapper}>
className={`${styles.iconWrapper} ${isMapView ? styles.active : ""}`} <Typography variant="Body/Supporting text (caption)/smBold">
> <NextLink
<Link className={styles.link}
className={styles.link} href={mapUrl}
href={mapUrl} onClick={trackHotelMapClick}
onClick={trackHotelMapClick} aria-label={intl.formatMessage({
> defaultMessage: "See map",
<MaterialIcon })}
icon="map" >
color={isMapView ? "Icon/Inverted" : "Icon/Interactive/Accent"} <MaterialIcon icon="map" color="CurrentColor" />
/>
<Typography variant="Body/Supporting text (caption)/smBold">
<span> <span>
{intl.formatMessage({ {intl.formatMessage({
defaultMessage: "Map", defaultMessage: "Map",
})} })}
</span> </span>
</Typography> </NextLink>
</Link> </Typography>
</span> </span>
</div> </div>
) )

View File

@@ -1,47 +1,43 @@
.mobileToggle { .mobileToggle {
position: fixed; position: sticky;
left: 50%; bottom: var(--Space-x5);
transform: translate(-50%, 0); margin-bottom: var(--Space-x5);
bottom: var(--Spacing-x5);
z-index: var(--hotel-mobile-map-toggle-button-z-index); z-index: var(--hotel-mobile-map-toggle-button-z-index);
margin: 0 auto;
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
gap: var(--Spacing-x-half); gap: var(--Space-x05);
align-items: center; align-items: center;
border-radius: 4rem; border-radius: var(--Corner-radius-Rounded);
background-color: var(--Base-Surface-Primary-light-Normal); background-color: var(--Component-Button-Inverted-Fill-Default);
box-shadow: 0 0 30px 2px rgba(0, 0, 0, 0.15); box-shadow: 0 0 30px 2px rgba(0, 0, 0, 0.15);
padding: var(--Spacing-x-half); padding: 6px;
width: fit-content;
justify-self: center;
} }
.iconWrapper { .iconWrapper {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: var(--Spacing-x-half); gap: var(--Space-x05);
padding: var(--Spacing-x1) var(--Spacing-x2); padding: var(--Space-x1) var(--Space-x2);
background-color: var(--Base-Surface-Primary-light-Normal); background-color: transparent;
border-width: 0;
cursor: pointer;
border-radius: 2.5rem; border-radius: 2.5rem;
color: var(--Base-Text-Accent); color: var(--Text-Accent-Primary);
}
.iconWrapper:hover {
background-color: var(--Base-Surface-Primary-light-Hover);
}
.iconWrapper.active { &.active {
background-color: var(--Primary-Strong-Surface-Normal); background-color: var(--Surface-Brand-Primary-2-Default);
color: var(--Base-Text-Inverted); color: var(--Text-Inverted);
} }
.iconWrapper.active:hover {
background-color: var(--Primary-Strong-Surface-Hover); &:not(.active) {
cursor: pointer;
}
} }
.link { .link {
display: contents; display: contents;
color: var(--Base-Text-Accent); color: var(--Text-Accent-Primary);
} }
@media screen and (min-width: 1367px) { @media screen and (min-width: 1367px) {