feat(BOOK-757): Moved TeaserCard to design system and added stories
Approved-by: Bianca Widstam
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { TeaserCard } from "@scandic-hotels/design-system/TeaserCard"
|
||||
import {
|
||||
CardsGridEnum,
|
||||
CardsGridLayoutEnum,
|
||||
@@ -9,7 +10,6 @@ import { SectionHeader } from "@/components/Section/Header"
|
||||
import Card from "@/components/TempDesignSystem/Card"
|
||||
import Grids from "@/components/TempDesignSystem/Grids"
|
||||
import LoyaltyCard from "@/components/TempDesignSystem/LoyaltyCard"
|
||||
import TeaserCard from "@/components/TempDesignSystem/TeaserCard"
|
||||
|
||||
import type { CardsGrid as CardsGridBlock } from "@scandic-hotels/trpc/types/blocks"
|
||||
import type { VariantProps } from "class-variance-authority"
|
||||
@@ -89,8 +89,8 @@ export default function CardsGrid({
|
||||
return (
|
||||
<TeaserCard
|
||||
key={card.system.uid}
|
||||
title={card.heading}
|
||||
description={card.body_text}
|
||||
heading={card.heading}
|
||||
bodyText={card.body_text}
|
||||
primaryButton={card.primaryButton}
|
||||
secondaryButton={card.secondaryButton}
|
||||
sidePeekButton={card.sidePeekButton}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml"
|
||||
import { TeaserCard } from "@scandic-hotels/design-system/TeaserCard"
|
||||
import { DynamicContentEnum } from "@scandic-hotels/trpc/types/dynamicContent"
|
||||
import { SidebarEnums } from "@scandic-hotels/trpc/types/sidebar"
|
||||
|
||||
@@ -7,7 +8,6 @@ import EmployeeBenefitsAuthCard from "@/components/DigitalTeamMemberCard/Employe
|
||||
|
||||
import ShortcutsList from "../Blocks/ShortcutsList"
|
||||
import Card from "../TempDesignSystem/Card"
|
||||
import TeaserCard from "../TempDesignSystem/TeaserCard"
|
||||
import JoinLoyaltyContact from "./JoinLoyalty"
|
||||
|
||||
import styles from "./sidebar.module.css"
|
||||
@@ -71,9 +71,9 @@ export default function Sidebar({ blocks }: SidebarProps) {
|
||||
return (
|
||||
<TeaserCard
|
||||
key={block.teaser_card.system.uid}
|
||||
title={block.teaser_card.heading}
|
||||
description={block.teaser_card.body_text}
|
||||
intent={block.teaser_card.theme}
|
||||
heading={block.teaser_card.heading}
|
||||
bodyText={block.teaser_card.body_text}
|
||||
style={block.teaser_card.theme}
|
||||
primaryButton={block.teaser_card.primaryButton}
|
||||
secondaryButton={block.teaser_card.secondaryButton}
|
||||
sidePeekButton={block.teaser_card.sidePeekButton}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { Button } from "@scandic-hotels/design-system/Button"
|
||||
import ButtonLink from "@scandic-hotels/design-system/ButtonLink"
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { JsonToHtml } from "@scandic-hotels/design-system/JsonToHtml"
|
||||
import SidePeek from "@scandic-hotels/design-system/SidePeek"
|
||||
|
||||
import styles from "./sidepeek.module.css"
|
||||
|
||||
import type { TeaserCardSidepeekProps } from "@/types/components/teaserCard"
|
||||
|
||||
export default function TeaserCardSidepeek({
|
||||
button,
|
||||
sidePeekContent,
|
||||
}: TeaserCardSidepeekProps) {
|
||||
const intl = useIntl()
|
||||
const [sidePeekIsOpen, setSidePeekIsOpen] = useState(false)
|
||||
const { heading, content, primary_button, secondary_button } = sidePeekContent
|
||||
|
||||
return (
|
||||
<div className={styles.teaserCardSidepeek}>
|
||||
<Button
|
||||
onPress={() => setSidePeekIsOpen(true)}
|
||||
variant="Secondary"
|
||||
color="Primary"
|
||||
size="sm"
|
||||
>
|
||||
{button.call_to_action_text}
|
||||
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />
|
||||
</Button>
|
||||
<SidePeek
|
||||
title={heading}
|
||||
isOpen={sidePeekIsOpen}
|
||||
handleClose={() => setSidePeekIsOpen(false)}
|
||||
openInRoot
|
||||
closeLabel={intl.formatMessage({
|
||||
id: "common.close",
|
||||
defaultMessage: "Close",
|
||||
})}
|
||||
>
|
||||
{content ? (
|
||||
<JsonToHtml
|
||||
nodes={content.json.children}
|
||||
embeds={content.embedded_itemsConnection.edges}
|
||||
/>
|
||||
) : null}
|
||||
<div className={styles.ctaContainer}>
|
||||
{primary_button && (
|
||||
<ButtonLink
|
||||
variant="Primary"
|
||||
color="Primary"
|
||||
size="sm"
|
||||
href={primary_button.href}
|
||||
target={primary_button.openInNewTab ? "_blank" : undefined}
|
||||
>
|
||||
{primary_button.title}
|
||||
</ButtonLink>
|
||||
)}
|
||||
{secondary_button && (
|
||||
<ButtonLink
|
||||
variant="Secondary"
|
||||
color="Primary"
|
||||
size="sm"
|
||||
href={secondary_button.href}
|
||||
target={secondary_button.openInNewTab ? "_blank" : undefined}
|
||||
>
|
||||
{secondary_button.title}
|
||||
</ButtonLink>
|
||||
)}
|
||||
</div>
|
||||
</SidePeek>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
.teaserCardSidepeek {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.ctaContainer {
|
||||
display: grid;
|
||||
gap: var(--Space-x2);
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
import ButtonLink from "@scandic-hotels/design-system/ButtonLink"
|
||||
import Image from "@scandic-hotels/design-system/Image"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import TeaserCardSidepeek from "./Sidepeek"
|
||||
import { teaserCardVariants } from "./variants"
|
||||
|
||||
import styles from "./teaserCard.module.css"
|
||||
|
||||
import type { TeaserCardProps } from "@/types/components/teaserCard"
|
||||
|
||||
export default function TeaserCard({
|
||||
title,
|
||||
description,
|
||||
primaryButton,
|
||||
secondaryButton,
|
||||
sidePeekButton,
|
||||
sidePeekContent,
|
||||
image,
|
||||
intent,
|
||||
alwaysStack = false,
|
||||
className,
|
||||
}: TeaserCardProps) {
|
||||
const classNames = teaserCardVariants({ intent, alwaysStack, className })
|
||||
|
||||
return (
|
||||
<article className={classNames}>
|
||||
{image && (
|
||||
<div className={styles.imageContainer}>
|
||||
<Image
|
||||
src={image.url}
|
||||
alt={image.meta?.alt || ""}
|
||||
className={styles.image}
|
||||
focalPoint={image.focalPoint}
|
||||
dimensions={image.dimensions}
|
||||
fill
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<p>{title}</p>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{description}</p>
|
||||
</Typography>
|
||||
|
||||
{sidePeekButton && sidePeekContent ? (
|
||||
<TeaserCardSidepeek
|
||||
button={sidePeekButton}
|
||||
sidePeekContent={sidePeekContent}
|
||||
/>
|
||||
) : (
|
||||
<div className={styles.ctaContainer}>
|
||||
{primaryButton && (
|
||||
<ButtonLink
|
||||
variant="Tertiary"
|
||||
color="Primary"
|
||||
size="sm"
|
||||
className={styles.ctaButton}
|
||||
href={primaryButton.href}
|
||||
target={primaryButton.openInNewTab ? "_blank" : undefined}
|
||||
>
|
||||
{primaryButton.title}
|
||||
</ButtonLink>
|
||||
)}
|
||||
{secondaryButton && (
|
||||
<ButtonLink
|
||||
variant="Secondary"
|
||||
color="Primary"
|
||||
size="sm"
|
||||
className={styles.ctaButton}
|
||||
href={secondaryButton.href}
|
||||
target={secondaryButton.openInNewTab ? "_blank" : undefined}
|
||||
>
|
||||
{secondaryButton.title}
|
||||
</ButtonLink>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</article>
|
||||
)
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
.card {
|
||||
border-radius: var(--Corner-radius-md);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.imageContainer {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.default {
|
||||
background-color: var(--Base-Surface-Subtle-Normal);
|
||||
}
|
||||
|
||||
.featured {
|
||||
background-color: var(--Main-Grey-White);
|
||||
}
|
||||
|
||||
.default,
|
||||
.featured {
|
||||
border: 1px solid var(--Base-Border-Subtle);
|
||||
}
|
||||
|
||||
.image {
|
||||
width: 100%;
|
||||
height: 12.5rem; /* 200px */
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
gap: var(--Space-x15);
|
||||
padding: var(--Space-x2) var(--Space-x3);
|
||||
grid-template-rows: auto 1fr auto;
|
||||
flex-grow: 1;
|
||||
|
||||
color: var(--Main-Grey-100);
|
||||
}
|
||||
|
||||
.description {
|
||||
color: var(--Base-Text-Medium-contrast);
|
||||
}
|
||||
|
||||
.ctaContainer {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--Space-x1);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 1367px) {
|
||||
.card:not(.alwaysStack) .ctaContainer {
|
||||
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.card:not(.alwaysStack) .ctaContainer:has(:only-child) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { cva } from "class-variance-authority"
|
||||
|
||||
import styles from "./teaserCard.module.css"
|
||||
|
||||
export const teaserCardVariants = cva(styles.card, {
|
||||
variants: {
|
||||
intent: {
|
||||
default: styles.default,
|
||||
featured: styles.featured,
|
||||
},
|
||||
alwaysStack: {
|
||||
true: styles.alwaysStack,
|
||||
false: "",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
intent: "default",
|
||||
alwaysStack: false,
|
||||
},
|
||||
})
|
||||
@@ -1,27 +0,0 @@
|
||||
import type { ImageVaultAsset } from "@scandic-hotels/common/utils/imageVault"
|
||||
import type { TeaserCard } from "@scandic-hotels/trpc/types/blocks"
|
||||
import type { VariantProps } from "class-variance-authority"
|
||||
|
||||
import type { CardProps } from "@/components/TempDesignSystem/Card/card"
|
||||
import type { teaserCardVariants } from "@/components/TempDesignSystem/TeaserCard/variants"
|
||||
|
||||
interface SidePeekButton {
|
||||
call_to_action_text: string
|
||||
}
|
||||
|
||||
export interface TeaserCardProps
|
||||
extends VariantProps<typeof teaserCardVariants> {
|
||||
title: string
|
||||
description: string
|
||||
primaryButton?: CardProps["primaryButton"]
|
||||
secondaryButton?: CardProps["secondaryButton"]
|
||||
sidePeekButton?: SidePeekButton
|
||||
sidePeekContent?: TeaserCard["sidepeek_content"]
|
||||
image?: ImageVaultAsset
|
||||
className?: string
|
||||
}
|
||||
|
||||
export interface TeaserCardSidepeekProps {
|
||||
button: SidePeekButton
|
||||
sidePeekContent: NonNullable<TeaserCard["sidepeek_content"]>
|
||||
}
|
||||
Reference in New Issue
Block a user