fix(SW-2657): Added sidepeek image component to handle images inside hotel page sidepeeks

Approved-by: Matilda Landström
This commit is contained in:
Erik Tiekstra
2025-05-13 05:13:33 +00:00
parent e78d9f2a86
commit dc06353db0
8 changed files with 56 additions and 107 deletions

View File

@@ -0,0 +1,13 @@
.sidePeekImages {
display: flex;
align-items: center;
gap: var(--Space-x2);
}
.image {
object-fit: cover;
height: 240px;
min-width: 0; /* Prevents image from causing flex item overflow by allowing shrinking below content size */
width: 100%;
border-radius: var(--Corner-radius-md);
}

View File

@@ -0,0 +1,33 @@
import Image from "@/components/Image"
import styles from "./images.module.css"
import type { ApiImage } from "@/types/hotel"
interface SidePeekImagesProps {
images: ApiImage[]
}
export default function SidePeekImages({ images }: SidePeekImagesProps) {
const showMultipleImages = images.length > 2
const imageWidth = showMultipleImages ? 240 : 496
const sizesString = showMultipleImages
? "(min-width: 1367px) 240px, 50vw"
: "(min-width: 1367px) 496px, 100vw"
return (
<div className={styles.sidePeekImages}>
{images.map(({ metaData, imageSizes }) => (
<Image
key={imageSizes.tiny}
src={imageSizes.tiny}
alt={metaData.altText}
height={240}
width={imageWidth}
sizes={sizesString}
className={styles.image}
/>
))}
</div>
)
}

View File

@@ -1,4 +1,3 @@
import Image from "@/components/Image"
import Button from "@/components/TempDesignSystem/Button"
import Link from "@/components/TempDesignSystem/Link"
import SidePeek from "@/components/TempDesignSystem/SidePeek"
@@ -7,6 +6,7 @@ import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import Title from "@/components/TempDesignSystem/Text/Title"
import { getIntl } from "@/i18n"
import SidePeekImages from "../Images"
import { getConferenceRoomTexts } from "./util"
import styles from "./meetingsAndConferences.module.css"
@@ -22,18 +22,7 @@ export default async function MeetingsAndConferencesSidePeek({
}: MeetingsAndConferencesSidePeekProps) {
const intl = await getIntl()
const { seatingText, roomText } = await getConferenceRoomTexts(meetingRooms)
const fallbackAlt = intl.formatMessage({
defaultMessage: "Creative spaces for meetings",
})
const primaryImage = meetingFacilities?.heroImages[0]?.imageSizes.medium
const primaryAltText =
meetingFacilities?.heroImages[0]?.metaData.altText || fallbackAlt
const secondaryImage = meetingFacilities?.heroImages[1]?.imageSizes.medium
const secondaryAltText =
meetingFacilities?.heroImages[1]?.metaData.altText || fallbackAlt
const visibleImages = meetingFacilities?.heroImages.slice(0, 2)
return (
<SidePeek
@@ -50,26 +39,9 @@ export default async function MeetingsAndConferencesSidePeek({
})}
</Title>
</Subtitle>
{primaryImage && (
<div className={secondaryImage ? styles.imageContainer : ""}>
<Image
src={primaryImage}
alt={primaryAltText}
height={300}
width={200}
className={styles.image}
/>
{secondaryImage && (
<Image
src={secondaryImage}
alt={secondaryAltText}
height={300}
width={200}
className={`${styles.image} ${styles.secondaryImage}`}
/>
)}
</div>
)}
{visibleImages?.length ? (
<SidePeekImages images={visibleImages} />
) : null}
{descriptions?.medium && (
<Body color="uiTextHighContrast">{descriptions.medium}</Body>
)}

View File

@@ -6,17 +6,6 @@
); /* Creates space between the wrapper and buttonContainer */
}
.image {
width: 100%;
height: 300px;
object-fit: cover;
border-radius: var(--Corner-radius-md);
}
.secondaryImage {
display: none;
}
.buttonContainer {
background-color: var(--Base-Background-Primary-Normal);
border-top: 1px solid var(--Base-Border-Subtle);
@@ -26,19 +15,3 @@
left: 0;
bottom: 0;
}
@media screen and (min-width: 768px) {
.imageContainer {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--Spacing-x2);
}
.image {
height: 240px;
}
.secondaryImage {
display: block;
}
}

View File

@@ -2,11 +2,12 @@ import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import ButtonLink from "@/components/ButtonLink"
import Image from "@/components/Image"
import OpeningHours from "@/components/OpeningHours"
import Link from "@/components/TempDesignSystem/Link"
import { getIntl } from "@/i18n"
import SidePeekImages from "../../Images"
import styles from "./restaurantBarItem.module.css"
import type { RestaurantBarItemProps } from "@/types/components/hotelPage/sidepeek/restaurantBar"
@@ -24,9 +25,7 @@ export default async function RestaurantBarItem({
restaurantPage,
mainBody,
} = restaurant
const { images } = restaurant.content
const visibleImages = restaurant.content.images.slice(0, 2)
const imageWidth = images.length === 2 ? 240 : 496
return (
<div className={styles.restaurantBarItem}>
@@ -35,20 +34,7 @@ export default async function RestaurantBarItem({
<h3 className={styles.heading}>{name}</h3>
</Typography>
</div>
{visibleImages.length ? (
<div className={styles.imageWrapper}>
{visibleImages.map(({ metaData, imageSizes }) => (
<Image
key={imageSizes.tiny}
src={imageSizes.tiny}
alt={metaData.altText}
width={imageWidth}
height={240}
className={styles.image}
/>
))}
</div>
) : null}
{visibleImages.length ? <SidePeekImages images={visibleImages} /> : null}
<Typography variant="Body/Paragraph/mdRegular">
<p>{content.texts.descriptions.short}</p>
</Typography>

View File

@@ -19,19 +19,6 @@
bottom: -16px;
}
.imageWrapper {
display: flex;
align-items: center;
gap: var(--Space-x2);
}
.image {
border-radius: var(--Corner-radius-md);
overflow: hidden;
width: 100%;
object-fit: cover;
}
.content {
display: grid;
gap: var(--Space-x15);

View File

@@ -4,13 +4,6 @@
gap: var(--Spacing-x2);
}
.image {
width: 100%;
height: 270px;
object-fit: cover;
border-radius: var(--Corner-radius-md);
}
.information {
display: flex;
flex-direction: column;

View File

@@ -1,9 +1,9 @@
import { Typography } from "@scandic-hotels/design-system/Typography"
import Image from "@/components/Image"
import { getIntl } from "@/i18n"
import { translateWellnessType } from "../../../utils"
import SidePeekImages from "../../Images"
import { translateWellnessDetails } from "./utils"
import styles from "./facility.module.css"
@@ -32,15 +32,7 @@ export default async function Facility({ data }: FacilityProps) {
return (
<div className={styles.content}>
{image?.imageSizes.medium && (
<Image
src={image.imageSizes.medium}
alt={image.metaData.altText || ""}
className={styles.image}
height={400}
width={200}
/>
)}
{image ? <SidePeekImages images={[image]} /> : null}
<div className={styles.information}>
<Typography variant="Title/Subtitle/lg" className={styles.title}>
<h3>{translateWellnessType(data.type, intl)}</h3>