feat(SW-1806): Implemented design systems button inside buttonLink component and changed teasercard buttons

Approved-by: Matilda Landström
This commit is contained in:
Erik Tiekstra
2025-03-28 06:56:08 +00:00
parent 2f0224cfd5
commit 45c992dcef
14 changed files with 152 additions and 91 deletions

View File

@@ -14,7 +14,10 @@ export default function ShortcutsListItems({
return (
<ul className={`${styles.list} ${className}`}>
{shortcutsListItems.map((shortcut) => (
<li key={shortcut.title} className={styles.listItem}>
<li
key={`${shortcut.text}_${shortcut.url}`}
className={styles.listItem}
>
<Link
href={shortcut.url}
target={shortcut.openInNewTab ? "_blank" : undefined}

View File

@@ -0,0 +1,9 @@
.buttonLink {
border-radius: var(--Corner-radius-rounded);
border-width: 2px;
border-style: solid;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}

View File

@@ -1,25 +1,47 @@
"use client"
import NextLink from "next/link"
import Link from "next/link"
import { usePathname } from "next/navigation"
import { useMemo } from "react"
import { type ComponentProps, type PropsWithChildren, useMemo } from "react"
import Button from "@/components/TempDesignSystem/Button"
import { trackClick } from "@/utils/tracking"
import type { ButtonLinkProps } from "@/types/components/buttonLink"
import { variants } from "./variants"
import type { VariantProps } from "class-variance-authority"
export interface ButtonLinkProps
extends PropsWithChildren,
Omit<ComponentProps<typeof Link>, "color">,
VariantProps<typeof variants> {
trackingId?: string
trackingParams?: Record<string, string>
appendToCurrentPath?: boolean
}
export default function ButtonLink({
children,
variant,
color,
size,
typography,
className,
href,
target,
onClick = () => {},
trackingId,
trackingParams,
onClick = () => {},
appendToCurrentPath,
...buttonProps
...props
}: ButtonLinkProps) {
const currentPageSlug = usePathname()
const classNames = variants({
variant,
color,
size,
typography,
className,
})
const fullUrl = useMemo(() => {
let newPath = href
@@ -31,19 +53,17 @@ export default function ButtonLink({
}, [href, appendToCurrentPath, currentPageSlug])
return (
<Button {...buttonProps} asChild>
<NextLink
href={fullUrl}
target={target}
onClick={(e) => {
onClick(e)
if (trackingId) {
trackClick(trackingId, trackingParams)
}
}}
>
{children}
</NextLink>
</Button>
<Link
className={classNames}
href={fullUrl}
target={target}
onClick={(e) => {
onClick(e)
if (trackingId) {
trackClick(trackingId, trackingParams)
}
}}
{...props}
/>
)
}

View File

@@ -0,0 +1,7 @@
import { cva } from "class-variance-authority"
import { withButton } from "@scandic-hotels/design-system/Button"
import styles from "./buttonLink.module.css"
export const variants = cva(styles.buttonLink, withButton({}))

View File

@@ -30,7 +30,10 @@ export default async function AccessibilityAmenity({
{accessibilityPageUrl && (
<ButtonLink
href={`/${accessibilityPageUrl}`}
intent="secondary"
variant="Secondary"
color="Primary"
size="Medium"
typography="Body/Paragraph/mdBold"
appendToCurrentPath
>
{intl.formatMessage({ id: "About accessibility" })}

View File

@@ -30,7 +30,10 @@ export default async function ParkingAmenity({
{parkingPageUrl && (
<ButtonLink
href={`/${parkingPageUrl}`}
intent="secondary"
variant="Secondary"
color="Primary"
size="Medium"
typography="Body/Paragraph/mdBold"
appendToCurrentPath
>
{intl.formatMessage({ id: "About parking" })}

View File

@@ -102,9 +102,10 @@ export default async function RestaurantBarItem({
<div className={styles.ctaWrapper}>
{bookTableUrl ? (
<ButtonLink
fullWidth
theme="base"
intent="primary"
variant="Primary"
color="Primary"
size="Medium"
typography="Body/Paragraph/mdBold"
href={bookTableUrl}
target="_blank"
trackingId="book a table"
@@ -117,9 +118,10 @@ export default async function RestaurantBarItem({
) : null}
{restaurantPage && mainBody?.length ? (
<ButtonLink
fullWidth
theme="base"
intent="secondary"
variant="Secondary"
color="Primary"
size="Medium"
typography="Body/Paragraph/mdBold"
href={`/${restaurant.nameInUrl}`}
appendToCurrentPath
>

View File

@@ -2,12 +2,12 @@
import { useState } from "react"
import { Button } from "@scandic-hotels/design-system/Button"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons"
import ButtonLink from "@/components/ButtonLink"
import JsonToHtml from "@/components/JsonToHtml"
import Button from "@/components/TempDesignSystem/Button"
import Link from "../../Link"
import SidePeek from "../../SidePeek"
import styles from "./sidepeek.module.css"
@@ -22,14 +22,13 @@ export default function TeaserCardSidepeek({
const { heading, content, primary_button, secondary_button } = sidePeekContent
return (
<div>
<div className={styles.teaserCardSidepeek}>
<Button
onPress={() => setSidePeekIsOpen(true)}
theme="base"
variant="icon"
intent="text"
size="small"
wrapping
variant="Secondary"
color="Primary"
size="Small"
typography="Body/Supporting text (caption)/smBold"
>
{button.call_to_action_text}
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />
@@ -46,25 +45,28 @@ export default function TeaserCardSidepeek({
/>
<div className={styles.ctaContainer}>
{primary_button && (
<Button asChild theme="base" intent="primary" size="small">
<Link
href={primary_button.href}
target={primary_button.openInNewTab ? "_blank" : undefined}
color="none"
>
{primary_button.title}
</Link>
</Button>
<ButtonLink
variant="Primary"
color="Primary"
size="Small"
typography="Body/Supporting text (caption)/smBold"
href={primary_button.href}
target={primary_button.openInNewTab ? "_blank" : undefined}
>
{primary_button.title}
</ButtonLink>
)}
{secondary_button && (
<Button asChild intent="secondary" size="small">
<Link
href={secondary_button.href}
target={secondary_button.openInNewTab ? "_blank" : undefined}
>
{secondary_button.title}
</Link>
</Button>
<ButtonLink
variant="Secondary"
color="Primary"
size="Small"
typography="Body/Supporting text (caption)/smBold"
href={secondary_button.href}
target={secondary_button.openInNewTab ? "_blank" : undefined}
>
{secondary_button.title}
</ButtonLink>
)}
</div>
</SidePeek>

View File

@@ -1,3 +1,7 @@
.teaserCardSidepeek {
display: grid;
}
.ctaContainer {
display: grid;
gap: var(--Spacing-x2);

View File

@@ -1,6 +1,5 @@
import ButtonLink from "@/components/ButtonLink"
import Image from "@/components/Image"
import Button from "@/components/TempDesignSystem/Button"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import Subtitle from "../Text/Subtitle"
@@ -51,37 +50,30 @@ export default function TeaserCard({
) : (
<div className={styles.ctaContainer}>
{primaryButton && (
<Button
asChild
intent="primary"
size="small"
<ButtonLink
variant="Tertiary"
color="Primary"
size="Small"
typography="Body/Supporting text (caption)/smBold"
className={styles.ctaButton}
href={primaryButton.href}
target={primaryButton.openInNewTab ? "_blank" : undefined}
>
<Link
href={primaryButton.href}
target={primaryButton.openInNewTab ? "_blank" : undefined}
color="none"
>
{primaryButton.title}
</Link>
</Button>
{primaryButton.title}
</ButtonLink>
)}
{secondaryButton && (
<Button
asChild
intent="secondary"
size="small"
<ButtonLink
variant="Secondary"
color="Primary"
size="Small"
typography="Body/Supporting text (caption)/smBold"
className={styles.ctaButton}
href={secondaryButton.href}
target={secondaryButton.openInNewTab ? "_blank" : undefined}
>
<Link
href={secondaryButton.href}
target={secondaryButton.openInNewTab ? "_blank" : undefined}
color="burgundy"
weight="bold"
>
{secondaryButton.title}
</Link>
</Button>
{secondaryButton.title}
</ButtonLink>
)}
</div>
)}

View File

@@ -48,10 +48,6 @@
width: 100%;
}
.ctaButton {
width: 100%;
}
@media (min-width: 1367px) {
.card:not(.alwaysStack) .ctaContainer {
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));

View File

@@ -3,6 +3,9 @@
border-width: 2px;
border-style: solid;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.size-large {
@@ -85,10 +88,6 @@
color: inherit;
padding: 0;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
}
.color-icon-default {

View File

@@ -1 +1,3 @@
export { Button } from './Button'
// eslint-disable-next-line react-refresh/only-export-components
export { withButton } from './variants'

View File

@@ -1,7 +1,11 @@
import { cva } from 'class-variance-authority'
import { withTypography } from '../Typography/variants'
import {
config as typographyConfig,
withTypography,
} from '../Typography/variants'
import { deepmerge } from 'deepmerge-ts'
import styles from './button.module.css'
export const config = {
@@ -32,3 +36,18 @@ export const config = {
} as const
export const variants = cva(styles.button, withTypography(config))
const buttonConfig = {
variants: {
...config.variants,
typography: typographyConfig.variants.variant,
},
defaultVariants: {
...config.defaultVariants,
typography: typographyConfig.defaultVariants.variant,
},
} as const
export function withButton<T>(config: T) {
return deepmerge(buttonConfig, config)
}