fix(SW-2721): Facilities only uses 2 columns on viewports >= 768px
Approved-by: Matilda Landström
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.grid:not(.allVisible) :nth-child(n + 4) {
|
||||
.grid:not(.allVisible) > :nth-child(n + 4) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
"use client"
|
||||
|
||||
import { cx } from "class-variance-authority"
|
||||
import { useRef, useState } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { FacilityIcon } from "@/components/SidePeeks/RoomSidePeek/facilityIcon"
|
||||
import ShowMoreButton from "@/components/TempDesignSystem/ShowMoreButton"
|
||||
|
||||
import styles from "./roomFacilities.module.css"
|
||||
|
||||
import type { Room } from "@/types/hotel"
|
||||
|
||||
interface RoomFacilitiesProps {
|
||||
roomFacilities: Room["roomFacilities"]
|
||||
}
|
||||
|
||||
export default function RoomFacilities({
|
||||
roomFacilities,
|
||||
}: RoomFacilitiesProps) {
|
||||
const intl = useIntl()
|
||||
const showMobileToggleButton = roomFacilities.length > 10
|
||||
const [allVisibleOnMobile, setAllVisibleOnMobile] = useState(
|
||||
!showMobileToggleButton
|
||||
)
|
||||
const scrollRef = useRef<HTMLHeadingElement>(null)
|
||||
|
||||
const mappedFacilities = roomFacilities
|
||||
.sort((a, b) => a.sortOrder - b.sortOrder)
|
||||
.map((facility) => {
|
||||
const facilityName = facility.availableInAllRooms
|
||||
? facility.name
|
||||
: intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "{facility} (available in some rooms)",
|
||||
},
|
||||
{
|
||||
facility: facility.name,
|
||||
}
|
||||
)
|
||||
return {
|
||||
...facility,
|
||||
name: facilityName,
|
||||
}
|
||||
})
|
||||
|
||||
function handleShowMore() {
|
||||
if (scrollRef.current && allVisibleOnMobile) {
|
||||
scrollRef.current.scrollIntoView({ behavior: "smooth" })
|
||||
}
|
||||
setAllVisibleOnMobile((state) => !state)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h3 ref={scrollRef} className={styles.heading}>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Room amenities",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<ul
|
||||
className={cx(styles.facilities, {
|
||||
[styles.allVisibleMobile]: allVisibleOnMobile,
|
||||
})}
|
||||
>
|
||||
{mappedFacilities.map((facility) => (
|
||||
<li className={styles.item} key={facility.name}>
|
||||
<FacilityIcon
|
||||
name={facility.icon}
|
||||
size={24}
|
||||
color="CurrentColor"
|
||||
className={styles.icon}
|
||||
/>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<span>{facility.name}</span>
|
||||
</Typography>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{showMobileToggleButton ? (
|
||||
<div className={styles.ctaWrapper}>
|
||||
<ShowMoreButton
|
||||
loadMoreData={handleShowMore}
|
||||
showLess={allVisibleOnMobile}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
.heading {
|
||||
/* Custom value to make the heading visible with a bit of margin when scrolled programmatically */
|
||||
scroll-margin-top: 16px;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
gap: var(--Spacing-x1);
|
||||
margin-bottom: var(--Spacing-x-half);
|
||||
align-items: self-start;
|
||||
justify-content: flex-start;
|
||||
color: var(--Text-Secondary);
|
||||
}
|
||||
|
||||
.icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ctaWrapper {
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
.facilities:not(.allVisibleMobile) > :nth-child(n + 11) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.facilities {
|
||||
column-count: 2;
|
||||
column-gap: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.ctaWrapper {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import { cx } from "class-variance-authority"
|
||||
import Link from "next/link"
|
||||
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
@@ -9,7 +8,6 @@ import { dt } from "@/lib/dt"
|
||||
|
||||
import ImageGallery from "@/components/ImageGallery"
|
||||
import { getBedIconName } from "@/components/SidePeeks/RoomSidePeek/bedIcon"
|
||||
import { FacilityIcon } from "@/components/SidePeeks/RoomSidePeek/facilityIcon"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import SidePeek from "@/components/TempDesignSystem/SidePeek"
|
||||
import { getIntl } from "@/i18n"
|
||||
@@ -17,6 +15,7 @@ import { getLang } from "@/i18n/serverContext"
|
||||
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
|
||||
|
||||
import { getRoomNameAsParam } from "../../utils"
|
||||
import RoomFacilities from "./RoomFacilities"
|
||||
|
||||
import styles from "./room.module.css"
|
||||
|
||||
@@ -95,45 +94,7 @@ export default async function RoomSidePeek({
|
||||
</div>
|
||||
|
||||
<div className={styles.innerContent}>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h3>
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Room amenities",
|
||||
})}
|
||||
</h3>
|
||||
</Typography>
|
||||
<ul className={styles.facilityList}>
|
||||
{room.roomFacilities
|
||||
.sort((a, b) => a.sortOrder - b.sortOrder)
|
||||
.map((facility) => {
|
||||
const facilityName = facility.availableInAllRooms
|
||||
? facility.name
|
||||
: intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "{facility} (available in some rooms)",
|
||||
},
|
||||
{
|
||||
facility: facility.name,
|
||||
}
|
||||
)
|
||||
|
||||
return (
|
||||
<li className={styles.listItem} key={facility.name}>
|
||||
<FacilityIcon
|
||||
name={facility.icon}
|
||||
size={24}
|
||||
color="Icon/Default"
|
||||
/>
|
||||
<Typography
|
||||
variant="Body/Paragraph/mdRegular"
|
||||
className={styles.iconText}
|
||||
>
|
||||
<span>{facilityName}</span>
|
||||
</Typography>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
<RoomFacilities roomFacilities={room.roomFacilities} />
|
||||
</div>
|
||||
|
||||
<div className={styles.innerContent}>
|
||||
@@ -155,16 +116,15 @@ export default async function RoomSidePeek({
|
||||
</div>
|
||||
<ul className={styles.bedOptions}>
|
||||
{room.roomTypes.map((roomType) => {
|
||||
const bedIcon = getBedIconName(roomType.mainBed.type)
|
||||
const iconName = getBedIconName(roomType.mainBed.type)
|
||||
return (
|
||||
<li className={styles.listItem} key={roomType.code}>
|
||||
<MaterialIcon color="Icon/Default" icon={bedIcon} />
|
||||
<Typography
|
||||
variant="Body/Paragraph/mdRegular"
|
||||
className={cx(styles.iconText, {
|
||||
[styles.noIcon]: !bedIcon,
|
||||
})}
|
||||
>
|
||||
<MaterialIcon
|
||||
color="CurrentColor"
|
||||
icon={iconName}
|
||||
className={styles.icon}
|
||||
/>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<span>{roomType.mainBed.description}</span>
|
||||
</Typography>
|
||||
</li>
|
||||
|
||||
@@ -26,11 +26,6 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.facilityList {
|
||||
column-count: 2;
|
||||
column-gap: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.bedOptions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -43,6 +38,11 @@
|
||||
margin-bottom: var(--Spacing-x-half);
|
||||
align-items: self-start;
|
||||
justify-content: flex-start;
|
||||
color: var(--Text-Secondary);
|
||||
}
|
||||
|
||||
.icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
@@ -54,8 +54,3 @@
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.iconText {
|
||||
color: var(--Text-Secondary);
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user