feat(SW-252): add new ux
This commit is contained in:
@@ -1,19 +1,18 @@
|
||||
.main {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(min-content, max-content));
|
||||
display: flex;
|
||||
gap: var(--Spacing-x4);
|
||||
padding: var(--Spacing-x4) var(--Spacing-x4) 0 var(--Spacing-x4);
|
||||
height: 100dvh;
|
||||
background-color: var(--Scandic-Brand-Warm-White);
|
||||
min-height: 100dvh;
|
||||
}
|
||||
|
||||
.hotelCards {
|
||||
display: grid;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x4);
|
||||
}
|
||||
|
||||
.link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--Spacing-x2) var(--Spacing-x0);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ChevronRightIcon } from "@/components/Icons"
|
||||
import StaticMap from "@/components/Maps/StaticMap"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { getLang, setLang } from "@/i18n/serverContext"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
@@ -41,7 +41,7 @@ export default async function SelectHotelPage({
|
||||
/>
|
||||
<Link className={styles.link} color="burgundy" href="#">
|
||||
{intl.formatMessage({ id: "Show map" })}
|
||||
<ChevronRightIcon color="burgundy" className={styles.icon} />
|
||||
<ChevronRightIcon color="burgundy" />
|
||||
</Link>
|
||||
<HotelFilter filters={hotelFilters} />
|
||||
</section>
|
||||
|
||||
@@ -1,76 +1,111 @@
|
||||
.card {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"image header"
|
||||
"hotel hotel"
|
||||
"prices prices";
|
||||
gap: var(--Spacing-x2);
|
||||
padding: var(--Spacing-x2);
|
||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||
border: 1px solid var(--Base-Border-Subtle);
|
||||
border-radius: var(--Corner-radius-Small);
|
||||
overflow: hidden;
|
||||
height: 460px;
|
||||
width: 480px;
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
width: 100%;
|
||||
max-width: 307px;
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-area: header;
|
||||
}
|
||||
|
||||
.image {
|
||||
height: auto;
|
||||
max-height: 180px;
|
||||
height: 100%;
|
||||
max-height: 95px;
|
||||
width: 116px;
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
grid-area: image;
|
||||
}
|
||||
|
||||
.information {
|
||||
.logo {
|
||||
margin-bottom: var(--Spacing-x-half);
|
||||
}
|
||||
|
||||
.hotel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x1);
|
||||
grid-area: hotel;
|
||||
}
|
||||
|
||||
.facilities {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--Spacing-x-half);
|
||||
}
|
||||
|
||||
.link {
|
||||
display: flex;
|
||||
padding: var(--Spacing-x1) var(--Spacing-x0);
|
||||
border-bottom: 1px solid var(--Base-Border-Subtle);
|
||||
}
|
||||
|
||||
.prices {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x2);
|
||||
padding: var(--Spacing-x2);
|
||||
grid-area: prices;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.description {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x1);
|
||||
font-family: var(--typography-Caption-Regular-fontFamily);
|
||||
font-size: var(--typography-Caption-Regular-fontSize);
|
||||
}
|
||||
|
||||
.chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.booking {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--Spacing-x1);
|
||||
.public,
|
||||
.member {
|
||||
max-width: fit-content;
|
||||
margin-bottom: var(--Spacing-x-half);
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
.card {
|
||||
grid-template-columns: 1fr min(480px);
|
||||
height: 285px;
|
||||
width: 850px;
|
||||
grid-template-areas:
|
||||
"image header"
|
||||
"image hotel"
|
||||
"image prices";
|
||||
grid-template-columns: auto-fill;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
max-width: 1050px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.image {
|
||||
min-height: 285px;
|
||||
max-height: 100%;
|
||||
width: 100%;
|
||||
max-width: 518px;
|
||||
}
|
||||
|
||||
.booking {
|
||||
justify-content: space-between;
|
||||
flex-direction: row-reverse;
|
||||
.header {
|
||||
padding-top: var(--Spacing-x2);
|
||||
padding-right: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.hotel {
|
||||
padding-right: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.prices {
|
||||
flex-direction: row;
|
||||
padding-right: var(--Spacing-x2);
|
||||
padding-bottom: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.link {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.button {
|
||||
width: auto;
|
||||
display: flex;
|
||||
width: 160px;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
import { ScandicLogoIcon } from "@/components/Icons"
|
||||
import {
|
||||
ChevronRightIcon,
|
||||
PriceTagIcon,
|
||||
ScandicLogoIcon,
|
||||
} from "@/components/Icons"
|
||||
import { getIconByIconName } from "@/components/Icons/get-icon-by-icon-name"
|
||||
import Image from "@/components/Image"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Chip from "@/components/TempDesignSystem/Chip"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
@@ -10,7 +19,7 @@ import styles from "./hotelCard.module.css"
|
||||
import { HotelCardProps } from "@/types/components/hotelReservation/selectHotel/hotelCardProps"
|
||||
|
||||
export default async function HotelCard({ hotel }: HotelCardProps) {
|
||||
const { formatMessage } = await getIntl()
|
||||
const intl = await getIntl()
|
||||
return (
|
||||
<article className={styles.card}>
|
||||
<Image
|
||||
@@ -20,33 +29,53 @@ export default async function HotelCard({ hotel }: HotelCardProps) {
|
||||
height={200}
|
||||
className={styles.image}
|
||||
/>
|
||||
<div className={styles.information}>
|
||||
<header className={styles.title}>
|
||||
<ScandicLogoIcon color="red" />
|
||||
<Title as="h4" textTransform="capitalize">
|
||||
{hotel.name}
|
||||
</Title>
|
||||
</header>
|
||||
<div className={styles.description}>
|
||||
<span>{`${hotel.address.streetAddress}, ${hotel.address.city}`}</span>
|
||||
<span>{hotel.hotelContent.texts.descriptions.short}</span>
|
||||
</div>
|
||||
<div className={styles.chips}>
|
||||
{hotel.detailedFacilities.slice(0, 6).map((chip, index) => (
|
||||
<Chip key={`chip-${index}`}>{chip.name}</Chip>
|
||||
<header className={styles.header}>
|
||||
<ScandicLogoIcon color="red" className={styles.logo} />
|
||||
<Title as="h4" textTransform="capitalize">
|
||||
{hotel.name}
|
||||
</Title>
|
||||
<Footnote color="textMediumContrast">{`${hotel.address.streetAddress}, ${hotel.address.city}`}</Footnote>
|
||||
<Footnote color="textMediumContrast">{`${hotel.location.distanceToCentre} ${intl.formatMessage({ id: "km to city center" })}`}</Footnote>
|
||||
</header>
|
||||
<section className={styles.hotel}>
|
||||
<div className={styles.facilities}>
|
||||
{hotel.detailedFacilities.slice(0, 6).map((data) => (
|
||||
<Caption key={data.id} color="textMediumContrast">
|
||||
{data.name}
|
||||
</Caption>
|
||||
))}
|
||||
</div>
|
||||
<footer className={styles.booking}>
|
||||
<Button
|
||||
theme="base"
|
||||
intent="primary"
|
||||
size="small"
|
||||
className={styles.button}
|
||||
>
|
||||
{formatMessage({ id: "Book" })}
|
||||
</Button>
|
||||
</footer>
|
||||
</div>
|
||||
<Link href="#" color="burgundy" className={styles.link}>
|
||||
{intl.formatMessage({ id: "See hotel details" })}
|
||||
<ChevronRightIcon color="burgundy" />
|
||||
</Link>
|
||||
</section>
|
||||
<section className={styles.prices}>
|
||||
<div>
|
||||
<Chip intent="sublte" className={styles.public}>
|
||||
<PriceTagIcon width={15} height={15} />
|
||||
{intl.formatMessage({ id: "Public price from" })}
|
||||
</Chip>
|
||||
<Caption color="textMediumContrast">2820 SEK / night</Caption>
|
||||
<Footnote color="textMediumContrast">approx 280 eur</Footnote>
|
||||
</div>
|
||||
<div>
|
||||
<Chip intent="pale" className={styles.member}>
|
||||
<PriceTagIcon width={15} height={15} />
|
||||
{intl.formatMessage({ id: "Member price from" })}
|
||||
</Chip>
|
||||
<Caption color="textMediumContrast">2820 SEK / night</Caption>
|
||||
<Footnote color="textMediumContrast">approx 280 eur</Footnote>
|
||||
</div>
|
||||
<Button
|
||||
theme="base"
|
||||
intent="tertiary"
|
||||
size="small"
|
||||
className={styles.button}
|
||||
>
|
||||
{intl.formatMessage({ id: "See rooms" })}
|
||||
</Button>
|
||||
</section>
|
||||
</article>
|
||||
)
|
||||
}
|
||||
|
||||
40
components/Icons/PriceTag.tsx
Normal file
40
components/Icons/PriceTag.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { iconVariants } from "./variants"
|
||||
|
||||
import type { IconProps } from "@/types/components/icon"
|
||||
|
||||
export default function PriceTagIcon({
|
||||
className,
|
||||
color,
|
||||
...props
|
||||
}: IconProps) {
|
||||
const classNames = iconVariants({ className, color })
|
||||
return (
|
||||
<svg
|
||||
className={classNames}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<mask
|
||||
id="mask0_69_3241"
|
||||
style={{ maskType: "alpha" }}
|
||||
maskUnits="userSpaceOnUse"
|
||||
x="0"
|
||||
y="0"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<rect width="24" height="24" fill="#D9D9D9" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_69_3241)">
|
||||
<path
|
||||
d="M14.15 21.2C13.7833 21.5667 13.3375 21.75 12.8125 21.75C12.2875 21.75 11.8417 21.5667 11.475 21.2L2.825 12.525C2.6493 12.3529 2.50955 12.1494 2.40575 11.9146C2.30192 11.6799 2.25 11.4333 2.25 11.175V4.125C2.25 3.60937 2.43359 3.16796 2.80077 2.80078C3.16796 2.43359 3.60937 2.25 4.125 2.25H11.175C11.4372 2.25 11.684 2.29792 11.9154 2.39375C12.1468 2.48958 12.35 2.625 12.525 2.8L21.2 11.4875C21.5667 11.8542 21.75 12.2979 21.75 12.8188C21.75 13.3396 21.5667 13.7833 21.2 14.15L14.15 21.2ZM12.8375 19.875L19.8625 12.825L11.175 4.125H4.125V11.175L12.8375 19.875ZM6.5875 8C6.98333 8 7.31979 7.86146 7.59688 7.58437C7.87396 7.30729 8.0125 6.97083 8.0125 6.575C8.0125 6.17917 7.87396 5.84271 7.59688 5.56562C7.31979 5.28854 6.98333 5.15 6.5875 5.15C6.19167 5.15 5.85521 5.28854 5.57812 5.56562C5.30104 5.84271 5.1625 6.17917 5.1625 6.575C5.1625 6.97083 5.30104 7.30729 5.57812 7.58437C5.85521 7.86146 6.19167 8 6.5875 8Z"
|
||||
fill="#26201E"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -33,6 +33,7 @@ export { default as PersonIcon } from "./Person"
|
||||
export { default as PetsIcon } from "./Pets"
|
||||
export { default as PhoneIcon } from "./Phone"
|
||||
export { default as PlusCircleIcon } from "./PlusCircle"
|
||||
export { default as PriceTagIcon } from "./PriceTag"
|
||||
export { default as RestaurantIcon } from "./Restaurant"
|
||||
export { default as SaunaIcon } from "./Sauna"
|
||||
export { default as ScandicLogoIcon } from "./ScandicLogo"
|
||||
|
||||
@@ -12,3 +12,11 @@ div.chip {
|
||||
background-color: var(--Scandic-Red-90);
|
||||
color: var(--Primary-Dark-On-Surface-Accent);
|
||||
}
|
||||
|
||||
.subtle {
|
||||
background-color: var(--Base-Surface-Subtle-Normal);
|
||||
}
|
||||
|
||||
.pale {
|
||||
background-color: var(--Scandic-Brand-Pale-Peach);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ export const chipVariants = cva(styles.chip, {
|
||||
variants: {
|
||||
intent: {
|
||||
primary: styles.primary,
|
||||
sublte: styles.subtle,
|
||||
pale: styles.pale,
|
||||
},
|
||||
variant: {
|
||||
default: styles.default,
|
||||
|
||||
@@ -206,4 +206,4 @@
|
||||
"Your level": "Your level",
|
||||
"Your points to spend": "Your points to spend",
|
||||
"Zip code": "Zip code"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user