feat(BOOK-62): Added new InfoCard component and using that on hotel pages
Approved-by: Bianca Widstam
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { cx } from 'class-variance-authority'
|
||||
import { MaterialIcon } from '../Icons/MaterialIcon'
|
||||
|
||||
import styles from './imageFallback.module.css'
|
||||
|
||||
interface ImageFallbackProps {
|
||||
interface ImageFallbackProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
width?: string
|
||||
height?: string
|
||||
}
|
||||
@@ -10,9 +11,15 @@ interface ImageFallbackProps {
|
||||
export default function ImageFallback({
|
||||
width = '100%',
|
||||
height = '100%',
|
||||
className,
|
||||
...props
|
||||
}: ImageFallbackProps) {
|
||||
return (
|
||||
<div className={styles.imageFallback} style={{ width, height }}>
|
||||
<div
|
||||
{...props}
|
||||
className={cx(styles.imageFallback, className)}
|
||||
style={{ width, height }}
|
||||
>
|
||||
<MaterialIcon
|
||||
icon="imagesmode"
|
||||
size={32}
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
import type { Meta, StoryObj } from '@storybook/nextjs-vite'
|
||||
|
||||
import { Theme } from '@scandic-hotels/common/utils/theme'
|
||||
import { InfoCard } from './InfoCard.tsx'
|
||||
import { infoCardConfig } from './variants.ts'
|
||||
|
||||
const DEFAULT_ARGS = {
|
||||
topTitle: "Here's to your health!",
|
||||
heading: 'Gym & Wellness',
|
||||
primaryButton: {
|
||||
href: '#',
|
||||
text: 'Primary button',
|
||||
},
|
||||
secondaryButton: {
|
||||
href: '#',
|
||||
text: 'Secondary button',
|
||||
},
|
||||
bodyText:
|
||||
'Our gym is open 24/7 and offers state-of-the-art equipment to help you stay fit during your stay.',
|
||||
}
|
||||
|
||||
const meta: Meta<typeof InfoCard> = {
|
||||
title: 'Components/InfoCard',
|
||||
component: InfoCard,
|
||||
argTypes: {
|
||||
topTitle: {
|
||||
control: 'text',
|
||||
table: {
|
||||
type: { summary: 'string' },
|
||||
},
|
||||
},
|
||||
topTitleAngled: {
|
||||
control: 'boolean',
|
||||
description:
|
||||
'Whether the top title should be angled. Only applies when `hotelTheme` is set to `Theme.scandic`.',
|
||||
type: 'boolean',
|
||||
},
|
||||
heading: {
|
||||
control: 'text',
|
||||
table: {
|
||||
type: { summary: 'string' },
|
||||
},
|
||||
},
|
||||
bodyText: {
|
||||
control: 'text',
|
||||
table: {
|
||||
type: { summary: 'string' },
|
||||
},
|
||||
},
|
||||
theme: {
|
||||
control: 'select',
|
||||
options: Object.keys(infoCardConfig.variants.theme),
|
||||
table: {
|
||||
type: {
|
||||
summary: Object.keys(infoCardConfig.variants.theme).join(' | '),
|
||||
},
|
||||
},
|
||||
},
|
||||
height: {
|
||||
control: 'select',
|
||||
options: Object.keys(infoCardConfig.variants.height),
|
||||
table: {
|
||||
type: {
|
||||
summary: Object.keys(infoCardConfig.variants.height).join(' | '),
|
||||
},
|
||||
},
|
||||
},
|
||||
hotelTheme: {
|
||||
control: 'select',
|
||||
options: Object.keys(infoCardConfig.variants.hotelTheme),
|
||||
description:
|
||||
'The hotel theme to adjust button colors for better contrast.',
|
||||
table: {
|
||||
type: { summary: 'Theme', detail: Object.values(Theme).join(' | ') },
|
||||
},
|
||||
},
|
||||
backgroundImage: {
|
||||
control: 'object',
|
||||
table: {
|
||||
type: {
|
||||
summary: 'InfoCardBackgroundImage',
|
||||
detail:
|
||||
'{ src: string, alt?: string, focalPoint?: { x: number, y: number }, dimensions?: { width: number, height: number, aspectRatio?: number } }',
|
||||
},
|
||||
},
|
||||
},
|
||||
primaryButton: {
|
||||
control: 'object',
|
||||
table: {
|
||||
type: {
|
||||
summary: 'InfoCardButton',
|
||||
detail:
|
||||
'{ href: string, text: string, openInNewTab?: boolean, scrollOnClick?: boolean, onClick?: MouseEventHandler }',
|
||||
},
|
||||
},
|
||||
},
|
||||
secondaryButton: {
|
||||
control: 'object',
|
||||
table: {
|
||||
type: {
|
||||
summary: 'InfoCardButton',
|
||||
detail:
|
||||
'{ href: string, text: string, openInNewTab?: boolean, scrollOnClick?: boolean, onClick?: MouseEventHandler }',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
args: { ...DEFAULT_ARGS },
|
||||
decorators: [
|
||||
(Story, context) => {
|
||||
if (context.name.toLowerCase().indexOf('all themes') >= 0) {
|
||||
return (
|
||||
<div
|
||||
className={context.args.hotelTheme!}
|
||||
style={{ display: 'grid', gap: '1rem' }}
|
||||
>
|
||||
{Object.keys(infoCardConfig.variants.theme).map((theme) => {
|
||||
console.log(theme)
|
||||
const args = {
|
||||
...context.args,
|
||||
backgroundImage:
|
||||
theme === 'Image'
|
||||
? {
|
||||
src: './img/img1.jpg',
|
||||
alt: 'Image alt text',
|
||||
}
|
||||
: undefined,
|
||||
}
|
||||
return (
|
||||
<div style={{ display: 'grid', gap: '0.5rem' }}>
|
||||
<h3>{theme}</h3>
|
||||
<InfoCard
|
||||
{...args}
|
||||
theme={theme as keyof typeof infoCardConfig.variants.theme}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex' }}>
|
||||
<Story />
|
||||
</div>
|
||||
)
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof InfoCard>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
},
|
||||
}
|
||||
|
||||
export const Primary_1: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
theme: 'Primary 1',
|
||||
},
|
||||
}
|
||||
|
||||
export const Primary_2: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
theme: 'Primary 2',
|
||||
},
|
||||
}
|
||||
|
||||
export const Primary_3: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
theme: 'Primary 3',
|
||||
},
|
||||
}
|
||||
|
||||
export const Accent: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
theme: 'Accent',
|
||||
},
|
||||
}
|
||||
|
||||
export const White: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
theme: 'White',
|
||||
},
|
||||
}
|
||||
|
||||
export const Image: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
backgroundImage: {
|
||||
src: './img/img1.jpg',
|
||||
alt: 'Image alt text',
|
||||
},
|
||||
theme: 'Image',
|
||||
},
|
||||
}
|
||||
|
||||
export const AllThemesScandic: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
hotelTheme: Theme.scandic,
|
||||
},
|
||||
}
|
||||
|
||||
export const AllThemesDowntownCamper: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
hotelTheme: Theme.downtownCamper,
|
||||
},
|
||||
}
|
||||
|
||||
export const AllThemesHaymarket: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
hotelTheme: Theme.haymarket,
|
||||
},
|
||||
}
|
||||
|
||||
export const AllThemesScandicGo: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
hotelTheme: Theme.scandicGo,
|
||||
},
|
||||
}
|
||||
|
||||
export const AllThemesGrandHotel: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
hotelTheme: Theme.grandHotel,
|
||||
},
|
||||
}
|
||||
|
||||
export const AllThemesHotelNorge: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
hotelTheme: Theme.hotelNorge,
|
||||
},
|
||||
}
|
||||
|
||||
export const AllThemesMarski: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
hotelTheme: Theme.marski,
|
||||
},
|
||||
}
|
||||
|
||||
export const AllThemesTheDock: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
hotelTheme: Theme.theDock,
|
||||
},
|
||||
}
|
||||
100
packages/design-system/lib/components/InfoCard/InfoCard.tsx
Normal file
100
packages/design-system/lib/components/InfoCard/InfoCard.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import ButtonLink from '../ButtonLink'
|
||||
import Image from '../Image'
|
||||
import { Typography } from '../Typography'
|
||||
|
||||
import { getButtonProps } from './utils'
|
||||
|
||||
import { infoCardVariants } from './variants'
|
||||
|
||||
import styles from './infoCard.module.css'
|
||||
|
||||
import ImageFallback from '../ImageFallback'
|
||||
import type { InfoCardProps } from './types'
|
||||
|
||||
export function InfoCard({
|
||||
primaryButton,
|
||||
secondaryButton,
|
||||
topTitle,
|
||||
heading,
|
||||
bodyText,
|
||||
className,
|
||||
theme,
|
||||
height,
|
||||
backgroundImage,
|
||||
topTitleAngled,
|
||||
hotelTheme,
|
||||
}: InfoCardProps) {
|
||||
const classNames = infoCardVariants({
|
||||
theme,
|
||||
hotelTheme,
|
||||
topTitleAngled,
|
||||
height,
|
||||
className,
|
||||
})
|
||||
const buttonProps = getButtonProps(theme, hotelTheme)
|
||||
|
||||
return (
|
||||
<div className={classNames}>
|
||||
{theme === 'Image' ? (
|
||||
<div className={styles.backgroundImageWrapper}>
|
||||
{backgroundImage ? (
|
||||
<Image
|
||||
src={backgroundImage.src}
|
||||
className={styles.backgroundImage}
|
||||
alt={backgroundImage.alt ?? ''}
|
||||
fill
|
||||
sizes="(min-width: 1367px) 700px, 900px"
|
||||
focalPoint={backgroundImage.focalPoint}
|
||||
dimensions={backgroundImage.dimensions}
|
||||
/>
|
||||
) : (
|
||||
<ImageFallback className={styles.backgroundImage} />
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
<div className={styles.content}>
|
||||
<div className={styles.titleWrapper}>
|
||||
{topTitle ? (
|
||||
<Typography variant="Title/Decorative/md">
|
||||
<span className={styles.topTitle}>{topTitle}</span>
|
||||
</Typography>
|
||||
) : null}
|
||||
<Typography variant="Title/smLowCase">
|
||||
<h3 className={styles.heading}>{heading}</h3>
|
||||
</Typography>
|
||||
</div>
|
||||
{bodyText ? (
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p className={styles.bodyText}>{bodyText}</p>
|
||||
</Typography>
|
||||
) : null}
|
||||
<div className={styles.buttonContainer}>
|
||||
{primaryButton ? (
|
||||
<ButtonLink
|
||||
size="Small"
|
||||
href={primaryButton.href}
|
||||
typography="Body/Supporting text (caption)/smBold"
|
||||
onClick={primaryButton.onClick}
|
||||
scroll={primaryButton.scrollOnClick ?? false}
|
||||
{...buttonProps.primaryButton}
|
||||
>
|
||||
{primaryButton.text}
|
||||
</ButtonLink>
|
||||
) : null}
|
||||
{secondaryButton ? (
|
||||
<ButtonLink
|
||||
size="Small"
|
||||
href={secondaryButton.href}
|
||||
typography="Body/Supporting text (caption)/smBold"
|
||||
onClick={secondaryButton.onClick}
|
||||
scroll={secondaryButton.scrollOnClick ?? false}
|
||||
{...buttonProps.secondaryButton}
|
||||
>
|
||||
{secondaryButton.text}
|
||||
</ButtonLink>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
2
packages/design-system/lib/components/InfoCard/index.tsx
Normal file
2
packages/design-system/lib/components/InfoCard/index.tsx
Normal file
@@ -0,0 +1,2 @@
|
||||
export { InfoCard } from './InfoCard'
|
||||
export type { InfoCardProps } from './types'
|
||||
@@ -0,0 +1,130 @@
|
||||
.infoCard {
|
||||
--background-color: var(--Surface-Brand-Primary-1-Default);
|
||||
--topTitle-color: var(--Text-Brand-OnPrimary-1-Accent);
|
||||
--heading-color: var(--Text-Brand-OnPrimary-1-Heading);
|
||||
--text-color: var(--Text-Brand-OnPrimary-1-Default);
|
||||
position: relative;
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: var(--Corner-radius-md);
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
text-wrap: balance;
|
||||
overflow: hidden;
|
||||
background-color: var(--background-color);
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.height-fixed {
|
||||
height: 320px;
|
||||
}
|
||||
|
||||
.height-dynamic {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.theme-primary-1 {
|
||||
--background-color: var(--Surface-Brand-Primary-1-Default);
|
||||
--topTitle-color: var(--Text-Brand-OnPrimary-1-Accent);
|
||||
--heading-color: var(--Text-Brand-OnPrimary-1-Heading);
|
||||
--text-color: var(--Text-Brand-OnPrimary-1-Default);
|
||||
}
|
||||
.theme-primary-2 {
|
||||
--background-color: var(--Surface-Brand-Primary-2-Default);
|
||||
--topTitle-color: var(--Text-Brand-OnPrimary-2-Accent);
|
||||
--heading-color: var(--Text-Brand-OnPrimary-2-Heading);
|
||||
--text-color: var(--Text-Brand-OnPrimary-2-Default);
|
||||
}
|
||||
.theme-primary-3 {
|
||||
--background-color: var(--Surface-Brand-Primary-3-Default);
|
||||
--topTitle-color: var(--Text-Brand-OnPrimary-3-Accent);
|
||||
--heading-color: var(--Text-Brand-OnPrimary-3-Heading);
|
||||
--text-color: var(--Text-Brand-OnPrimary-3-Default);
|
||||
}
|
||||
.theme-accent {
|
||||
--background-color: var(--Surface-Brand-Accent-Default);
|
||||
--topTitle-color: var(--Text-Brand-OnAccent-Accent);
|
||||
--heading-color: var(--Text-Brand-OnAccent-Heading);
|
||||
--text-color: var(--Text-Brand-OnAccent-Default);
|
||||
}
|
||||
.theme-white {
|
||||
--background-color: var(--Surface-Primary-Default);
|
||||
--topTitle-color: var(--Text-Accent-Primary);
|
||||
--heading-color: var(--Text-Heading);
|
||||
--text-color: var(--Text-Default);
|
||||
}
|
||||
.theme-image {
|
||||
--background-color: transparent;
|
||||
--topTitle-color: var(--Text-Inverted);
|
||||
--heading-color: var(--Text-Inverted);
|
||||
--text-color: var(--Text-Inverted);
|
||||
}
|
||||
|
||||
.titleWrapper {
|
||||
display: grid;
|
||||
gap: var(--Space-x1);
|
||||
justify-items: center;
|
||||
}
|
||||
|
||||
.topTitle {
|
||||
color: var(--topTitle-color);
|
||||
}
|
||||
|
||||
.top-title-angled .topTitle {
|
||||
transform: rotate(-3deg);
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
.heading {
|
||||
color: var(--heading-color);
|
||||
}
|
||||
|
||||
.bodyText {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.backgroundImageWrapper {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
overflow: hidden;
|
||||
z-index: -1;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgba(0, 0, 0, 0) 0%,
|
||||
rgba(0, 0, 0, 0.36) 50%,
|
||||
rgba(0, 0, 0, 0.75) 100%
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
.backgroundImage {
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
height: min(100%, 320px);
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
max-width: 800px;
|
||||
padding: var(--Space-x4) var(--Space-x3);
|
||||
gap: var(--Space-x2);
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--Space-x1);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.primaryButton,
|
||||
.secondaryButton {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
30
packages/design-system/lib/components/InfoCard/types.ts
Normal file
30
packages/design-system/lib/components/InfoCard/types.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import type { VariantProps } from 'class-variance-authority'
|
||||
|
||||
import { MouseEventHandler } from 'react'
|
||||
import type { infoCardVariants } from './variants'
|
||||
|
||||
export type InfoCardBackgroundImage = {
|
||||
src: string
|
||||
alt?: string
|
||||
focalPoint?: { x: number; y: number }
|
||||
dimensions?: { width: number; height: number; aspectRatio?: number }
|
||||
}
|
||||
|
||||
export type InfoCardButton = {
|
||||
href: string
|
||||
text: string
|
||||
openInNewTab?: boolean
|
||||
scrollOnClick?: boolean
|
||||
onClick?: MouseEventHandler<HTMLAnchorElement>
|
||||
}
|
||||
|
||||
export interface InfoCardProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof infoCardVariants> {
|
||||
topTitle?: string | null
|
||||
heading?: string | null
|
||||
bodyText?: string | null
|
||||
backgroundImage?: InfoCardBackgroundImage
|
||||
primaryButton?: InfoCardButton | null
|
||||
secondaryButton?: InfoCardButton | null
|
||||
}
|
||||
166
packages/design-system/lib/components/InfoCard/utils.ts
Normal file
166
packages/design-system/lib/components/InfoCard/utils.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import type { VariantProps } from 'class-variance-authority'
|
||||
|
||||
import { Theme } from '@scandic-hotels/common/utils/theme'
|
||||
import type { variants as buttonVariants } from '../Button/variants'
|
||||
import type { infoCardVariants } from './variants'
|
||||
|
||||
type ButtonVariants = VariantProps<typeof buttonVariants>
|
||||
type InfoCardButtonProps = {
|
||||
primaryButton: {
|
||||
variant: ButtonVariants['variant']
|
||||
color: ButtonVariants['color']
|
||||
}
|
||||
secondaryButton: {
|
||||
variant: ButtonVariants['variant']
|
||||
color: ButtonVariants['color']
|
||||
}
|
||||
}
|
||||
|
||||
const PRIMARY = { variant: 'Primary', color: 'Primary' } as const
|
||||
const PRIMARY_INVERTED = { variant: 'Primary', color: 'Inverted' } as const
|
||||
const SECONDARY = { variant: 'Secondary', color: 'Primary' } as const
|
||||
const SECONDARY_INVERTED = { variant: 'Secondary', color: 'Inverted' } as const
|
||||
const TERTIARY = { variant: 'Tertiary', color: 'Primary' } as const
|
||||
|
||||
// Determine button variant and color based on card theme and hotel theme.
|
||||
// This is done to avoid low contrast issues and conflicting colors in
|
||||
// certain combinations and according to design guidelines.
|
||||
export function getButtonProps(
|
||||
cardTheme: VariantProps<typeof infoCardVariants>['theme'],
|
||||
hotelTheme: Theme | null = Theme.scandic
|
||||
): InfoCardButtonProps {
|
||||
let buttonProps: InfoCardButtonProps = {
|
||||
primaryButton: TERTIARY,
|
||||
secondaryButton: SECONDARY,
|
||||
}
|
||||
|
||||
// Image theme always uses inverted buttons, regardless of hotel theme
|
||||
if (cardTheme === 'Image') {
|
||||
return {
|
||||
primaryButton: PRIMARY_INVERTED,
|
||||
secondaryButton: SECONDARY_INVERTED,
|
||||
}
|
||||
}
|
||||
|
||||
switch (hotelTheme) {
|
||||
case Theme.scandic:
|
||||
if (cardTheme === 'Primary 2' || cardTheme === 'Primary 3') {
|
||||
buttonProps = {
|
||||
primaryButton: PRIMARY_INVERTED,
|
||||
secondaryButton: SECONDARY_INVERTED,
|
||||
}
|
||||
}
|
||||
break
|
||||
case Theme.downtownCamper:
|
||||
if (
|
||||
cardTheme === 'Primary 1' ||
|
||||
cardTheme === 'Primary 2' ||
|
||||
cardTheme === 'Primary 3' ||
|
||||
cardTheme === 'Accent'
|
||||
) {
|
||||
buttonProps = {
|
||||
primaryButton: PRIMARY_INVERTED,
|
||||
secondaryButton: SECONDARY_INVERTED,
|
||||
}
|
||||
}
|
||||
break
|
||||
case Theme.haymarket:
|
||||
if (cardTheme === 'Primary 1' || cardTheme === 'White') {
|
||||
buttonProps = {
|
||||
primaryButton: PRIMARY,
|
||||
secondaryButton: SECONDARY,
|
||||
}
|
||||
} else if (
|
||||
cardTheme === 'Primary 2' ||
|
||||
cardTheme === 'Primary 3' ||
|
||||
cardTheme === 'Accent'
|
||||
) {
|
||||
buttonProps = {
|
||||
primaryButton: PRIMARY_INVERTED,
|
||||
secondaryButton: SECONDARY_INVERTED,
|
||||
}
|
||||
}
|
||||
break
|
||||
case Theme.scandicGo:
|
||||
if (cardTheme === 'Primary 1' || cardTheme === 'Primary 2') {
|
||||
buttonProps = {
|
||||
primaryButton: PRIMARY_INVERTED,
|
||||
secondaryButton: SECONDARY_INVERTED,
|
||||
}
|
||||
}
|
||||
break
|
||||
case Theme.grandHotel:
|
||||
if (
|
||||
cardTheme === 'Primary 2' ||
|
||||
cardTheme === 'Primary 3' ||
|
||||
cardTheme === 'Accent' ||
|
||||
cardTheme === 'White'
|
||||
) {
|
||||
buttonProps = {
|
||||
primaryButton: PRIMARY,
|
||||
secondaryButton: SECONDARY,
|
||||
}
|
||||
} else if (cardTheme === 'Primary 1') {
|
||||
buttonProps = {
|
||||
primaryButton: PRIMARY_INVERTED,
|
||||
secondaryButton: SECONDARY_INVERTED,
|
||||
}
|
||||
}
|
||||
break
|
||||
case Theme.hotelNorge:
|
||||
if (
|
||||
cardTheme === 'Primary 1' ||
|
||||
cardTheme === 'Primary 2' ||
|
||||
cardTheme === 'Primary 3'
|
||||
) {
|
||||
buttonProps = {
|
||||
primaryButton: PRIMARY_INVERTED,
|
||||
secondaryButton: SECONDARY_INVERTED,
|
||||
}
|
||||
}
|
||||
break
|
||||
case Theme.marski:
|
||||
if (cardTheme === 'Primary 1') {
|
||||
buttonProps = {
|
||||
primaryButton: TERTIARY,
|
||||
secondaryButton: SECONDARY_INVERTED,
|
||||
}
|
||||
} else if (cardTheme === 'White') {
|
||||
buttonProps = {
|
||||
primaryButton: PRIMARY,
|
||||
secondaryButton: SECONDARY,
|
||||
}
|
||||
} else if (
|
||||
cardTheme === 'Primary 2' ||
|
||||
cardTheme === 'Primary 3' ||
|
||||
cardTheme === 'Accent'
|
||||
) {
|
||||
buttonProps = {
|
||||
primaryButton: PRIMARY_INVERTED,
|
||||
secondaryButton: SECONDARY_INVERTED,
|
||||
}
|
||||
}
|
||||
break
|
||||
case Theme.theDock:
|
||||
if (
|
||||
cardTheme === 'Primary 1' ||
|
||||
cardTheme === 'Accent' ||
|
||||
cardTheme === 'White'
|
||||
) {
|
||||
buttonProps = {
|
||||
primaryButton: PRIMARY,
|
||||
secondaryButton: SECONDARY,
|
||||
}
|
||||
} else if (cardTheme === 'Primary 2' || cardTheme === 'Primary 3') {
|
||||
buttonProps = {
|
||||
primaryButton: PRIMARY_INVERTED,
|
||||
secondaryButton: SECONDARY_INVERTED,
|
||||
}
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return buttonProps
|
||||
}
|
||||
70
packages/design-system/lib/components/InfoCard/variants.ts
Normal file
70
packages/design-system/lib/components/InfoCard/variants.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { cva } from 'class-variance-authority'
|
||||
|
||||
import { DEFAULT_THEME, Theme } from '@scandic-hotels/common/utils/theme'
|
||||
import styles from './infoCard.module.css'
|
||||
|
||||
const variantKeys = {
|
||||
theme: {
|
||||
'Primary 1': 'Primary 1',
|
||||
'Primary 2': 'Primary 2',
|
||||
'Primary 3': 'Primary 3',
|
||||
Accent: 'Accent',
|
||||
Image: 'Image',
|
||||
White: 'White',
|
||||
},
|
||||
height: {
|
||||
fixed: 'fixed',
|
||||
dynamic: 'dynamic',
|
||||
},
|
||||
} as const
|
||||
|
||||
export const infoCardConfig = {
|
||||
variants: {
|
||||
theme: {
|
||||
[variantKeys.theme['Primary 1']]: styles['theme-primary-1'],
|
||||
[variantKeys.theme['Primary 2']]: styles['theme-primary-2'],
|
||||
[variantKeys.theme['Primary 3']]: styles['theme-primary-3'],
|
||||
[variantKeys.theme['Accent']]: styles['theme-accent'],
|
||||
[variantKeys.theme['Image']]: styles['theme-image'],
|
||||
[variantKeys.theme['White']]: styles['theme-white'],
|
||||
},
|
||||
height: {
|
||||
[variantKeys.height.fixed]: styles['height-fixed'],
|
||||
[variantKeys.height.dynamic]: styles['height-dynamic'],
|
||||
},
|
||||
// Only Theme.scandic can be used with the Angled variant.
|
||||
// The topTitleAngled variant will be applied using the compoundVariants.
|
||||
topTitleAngled: {
|
||||
true: undefined,
|
||||
false: undefined,
|
||||
},
|
||||
// The hotelTheme is not used to apply styles directly,
|
||||
// but is needed for compound variants and to get the correct button color.
|
||||
// The class name for the hotelTheme is applied on page level.
|
||||
hotelTheme: {
|
||||
[Theme.scandic]: undefined,
|
||||
[Theme.downtownCamper]: undefined,
|
||||
[Theme.haymarket]: undefined,
|
||||
[Theme.scandicGo]: undefined,
|
||||
[Theme.grandHotel]: undefined,
|
||||
[Theme.hotelNorge]: undefined,
|
||||
[Theme.marski]: undefined,
|
||||
[Theme.theDock]: undefined,
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
{
|
||||
hotelTheme: Theme.scandic,
|
||||
topTitleAngled: true,
|
||||
class: styles['top-title-angled'],
|
||||
},
|
||||
],
|
||||
defaultVariants: {
|
||||
theme: variantKeys.theme['Primary 1'],
|
||||
height: variantKeys.height.fixed,
|
||||
topTitleAngled: false,
|
||||
hotelTheme: DEFAULT_THEME,
|
||||
},
|
||||
}
|
||||
|
||||
export const infoCardVariants = cva(styles.infoCard, infoCardConfig)
|
||||
@@ -134,6 +134,7 @@
|
||||
"./ImageContainer": "./lib/components/ImageContainer/index.tsx",
|
||||
"./ImageFallback": "./lib/components/ImageFallback/index.tsx",
|
||||
"./ImageGallery": "./lib/components/ImageGallery/index.tsx",
|
||||
"./InfoCard": "./lib/components/InfoCard/index.tsx",
|
||||
"./Input": "./lib/components/Input/index.tsx",
|
||||
"./JsonToHtml": "./lib/components/JsonToHtml/JsonToHtml.tsx",
|
||||
"./Label": "./lib/components/Label/index.tsx",
|
||||
|
||||
Reference in New Issue
Block a user