Merged in feat/reusable-card (pull request #190)
Feat/reusable card and button design Approved-by: Michael Zetterberg
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
.layout {
|
.layout {
|
||||||
--header-height: 4.5rem;
|
--header-height: 4.5rem;
|
||||||
|
|
||||||
background-color: var(--Brand-Coffee-Subtle);
|
background-color: var(--Scandic-Brand-Warm-White);
|
||||||
display: grid;
|
display: grid;
|
||||||
font-family: var(--ff-fira-sans);
|
font-family: var(--ff-fira-sans);
|
||||||
grid-template-rows: var(--header-height) auto 1fr;
|
grid-template-rows: var(--header-height) auto 1fr;
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ export default function EditProfile({ params }: PageArgs<LangParams>) {
|
|||||||
<Button
|
<Button
|
||||||
aria-label="Cancel"
|
aria-label="Cancel"
|
||||||
asChild
|
asChild
|
||||||
bgcolor="white"
|
|
||||||
form="edit-profile"
|
form="edit-profile"
|
||||||
size="small"
|
size="small"
|
||||||
type="reset"
|
type="reset"
|
||||||
@@ -24,12 +23,10 @@ export default function EditProfile({ params }: PageArgs<LangParams>) {
|
|||||||
<Link href={profile[params.lang]}>{_("Cancel")}</Link>
|
<Link href={profile[params.lang]}>{_("Cancel")}</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
bgcolor="quarternary"
|
|
||||||
disabled={!isValid || isPending}
|
disabled={!isValid || isPending}
|
||||||
form="edit-profile"
|
form="edit-profile"
|
||||||
size="small"
|
size="small"
|
||||||
type="submit"
|
type="submit"
|
||||||
weight="regular"
|
|
||||||
>
|
>
|
||||||
{_("Save")}
|
{_("Save")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import type { LangParams, PageArgs } from "@/types/params"
|
|||||||
|
|
||||||
export default function ProfileView({ params }: PageArgs<LangParams>) {
|
export default function ProfileView({ params }: PageArgs<LangParams>) {
|
||||||
return (
|
return (
|
||||||
<Button asChild bgcolor="quarternary" size="small" weight="regular">
|
<Button asChild size="small">
|
||||||
<Link href={profileEdit[params.lang]}>{_("Edit")}</Link>
|
<Link href={profileEdit[params.lang]}>{_("Edit")}</Link>
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.layout {
|
.layout {
|
||||||
display: grid;
|
display: grid;
|
||||||
font-family: var(--ff-fira-sans);
|
font-family: var(--ff-fira-sans);
|
||||||
background-color: var(--Brand-Coffee-Subtle);
|
background-color: var(--Scandic-Brand-Warm-White);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { firaMono, firaSans } from "@/app/[lang]/(live)/fonts"
|
|
||||||
|
|
||||||
import styles from "./layout.module.css"
|
import styles from "./layout.module.css"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -11,15 +9,8 @@ import {
|
|||||||
|
|
||||||
export default function ContentTypeLayout({
|
export default function ContentTypeLayout({
|
||||||
children,
|
children,
|
||||||
params,
|
|
||||||
}: React.PropsWithChildren<
|
}: React.PropsWithChildren<
|
||||||
LayoutArgs<LangParams & ContentTypeParams & UIDParams>
|
LayoutArgs<LangParams & ContentTypeParams & UIDParams>
|
||||||
>) {
|
>) {
|
||||||
return (
|
return <div className={styles.layout}>{children}</div>
|
||||||
<div
|
|
||||||
className={`${firaMono.variable} ${firaSans.variable} ${styles.layout}`}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Fira_Mono, Fira_Sans } from "next/font/google"
|
import { Fira_Mono, Fira_Sans } from "next/font/google"
|
||||||
|
import localFont from "next/font/local"
|
||||||
|
|
||||||
export const firaMono = Fira_Mono({
|
export const firaMono = Fira_Mono({
|
||||||
subsets: ["latin"],
|
subsets: ["latin"],
|
||||||
@@ -11,3 +12,14 @@ export const firaSans = Fira_Sans({
|
|||||||
weight: ["300", "400", "600", "900"],
|
weight: ["300", "400", "600", "900"],
|
||||||
variable: "--ff-fira-sans",
|
variable: "--ff-fira-sans",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const biroScriptPlus = localFont({
|
||||||
|
src: [
|
||||||
|
{
|
||||||
|
path: "../../../public/_static/fonts/biro-script-plus/Biro-Script-Plus.ttf",
|
||||||
|
style: "normal",
|
||||||
|
weight: "500",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
variable: "--ff-biro-script-plus",
|
||||||
|
})
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import TrpcProvider from "@/lib/trpc/Provider"
|
|||||||
import AdobeScript from "@/components/Current/AdobeScript"
|
import AdobeScript from "@/components/Current/AdobeScript"
|
||||||
import VwoScript from "@/components/Current/VwoScript"
|
import VwoScript from "@/components/Current/VwoScript"
|
||||||
|
|
||||||
|
import { biroScriptPlus, firaMono, firaSans } from "./fonts"
|
||||||
|
|
||||||
import type { Metadata } from "next"
|
import type { Metadata } from "next"
|
||||||
|
|
||||||
import type { LangParams, LayoutArgs } from "@/types/params"
|
import type { LangParams, LayoutArgs } from "@/types/params"
|
||||||
@@ -42,7 +44,9 @@ export default async function RootLayout({
|
|||||||
<AdobeScript />
|
<AdobeScript />
|
||||||
<VwoScript />
|
<VwoScript />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body
|
||||||
|
className={`${firaMono.variable} ${firaSans.variable} ${biroScriptPlus.variable} `}
|
||||||
|
>
|
||||||
<TrpcProvider lang={params.lang}>{children}</TrpcProvider>
|
<TrpcProvider lang={params.lang}>{children}</TrpcProvider>
|
||||||
<Script id="page-tracking">{`
|
<Script id="page-tracking">{`
|
||||||
typeof _satellite !== "undefined" && _satellite.pageBottom();
|
typeof _satellite !== "undefined" && _satellite.pageBottom();
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ import type {
|
|||||||
import { RTEMarkType } from "@/types/rte/node"
|
import { RTEMarkType } from "@/types/rte/node"
|
||||||
import type { RenderOptions } from "@/types/rte/option"
|
import type { RenderOptions } from "@/types/rte/option"
|
||||||
|
|
||||||
function extractPossibleAttributes(attrs: Attributes) {
|
function extractPossibleAttributes(attrs: Attributes | undefined) {
|
||||||
|
if (!attrs) return {}
|
||||||
const props: Record<string, any> = {}
|
const props: Record<string, any> = {}
|
||||||
if (attrs.id) {
|
if (attrs.id) {
|
||||||
props.id = attrs.id
|
props.id = attrs.id
|
||||||
@@ -252,7 +253,7 @@ export const renderOptions: RenderOptions = {
|
|||||||
const type = node.attrs.type
|
const type = node.attrs.type
|
||||||
if (type === RTEItemTypeEnum.asset) {
|
if (type === RTEItemTypeEnum.asset) {
|
||||||
const image = embeds?.[node?.attrs?.["asset-uid"]]
|
const image = embeds?.[node?.attrs?.["asset-uid"]]
|
||||||
if (image.node.__typename === EmbedEnum.SysAsset) {
|
if (image?.node.__typename === EmbedEnum.SysAsset) {
|
||||||
const alt = image?.node?.title ?? node.attrs.alt
|
const alt = image?.node?.title ?? node.attrs.alt
|
||||||
const alignment = node.attrs?.style?.["text-align"]
|
const alignment = node.attrs?.style?.["text-align"]
|
||||||
? {
|
? {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import type { RenderOptions } from "@/types/rte/option"
|
|||||||
|
|
||||||
export function groupEmbedsByUid(embedsArray: Node<Embeds>[]) {
|
export function groupEmbedsByUid(embedsArray: Node<Embeds>[]) {
|
||||||
const embedsByUid = embedsArray.reduce<EmbedByUid>((acc, embed) => {
|
const embedsByUid = embedsArray.reduce<EmbedByUid>((acc, embed) => {
|
||||||
if (embed.node.system.uid) {
|
if (embed.node.system?.uid) {
|
||||||
acc[embed.node.system.uid] = embed
|
acc[embed.node.system.uid] = embed
|
||||||
}
|
}
|
||||||
return acc
|
return acc
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
.container {
|
|
||||||
display: grid;
|
|
||||||
gap: 2.4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.titleContainer {
|
|
||||||
display: grid;
|
|
||||||
gap: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cardContainer {
|
|
||||||
display: grid;
|
|
||||||
gap: 1.6rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 950px) {
|
|
||||||
.cardContainer {
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cardWrapper:last-child {
|
|
||||||
grid-column: span 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import { _ } from "@/lib/translation"
|
|
||||||
|
|
||||||
import Card from "@/components/TempDesignSystem/Card"
|
|
||||||
import Title from "@/components/Title"
|
|
||||||
|
|
||||||
import styles from "./cardGrid.module.css"
|
|
||||||
|
|
||||||
import { CardGridProps } from "@/types/components/loyalty/blocks"
|
|
||||||
|
|
||||||
export default function CardGrid({ card_grid }: CardGridProps) {
|
|
||||||
return (
|
|
||||||
<section className={styles.container}>
|
|
||||||
<header className={styles.titleContainer}>
|
|
||||||
<Title as="h3" level="h2" weight="semiBold" uppercase>
|
|
||||||
{card_grid.title}
|
|
||||||
</Title>
|
|
||||||
{card_grid.subtitle ? (
|
|
||||||
<Title
|
|
||||||
as="h5"
|
|
||||||
level="h3"
|
|
||||||
weight="regular"
|
|
||||||
className={styles.subtitle}
|
|
||||||
>
|
|
||||||
{card_grid.subtitle}
|
|
||||||
</Title>
|
|
||||||
) : null}
|
|
||||||
</header>
|
|
||||||
<div className={styles.cardContainer}>
|
|
||||||
{card_grid.cards.map((card, i) => (
|
|
||||||
<div className={styles.cardWrapper} key={`${card.title}+${i}`}>
|
|
||||||
<Card
|
|
||||||
subtitle={card.subtitle}
|
|
||||||
title={card.title}
|
|
||||||
link={card.link}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
4
components/Loyalty/Blocks/CardsGrid/cardsGrid.module.css
Normal file
4
components/Loyalty/Blocks/CardsGrid/cardsGrid.module.css
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
.section {
|
||||||
|
display: grid;
|
||||||
|
gap: 2.4rem;
|
||||||
|
}
|
||||||
30
components/Loyalty/Blocks/CardsGrid/index.tsx
Normal file
30
components/Loyalty/Blocks/CardsGrid/index.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { _ } from "@/lib/translation"
|
||||||
|
|
||||||
|
import Header from "@/components/MyPages/Blocks/Header"
|
||||||
|
import Card from "@/components/TempDesignSystem/Card"
|
||||||
|
import CardGrid from "@/components/TempDesignSystem/CardGrid"
|
||||||
|
|
||||||
|
import styles from "./cardsGrid.module.css"
|
||||||
|
|
||||||
|
import { CardsGridProps } from "@/types/components/loyalty/blocks"
|
||||||
|
|
||||||
|
export default function CardsGrid({ cards_grid }: CardsGridProps) {
|
||||||
|
return (
|
||||||
|
<section className={styles.section}>
|
||||||
|
<Header title={cards_grid.title} subtitle={cards_grid.preamble} />
|
||||||
|
<CardGrid variant={cards_grid.layout}>
|
||||||
|
{cards_grid.cards.map((card) => (
|
||||||
|
<Card
|
||||||
|
theme={cards_grid.theme || "one"}
|
||||||
|
key={card.system.uid}
|
||||||
|
scriptedTopTitle={card.scripted_top_title}
|
||||||
|
heading={card.heading}
|
||||||
|
bodyText={card.body_text}
|
||||||
|
secondaryButton={card.secondaryButton}
|
||||||
|
primaryButton={card.primaryButton}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</CardGrid>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 37rem;
|
height: 37rem;
|
||||||
border-radius: 1.6rem;
|
border-radius: 1.6rem;
|
||||||
background-color: var(--Base-Fill-Normal);
|
background-color: var(--UI-Grey-10);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-right: 1.6rem;
|
margin-right: 1.6rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
height: 37rem;
|
height: 37rem;
|
||||||
min-width: 32rem;
|
min-width: 32rem;
|
||||||
padding: 4rem 1rem;
|
padding: 4rem 1rem;
|
||||||
background-color: var(--Base-Fill-Normal);
|
background-color: var(--UI-Grey-10);
|
||||||
border-radius: 1.6rem;
|
border-radius: 1.6rem;
|
||||||
gap: 1.8rem;
|
gap: 1.8rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import JsonToHtml from "@/components/JsonToHtml"
|
|||||||
import DynamicContentBlock from "@/components/Loyalty/Blocks/DynamicContent"
|
import DynamicContentBlock from "@/components/Loyalty/Blocks/DynamicContent"
|
||||||
import Shortcuts from "@/components/MyPages/Blocks/Shortcuts"
|
import Shortcuts from "@/components/MyPages/Blocks/Shortcuts"
|
||||||
|
|
||||||
import CardGrid from "./CardGrid"
|
import CardsGrid from "./CardsGrid"
|
||||||
|
|
||||||
import type { BlocksProps } from "@/types/components/loyalty/blocks"
|
import type { BlocksProps } from "@/types/components/loyalty/blocks"
|
||||||
import { LoyaltyBlocksTypenameEnum } from "@/types/components/loyalty/enums"
|
import { LoyaltyBlocksTypenameEnum } from "@/types/components/loyalty/enums"
|
||||||
@@ -10,8 +10,6 @@ import { LoyaltyBlocksTypenameEnum } from "@/types/components/loyalty/enums"
|
|||||||
export function Blocks({ blocks }: BlocksProps) {
|
export function Blocks({ blocks }: BlocksProps) {
|
||||||
return blocks.map((block) => {
|
return blocks.map((block) => {
|
||||||
switch (block.__typename) {
|
switch (block.__typename) {
|
||||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid:
|
|
||||||
return <CardGrid card_grid={block.card_grid} />
|
|
||||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent:
|
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent:
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
@@ -31,6 +29,8 @@ export function Blocks({ blocks }: BlocksProps) {
|
|||||||
subtitle={block.shortcuts.preamble}
|
subtitle={block.shortcuts.preamble}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardsGrid:
|
||||||
|
return <CardsGrid cards_grid={block.cards_grid} />
|
||||||
default:
|
default:
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-top: 0.5px solid var(--Base-Border-Disabled);
|
border-top: 0.5px solid var(--UI-Grey-30);
|
||||||
padding: 3.4rem;
|
padding: 3.4rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
gap: 6.2rem;
|
gap: 6.2rem;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
.contactContainer {
|
.contactContainer {
|
||||||
display: block;
|
display: block;
|
||||||
border-top: 0.5px solid var(--Base-Border-Disabled);
|
border-top: 0.5px solid var(--UI-Grey-30);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 3.4rem;
|
padding: 3.4rem;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
min-height: 280px;
|
min-height: 280px;
|
||||||
background-color: var(--Base-Fill-Normal);
|
background-color: var(--UI-Grey-10);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export default async function NextLevelBenefitsBlock({
|
|||||||
<CardGrid variant="twoColumnGrid">
|
<CardGrid variant="twoColumnGrid">
|
||||||
{perks.map((perk) => (
|
{perks.map((perk) => (
|
||||||
<article key={perk.id} className={styles.card}>
|
<article key={perk.id} className={styles.card}>
|
||||||
<Button type="button" intent="secondary" disabled>
|
<Button type="button" disabled>
|
||||||
<Lock height={16} />
|
<Lock height={16} />
|
||||||
Level up to unlock
|
Level up to unlock
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default function ShowMoreButton({
|
|||||||
<Button
|
<Button
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
intent="primary"
|
intent="primary"
|
||||||
bgcolor="white"
|
theme="secondaryDark"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={loadMoreData}
|
onClick={loadMoreData}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export default function EmptyUpcomingStaysBlock() {
|
|||||||
{_("Where should you go next?")}
|
{_("Where should you go next?")}
|
||||||
</span>
|
</span>
|
||||||
</Title>
|
</Title>
|
||||||
<Button intent="primary" bgcolor="quarternary" asChild type="button">
|
<Button intent="primary" asChild type="button">
|
||||||
<Link className={styles.link} href={"#"} key="getInspired">
|
<Link className={styles.link} href={"#"} key="getInspired">
|
||||||
{_("Get inspired")}
|
{_("Get inspired")}
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export default function EmptyUpcomingStaysBlock() {
|
|||||||
{_("Where should you go next?")}
|
{_("Where should you go next?")}
|
||||||
</span>
|
</span>
|
||||||
</Title>
|
</Title>
|
||||||
<Button intent="primary" bgcolor="quarternary" asChild type="button">
|
<Button intent="primary" asChild type="button">
|
||||||
<Link className={styles.link} href={"#"} key="getInspired">
|
<Link className={styles.link} href={"#"} key="getInspired">
|
||||||
{_("Get inspired")}
|
{_("Get inspired")}
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -4,21 +4,43 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
font-family: var(--ff-fira-sans);
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 150%;
|
||||||
|
letter-spacing: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary {
|
||||||
|
color: var(--font-color,);
|
||||||
|
background-color: var(--background-color,);
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary:hover,
|
||||||
|
.primary:active,
|
||||||
|
.primary:focus {
|
||||||
|
background-color: var(--hover-background,);
|
||||||
|
color: var(--hover-color,);
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary {
|
||||||
|
background-color: transparent;
|
||||||
|
border: 0.1rem solid var(--background-color);
|
||||||
|
color: var(--background-color,);
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary:hover,
|
||||||
|
.secondary:active,
|
||||||
|
.secondary:focus {
|
||||||
|
border: 0.1rem solid var(--hover-color,);
|
||||||
|
color: var(--hover-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.default {
|
.default {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: var(--some-white-color, #fff);
|
|
||||||
border-radius: 4rem;
|
border-radius: 4rem;
|
||||||
color: var(--some-grey-color, #111);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
font-family: var(--ff-fira-sans);
|
|
||||||
font-size: 1.8rem;
|
|
||||||
font-weight: 500;
|
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
letter-spacing: 1%;
|
|
||||||
line-height: 2.2rem;
|
|
||||||
padding: 0.75rem 1.65rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
@@ -26,125 +48,110 @@
|
|||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Primary styles */
|
|
||||||
.primary {
|
|
||||||
background-color: var(--some-grey-color, #444343);
|
|
||||||
border: 2px solid transparent;
|
|
||||||
outline: 1px solid transparent;
|
|
||||||
border-radius: 46px;
|
|
||||||
color: var(--Main-Grey-00, #fff);
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary:hover {
|
|
||||||
background: var(--some-grey-color, #444343);
|
|
||||||
}
|
|
||||||
|
|
||||||
.primary:active,
|
|
||||||
.primary:focus {
|
|
||||||
border: var(--some-grey-color, #444343);
|
|
||||||
outline: var(--some-grey-color, #444343);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Secondary styles */
|
|
||||||
.secondary {
|
|
||||||
border: 1px solid var(--some-grey-color, #444343);
|
|
||||||
background-color: transparent;
|
|
||||||
color: var(--some-grey-color, #444343);
|
|
||||||
border-radius: 46px;
|
|
||||||
font-size: 12px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary:hover {
|
|
||||||
border: 1px solid var(--some-grey-color, #444343);
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary:active,
|
|
||||||
.secondary:focus {
|
|
||||||
border: 1px solid var(--some-grey-color, #444343);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disabled styles */
|
/* Disabled styles */
|
||||||
.btn:disabled {
|
.btn:disabled {
|
||||||
border: 1px solid var(--some-grey-color, #444343);
|
background-color: var(--disabled-background-color);
|
||||||
background-color: transparent;
|
color: var(--disabled-color);
|
||||||
color: var(--some-grey-color, #444343);
|
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sizes */
|
||||||
.small {
|
.small {
|
||||||
border-radius: 3rem;
|
padding: var(--Spacing-x1) var(--Spacing-x2);
|
||||||
|
gap: 0.2rem;
|
||||||
|
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
height: 2.6rem;
|
height: 4rem;
|
||||||
line-height: 1.7rem;
|
|
||||||
padding: 0.8rem 2.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.average {
|
|
||||||
border-radius: 4.7rem;
|
|
||||||
font-size: 1.4rem;
|
|
||||||
height: 3.2rem;
|
|
||||||
letter-spacing: 1%;
|
|
||||||
line-height: 1.6rem;
|
|
||||||
padding: 0.65rem 1.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.light {
|
|
||||||
font-weight: 300;
|
|
||||||
}
|
|
||||||
|
|
||||||
.regular {
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.medium {
|
.medium {
|
||||||
font-weight: 500;
|
height: 3rem;
|
||||||
|
padding: 1.2rem var(--Spacing-x2,);
|
||||||
|
|
||||||
|
font-size: 1.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.semiBold {
|
.large {
|
||||||
font-weight: 600;
|
padding: var(--Spacing-x2) 2.4rem;
|
||||||
|
gap: 0.4rem;
|
||||||
|
|
||||||
|
font-size: 1.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bold {
|
.primaryLight {
|
||||||
font-weight: 700;
|
--font-color: var(--Theme-Primary-Light-Button-Primary-On-Fill-Normal);
|
||||||
|
--background-color: var(--Theme-Primary-Light-Button-Primary-Fill-Normal,);
|
||||||
|
--hover-background: var(--Theme-Primary-Light-Button-Primary-Fill-Hover,);
|
||||||
|
--hover-color: var(--Theme-Primary-Light-Button-Primary-On-Fill-Hover,);
|
||||||
|
|
||||||
|
--disabled-background-color: var(
|
||||||
|
--Theme-Primary-Light-Button-Primary-Fill-Disabled,
|
||||||
|
);
|
||||||
|
--disabled-color: var(--Theme-Primary-Light-Button-Primary-On-Fill-Disabled,);
|
||||||
}
|
}
|
||||||
|
|
||||||
.black {
|
.primaryDark {
|
||||||
font-weight: 900;
|
--font-color: var(--Theme-Primary-Dark-Button-Primary-On-Fill-Normal,);
|
||||||
|
--background-color: var(--Theme-Primary-Dark-Button-Primary-Fill-Normal,);
|
||||||
|
--hover-color: var(--Theme-Primary-Dark-Button-Primary-On-Fill-Hover,);
|
||||||
|
--hover-background: var(--Theme-Primary-Dark-Button-Primary-Fill-Hover,);
|
||||||
|
|
||||||
|
--disabled-background-color: var(
|
||||||
|
--Theme-Primary-Dark-Button-Primary-Fill-Disabled,
|
||||||
|
);
|
||||||
|
--disabled-color: var(--Theme-Primary-Dark-Button-Primary-On-Fill-Disabled,);
|
||||||
}
|
}
|
||||||
|
|
||||||
.primary {
|
.secondaryLight {
|
||||||
background-color: var(--scandic-blue, #02838e);
|
--font-color: var(--Theme-Secondary-Light-Button-Primary-On-Fill-Normal,);
|
||||||
border: 0.1rem solid var(--scandic-blue, #02838e);
|
--background-color: var(--Theme-Secondary-Light-Button-Primary-Fill-Normal,);
|
||||||
color: var(--some-white-color, #fff);
|
--hover-color: var(--Theme-Secondary-Light-Button-Primary-On-Fill-Hover,);
|
||||||
|
--hover-background: var(--Theme-Secondary-Light-Button-Primary-Fill-Hover,);
|
||||||
|
|
||||||
|
--disabled-background-color: var(
|
||||||
|
--Theme-Secondary-Light-Button-Primary-Fill-Disabled,
|
||||||
|
);
|
||||||
|
--disabled-color: var(
|
||||||
|
--Theme-Secondary-Light-Button-Primary-On-Fill-Disabled,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.secondary {
|
.secondaryDark {
|
||||||
background-color: var(--some-black-color, #000);
|
--font-color: var(--Theme-Secondary-Dark-Button-Primary-On-Fill-Normal,);
|
||||||
border: 0.1rem solid var(--some-black-color, #000);
|
--background-color: var(--Theme-Secondary-Dark-Button-Primary-Fill-Normal,);
|
||||||
color: var(--some-white-color, #fff);
|
--hover-color: var(--Theme-Secondary-Dark-Button-Primary-On-Fill-Hover,);
|
||||||
|
--hover-background: var(--Theme-Secondary-Dark-Button-Primary-Fill-Hover,);
|
||||||
|
|
||||||
|
--disabled-background-color: var(
|
||||||
|
--Theme-Secondary-Dark-Button-Primary-Fill-Disabled,
|
||||||
|
);
|
||||||
|
--disabled-color: var(
|
||||||
|
--Theme-Secondary-Dark-Button-Primary-On-Fill-Disabled,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tertiary {
|
.tertiaryLight {
|
||||||
background-color: var(--some-red-color, #d60728);
|
--font-color: var(--Theme-Tertiary-Light-Button-Primary-On-Fill-Normal,);
|
||||||
border: 0.1rem solid var(--some-red-color, #d60728);
|
--background-color: var(--Theme-Tertiary-Light-Button-Primary-Fill-Normal,);
|
||||||
color: var(--some-white-color, #fff);
|
--hover-color: var(--Theme-Tertiary-Light-Button-Primary-On-Fill-Hover,);
|
||||||
|
--hover-background: var(--Theme-Tertiary-Light-Button-Primary-Fill-Hover,);
|
||||||
|
|
||||||
|
--disabled-background-color: var(
|
||||||
|
--Theme-Tertiary-Light-Button-Primary-Fill-Disabled,
|
||||||
|
);
|
||||||
|
--disabled-color: var(
|
||||||
|
--Theme-Tertiary-Light-Button-Primary-On-Fill-Disabled,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.quarternary {
|
.tertiaryDark {
|
||||||
background-color: var(--some-grey-color, #727272);
|
--font-color: var(--Theme-Tertiary-Dark-Button-Primary-On-Fill-Normal);
|
||||||
border: 0.1rem solid var(--some-black-color, #727272);
|
--background-color: var(--Theme-Tertiary-Dark-Button-Primary-Fill-Normal);
|
||||||
color: var(--some-white-color, #fff);
|
--hover-color: var(--Theme-Tertiary-Dark-Button-Primary-On-Fill-Hover);
|
||||||
}
|
--hover-background: var(--Theme-Tertiary-Dark-Button-Primary-Fill-Hover);
|
||||||
|
|
||||||
.white {
|
--disabled-background-color: var(
|
||||||
background-color: var(--some-white-color, #fff);
|
--Theme-Tertiary-Dark-Button-Primary-Fill-Disabled,
|
||||||
border: 0.1rem solid var(--some-black-color, #000);
|
);
|
||||||
color: var(--some-black-color, #000);
|
--disabled-color: var(--Theme-Tertiary-Dark-Button-Primary-On-Fill-Disabled,);
|
||||||
}
|
|
||||||
|
|
||||||
.btn:disabled {
|
|
||||||
background-color: var(--some-grey-color, #d9d9d9);
|
|
||||||
color: var(--some-grey-color, #757575);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,23 +8,21 @@ import type { ButtonProps } from "./button"
|
|||||||
|
|
||||||
export default function Button({
|
export default function Button({
|
||||||
asChild = false,
|
asChild = false,
|
||||||
bgcolor,
|
theme,
|
||||||
className,
|
className,
|
||||||
disabled,
|
disabled,
|
||||||
intent,
|
intent,
|
||||||
size,
|
size,
|
||||||
variant,
|
variant,
|
||||||
weight,
|
|
||||||
...props
|
...props
|
||||||
}: ButtonProps) {
|
}: ButtonProps) {
|
||||||
const Comp = asChild ? Slot : "button"
|
const Comp = asChild ? Slot : "button"
|
||||||
const classNames = buttonVariants({
|
const classNames = buttonVariants({
|
||||||
bgcolor,
|
theme,
|
||||||
className,
|
className,
|
||||||
intent,
|
intent,
|
||||||
size,
|
size,
|
||||||
variant,
|
variant,
|
||||||
weight,
|
|
||||||
})
|
})
|
||||||
return <Comp className={classNames} disabled={disabled} {...props} />
|
return <Comp className={classNames} disabled={disabled} {...props} />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,13 @@ import styles from "./button.module.css"
|
|||||||
|
|
||||||
export const buttonVariants = cva(styles.btn, {
|
export const buttonVariants = cva(styles.btn, {
|
||||||
variants: {
|
variants: {
|
||||||
bgcolor: {
|
theme: {
|
||||||
primary: styles.primary,
|
primaryLight: styles.primaryLight,
|
||||||
secondary: styles.secondary,
|
primaryDark: styles.primaryDark,
|
||||||
tertiary: styles.tertiary,
|
secondaryLight: styles.secondaryLight,
|
||||||
quarternary: styles.quarternary,
|
secondaryDark: styles.secondaryDark,
|
||||||
white: styles.white,
|
tertiaryLight: styles.tertiaryLight,
|
||||||
|
tertiaryDark: styles.tertiaryDark,
|
||||||
},
|
},
|
||||||
intent: {
|
intent: {
|
||||||
primary: styles.primary,
|
primary: styles.primary,
|
||||||
@@ -17,23 +18,18 @@ export const buttonVariants = cva(styles.btn, {
|
|||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
small: styles.small,
|
small: styles.small,
|
||||||
regular: styles.average,
|
medium: styles.medium,
|
||||||
|
large: styles.large,
|
||||||
},
|
},
|
||||||
variant: {
|
variant: {
|
||||||
default: styles.default,
|
default: styles.default,
|
||||||
icon: styles.icon,
|
icon: styles.icon,
|
||||||
},
|
},
|
||||||
weight: {
|
|
||||||
light: styles.light,
|
|
||||||
regular: styles.regular,
|
|
||||||
medium: styles.medium,
|
|
||||||
semiBold: styles.semiBold,
|
|
||||||
bold: styles.bold,
|
|
||||||
black: styles.black,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: "default",
|
variant: "default",
|
||||||
weight: "regular",
|
size: "medium",
|
||||||
|
theme: "primaryLight",
|
||||||
|
intent: "primary",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,15 +1,80 @@
|
|||||||
.linkCard {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 37rem;
|
height: 48rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-right: 1.6rem;
|
margin-right: 1.6rem;
|
||||||
border-radius: 1.6rem;
|
border-radius: 1.6rem;
|
||||||
gap: 1rem;
|
gap: var(--Spacing-x2);
|
||||||
padding: 1.6rem;
|
padding: 0px 3.2rem;
|
||||||
|
|
||||||
background-color: var(--Base-Fill-Normal);
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.themeOne {
|
||||||
|
--font-color: var(--Brand-Main-Strong, #4d001b);
|
||||||
|
--script-color: var(--UI-Red-70, #ad0015);
|
||||||
|
--divider-color: var(--UI-Red-10, #f7c1c2);
|
||||||
|
|
||||||
|
background: var(--Theme-Primary-Light-Surface-Normal, #f7e1d5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.themeTwo {
|
||||||
|
--font-color: var(--Brand-Forest-Strong, #093021);
|
||||||
|
--script-color: var(--UI-Green-70, #286806);
|
||||||
|
--divider-color: var(--UI-Green-10, #badda8);
|
||||||
|
|
||||||
|
background: var(--Brand-Forest-Subtle, #d2edaf);
|
||||||
|
}
|
||||||
|
|
||||||
|
.themeThree {
|
||||||
|
--font-color: var(--Brand-Sea-Strong, #0d1440);
|
||||||
|
--script-color: var(--UI-Blue-70, #1555b4);
|
||||||
|
--divider-color: var(--UI-Blue-10, #c7d9f5);
|
||||||
|
|
||||||
|
background: var(--Brand-Sea-Accent, #fff0c2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scriptContainer {
|
||||||
|
display: grid;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scriptedTitle {
|
||||||
|
color: var(--script-color);
|
||||||
|
|
||||||
|
font-family: var(--ff-biro-script-plus);
|
||||||
|
font-size: var(--typography-Script-2-fontSize);
|
||||||
|
font-weight: var(--typography-Script-2-fontWeight);
|
||||||
|
line-height: var(--typography-Script-2-lineHeight);
|
||||||
|
letter-spacing: 0.48px;
|
||||||
|
padding: 1rem;
|
||||||
|
|
||||||
|
transform: rotate(-3deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
border-bottom-color: var(--divider-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
color: var(--font-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bodyText {
|
||||||
|
color: var(--font-color);
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
font-size: var(--typography-Body-Regular-fontSize);
|
||||||
|
font-weight: var(--typography-Body-Regular-fontWeight);
|
||||||
|
line-height: var(--typography-Body-Regular-lineHeight);
|
||||||
|
letter-spacing: 0.096px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonContainer {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.8rem;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,24 @@
|
|||||||
export type CardProps = {
|
import { cardVariants } from "./variants"
|
||||||
link?: {
|
|
||||||
|
import type { VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
|
export interface CardProps
|
||||||
|
extends React.HTMLAttributes<HTMLDivElement>,
|
||||||
|
VariantProps<typeof cardVariants> {
|
||||||
|
primaryButton?: {
|
||||||
href: string
|
href: string
|
||||||
title: string
|
title: string
|
||||||
|
openInNewTab?: boolean
|
||||||
|
isExternal: boolean
|
||||||
}
|
}
|
||||||
title?: string | null
|
secondaryButton?: {
|
||||||
subtitle?: string | null
|
href: string
|
||||||
openInNewTab?: boolean
|
title: string
|
||||||
|
openInNewTab?: boolean
|
||||||
|
isExternal: boolean
|
||||||
|
}
|
||||||
|
scriptedTopTitle?: string | null
|
||||||
|
heading?: string | null
|
||||||
|
bodyText?: string | null
|
||||||
|
backgroundImage?: { url: string }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,93 @@
|
|||||||
import Title from "@/components/Title"
|
import Title from "@/components/Title"
|
||||||
|
|
||||||
import Button from "../Button"
|
import Button from "../Button"
|
||||||
|
import { ButtonProps } from "../Button/button"
|
||||||
|
import Divider from "../Divider"
|
||||||
import Link from "../Link"
|
import Link from "../Link"
|
||||||
import { CardProps } from "./card"
|
import { CardProps } from "./card"
|
||||||
|
import { cardVariants } from "./variants"
|
||||||
|
|
||||||
import styles from "./card.module.css"
|
import styles from "./card.module.css"
|
||||||
|
|
||||||
export default function Card({
|
export default function Card({
|
||||||
link,
|
primaryButton,
|
||||||
subtitle,
|
secondaryButton,
|
||||||
title,
|
scriptedTopTitle,
|
||||||
openInNewTab = false,
|
heading,
|
||||||
|
bodyText,
|
||||||
|
backgroundImage,
|
||||||
|
className,
|
||||||
|
theme,
|
||||||
}: CardProps) {
|
}: CardProps) {
|
||||||
|
let buttonTheme: ButtonProps["theme"] = "primaryLight"
|
||||||
|
|
||||||
|
switch (theme) {
|
||||||
|
case "one":
|
||||||
|
buttonTheme = "primaryLight"
|
||||||
|
break
|
||||||
|
case "two":
|
||||||
|
buttonTheme = "secondaryLight"
|
||||||
|
break
|
||||||
|
case "three":
|
||||||
|
buttonTheme = "tertiaryLight"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<article className={styles.linkCard}>
|
<article
|
||||||
{title ? (
|
className={cardVariants({
|
||||||
<Title level="h3" weight="semiBold">
|
className,
|
||||||
{title}
|
theme,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{scriptedTopTitle ? (
|
||||||
|
<section className={styles.scriptContainer}>
|
||||||
|
<Title level="h3" weight="semiBold" className={styles.scriptedTitle}>
|
||||||
|
{scriptedTopTitle}
|
||||||
|
</Title>
|
||||||
|
<Divider className={styles.divider} />
|
||||||
|
</section>
|
||||||
|
) : null}
|
||||||
|
{heading ? (
|
||||||
|
<Title
|
||||||
|
level="h3"
|
||||||
|
as="h5"
|
||||||
|
weight="semiBold"
|
||||||
|
uppercase
|
||||||
|
className={styles.heading}
|
||||||
|
>
|
||||||
|
{heading}
|
||||||
</Title>
|
</Title>
|
||||||
) : null}
|
) : null}
|
||||||
{subtitle ? (
|
{bodyText ? <p className={styles.bodyText}>{bodyText}</p> : null}
|
||||||
<Title level="h5" weight="light">
|
<div className={styles.buttonContainer}>
|
||||||
{subtitle}
|
{primaryButton ? (
|
||||||
</Title>
|
<Button asChild theme={buttonTheme} size="small">
|
||||||
) : null}
|
<Link
|
||||||
{link ? (
|
href={primaryButton.href}
|
||||||
<Button asChild intent="primary">
|
target={primaryButton.openInNewTab ? "_blank" : undefined}
|
||||||
<Link href={link.href} target={openInNewTab ? "_blank" : undefined}>
|
>
|
||||||
{link.title}
|
{primaryButton.title}
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
|
{secondaryButton ? (
|
||||||
|
<Button
|
||||||
|
asChild
|
||||||
|
theme={buttonTheme}
|
||||||
|
size="small"
|
||||||
|
intent="secondary"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href={secondaryButton.href}
|
||||||
|
target={secondaryButton.openInNewTab ? "_blank" : undefined}
|
||||||
|
>
|
||||||
|
{secondaryButton.title}
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
</article>
|
</article>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
16
components/TempDesignSystem/Card/variants.ts
Normal file
16
components/TempDesignSystem/Card/variants.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { cva } from "class-variance-authority"
|
||||||
|
|
||||||
|
import styles from "./card.module.css"
|
||||||
|
|
||||||
|
export const cardVariants = cva(styles.container, {
|
||||||
|
variants: {
|
||||||
|
theme: {
|
||||||
|
one: styles.themeOne,
|
||||||
|
two: styles.themeTwo,
|
||||||
|
three: styles.themeThree,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
theme: "one",
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -37,14 +37,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 950px) {
|
@media screen and (min-width: 950px) {
|
||||||
.twoColumnGrid {
|
.twoColumnGrid,
|
||||||
|
.twoPlusOne {
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
.treeColumnGrid {
|
.threeColumnGrid {
|
||||||
grid-template-columns: repeat(3, 1fr);
|
grid-template-columns: repeat(3, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.twoPlusOne > *:last-child {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
.carousel {
|
.carousel {
|
||||||
grid-auto-flow: unset;
|
grid-auto-flow: unset;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ export const cardGridVariants = cva(styles.gridContainer, {
|
|||||||
},
|
},
|
||||||
variant: {
|
variant: {
|
||||||
twoColumnGrid: styles.twoColumnGrid,
|
twoColumnGrid: styles.twoColumnGrid,
|
||||||
treeColumnGrid: styles.treeColumnGrid,
|
threeColumnGrid: styles.threeColumnGrid,
|
||||||
|
twoPlusOne: styles.twoPlusOne,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: "treeColumnGrid",
|
variant: "threeColumnGrid",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
/* font-family: var(--ff-brandon-text); */
|
/* font-family: var(--ff-brandon-text); */
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
color: var(--Scandic-Brand-Burgundy);
|
||||||
}
|
}
|
||||||
|
|
||||||
.uppercase {
|
.uppercase {
|
||||||
|
|||||||
49
lib/graphql/Fragments/Blocks/Card.graphql
Normal file
49
lib/graphql/Fragments/Blocks/Card.graphql
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
fragment CardBlock on Card {
|
||||||
|
heading
|
||||||
|
body_text
|
||||||
|
background_image
|
||||||
|
scripted_top_title
|
||||||
|
title
|
||||||
|
secondary_button {
|
||||||
|
is_contentstack_link
|
||||||
|
cta_text
|
||||||
|
open_in_new_tab
|
||||||
|
external_link {
|
||||||
|
title
|
||||||
|
href
|
||||||
|
}
|
||||||
|
linkConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
__typename
|
||||||
|
...LoyaltyPageLink
|
||||||
|
...ContentPageLink
|
||||||
|
...AccountPageLink
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
primary_button {
|
||||||
|
is_contentstack_link
|
||||||
|
cta_text
|
||||||
|
open_in_new_tab
|
||||||
|
external_link {
|
||||||
|
title
|
||||||
|
href
|
||||||
|
}
|
||||||
|
linkConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
__typename
|
||||||
|
...LoyaltyPageLink
|
||||||
|
...ContentPageLink
|
||||||
|
...AccountPageLink
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
system {
|
||||||
|
locale
|
||||||
|
uid
|
||||||
|
}
|
||||||
|
}
|
||||||
29
lib/graphql/Fragments/Blocks/Refs/Card.graphql
Normal file
29
lib/graphql/Fragments/Blocks/Refs/Card.graphql
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
fragment CardBlockRef on Card {
|
||||||
|
secondary_button {
|
||||||
|
linkConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
__typename
|
||||||
|
...LoyaltyPageRef
|
||||||
|
...ContentPageRef
|
||||||
|
...AccountPageRef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
primary_button {
|
||||||
|
linkConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
__typename
|
||||||
|
...LoyaltyPageRef
|
||||||
|
...ContentPageRef
|
||||||
|
...AccountPageRef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
#import "../Fragments/Image.graphql"
|
#import "../Fragments/Image.graphql"
|
||||||
|
#import "../Fragments/Blocks/Card.graphql"
|
||||||
|
#import "../Fragments/Blocks/Refs/Card.graphql"
|
||||||
#import "../Fragments/PageLink/AccountPageLink.graphql"
|
#import "../Fragments/PageLink/AccountPageLink.graphql"
|
||||||
#import "../Fragments/PageLink/ContentPageLink.graphql"
|
#import "../Fragments/PageLink/ContentPageLink.graphql"
|
||||||
#import "../Fragments/PageLink/LoyaltyPageLink.graphql"
|
#import "../Fragments/PageLink/LoyaltyPageLink.graphql"
|
||||||
@@ -11,8 +13,8 @@
|
|||||||
query GetLoyaltyPage($locale: String!, $uid: String!) {
|
query GetLoyaltyPage($locale: String!, $uid: String!) {
|
||||||
loyalty_page(uid: $uid, locale: $locale) {
|
loyalty_page(uid: $uid, locale: $locale) {
|
||||||
blocks {
|
blocks {
|
||||||
__typename
|
|
||||||
... on LoyaltyPageBlocksShortcuts {
|
... on LoyaltyPageBlocksShortcuts {
|
||||||
|
__typename
|
||||||
shortcuts {
|
shortcuts {
|
||||||
title
|
title
|
||||||
preamble
|
preamble
|
||||||
@@ -22,10 +24,9 @@ query GetLoyaltyPage($locale: String!, $uid: String!) {
|
|||||||
linkConnection {
|
linkConnection {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
__typename
|
|
||||||
...AccountPageLink
|
|
||||||
...LoyaltyPageLink
|
...LoyaltyPageLink
|
||||||
...ContentPageLink
|
...ContentPageLink
|
||||||
|
...AccountPageLink
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
totalCount
|
totalCount
|
||||||
@@ -34,6 +35,7 @@ query GetLoyaltyPage($locale: String!, $uid: String!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
... on LoyaltyPageBlocksDynamicContent {
|
... on LoyaltyPageBlocksDynamicContent {
|
||||||
|
__typename
|
||||||
dynamic_content {
|
dynamic_content {
|
||||||
title
|
title
|
||||||
subtitle
|
subtitle
|
||||||
@@ -52,30 +54,8 @@ query GetLoyaltyPage($locale: String!, $uid: String!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
... on LoyaltyPageBlocksCardGrid {
|
|
||||||
card_grid {
|
|
||||||
title
|
|
||||||
subtitle
|
|
||||||
cards {
|
|
||||||
referenceConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
__typename
|
|
||||||
...LoyaltyPageLink
|
|
||||||
...ContentPageLink
|
|
||||||
...AccountPageLink
|
|
||||||
}
|
|
||||||
}
|
|
||||||
totalCount
|
|
||||||
}
|
|
||||||
title
|
|
||||||
subtitle
|
|
||||||
open_in_new_tab
|
|
||||||
cta_text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
... on LoyaltyPageBlocksContent {
|
... on LoyaltyPageBlocksContent {
|
||||||
|
__typename
|
||||||
content {
|
content {
|
||||||
content {
|
content {
|
||||||
json
|
json
|
||||||
@@ -83,7 +63,6 @@ query GetLoyaltyPage($locale: String!, $uid: String!) {
|
|||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
__typename
|
__typename
|
||||||
...Image
|
|
||||||
...LoyaltyPageLink
|
...LoyaltyPageLink
|
||||||
...ContentPageLink
|
...ContentPageLink
|
||||||
}
|
}
|
||||||
@@ -93,6 +72,22 @@ query GetLoyaltyPage($locale: String!, $uid: String!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
... on LoyaltyPageBlocksCardsGrid {
|
||||||
|
__typename
|
||||||
|
cards_grid {
|
||||||
|
title
|
||||||
|
preamble
|
||||||
|
layout
|
||||||
|
theme
|
||||||
|
cardConnection(limit: 10) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
...CardBlock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
title
|
title
|
||||||
heading
|
heading
|
||||||
@@ -185,23 +180,6 @@ query GetLoyaltyPageRefs($locale: String!, $uid: String!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
... on LoyaltyPageBlocksCardGrid {
|
|
||||||
__typename
|
|
||||||
card_grid {
|
|
||||||
cards {
|
|
||||||
referenceConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
__typename
|
|
||||||
...AccountPageRef
|
|
||||||
...ContentPageRef
|
|
||||||
...LoyaltyPageRef
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
... on LoyaltyPageBlocksContent {
|
... on LoyaltyPageBlocksContent {
|
||||||
__typename
|
__typename
|
||||||
content {
|
content {
|
||||||
@@ -228,6 +206,18 @@ query GetLoyaltyPageRefs($locale: String!, $uid: String!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
... on LoyaltyPageBlocksCardsGrid {
|
||||||
|
__typename
|
||||||
|
cards_grid {
|
||||||
|
cardConnection(limit: 10) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
...CardBlockRef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sidebar {
|
sidebar {
|
||||||
... on LoyaltyPageSidebarContent {
|
... on LoyaltyPageSidebarContent {
|
||||||
|
|||||||
BIN
public/_static/fonts/biro-script-plus/Biro-Script-Plus.ttf
Normal file
BIN
public/_static/fonts/biro-script-plus/Biro-Script-Plus.ttf
Normal file
Binary file not shown.
@@ -13,37 +13,28 @@ import { PageLinkEnum } from "@/types/requests/pageLinks"
|
|||||||
import { EdgesWithTotalCount } from "@/types/requests/utils/edges"
|
import { EdgesWithTotalCount } from "@/types/requests/utils/edges"
|
||||||
import { RTEDocument } from "@/types/rte/node"
|
import { RTEDocument } from "@/types/rte/node"
|
||||||
|
|
||||||
const loyaltyPageBlockCardGrid = z.object({
|
const pageLink = z.object({
|
||||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid),
|
edges: z.array(
|
||||||
card_grid: z.object({
|
z.object({
|
||||||
title: z.string().nullable(),
|
node: z.object({
|
||||||
subtitle: z.string().nullable(),
|
system: z.object({
|
||||||
cards: z.array(
|
uid: z.string(),
|
||||||
z.object({
|
locale: z.nativeEnum(Lang),
|
||||||
title: z.string().nullable(),
|
|
||||||
subtitle: z.string().nullable(),
|
|
||||||
referenceConnection: z.object({
|
|
||||||
edges: z.array(
|
|
||||||
z.object({
|
|
||||||
node: z.object({
|
|
||||||
system: z.object({
|
|
||||||
uid: z.string(),
|
|
||||||
locale: z.nativeEnum(Lang),
|
|
||||||
}),
|
|
||||||
url: z.string(),
|
|
||||||
title: z.string(),
|
|
||||||
__typename: z.string(),
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
),
|
|
||||||
totalCount: z.number(),
|
|
||||||
}),
|
}),
|
||||||
open_in_new_tab: z.boolean(),
|
web: z
|
||||||
cta_text: z.string().nullable(),
|
.object({
|
||||||
})
|
original_url: z.string().nullable(),
|
||||||
),
|
})
|
||||||
}),
|
.nullable()
|
||||||
|
.optional(),
|
||||||
|
url: z.string(),
|
||||||
|
title: z.string(),
|
||||||
|
__typename: z.string().optional(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
const loyaltyPageDynamicContent = z.object({
|
const loyaltyPageDynamicContent = z.object({
|
||||||
__typename: z.literal(
|
__typename: z.literal(
|
||||||
LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksDynamicContent
|
LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksDynamicContent
|
||||||
@@ -54,21 +45,7 @@ const loyaltyPageDynamicContent = z.object({
|
|||||||
component: z.nativeEnum(LoyaltyComponentEnum),
|
component: z.nativeEnum(LoyaltyComponentEnum),
|
||||||
link: z.object({
|
link: z.object({
|
||||||
text: z.string().nullable(),
|
text: z.string().nullable(),
|
||||||
pageConnection: z.object({
|
pageConnection: pageLink,
|
||||||
edges: z.array(
|
|
||||||
z.object({
|
|
||||||
node: z.object({
|
|
||||||
system: z.object({
|
|
||||||
uid: z.string(),
|
|
||||||
locale: z.nativeEnum(Lang),
|
|
||||||
}),
|
|
||||||
url: z.string(),
|
|
||||||
title: z.string(),
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
),
|
|
||||||
totalCount: z.number(),
|
|
||||||
}),
|
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
@@ -80,26 +57,7 @@ const loyaltyPageShortcuts = z.object({
|
|||||||
preamble: z.string().nullable(),
|
preamble: z.string().nullable(),
|
||||||
shortcuts: z.array(
|
shortcuts: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
linkConnection: z.object({
|
linkConnection: pageLink,
|
||||||
edges: z.array(
|
|
||||||
z.object({
|
|
||||||
node: z.object({
|
|
||||||
system: z.object({
|
|
||||||
uid: z.string(),
|
|
||||||
locale: z.nativeEnum(Lang),
|
|
||||||
}),
|
|
||||||
url: z.string(),
|
|
||||||
web: z
|
|
||||||
.object({
|
|
||||||
original_url: z.string().nullable(),
|
|
||||||
})
|
|
||||||
.nullable(),
|
|
||||||
title: z.string(),
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
),
|
|
||||||
totalCount: z.number(),
|
|
||||||
}),
|
|
||||||
text: z.string().nullable(),
|
text: z.string().nullable(),
|
||||||
open_in_new_tab: z.boolean(),
|
open_in_new_tab: z.boolean(),
|
||||||
})
|
})
|
||||||
@@ -107,6 +65,59 @@ const loyaltyPageShortcuts = z.object({
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const cardBlock = z.object({
|
||||||
|
heading: z.string().nullable(),
|
||||||
|
body_text: z.string().nullable(),
|
||||||
|
background_image: z.any(),
|
||||||
|
scripted_top_title: z.string().nullable(),
|
||||||
|
primary_button: z
|
||||||
|
.object({
|
||||||
|
is_contentstack_link: z.boolean(),
|
||||||
|
cta_text: z.string().nullable(),
|
||||||
|
open_in_new_tab: z.boolean(),
|
||||||
|
external_link: z.object({
|
||||||
|
title: z.string().nullable(),
|
||||||
|
href: z.string().nullable(),
|
||||||
|
}),
|
||||||
|
linkConnection: pageLink,
|
||||||
|
})
|
||||||
|
.nullable(),
|
||||||
|
secondary_button: z
|
||||||
|
.object({
|
||||||
|
is_contentstack_link: z.boolean(),
|
||||||
|
cta_text: z.string().nullable(),
|
||||||
|
open_in_new_tab: z.boolean().nullable(),
|
||||||
|
external_link: z.object({
|
||||||
|
title: z.string().nullable(),
|
||||||
|
href: z.string().nullable(),
|
||||||
|
}),
|
||||||
|
linkConnection: pageLink,
|
||||||
|
})
|
||||||
|
.nullable(),
|
||||||
|
|
||||||
|
system: z.object({
|
||||||
|
locale: z.nativeEnum(Lang),
|
||||||
|
uid: z.string(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const loyaltyPageCards = z.object({
|
||||||
|
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardsGrid),
|
||||||
|
cards_grid: z.object({
|
||||||
|
title: z.string().nullable(),
|
||||||
|
preamble: z.string().nullable(),
|
||||||
|
layout: z.enum(["twoColumnGrid", "threeColumnGrid", "twoPlusOne"]),
|
||||||
|
theme: z.enum(["one", "two", "three"]).nullable(),
|
||||||
|
cardConnection: z.object({
|
||||||
|
edges: z.array(
|
||||||
|
z.object({
|
||||||
|
node: cardBlock,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
const loyaltyPageBlockTextContent = z.object({
|
const loyaltyPageBlockTextContent = z.object({
|
||||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent),
|
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent),
|
||||||
content: z.object({
|
content: z.object({
|
||||||
@@ -121,10 +132,10 @@ const loyaltyPageBlockTextContent = z.object({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const loyaltyPageBlockItem = z.discriminatedUnion("__typename", [
|
const loyaltyPageBlockItem = z.discriminatedUnion("__typename", [
|
||||||
loyaltyPageBlockCardGrid,
|
|
||||||
loyaltyPageDynamicContent,
|
loyaltyPageDynamicContent,
|
||||||
loyaltyPageBlockTextContent,
|
loyaltyPageBlockTextContent,
|
||||||
loyaltyPageShortcuts,
|
loyaltyPageShortcuts,
|
||||||
|
loyaltyPageCards,
|
||||||
])
|
])
|
||||||
|
|
||||||
const loyaltyPageSidebarTextContent = z.object({
|
const loyaltyPageSidebarTextContent = z.object({
|
||||||
@@ -154,7 +165,6 @@ const loyaltyPageJoinLoyaltyContact = z.object({
|
|||||||
),
|
),
|
||||||
contact: z.object({
|
contact: z.object({
|
||||||
display_text: z.string().nullable(),
|
display_text: z.string().nullable(),
|
||||||
|
|
||||||
contact_field: z.string(),
|
contact_field: z.string(),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
@@ -178,26 +188,6 @@ export const validateLoyaltyPageSchema = z.object({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Block types
|
// Block types
|
||||||
type CardGridRaw = z.infer<typeof loyaltyPageBlockCardGrid>
|
|
||||||
|
|
||||||
export type CardGridCard = Omit<
|
|
||||||
CardGridRaw["card_grid"]["cards"][number],
|
|
||||||
"referenceConnection"
|
|
||||||
> & {
|
|
||||||
link:
|
|
||||||
| {
|
|
||||||
href: string
|
|
||||||
title: string
|
|
||||||
}
|
|
||||||
| undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CardGrid = Omit<CardGridRaw, "card_grid"> & {
|
|
||||||
card_grid: Omit<CardGridRaw["card_grid"], "cards"> & {
|
|
||||||
cards: CardGridCard[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type DynamicContentRaw = z.infer<typeof loyaltyPageDynamicContent>
|
type DynamicContentRaw = z.infer<typeof loyaltyPageDynamicContent>
|
||||||
|
|
||||||
export type DynamicContent = Omit<DynamicContentRaw, "dynamic_content"> & {
|
export type DynamicContent = Omit<DynamicContentRaw, "dynamic_content"> & {
|
||||||
@@ -222,6 +212,34 @@ export interface RteBlockContent extends BlockContentRaw {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CardsGridRaw = z.infer<typeof loyaltyPageCards>
|
||||||
|
|
||||||
|
export type CardsRaw =
|
||||||
|
CardsGridRaw["cards_grid"]["cardConnection"]["edges"][number]["node"]
|
||||||
|
|
||||||
|
export type CardsGrid = Omit<CardsGridRaw, "cards_grid"> & {
|
||||||
|
cards_grid: Omit<CardsGridRaw["cards_grid"], "cardConnection"> & {
|
||||||
|
cards: (Omit<CardsRaw, "primaryButton" | "secondaryButton"> & {
|
||||||
|
primaryButton:
|
||||||
|
| {
|
||||||
|
openInNewTab: boolean
|
||||||
|
title: string
|
||||||
|
href: string
|
||||||
|
isExternal: boolean
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
secondaryButton:
|
||||||
|
| {
|
||||||
|
openInNewTab: boolean
|
||||||
|
title: string
|
||||||
|
href: string
|
||||||
|
isExternal: boolean
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
})[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ShortcutsRaw = z.infer<typeof loyaltyPageShortcuts>
|
type ShortcutsRaw = z.infer<typeof loyaltyPageShortcuts>
|
||||||
|
|
||||||
export type Shortcuts = Omit<ShortcutsRaw, "shortcuts"> & {
|
export type Shortcuts = Omit<ShortcutsRaw, "shortcuts"> & {
|
||||||
@@ -235,7 +253,7 @@ export type Shortcuts = Omit<ShortcutsRaw, "shortcuts"> & {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Block = CardGrid | RteBlockContent | DynamicContent | Shortcuts
|
export type Block = RteBlockContent | DynamicContent | Shortcuts | CardsGrid
|
||||||
|
|
||||||
// Sidebar block types
|
// Sidebar block types
|
||||||
type SidebarContentRaw = z.infer<typeof loyaltyPageSidebarTextContent>
|
type SidebarContentRaw = z.infer<typeof loyaltyPageSidebarTextContent>
|
||||||
@@ -275,14 +293,34 @@ const pageConnectionRefs = z.object({
|
|||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
const loyaltyPageBlockCardGridRefs = z.object({
|
const cardBlockRefs = z.object({
|
||||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid),
|
primary_button: z
|
||||||
card_grid: z.object({
|
.object({
|
||||||
cards: z.array(
|
linkConnection: pageConnectionRefs,
|
||||||
z.object({
|
})
|
||||||
referenceConnection: pageConnectionRefs,
|
.nullable(),
|
||||||
})
|
secondary_button: z
|
||||||
),
|
.object({
|
||||||
|
linkConnection: pageConnectionRefs,
|
||||||
|
})
|
||||||
|
.nullable(),
|
||||||
|
|
||||||
|
system: z.object({
|
||||||
|
content_type_uid: z.string(),
|
||||||
|
uid: z.string(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const loyaltyPageCardsRefs = z.object({
|
||||||
|
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardsGrid),
|
||||||
|
cards_grid: z.object({
|
||||||
|
cardConnection: z.object({
|
||||||
|
edges: z.array(
|
||||||
|
z.object({
|
||||||
|
node: cardBlockRefs,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -318,10 +356,10 @@ const loyaltyPageBlockTextContentRefs = z.object({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const loyaltyPageBlocRefsItem = z.discriminatedUnion("__typename", [
|
const loyaltyPageBlocRefsItem = z.discriminatedUnion("__typename", [
|
||||||
loyaltyPageBlockCardGridRefs,
|
|
||||||
loyaltyPageDynamicContentRefs,
|
loyaltyPageDynamicContentRefs,
|
||||||
loyaltyPageBlockTextContentRefs,
|
loyaltyPageBlockTextContentRefs,
|
||||||
loyaltyPageShortcutsRefs,
|
loyaltyPageShortcutsRefs,
|
||||||
|
loyaltyPageCardsRefs,
|
||||||
])
|
])
|
||||||
|
|
||||||
const loyaltyPageSidebarTextContentRef = z.object({
|
const loyaltyPageSidebarTextContentRef = z.object({
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
import { request } from "@/lib/graphql/request"
|
import { request } from "@/lib/graphql/request"
|
||||||
import { _ } from "@/lib/translation"
|
import { _ } from "@/lib/translation"
|
||||||
import { internalServerError, notFound } from "@/server/errors/trpc"
|
import { internalServerError, notFound } from "@/server/errors/trpc"
|
||||||
import { contentstackProcedure, publicProcedure, router } from "@/server/trpc"
|
import { contentstackProcedure, router } from "@/server/trpc"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
generateRefsResponseTag,
|
generateRefsResponseTag,
|
||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
|
|
||||||
import { removeEmptyObjects } from "../../utils"
|
import { removeEmptyObjects } from "../../utils"
|
||||||
import {
|
import {
|
||||||
|
CardsRaw,
|
||||||
type LoyaltyPage,
|
type LoyaltyPage,
|
||||||
type LoyaltyPageDataRaw,
|
type LoyaltyPageDataRaw,
|
||||||
type LoyaltyPageRefsDataRaw,
|
type LoyaltyPageRefsDataRaw,
|
||||||
@@ -31,6 +32,26 @@ import { Embeds } from "@/types/requests/embeds"
|
|||||||
import { Edges } from "@/types/requests/utils/edges"
|
import { Edges } from "@/types/requests/utils/edges"
|
||||||
import { RTEDocument } from "@/types/rte/node"
|
import { RTEDocument } from "@/types/rte/node"
|
||||||
|
|
||||||
|
function makeButtonObject(
|
||||||
|
button: CardsRaw["primary_button" | "secondary_button"]
|
||||||
|
) {
|
||||||
|
if (!button) return undefined
|
||||||
|
return {
|
||||||
|
openInNewTab: button.open_in_new_tab,
|
||||||
|
title:
|
||||||
|
button.cta_text ||
|
||||||
|
(button.is_contentstack_link && button.linkConnection.edges.length
|
||||||
|
? button.linkConnection.edges[0].node.title
|
||||||
|
: button.external_link.title),
|
||||||
|
href:
|
||||||
|
button.is_contentstack_link && button.linkConnection.edges.length
|
||||||
|
? button.linkConnection.edges[0].node.web?.original_url ||
|
||||||
|
`/${button.linkConnection.edges[0].node.system.locale}${button.linkConnection.edges[0].node.url}`
|
||||||
|
: button.external_link.href,
|
||||||
|
isExternal: !button.is_contentstack_link,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const loyaltyPageQueryRouter = router({
|
export const loyaltyPageQueryRouter = router({
|
||||||
get: contentstackProcedure.query(async ({ ctx }) => {
|
get: contentstackProcedure.query(async ({ ctx }) => {
|
||||||
const { lang, uid } = ctx
|
const { lang, uid } = ctx
|
||||||
@@ -60,6 +81,8 @@ export const loyaltyPageQueryRouter = router({
|
|||||||
const validatedLoyaltyPageRefs =
|
const validatedLoyaltyPageRefs =
|
||||||
validateLoyaltyPageRefsSchema.safeParse(cleanedData)
|
validateLoyaltyPageRefsSchema.safeParse(cleanedData)
|
||||||
if (!validatedLoyaltyPageRefs.success) {
|
if (!validatedLoyaltyPageRefs.success) {
|
||||||
|
console.error("Bad validation for `GetLoyaltyPageRefs`")
|
||||||
|
console.error(validatedLoyaltyPageRefs.error)
|
||||||
throw internalServerError(validatedLoyaltyPageRefs.error)
|
throw internalServerError(validatedLoyaltyPageRefs.error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,30 +137,12 @@ export const loyaltyPageQueryRouter = router({
|
|||||||
const blocks = validatedLoyaltyPage.data.loyalty_page.blocks
|
const blocks = validatedLoyaltyPage.data.loyalty_page.blocks
|
||||||
? validatedLoyaltyPage.data.loyalty_page.blocks.map((block) => {
|
? validatedLoyaltyPage.data.loyalty_page.blocks.map((block) => {
|
||||||
switch (block.__typename) {
|
switch (block.__typename) {
|
||||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid:
|
|
||||||
return {
|
|
||||||
...block,
|
|
||||||
card_grid: {
|
|
||||||
...block.card_grid,
|
|
||||||
cards: block.card_grid.cards.map((card) => {
|
|
||||||
return {
|
|
||||||
...card,
|
|
||||||
link: card.referenceConnection.totalCount
|
|
||||||
? {
|
|
||||||
href: `/${card.referenceConnection.edges[0].node.system.locale}${card.referenceConnection.edges[0].node.url}`,
|
|
||||||
title: card.cta_text || _("Read more"),
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksDynamicContent:
|
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksDynamicContent:
|
||||||
return {
|
return {
|
||||||
...block,
|
...block,
|
||||||
dynamic_content: {
|
dynamic_content: {
|
||||||
...block.dynamic_content,
|
...block.dynamic_content,
|
||||||
link: block.dynamic_content.link.pageConnection.totalCount
|
link: block.dynamic_content.link.pageConnection.edges.length
|
||||||
? {
|
? {
|
||||||
text: block.dynamic_content.link.text,
|
text: block.dynamic_content.link.text,
|
||||||
href: `/${block.dynamic_content.link.pageConnection.edges[0].node.system.locale}${block.dynamic_content.link.pageConnection.edges[0].node.url}`,
|
href: `/${block.dynamic_content.link.pageConnection.edges[0].node.system.locale}${block.dynamic_content.link.pageConnection.edges[0].node.url}`,
|
||||||
@@ -174,6 +179,24 @@ export const loyaltyPageQueryRouter = router({
|
|||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardsGrid:
|
||||||
|
return {
|
||||||
|
...block,
|
||||||
|
cards_grid: {
|
||||||
|
...block.cards_grid,
|
||||||
|
cards: block.cards_grid.cardConnection.edges.map(
|
||||||
|
({ node: card }) => {
|
||||||
|
return {
|
||||||
|
...card,
|
||||||
|
primaryButton: makeButtonObject(card.primary_button),
|
||||||
|
secondaryButton: makeButtonObject(
|
||||||
|
card.secondary_button
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,16 @@ export function getConnections(refs: LoyaltyPageRefsDataRaw) {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid: {
|
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardsGrid: {
|
||||||
item.card_grid.cards.forEach((card) => {
|
connections.push(item.cards_grid.cardConnection)
|
||||||
if (card.referenceConnection.edges.length) {
|
item.cards_grid.cardConnection.edges.forEach((card) => {
|
||||||
connections.push(card.referenceConnection)
|
if (card.node.primary_button) {
|
||||||
|
connections.push(card.node.primary_button?.linkConnection)
|
||||||
|
} else if (card.node.secondary_button) {
|
||||||
|
connections.push(card.node.secondary_button?.linkConnection)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksShortcuts: {
|
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksShortcuts: {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
Block,
|
Block,
|
||||||
CardGrid,
|
CardsGrid,
|
||||||
DynamicContent,
|
DynamicContent,
|
||||||
RteBlockContent,
|
RteBlockContent,
|
||||||
} from "@/server/routers/contentstack/loyaltyPage/output"
|
} from "@/server/routers/contentstack/loyaltyPage/output"
|
||||||
@@ -17,7 +17,7 @@ export type DynamicComponentProps = {
|
|||||||
component: DynamicContent["dynamic_content"]["component"]
|
component: DynamicContent["dynamic_content"]["component"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CardGridProps = Pick<CardGrid, "card_grid">
|
export type CardsGridProps = Pick<CardsGrid, "cards_grid">
|
||||||
|
|
||||||
export type Content = { content: RteBlockContent["content"]["content"] }
|
export type Content = { content: RteBlockContent["content"]["content"] }
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export type LoyaltyComponent = keyof typeof LoyaltyComponentEnum
|
|||||||
|
|
||||||
export enum LoyaltyBlocksTypenameEnum {
|
export enum LoyaltyBlocksTypenameEnum {
|
||||||
LoyaltyPageBlocksDynamicContent = "LoyaltyPageBlocksDynamicContent",
|
LoyaltyPageBlocksDynamicContent = "LoyaltyPageBlocksDynamicContent",
|
||||||
LoyaltyPageBlocksCardGrid = "LoyaltyPageBlocksCardGrid",
|
|
||||||
LoyaltyPageBlocksContent = "LoyaltyPageBlocksContent",
|
LoyaltyPageBlocksContent = "LoyaltyPageBlocksContent",
|
||||||
LoyaltyPageBlocksShortcuts = "LoyaltyPageBlocksShortcuts",
|
LoyaltyPageBlocksShortcuts = "LoyaltyPageBlocksShortcuts",
|
||||||
|
LoyaltyPageBlocksCardsGrid = "LoyaltyPageBlocksCardsGrid",
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user