Merged in feat/SW-1630-implement-mobile-tablet-design (pull request #1395)

Feat/SW-1630 implement mobile tablet design

* feat(SW-1630): add mobile and tablet design

* feat(SW-1630): adjust zoom buttons

* feat(SW-1630): css changes

* feat(SW-1630): modify breakpoints


Approved-by: Erik Tiekstra
This commit is contained in:
Fredrik Thorsson
2025-02-25 10:10:20 +00:00
parent 2c72957dc6
commit f4234334be
13 changed files with 149 additions and 23 deletions

View File

@@ -11,7 +11,23 @@
} }
.hotelList { .hotelList {
display: grid; display: flex;
flex-direction: column;
gap: var(--Spacing-x3); gap: var(--Spacing-x3);
list-style: none; list-style: none;
} }
@media screen and (max-width: 949px) {
.hotelListWrapper {
overflow-y: scroll;
}
.hotelList {
flex-direction: row;
align-items: end;
}
.header {
display: none;
}
}

View File

@@ -1,4 +1,5 @@
.hotelListItem { .hotelListItem {
display: grid;
background-color: var(--Base-Surface-Primary-light-Normal); background-color: var(--Base-Surface-Primary-light-Normal);
border: 1px solid var(--Base-Border-Subtle); border: 1px solid var(--Base-Border-Subtle);
border-radius: var(--Corner-radius-Medium); border-radius: var(--Corner-radius-Medium);
@@ -6,7 +7,8 @@
} }
.content { .content {
display: grid; display: flex;
flex-direction: column;
gap: var(--Spacing-x2); gap: var(--Spacing-x2);
padding: var(--Spacing-x2) var(--Spacing-x3); padding: var(--Spacing-x2) var(--Spacing-x3);
align-content: start; align-content: start;
@@ -41,3 +43,27 @@
.ctaWrapper { .ctaWrapper {
justify-self: stretch; justify-self: stretch;
} }
@media screen and (max-width: 950px) {
.hotelListItem {
width: 360px;
min-height: 150px;
grid-template-columns: 1fr 2fr;
}
.content {
padding: var(--Spacing-x-one-and-half);
gap: var(--Spacing-x1);
}
.logo,
.captions,
.amenityItem:nth-child(n + 4),
.amenityName {
display: none;
}
.ctaWrapper {
margin-top: auto;
}
}

View File

@@ -38,7 +38,9 @@ export default function HotelListItem({ hotel, url }: HotelListItemProps) {
/> />
<div className={styles.content}> <div className={styles.content}>
<div className={styles.intro}> <div className={styles.intro}>
<HotelLogo hotelId={hotel.operaId} hotelType={hotel.hotelType} /> <div className={styles.logo}>
<HotelLogo hotelId={hotel.operaId} hotelType={hotel.hotelType} />
</div>
<Subtitle type="one" asChild> <Subtitle type="one" asChild>
<h3>{hotel.name}</h3> <h3>{hotel.name}</h3>
</Subtitle> </Subtitle>
@@ -67,7 +69,7 @@ export default function HotelListItem({ hotel, url }: HotelListItemProps) {
{IconComponent && ( {IconComponent && (
<IconComponent color="grey80" width={20} height={20} /> <IconComponent color="grey80" width={20} height={20} />
)} )}
{amenity.name} <span className={styles.amenityName}>{amenity.name}</span>
</li> </li>
) )
})} })}

View File

@@ -0,0 +1,5 @@
@media screen and (max-width: 949px) {
.title {
display: none;
}
}

View File

@@ -7,6 +7,8 @@ import { getIntl } from "@/i18n"
import Map from "../../Map" import Map from "../../Map"
import HotelList from "./HotelList" import HotelList from "./HotelList"
import styles from "./cityMap.module.css"
import type { CityLocation } from "@/types/trpc/routers/hotel/locations" import type { CityLocation } from "@/types/trpc/routers/hotel/locations"
interface CityMapProps { interface CityMapProps {
@@ -27,7 +29,12 @@ export default async function CityMap({ city, cityIdentifier }: CityMapProps) {
apiKey={env.GOOGLE_STATIC_MAP_KEY} apiKey={env.GOOGLE_STATIC_MAP_KEY}
pageType="city" pageType="city"
> >
<Title level="h2" as="h3" textTransform="regular"> <Title
level="h2"
as="h3"
textTransform="regular"
className={styles.title}
>
{intl.formatMessage({ id: `Hotels in {city}` }, { city: city.name })} {intl.formatMessage({ id: `Hotels in {city}` }, { city: city.name })}
</Title> </Title>
<HotelList hotels={hotels} /> <HotelList hotels={hotels} />

View File

@@ -11,7 +11,23 @@
} }
.cityList { .cityList {
display: grid; display: flex;
flex-direction: column;
gap: var(--Spacing-x3); gap: var(--Spacing-x3);
list-style: none; list-style: none;
} }
@media screen and (max-width: 949px) {
.cityListWrapper {
overflow-x: scroll;
}
.cityList {
flex-direction: row;
align-items: end;
}
.header {
display: none;
}
}

View File

@@ -1,4 +1,5 @@
.cityListItem { .cityListItem {
display: grid;
background-color: var(--Base-Surface-Primary-light-Normal); background-color: var(--Base-Surface-Primary-light-Normal);
border: 1px solid var(--Base-Border-Subtle); border: 1px solid var(--Base-Border-Subtle);
border-radius: var(--Corner-radius-Medium); border-radius: var(--Corner-radius-Medium);
@@ -20,3 +21,28 @@
gap: var(--Spacing-x2); gap: var(--Spacing-x2);
padding: var(--Spacing-x2) var(--Spacing-x3); padding: var(--Spacing-x2) var(--Spacing-x3);
} }
@media screen and (max-width: 949px) {
.cityListItem {
width: 360px;
min-height: 120px;
grid-template-columns: 1fr 2fr;
}
.imageWrapper {
height: 100%;
}
.content {
padding: var(--Spacing-x-one-and-half);
gap: var(--Spacing-x1);
}
.experienceList {
display: none;
}
.ctaWrapper {
margin-top: auto;
}
}

View File

@@ -36,15 +36,19 @@ export default async function CityListItem({ city }: CityListItemProps) {
<Subtitle asChild> <Subtitle asChild>
<h3>{city.heading}</h3> <h3>{city.heading}</h3>
</Subtitle> </Subtitle>
<ExperienceList experiences={city.experiences} /> <div className={styles.experienceList}>
<Button intent="tertiary" theme="base" size="small" asChild> <ExperienceList experiences={city.experiences} />
<Link href={city.url}> </div>
{intl.formatMessage( <div className={styles.ctaWrapper}>
{ id: "Explore {city}" }, <Button intent="tertiary" theme="base" size="small" asChild>
{ city: city.cityName } <Link href={city.url}>
)} {intl.formatMessage(
</Link> { id: "Explore {city}" },
</Button> { city: city.cityName }
)}
</Link>
</Button>
</div>
</section> </section>
</article> </article>
) )

View File

@@ -0,0 +1,5 @@
@media screen and (max-width: 949px) {
.title {
display: none;
}
}

View File

@@ -10,6 +10,8 @@ import { getIntl } from "@/i18n"
import Map from "../../Map" import Map from "../../Map"
import CityList from "./CityList" import CityList from "./CityList"
import styles from "./countryMap.module.css"
import type { Country } from "@/types/enums/country" import type { Country } from "@/types/enums/country"
interface CountryMapProps { interface CountryMapProps {
@@ -34,7 +36,12 @@ export default async function CountryMap({ country }: CountryMapProps) {
apiKey={env.GOOGLE_STATIC_MAP_KEY} apiKey={env.GOOGLE_STATIC_MAP_KEY}
pageType="country" pageType="country"
> >
<Title level="h2" as="h3" textTransform="regular"> <Title
level="h2"
as="h3"
textTransform="regular"
className={styles.title}
>
{intl.formatMessage({ id: `Destinations in {country}` }, { country })} {intl.formatMessage({ id: `Destinations in {country}` }, { country })}
</Title> </Title>
<CityList cities={cities} /> <CityList cities={cities} />

View File

@@ -53,7 +53,7 @@
box-shadow: var(--button-box-shadow); box-shadow: var(--button-box-shadow);
} }
@media screen and (min-width: 768px) { @media screen and (min-width: 950px) {
.ctaButtons { .ctaButtons {
top: var(--Spacing-x4); top: var(--Spacing-x4);
right: var(--Spacing-x4); right: var(--Spacing-x4);
@@ -63,5 +63,6 @@
.zoomButtons { .zoomButtons {
display: flex; display: flex;
flex-direction: row-reverse;
} }
} }

View File

@@ -100,10 +100,10 @@ export default function DynamicMap({
variant="icon" variant="icon"
size="small" size="small"
className={styles.zoomButton} className={styles.zoomButton}
onClick={zoomOut} onClick={zoomIn}
aria-label={intl.formatMessage({ id: "Zoom in" })} aria-label={intl.formatMessage({ id: "Zoom out" })}
> >
<MinusIcon color="burgundy" width={20} height={20} /> <PlusIcon color="burgundy" width={20} height={20} />
</Button> </Button>
<Button <Button
theme="base" theme="base"
@@ -111,10 +111,10 @@ export default function DynamicMap({
variant="icon" variant="icon"
size="small" size="small"
className={styles.zoomButton} className={styles.zoomButton}
onClick={zoomIn} onClick={zoomOut}
aria-label={intl.formatMessage({ id: "Zoom out" })} aria-label={intl.formatMessage({ id: "Zoom in" })}
> >
<PlusIcon color="burgundy" width={20} height={20} /> <MinusIcon color="burgundy" width={20} height={20} />
</Button> </Button>
</div> </div>
</div> </div>

View File

@@ -33,3 +33,14 @@
box-shadow: var(--button-box-shadow); box-shadow: var(--button-box-shadow);
gap: var(--Spacing-x-half); gap: var(--Spacing-x-half);
} }
@media screen and (max-width: 949px) {
.sidebar {
position: absolute;
max-width: none;
padding: 0 var(--Spacing-x2) var(--Spacing-x3);
overflow: hidden;
bottom: 0;
z-index: 3;
}
}