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 (
|
return (
|
||||||
<ul className={`${styles.list} ${className}`}>
|
<ul className={`${styles.list} ${className}`}>
|
||||||
{shortcutsListItems.map((shortcut) => (
|
{shortcutsListItems.map((shortcut) => (
|
||||||
<li key={shortcut.title} className={styles.listItem}>
|
<li
|
||||||
|
key={`${shortcut.text}_${shortcut.url}`}
|
||||||
|
className={styles.listItem}
|
||||||
|
>
|
||||||
<Link
|
<Link
|
||||||
href={shortcut.url}
|
href={shortcut.url}
|
||||||
target={shortcut.openInNewTab ? "_blank" : undefined}
|
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"
|
"use client"
|
||||||
|
|
||||||
import NextLink from "next/link"
|
import Link from "next/link"
|
||||||
import { usePathname } from "next/navigation"
|
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 { 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({
|
export default function ButtonLink({
|
||||||
children,
|
variant,
|
||||||
|
color,
|
||||||
|
size,
|
||||||
|
typography,
|
||||||
|
className,
|
||||||
href,
|
href,
|
||||||
target,
|
target,
|
||||||
|
onClick = () => {},
|
||||||
trackingId,
|
trackingId,
|
||||||
trackingParams,
|
trackingParams,
|
||||||
onClick = () => {},
|
|
||||||
appendToCurrentPath,
|
appendToCurrentPath,
|
||||||
...buttonProps
|
...props
|
||||||
}: ButtonLinkProps) {
|
}: ButtonLinkProps) {
|
||||||
const currentPageSlug = usePathname()
|
const currentPageSlug = usePathname()
|
||||||
|
const classNames = variants({
|
||||||
|
variant,
|
||||||
|
color,
|
||||||
|
size,
|
||||||
|
|
||||||
|
typography,
|
||||||
|
className,
|
||||||
|
})
|
||||||
|
|
||||||
const fullUrl = useMemo(() => {
|
const fullUrl = useMemo(() => {
|
||||||
let newPath = href
|
let newPath = href
|
||||||
@@ -31,19 +53,17 @@ export default function ButtonLink({
|
|||||||
}, [href, appendToCurrentPath, currentPageSlug])
|
}, [href, appendToCurrentPath, currentPageSlug])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button {...buttonProps} asChild>
|
<Link
|
||||||
<NextLink
|
className={classNames}
|
||||||
href={fullUrl}
|
href={fullUrl}
|
||||||
target={target}
|
target={target}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
onClick(e)
|
onClick(e)
|
||||||
if (trackingId) {
|
if (trackingId) {
|
||||||
trackClick(trackingId, trackingParams)
|
trackClick(trackingId, trackingParams)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
{...props}
|
||||||
{children}
|
/>
|
||||||
</NextLink>
|
|
||||||
</Button>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
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 && (
|
{accessibilityPageUrl && (
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
href={`/${accessibilityPageUrl}`}
|
href={`/${accessibilityPageUrl}`}
|
||||||
intent="secondary"
|
variant="Secondary"
|
||||||
|
color="Primary"
|
||||||
|
size="Medium"
|
||||||
|
typography="Body/Paragraph/mdBold"
|
||||||
appendToCurrentPath
|
appendToCurrentPath
|
||||||
>
|
>
|
||||||
{intl.formatMessage({ id: "About accessibility" })}
|
{intl.formatMessage({ id: "About accessibility" })}
|
||||||
|
|||||||
@@ -30,7 +30,10 @@ export default async function ParkingAmenity({
|
|||||||
{parkingPageUrl && (
|
{parkingPageUrl && (
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
href={`/${parkingPageUrl}`}
|
href={`/${parkingPageUrl}`}
|
||||||
intent="secondary"
|
variant="Secondary"
|
||||||
|
color="Primary"
|
||||||
|
size="Medium"
|
||||||
|
typography="Body/Paragraph/mdBold"
|
||||||
appendToCurrentPath
|
appendToCurrentPath
|
||||||
>
|
>
|
||||||
{intl.formatMessage({ id: "About parking" })}
|
{intl.formatMessage({ id: "About parking" })}
|
||||||
|
|||||||
@@ -102,9 +102,10 @@ export default async function RestaurantBarItem({
|
|||||||
<div className={styles.ctaWrapper}>
|
<div className={styles.ctaWrapper}>
|
||||||
{bookTableUrl ? (
|
{bookTableUrl ? (
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
fullWidth
|
variant="Primary"
|
||||||
theme="base"
|
color="Primary"
|
||||||
intent="primary"
|
size="Medium"
|
||||||
|
typography="Body/Paragraph/mdBold"
|
||||||
href={bookTableUrl}
|
href={bookTableUrl}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
trackingId="book a table"
|
trackingId="book a table"
|
||||||
@@ -117,9 +118,10 @@ export default async function RestaurantBarItem({
|
|||||||
) : null}
|
) : null}
|
||||||
{restaurantPage && mainBody?.length ? (
|
{restaurantPage && mainBody?.length ? (
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
fullWidth
|
variant="Secondary"
|
||||||
theme="base"
|
color="Primary"
|
||||||
intent="secondary"
|
size="Medium"
|
||||||
|
typography="Body/Paragraph/mdBold"
|
||||||
href={`/${restaurant.nameInUrl}`}
|
href={`/${restaurant.nameInUrl}`}
|
||||||
appendToCurrentPath
|
appendToCurrentPath
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
|
import { Button } from "@scandic-hotels/design-system/Button"
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons"
|
||||||
|
|
||||||
|
import ButtonLink from "@/components/ButtonLink"
|
||||||
import JsonToHtml from "@/components/JsonToHtml"
|
import JsonToHtml from "@/components/JsonToHtml"
|
||||||
import Button from "@/components/TempDesignSystem/Button"
|
|
||||||
|
|
||||||
import Link from "../../Link"
|
|
||||||
import SidePeek from "../../SidePeek"
|
import SidePeek from "../../SidePeek"
|
||||||
|
|
||||||
import styles from "./sidepeek.module.css"
|
import styles from "./sidepeek.module.css"
|
||||||
@@ -22,14 +22,13 @@ export default function TeaserCardSidepeek({
|
|||||||
const { heading, content, primary_button, secondary_button } = sidePeekContent
|
const { heading, content, primary_button, secondary_button } = sidePeekContent
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={styles.teaserCardSidepeek}>
|
||||||
<Button
|
<Button
|
||||||
onPress={() => setSidePeekIsOpen(true)}
|
onPress={() => setSidePeekIsOpen(true)}
|
||||||
theme="base"
|
variant="Secondary"
|
||||||
variant="icon"
|
color="Primary"
|
||||||
intent="text"
|
size="Small"
|
||||||
size="small"
|
typography="Body/Supporting text (caption)/smBold"
|
||||||
wrapping
|
|
||||||
>
|
>
|
||||||
{button.call_to_action_text}
|
{button.call_to_action_text}
|
||||||
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />
|
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />
|
||||||
@@ -46,25 +45,28 @@ export default function TeaserCardSidepeek({
|
|||||||
/>
|
/>
|
||||||
<div className={styles.ctaContainer}>
|
<div className={styles.ctaContainer}>
|
||||||
{primary_button && (
|
{primary_button && (
|
||||||
<Button asChild theme="base" intent="primary" size="small">
|
<ButtonLink
|
||||||
<Link
|
variant="Primary"
|
||||||
href={primary_button.href}
|
color="Primary"
|
||||||
target={primary_button.openInNewTab ? "_blank" : undefined}
|
size="Small"
|
||||||
color="none"
|
typography="Body/Supporting text (caption)/smBold"
|
||||||
>
|
href={primary_button.href}
|
||||||
{primary_button.title}
|
target={primary_button.openInNewTab ? "_blank" : undefined}
|
||||||
</Link>
|
>
|
||||||
</Button>
|
{primary_button.title}
|
||||||
|
</ButtonLink>
|
||||||
)}
|
)}
|
||||||
{secondary_button && (
|
{secondary_button && (
|
||||||
<Button asChild intent="secondary" size="small">
|
<ButtonLink
|
||||||
<Link
|
variant="Secondary"
|
||||||
href={secondary_button.href}
|
color="Primary"
|
||||||
target={secondary_button.openInNewTab ? "_blank" : undefined}
|
size="Small"
|
||||||
>
|
typography="Body/Supporting text (caption)/smBold"
|
||||||
{secondary_button.title}
|
href={secondary_button.href}
|
||||||
</Link>
|
target={secondary_button.openInNewTab ? "_blank" : undefined}
|
||||||
</Button>
|
>
|
||||||
|
{secondary_button.title}
|
||||||
|
</ButtonLink>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</SidePeek>
|
</SidePeek>
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
.teaserCardSidepeek {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
.ctaContainer {
|
.ctaContainer {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--Spacing-x2);
|
gap: var(--Spacing-x2);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
|
import ButtonLink from "@/components/ButtonLink"
|
||||||
import Image from "@/components/Image"
|
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 Body from "@/components/TempDesignSystem/Text/Body"
|
||||||
|
|
||||||
import Subtitle from "../Text/Subtitle"
|
import Subtitle from "../Text/Subtitle"
|
||||||
@@ -51,37 +50,30 @@ export default function TeaserCard({
|
|||||||
) : (
|
) : (
|
||||||
<div className={styles.ctaContainer}>
|
<div className={styles.ctaContainer}>
|
||||||
{primaryButton && (
|
{primaryButton && (
|
||||||
<Button
|
<ButtonLink
|
||||||
asChild
|
variant="Tertiary"
|
||||||
intent="primary"
|
color="Primary"
|
||||||
size="small"
|
size="Small"
|
||||||
|
typography="Body/Supporting text (caption)/smBold"
|
||||||
className={styles.ctaButton}
|
className={styles.ctaButton}
|
||||||
|
href={primaryButton.href}
|
||||||
|
target={primaryButton.openInNewTab ? "_blank" : undefined}
|
||||||
>
|
>
|
||||||
<Link
|
{primaryButton.title}
|
||||||
href={primaryButton.href}
|
</ButtonLink>
|
||||||
target={primaryButton.openInNewTab ? "_blank" : undefined}
|
|
||||||
color="none"
|
|
||||||
>
|
|
||||||
{primaryButton.title}
|
|
||||||
</Link>
|
|
||||||
</Button>
|
|
||||||
)}
|
)}
|
||||||
{secondaryButton && (
|
{secondaryButton && (
|
||||||
<Button
|
<ButtonLink
|
||||||
asChild
|
variant="Secondary"
|
||||||
intent="secondary"
|
color="Primary"
|
||||||
size="small"
|
size="Small"
|
||||||
|
typography="Body/Supporting text (caption)/smBold"
|
||||||
className={styles.ctaButton}
|
className={styles.ctaButton}
|
||||||
|
href={secondaryButton.href}
|
||||||
|
target={secondaryButton.openInNewTab ? "_blank" : undefined}
|
||||||
>
|
>
|
||||||
<Link
|
{secondaryButton.title}
|
||||||
href={secondaryButton.href}
|
</ButtonLink>
|
||||||
target={secondaryButton.openInNewTab ? "_blank" : undefined}
|
|
||||||
color="burgundy"
|
|
||||||
weight="bold"
|
|
||||||
>
|
|
||||||
{secondaryButton.title}
|
|
||||||
</Link>
|
|
||||||
</Button>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -48,10 +48,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ctaButton {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1367px) {
|
@media (min-width: 1367px) {
|
||||||
.card:not(.alwaysStack) .ctaContainer {
|
.card:not(.alwaysStack) .ctaContainer {
|
||||||
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
border-width: 2px;
|
border-width: 2px;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.size-large {
|
.size-large {
|
||||||
@@ -85,10 +88,6 @@
|
|||||||
color: inherit;
|
color: inherit;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-icon-default {
|
.color-icon-default {
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
export { Button } from './Button'
|
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 { 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'
|
import styles from './button.module.css'
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
@@ -32,3 +36,18 @@ export const config = {
|
|||||||
} as const
|
} as const
|
||||||
|
|
||||||
export const variants = cva(styles.button, withTypography(config))
|
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