fix(SW-2657): Added sidepeek image component to handle images inside hotel page sidepeeks
Approved-by: Matilda Landström
This commit is contained in:
@@ -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);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import Image from "@/components/Image"
|
|
||||||
import Button from "@/components/TempDesignSystem/Button"
|
import Button from "@/components/TempDesignSystem/Button"
|
||||||
import Link from "@/components/TempDesignSystem/Link"
|
import Link from "@/components/TempDesignSystem/Link"
|
||||||
import SidePeek from "@/components/TempDesignSystem/SidePeek"
|
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 Title from "@/components/TempDesignSystem/Text/Title"
|
||||||
import { getIntl } from "@/i18n"
|
import { getIntl } from "@/i18n"
|
||||||
|
|
||||||
|
import SidePeekImages from "../Images"
|
||||||
import { getConferenceRoomTexts } from "./util"
|
import { getConferenceRoomTexts } from "./util"
|
||||||
|
|
||||||
import styles from "./meetingsAndConferences.module.css"
|
import styles from "./meetingsAndConferences.module.css"
|
||||||
@@ -22,18 +22,7 @@ export default async function MeetingsAndConferencesSidePeek({
|
|||||||
}: MeetingsAndConferencesSidePeekProps) {
|
}: MeetingsAndConferencesSidePeekProps) {
|
||||||
const intl = await getIntl()
|
const intl = await getIntl()
|
||||||
const { seatingText, roomText } = await getConferenceRoomTexts(meetingRooms)
|
const { seatingText, roomText } = await getConferenceRoomTexts(meetingRooms)
|
||||||
|
const visibleImages = meetingFacilities?.heroImages.slice(0, 2)
|
||||||
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
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidePeek
|
<SidePeek
|
||||||
@@ -50,26 +39,9 @@ export default async function MeetingsAndConferencesSidePeek({
|
|||||||
})}
|
})}
|
||||||
</Title>
|
</Title>
|
||||||
</Subtitle>
|
</Subtitle>
|
||||||
{primaryImage && (
|
{visibleImages?.length ? (
|
||||||
<div className={secondaryImage ? styles.imageContainer : ""}>
|
<SidePeekImages images={visibleImages} />
|
||||||
<Image
|
) : null}
|
||||||
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>
|
|
||||||
)}
|
|
||||||
{descriptions?.medium && (
|
{descriptions?.medium && (
|
||||||
<Body color="uiTextHighContrast">{descriptions.medium}</Body>
|
<Body color="uiTextHighContrast">{descriptions.medium}</Body>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -6,17 +6,6 @@
|
|||||||
); /* Creates space between the wrapper and buttonContainer */
|
); /* 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 {
|
.buttonContainer {
|
||||||
background-color: var(--Base-Background-Primary-Normal);
|
background-color: var(--Base-Background-Primary-Normal);
|
||||||
border-top: 1px solid var(--Base-Border-Subtle);
|
border-top: 1px solid var(--Base-Border-Subtle);
|
||||||
@@ -26,19 +15,3 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
bottom: 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
|||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import ButtonLink from "@/components/ButtonLink"
|
import ButtonLink from "@/components/ButtonLink"
|
||||||
import Image from "@/components/Image"
|
|
||||||
import OpeningHours from "@/components/OpeningHours"
|
import OpeningHours from "@/components/OpeningHours"
|
||||||
import Link from "@/components/TempDesignSystem/Link"
|
import Link from "@/components/TempDesignSystem/Link"
|
||||||
import { getIntl } from "@/i18n"
|
import { getIntl } from "@/i18n"
|
||||||
|
|
||||||
|
import SidePeekImages from "../../Images"
|
||||||
|
|
||||||
import styles from "./restaurantBarItem.module.css"
|
import styles from "./restaurantBarItem.module.css"
|
||||||
|
|
||||||
import type { RestaurantBarItemProps } from "@/types/components/hotelPage/sidepeek/restaurantBar"
|
import type { RestaurantBarItemProps } from "@/types/components/hotelPage/sidepeek/restaurantBar"
|
||||||
@@ -24,9 +25,7 @@ export default async function RestaurantBarItem({
|
|||||||
restaurantPage,
|
restaurantPage,
|
||||||
mainBody,
|
mainBody,
|
||||||
} = restaurant
|
} = restaurant
|
||||||
const { images } = restaurant.content
|
|
||||||
const visibleImages = restaurant.content.images.slice(0, 2)
|
const visibleImages = restaurant.content.images.slice(0, 2)
|
||||||
const imageWidth = images.length === 2 ? 240 : 496
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.restaurantBarItem}>
|
<div className={styles.restaurantBarItem}>
|
||||||
@@ -35,20 +34,7 @@ export default async function RestaurantBarItem({
|
|||||||
<h3 className={styles.heading}>{name}</h3>
|
<h3 className={styles.heading}>{name}</h3>
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
{visibleImages.length ? (
|
{visibleImages.length ? <SidePeekImages images={visibleImages} /> : null}
|
||||||
<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}
|
|
||||||
<Typography variant="Body/Paragraph/mdRegular">
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
<p>{content.texts.descriptions.short}</p>
|
<p>{content.texts.descriptions.short}</p>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -19,19 +19,6 @@
|
|||||||
bottom: -16px;
|
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 {
|
.content {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--Space-x15);
|
gap: var(--Space-x15);
|
||||||
|
|||||||
@@ -4,13 +4,6 @@
|
|||||||
gap: var(--Spacing-x2);
|
gap: var(--Spacing-x2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.image {
|
|
||||||
width: 100%;
|
|
||||||
height: 270px;
|
|
||||||
object-fit: cover;
|
|
||||||
border-radius: var(--Corner-radius-md);
|
|
||||||
}
|
|
||||||
|
|
||||||
.information {
|
.information {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import Image from "@/components/Image"
|
|
||||||
import { getIntl } from "@/i18n"
|
import { getIntl } from "@/i18n"
|
||||||
|
|
||||||
import { translateWellnessType } from "../../../utils"
|
import { translateWellnessType } from "../../../utils"
|
||||||
|
import SidePeekImages from "../../Images"
|
||||||
import { translateWellnessDetails } from "./utils"
|
import { translateWellnessDetails } from "./utils"
|
||||||
|
|
||||||
import styles from "./facility.module.css"
|
import styles from "./facility.module.css"
|
||||||
@@ -32,15 +32,7 @@ export default async function Facility({ data }: FacilityProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
{image?.imageSizes.medium && (
|
{image ? <SidePeekImages images={[image]} /> : null}
|
||||||
<Image
|
|
||||||
src={image.imageSizes.medium}
|
|
||||||
alt={image.metaData.altText || ""}
|
|
||||||
className={styles.image}
|
|
||||||
height={400}
|
|
||||||
width={200}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<div className={styles.information}>
|
<div className={styles.information}>
|
||||||
<Typography variant="Title/Subtitle/lg" className={styles.title}>
|
<Typography variant="Title/Subtitle/lg" className={styles.title}>
|
||||||
<h3>{translateWellnessType(data.type, intl)}</h3>
|
<h3>{translateWellnessType(data.type, intl)}</h3>
|
||||||
|
|||||||
Reference in New Issue
Block a user