feat(SW-1806): Implemented design systems button inside buttonLink component and changed teasercard buttons
Approved-by: Matilda Landström
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
7
apps/scandic-web/components/ButtonLink/variants.ts
Normal file
7
apps/scandic-web/components/ButtonLink/variants.ts
Normal 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({}))
|
||||
@@ -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" })}
|
||||
|
||||
@@ -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" })}
|
||||
|
||||
@@ -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
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
.teaserCardSidepeek {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.ctaContainer {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x2);
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
export { Button } from './Button'
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
export { withButton } from './variants'
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user