Merge branch 'develop' of bitbucket.org:scandic-swap/web into feature/tracking

This commit is contained in:
Linus Flood
2024-10-03 15:18:54 +02:00
99 changed files with 3064 additions and 766 deletions

View File

@@ -1,7 +1,6 @@
.btn {
background: none;
/* No variable yet for radius 50px */
border-radius: 50px;
border-radius: var(--Corner-radius-Rounded);
cursor: pointer;
margin: 0;
padding: 0;
@@ -10,12 +9,12 @@
background-color 300ms ease,
color 300ms ease;
/* TODO: Waiting for variables for buttons from Design team */
font-family: var(--typography-Body-Bold-fontFamily);
font-size: var(--typography-Body-Bold-fontSize);
font-weight: 500;
line-height: 24px;
line-height: var(--typography-Body-Bold-lineHeight);
letter-spacing: 0.6%;
text-decoration: none;
}
.wrapping {
@@ -23,6 +22,10 @@
padding-right: 0 !important;
}
.fullWidth {
width: 100%;
}
/* INTENT */
.primary,
a.primary {
@@ -69,21 +72,33 @@ a.default {
}
/* SIZES */
.small {
.btn.small {
font-size: var(--typography-Caption-Bold-fontSize);
line-height: var(--typography-Caption-Bold-lineHeight);
gap: var(--Spacing-x-quarter);
height: 40px;
padding: calc(var(--Spacing-x1) + 2px) var(--Spacing-x2); /* Special case padding to adjust the missing border */
}
.btn.small.secondary {
padding: var(--Spacing-x1) var(--Spacing-x2);
}
.medium {
.btn.medium {
gap: var(--Spacing-x-half);
height: 48px;
padding: calc(var(--Spacing-x-one-and-half) + 2px) var(--Spacing-x2); /* Special case padding to adjust the missing border */
}
.medium.secondary {
padding: var(--Spacing-x-one-and-half) var(--Spacing-x2);
}
.large {
.btn.large {
gap: var(--Spacing-x-half);
padding: calc(var(--Spacing-x2) + 2px) var(--Spacing-x3); /* Special case padding to adjust the missing border */
}
.large.secondary {
gap: var(--Spacing-x-half);
height: 56px;
padding: var(--Spacing-x2) var(--Spacing-x3);
}
@@ -170,19 +185,19 @@ a.default {
fill: var(--Base-Button-Secondary-On-Fill-Disabled);
}
.baseTertiary {
.btn.baseTertiary {
background-color: var(--Base-Button-Tertiary-Fill-Normal);
color: var(--Base-Button-Tertiary-On-Fill-Normal);
}
.baseTertiary:active,
.baseTertiary:focus,
.baseTertiary:hover {
.btn.baseTertiary:active,
.btn.baseTertiary:focus,
.btn.baseTertiary:hover {
background-color: var(--Base-Button-Tertiary-Fill-Hover);
color: var(--Base-Button-Tertiary-On-Fill-Hover);
}
.baseTertiary:disabled {
.btn.baseTertiary:disabled {
background-color: var(--Base-Button-Tertiary-Fill-Disabled);
color: var(--Base-Button-Tertiary-On-Fill-Disabled);
}
@@ -800,4 +815,4 @@ a.default {
.icon.tertiaryLightSecondary:disabled svg,
.icon.tertiaryLightSecondary:disabled svg * {
fill: var(--Tertiary-Light-Button-Secondary-On-Fill-Disabled);
}
}

View File

@@ -8,14 +8,23 @@ import { buttonVariants } from "./variants"
import type { ButtonProps } from "./button"
export default function Button(props: ButtonProps) {
const { className, intent, size, theme, wrapping, variant, ...restProps } =
props
const {
className,
intent,
size,
theme,
fullWidth,
wrapping,
variant,
...restProps
} = props
const classNames = buttonVariants({
className,
intent,
size,
theme,
fullWidth,
wrapping,
variant,
})

View File

@@ -33,6 +33,9 @@ export const buttonVariants = cva(styles.btn, {
wrapping: {
true: styles.wrapping,
},
fullWidth: {
true: styles.fullWidth,
},
},
defaultVariants: {
intent: "primary",

View File

@@ -23,6 +23,8 @@ export interface CardProps
heading?: string | null
bodyText?: string | null
backgroundImage?: ImageVaultAsset
imageHeight?: number
imageWidth?: number
onPrimaryButtonClick?: () => void
onSecondaryButtonClick?: () => void
}

View File

@@ -1,6 +1,7 @@
import Link from "next/link"
import Image from "@/components/Image"
import Button from "@/components/TempDesignSystem/Button"
import Link from "@/components/TempDesignSystem/Link"
import BiroScript from "@/components/TempDesignSystem/Text/BiroScript"
import Body from "@/components/TempDesignSystem/Text/Body"
import Title from "@/components/TempDesignSystem/Text/Title"
@@ -21,10 +22,19 @@ export default function Card({
className,
theme,
backgroundImage,
imageHeight,
imageWidth,
onPrimaryButtonClick,
onSecondaryButtonClick,
}: CardProps) {
const { buttonTheme, primaryLinkColor, secondaryLinkColor } = getTheme(theme)
const buttonTheme = getTheme(theme)
imageHeight = imageHeight || 320
imageWidth =
imageWidth ||
(backgroundImage
? backgroundImage.dimensions.aspectRatio * imageHeight
: 420)
return (
<article
@@ -39,8 +49,8 @@ export default function Card({
src={backgroundImage.url}
className={styles.image}
alt={backgroundImage.meta.alt || backgroundImage.title}
width={backgroundImage.dimensions.width || 420}
height={backgroundImage.dimensions.height || 320}
width={imageWidth}
height={imageHeight}
/>
</div>
)}
@@ -76,7 +86,6 @@ export default function Card({
<Link
href={primaryButton.href}
target={primaryButton.openInNewTab ? "_blank" : undefined}
color={primaryLinkColor}
onClick={onPrimaryButtonClick}
>
{primaryButton.title}
@@ -94,7 +103,6 @@ export default function Card({
<Link
href={secondaryButton.href}
target={secondaryButton.openInNewTab ? "_blank" : undefined}
color={secondaryLinkColor}
onClick={onSecondaryButtonClick}
>
{secondaryButton.title}

View File

@@ -1,36 +1,47 @@
.divider {
border-bottom-style: solid;
border-bottom-width: 1px;
pointer-events: none;
}
.horizontal {
height: 1px;
width: 100%;
}
.dotted {
border-bottom-style: dotted;
.vertical {
height: 100%;
width: 1px;
}
.burgundy {
border-bottom-color: var(--Scandic-Brand-Burgundy);
background-color: var(--Scandic-Brand-Burgundy);
}
.pale {
border-bottom-color: var(--Primary-Dark-On-Surface-Text);
background-color: var(--Primary-Dark-On-Surface-Text);
}
.peach {
border-bottom-color: var(--Primary-Light-On-Surface-Divider);
background-color: var(--Primary-Light-On-Surface-Divider);
}
.beige {
border-bottom-color: var(--Scandic-Beige-20);
background-color: var(--Scandic-Beige-20);
}
.white {
border-bottom-color: var(--UI-Opacity-White-100);
background-color: var(--UI-Opacity-White-100);
}
.subtle {
border-bottom-color: var(--Base-Border-Subtle);
background-color: var(--Base-Border-Subtle);
}
.primaryLightSubtle {
background-color: var(--Primary-Light-On-Surface-Divider-subtle);
}
.baseSurfaceSubtleNormal {
background-color: var(--Base-Surface-Subtle-Normal);
}
.opacity100 {

View File

@@ -5,25 +5,27 @@ import styles from "./divider.module.css"
export const dividerVariants = cva(styles.divider, {
variants: {
color: {
burgundy: styles.burgundy,
peach: styles.peach,
baseSurfaceSubtleNormal: styles.baseSurfaceSubtleNormal,
beige: styles.beige,
white: styles.white,
subtle: styles.subtle,
burgundy: styles.burgundy,
pale: styles.pale,
peach: styles.peach,
primaryLightSubtle: styles.primaryLightSubtle,
subtle: styles.subtle,
white: styles.white,
},
opacity: {
100: styles.opacity100,
8: styles.opacity8,
},
variant: {
default: styles.default,
dotted: styles.dotted,
horizontal: styles.horizontal,
vertical: styles.vertical,
},
},
defaultVariants: {
color: "burgundy",
opacity: 100,
variant: "default",
variant: "horizontal",
},
})

View File

@@ -1,7 +1,7 @@
"use client"
import NextLink from "next/link"
import { usePathname, useRouter } from "next/navigation"
import { startTransition, useCallback } from "react"
import { usePathname, useRouter, useSearchParams } from "next/navigation"
import { startTransition, useCallback, useMemo } from "react"
import { trackClick } from "@/utils/tracking"
@@ -22,9 +22,14 @@ export default function Link({
variant,
trackingId,
onClick,
/**
* Decides if the link should include the current search params in the URL
*/
keepSearchParams,
...props
}: LinkProps) {
const currentPageSlug = usePathname()
const searchParams = useSearchParams()
let isActive = active || currentPageSlug === href
if (partialMatch && !isActive) {
@@ -42,6 +47,12 @@ export default function Link({
const router = useRouter()
const fullUrl = useMemo(() => {
const search =
keepSearchParams && searchParams.size ? `?${searchParams}` : ""
return `${href}${search}`
}, [href, searchParams, keepSearchParams])
const trackClickById = useCallback(() => {
if (trackingId) {
trackClick(trackingId)
@@ -65,12 +76,17 @@ export default function Link({
// track navigation nor start a router transition.
return
}
if (href.startsWith("tel:") || href.startsWith("mailto:")) {
// If href contains tel or mailto protocols we don't want to
// track navigation nor start a router transition.
return
}
e.preventDefault()
startTransition(() => {
router.push(href, { scroll })
router.push(fullUrl, { scroll })
})
}}
href={href}
href={fullUrl}
id={trackingId}
{...props}
/>

View File

@@ -10,4 +10,5 @@ export interface LinkProps
partialMatch?: boolean
prefetch?: boolean
trackingId?: string
keepSearchParams?: boolean
}

View File

@@ -1,7 +1,7 @@
"use client"
import { useIsSSR } from "@react-aria/ssr"
import { useContext } from "react"
import { useContext, useState } from "react"
import {
Dialog,
DialogTrigger,
@@ -29,6 +29,15 @@ function SidePeek({
}: React.PropsWithChildren<SidePeekProps>) {
const isSSR = useIsSSR()
const intl = useIntl()
const [rootDiv, setRootDiv] = useState<HTMLDivElement | undefined>(undefined)
function setRef(node: HTMLDivElement | null) {
if (node) {
setRootDiv(node)
}
}
const context = useContext(SidePeekContext)
function onClose() {
const closeHandler = handleClose || context?.handleClose
@@ -44,42 +53,45 @@ function SidePeek({
)
}
return (
<DialogTrigger>
<ModalOverlay
className={styles.overlay}
isOpen={isOpen || contentKey === context?.activeSidePeek}
onOpenChange={onClose}
isDismissable
>
<Modal className={styles.modal}>
<Dialog className={styles.dialog}>
<aside className={styles.sidePeek}>
<header className={styles.header}>
{title ? (
<Title
color="burgundy"
textTransform="uppercase"
level="h2"
as="h3"
<div ref={setRef}>
<DialogTrigger>
<ModalOverlay
UNSTABLE_portalContainer={rootDiv}
className={styles.overlay}
isOpen={isOpen || contentKey === context?.activeSidePeek}
onOpenChange={onClose}
isDismissable
>
<Modal className={styles.modal}>
<Dialog className={styles.dialog}>
<aside className={styles.sidePeek}>
<header className={styles.header}>
{title ? (
<Title
color="burgundy"
textTransform="uppercase"
level="h2"
as="h3"
>
{title}
</Title>
) : null}
<Button
aria-label={intl.formatMessage({ id: "Close" })}
className={styles.closeButton}
intent="text"
onPress={onClose}
>
{title}
</Title>
) : null}
<Button
aria-label={intl.formatMessage({ id: "Close" })}
className={styles.closeButton}
intent="text"
onPress={onClose}
>
<CloseIcon color="burgundy" height={32} width={32} />
</Button>
</header>
<div className={styles.sidePeekContent}>{children}</div>
</aside>
</Dialog>
</Modal>
</ModalOverlay>
</DialogTrigger>
<CloseIcon color="burgundy" height={32} width={32} />
</Button>
</header>
<div className={styles.sidePeekContent}>{children}</div>
</aside>
</Dialog>
</Modal>
</ModalOverlay>
</DialogTrigger>
</div>
)
}

View File

@@ -78,6 +78,7 @@
.sidePeekContent {
padding: var(--Spacing-x4);
overflow-y: auto;
}
@media screen and (min-width: 1367px) {
.modal {
@@ -94,8 +95,4 @@
.modal[data-exiting] {
animation: slide-in 250ms reverse;
}
.overlay {
top: 0;
}
}

View File

@@ -76,6 +76,10 @@
color: var(--UI-Text-Medium-contrast);
}
.textHighContrast {
color: var(--UI-Text-High-contrast);
}
.white {
color: var(--UI-Opacity-White-100);
}

View File

@@ -11,6 +11,7 @@ const config = {
pale: styles.pale,
red: styles.red,
textMediumContrast: styles.textMediumContrast,
textHighContrast: styles.textHighContrast,
white: styles.white,
peach50: styles.peach50,
peach80: styles.peach80,

View File

@@ -63,6 +63,10 @@ p.caption {
color: var(--UI-Text-Active);
}
.uiTextMediumContrast {
color: var(--UI-Text-Medium-contrast);
}
.center {
text-align: center;
}

View File

@@ -12,6 +12,7 @@ const config = {
red: styles.red,
white: styles.white,
uiTextActive: styles.uiTextActive,
uiTextMediumContrast: styles.uiTextMediumContrast,
},
textTransform: {
bold: styles.bold,