feat: added RoomCard and CardContainer component to HotelPage
This commit is contained in:
committed by
Chuma McPhoy
parent
6b5606fc8b
commit
68f40a144e
@@ -0,0 +1,15 @@
|
||||
.cardContainer {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x3);
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
}
|
||||
|
||||
.cardContainer.twoColumns {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
.cardContainer.threeColumns {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
.cardContainer.fourColumns {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cardContainerVariants } from "./variants"
|
||||
|
||||
export interface CardContainerProps
|
||||
extends React.PropsWithChildren<React.HTMLAttributes<HTMLElement>>,
|
||||
VariantProps<typeof cardContainerVariants> {}
|
||||
18
components/ContentType/HotelPage/CardContainer/index.tsx
Normal file
18
components/ContentType/HotelPage/CardContainer/index.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { CardContainerProps } from "./cardContainer"
|
||||
import { cardContainerVariants } from "./variants"
|
||||
|
||||
export function CardContainer({
|
||||
children,
|
||||
className,
|
||||
columns,
|
||||
...props
|
||||
}: CardContainerProps) {
|
||||
return (
|
||||
<section
|
||||
className={cardContainerVariants({ className, columns })}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
16
components/ContentType/HotelPage/CardContainer/variants.ts
Normal file
16
components/ContentType/HotelPage/CardContainer/variants.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { cva } from "class-variance-authority"
|
||||
|
||||
import styles from "./cardContainer.module.css"
|
||||
|
||||
export const cardContainerVariants = cva(styles.cardContainer, {
|
||||
variants: {
|
||||
columns: {
|
||||
2: styles.twoColumns,
|
||||
3: styles.threeColumns,
|
||||
4: styles.fourColumns,
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
columns: 3,
|
||||
},
|
||||
})
|
||||
52
components/ContentType/HotelPage/RoomCard/index.tsx
Normal file
52
components/ContentType/HotelPage/RoomCard/index.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
"use client"
|
||||
|
||||
import { ImageIcon } from "@/components/Icons"
|
||||
import Image from "@/components/Image"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
|
||||
import { RoomCardProps } from "./roomCard"
|
||||
|
||||
import styles from "./roomCard.module.css"
|
||||
|
||||
export function RoomCard({
|
||||
badgeText,
|
||||
title,
|
||||
subtitle,
|
||||
cta,
|
||||
image,
|
||||
imageCount,
|
||||
imageClick,
|
||||
}: RoomCardProps) {
|
||||
return (
|
||||
<article className={styles.roomCard}>
|
||||
<button className={styles.imageWrapper} onClick={imageClick}>
|
||||
{badgeText && <span className={styles.badge}>{badgeText}</span>}
|
||||
{imageCount && (
|
||||
<span className={styles.imageCount}>
|
||||
<ImageIcon color="white" />
|
||||
{imageCount}
|
||||
</span>
|
||||
)}
|
||||
<Image
|
||||
className={styles.image}
|
||||
src={image.src}
|
||||
alt={image.alt}
|
||||
height={image.height}
|
||||
width={image.width}
|
||||
/>
|
||||
</button>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.innerContent}>
|
||||
<Title as="h4" level="h3" textTransform="capitalize" color="black">
|
||||
{title}
|
||||
</Title>
|
||||
<Body color="grey">{subtitle}</Body>
|
||||
</div>
|
||||
<button className={styles.cta} onClick={cta.callback}>
|
||||
{cta.text}
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
.roomCard {
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
background-color: var(--Base-Surface-Primary-Normal);
|
||||
border: 1px solid var(--Base-Border-Subtle);
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.badge {
|
||||
position: absolute;
|
||||
top: var(--Spacing-x1);
|
||||
left: var(--Spacing-x1);
|
||||
background-color: var(--Scandic-Blue-100);
|
||||
padding: var(--Spacing-x-half) var(--Spacing-x1);
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
color: var(--Tertiary-Dark-On-Surface-Text, #fff0c2);
|
||||
text-transform: uppercase;
|
||||
font-family: var(--typography-Title-5-fontFamily);
|
||||
font-size: var(--typography-Footnote-Regular-fontSize);
|
||||
font-weight: var(--typography-Footnote-Regular-fontWeight);
|
||||
}
|
||||
|
||||
.imageCount {
|
||||
position: absolute;
|
||||
right: var(--Spacing-x1);
|
||||
bottom: var(--Spacing-x1);
|
||||
display: flex;
|
||||
gap: var(--Spacing-x-half);
|
||||
align-items: center;
|
||||
background-color: color-mix(
|
||||
in srgb,
|
||||
var(--Scandic-Beige-80) 80%,
|
||||
transparent
|
||||
);
|
||||
color: white;
|
||||
padding: var(--Spacing-x-half) var(--Spacing-x1);
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
gap: var(--Spacing-x-one-and-half);
|
||||
padding: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.innerContent {
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
gap: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.imageWrapper {
|
||||
position: relative;
|
||||
background-color: transparent;
|
||||
border-width: 0;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.image {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
border-top-left-radius: var(--Corner-radius-Medium);
|
||||
border-top-right-radius: var(--Corner-radius-Medium);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: var(--UI-Text-Placeholder, #787472);
|
||||
}
|
||||
|
||||
.cta {
|
||||
background-color: transparent;
|
||||
border-width: 0;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--Spacing-x-half);
|
||||
color: var(--Base-Text-Medium-contrast, #8f4350);
|
||||
font-family: var(--typography-Body-Bold-fontFamily);
|
||||
font-size: var(--typography-Body-Bold-fontSize);
|
||||
font-weight: 600;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.cta:hover {
|
||||
color: var(--Base-Text-High-contrast, #4d001b);
|
||||
}
|
||||
16
components/ContentType/HotelPage/RoomCard/roomCard.ts
Normal file
16
components/ContentType/HotelPage/RoomCard/roomCard.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { ImageProps } from "next/image"
|
||||
|
||||
interface RoomCardCtaProps {
|
||||
text: string
|
||||
callback: () => void
|
||||
}
|
||||
|
||||
export interface RoomCardProps {
|
||||
image: ImageProps
|
||||
imageCount: number
|
||||
imageClick: () => void
|
||||
title: string
|
||||
subtitle: string
|
||||
cta: RoomCardCtaProps
|
||||
badgeText?: string
|
||||
}
|
||||
Reference in New Issue
Block a user