diff --git a/apps/scandic-web/components/ContentType/CampaignPage/Hero/hero.module.css b/apps/scandic-web/components/ContentType/CampaignPage/Hero/hero.module.css new file mode 100644 index 000000000..441094b21 --- /dev/null +++ b/apps/scandic-web/components/ContentType/CampaignPage/Hero/hero.module.css @@ -0,0 +1,86 @@ +.content { + border-radius: var(--Corner-radius-Large); + transform: translateY(-170px); + margin: 0 auto -170px; + width: 90%; + padding: var(--Space-x3); + display: grid; + gap: var(--Space-x2); +} + +.imageContainer { + overflow: hidden; + width: 100%; + height: 478px; + position: relative; + border-radius: var(--Corner-radius-Large); +} + +.benefitList { + display: grid; + list-style-type: none; + gap: var(--Space-x05); +} + +.benefitList > li { + display: flex; + gap: var(--Space-x1); + align-items: center; +} + +.peach { + .content { + background-color: var(--Surface-Brand-Accent-Default); + } + + .heading { + color: var(--Text-Brand-OnAccent-Heading); + } + + .text { + color: var(--Text-Brand-OnPrimary-1-Default); + } + + .benefitList > li { + color: var(--Surface-Brand-Primary-1-OnSurface-Accent-Secondary); + } +} + +.burgundy { + .content { + background-color: var(--Surface-Brand-Primary-3-Default); + } + + .heading { + color: var(--Text-Brand-OnPrimary-3-Accent); + } + + .benefitList > li, + .text { + color: var(--Text-Brand-OnPrimary-3-Default); + } +} + +@media screen and (min-width: 768px) { + .content { + position: relative; + width: 100%; + transform: none; + border-radius: 0; + margin: 0; + align-content: center; + } + + .hero { + border-radius: var(--Corner-radius-Large); + display: grid; + grid-template-columns: repeat(3, 1fr); + overflow: hidden; + } + + .imageContainer { + grid-column: span 2; + position: relative; + border-radius: 0; + } +} diff --git a/apps/scandic-web/components/ContentType/CampaignPage/Hero/index.tsx b/apps/scandic-web/components/ContentType/CampaignPage/Hero/index.tsx new file mode 100644 index 000000000..eab52e756 --- /dev/null +++ b/apps/scandic-web/components/ContentType/CampaignPage/Hero/index.tsx @@ -0,0 +1,99 @@ +/* eslint-disable formatjs/no-literal-string-in-jsx */ +import { Divider } from "@scandic-hotels/design-system/Divider" +import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" +import { Typography } from "@scandic-hotels/design-system/Typography" + +import ButtonLink from "@/components/ButtonLink" +import Image from "@/components/Image" + +import { variants } from "./variants" + +import styles from "./hero.module.css" + +import type { HeroProps } from "./types" + +export default async function CampaignHero({ + image, + heading, + benefits, + rate_text, + button, + theme, +}: HeroProps) { + const classNames = variants({ + theme, + }) + return ( +
+ {image ? ( +
+ {image.meta.alt +
+ ) : null} +
+ +

{heading}

+
+ {benefits?.length ? ( + + ) : null} + + {rate_text ? ( + + {rate_text.bold_text ? ( + + {rate_text.bold_text} + + ) : null} + {rate_text.bold_text && rate_text.text ? " " : null} + {rate_text.text ? ( + + {rate_text.text} + + ) : null} + + ) : null} + {button.link ? ( + + {button.cta} + + ) : null} +
+
+ ) +} diff --git a/apps/scandic-web/components/ContentType/CampaignPage/Hero/types.ts b/apps/scandic-web/components/ContentType/CampaignPage/Hero/types.ts new file mode 100644 index 000000000..bf55686c4 --- /dev/null +++ b/apps/scandic-web/components/ContentType/CampaignPage/Hero/types.ts @@ -0,0 +1,9 @@ +import type { VariantProps } from "class-variance-authority" + +import type { Hero } from "@/types/trpc/routers/contentstack/campaignPage" +import type { variants } from "./variants" + +export interface HeroProps + extends React.HTMLAttributes, + VariantProps, + Omit {} diff --git a/apps/scandic-web/components/ContentType/CampaignPage/Hero/variants.ts b/apps/scandic-web/components/ContentType/CampaignPage/Hero/variants.ts new file mode 100644 index 000000000..c606a1a7e --- /dev/null +++ b/apps/scandic-web/components/ContentType/CampaignPage/Hero/variants.ts @@ -0,0 +1,17 @@ +import { cva } from "class-variance-authority" + +import styles from "./hero.module.css" + +const config = { + variants: { + theme: { + Peach: styles.peach, + Burgundy: styles.burgundy, + }, + }, + defaultVariants: { + theme: "Peach", + }, +} as const + +export const variants = cva(styles.hero, config) diff --git a/apps/scandic-web/components/ContentType/CampaignPage/campaignPage.module.css b/apps/scandic-web/components/ContentType/CampaignPage/campaignPage.module.css index 25df15236..c39479855 100644 --- a/apps/scandic-web/components/ContentType/CampaignPage/campaignPage.module.css +++ b/apps/scandic-web/components/ContentType/CampaignPage/campaignPage.module.css @@ -6,16 +6,6 @@ margin: 0 auto; } -.hero { - /* Temporary styles until we add the hero */ - width: 100%; - height: 478px; - display: flex; - justify-content: center; - align-items: center; - background-color: var(--Surface-Brand-Accent-Default); -} - .intro { display: grid; gap: var(--Space-x5); diff --git a/apps/scandic-web/components/ContentType/CampaignPage/index.tsx b/apps/scandic-web/components/ContentType/CampaignPage/index.tsx index 4bbed5f9e..84b8919b1 100644 --- a/apps/scandic-web/components/ContentType/CampaignPage/index.tsx +++ b/apps/scandic-web/components/ContentType/CampaignPage/index.tsx @@ -8,6 +8,7 @@ import { getCampaignPage } from "@/lib/trpc/memoizedRequests" import Blocks from "./Blocks" import CampaignPageSkeleton from "./CampaignPageSkeleton" +import CampaignHero from "./Hero" import styles from "./campaignPage.module.css" @@ -19,14 +20,13 @@ export default async function CampaignPage() { } const { campaignPage } = pageData - const { heading, subheading, preamble, blocks } = campaignPage + const { heading, subheading, preamble, blocks, hero } = campaignPage return ( <> }>
- {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} -
---PLACE FOR THE HERO---
+
diff --git a/apps/scandic-web/lib/graphql/Fragments/CampaignPage/Hero.graphql b/apps/scandic-web/lib/graphql/Fragments/CampaignPage/Hero.graphql new file mode 100644 index 000000000..0e1bfa18d --- /dev/null +++ b/apps/scandic-web/lib/graphql/Fragments/CampaignPage/Hero.graphql @@ -0,0 +1,78 @@ +#import "../PageLink/AccountPageLink.graphql" +#import "../PageLink/CampaignPageLink.graphql" +#import "../PageLink/CollectionPageLink.graphql" +#import "../PageLink/ContentPageLink.graphql" +#import "../PageLink/DestinationCityPageLink.graphql" +#import "../PageLink/DestinationCountryPageLink.graphql" +#import "../PageLink/DestinationOverviewPageLink.graphql" +#import "../PageLink/HotelPageLink.graphql" +#import "../PageLink/LoyaltyPageLink.graphql" +#import "../PageLink/StartPageLink.graphql" + +#import "../AccountPage/Ref.graphql" +#import "../CampaignPage/Ref.graphql" +#import "../CollectionPage/Ref.graphql" +#import "../ContentPage/Ref.graphql" +#import "../DestinationCityPage/Ref.graphql" +#import "../DestinationCountryPage/Ref.graphql" +#import "../DestinationOverviewPage/Ref.graphql" +#import "../HotelPage/Ref.graphql" +#import "../LoyaltyPage/Ref.graphql" +#import "../StartPage/Ref.graphql" + +fragment Hero_CampaignPage on CampaignPage { + hero { + image + heading + theme + benefits + rate_text { + bold_text + text + } + button { + cta + linkConnection { + edges { + node { + __typename + ...AccountPageLink + ...CampaignPageLink + ...CollectionPageLink + ...ContentPageLink + ...DestinationCityPageLink + ...DestinationCountryPageLink + ...DestinationOverviewPageLink + ...HotelPageLink + ...LoyaltyPageLink + ...StartPageLink + } + } + } + } + } +} + +fragment HeroRef_CampaignPage on CampaignPage { + hero { + button { + linkConnection { + edges { + node { + __typename + ...AccountPageRef + ...CampaignPageRef + ...CollectionPageRef + ...ContentPageRef + ...DestinationCityPageRef + ...DestinationCountryPageRef + ...DestinationOverviewPageRef + ...HotelPageRef + ...LoyaltyPageRef + ...StartPageRef + } + } + } + } + } +} diff --git a/apps/scandic-web/lib/graphql/Query/CampaignPage/CampaignPage.graphql b/apps/scandic-web/lib/graphql/Query/CampaignPage/CampaignPage.graphql index 6127bec86..745521c62 100644 --- a/apps/scandic-web/lib/graphql/Query/CampaignPage/CampaignPage.graphql +++ b/apps/scandic-web/lib/graphql/Query/CampaignPage/CampaignPage.graphql @@ -3,6 +3,7 @@ #import "../../Fragments/Blocks/Accordion.graphql" #import "../../Fragments/Blocks/Essentials.graphql" #import "../../Fragments/Blocks/CarouselCards.graphql" +#import "../../Fragments/CampaignPage/Hero.graphql" query GetCampaignPage($locale: String!, $uid: String!) { campaign_page(uid: $uid, locale: $locale) { @@ -26,6 +27,7 @@ query GetCampaignPage($locale: String!, $uid: String!) { created_at updated_at } + ...Hero_CampaignPage } trackingProps: campaign_page(locale: "en", uid: $uid) { url @@ -39,6 +41,7 @@ query GetCampaignPageRefs($locale: String!, $uid: String!) { ...CarouselCards_CampaignPageRefs ...Accordion_CampaignPageRefs } + ...HeroRef_CampaignPage system { ...System } diff --git a/apps/scandic-web/server/routers/contentstack/campaignPage/output.ts b/apps/scandic-web/server/routers/contentstack/campaignPage/output.ts index 16652e506..d2b3aca0e 100644 --- a/apps/scandic-web/server/routers/contentstack/campaignPage/output.ts +++ b/apps/scandic-web/server/routers/contentstack/campaignPage/output.ts @@ -11,6 +11,11 @@ import { carouselCardsSchema, } from "../schemas/blocks/carouselCards" import { essentialsBlockSchema } from "../schemas/blocks/essentials" +import { tempImageVaultAssetSchema } from "../schemas/imageVault" +import { + linkConnectionRefs, + linkConnectionSchema, +} from "../schemas/linkConnection" import { systemSchema } from "../schemas/system" import { CampaignPageEnum } from "@/types/enums/campaignPage" @@ -39,10 +44,25 @@ export const blocksSchema = z.discriminatedUnion("__typename", [ campaignPageAccordion, ]) +export const heroSchema = z.object({ + image: tempImageVaultAssetSchema, + heading: z.string(), + theme: z.enum(["Peach", "Burgundy"]).default("Peach"), + benefits: z.array(z.string()).nullish(), + rate_text: z + .object({ + bold_text: z.string().nullish(), + text: z.string().nullish(), + }) + .nullish(), + button: z.intersection(z.object({ cta: z.string() }), linkConnectionSchema), +}) + export const campaignPageSchema = z.object({ campaign_page: z.object({ title: z.string(), campaign_identifier: z.string().nullish(), + hero: heroSchema, heading: z.string(), subheading: z.string().nullish(), preamble: z.object({ @@ -80,9 +100,13 @@ const campaignPageBlockRefsItem = z.discriminatedUnion("__typename", [ campaignPageCarouselCardsRef, campaignPageAccordionRefs, ]) +const heroRefsSchema = z.object({ + button: linkConnectionRefs, +}) export const campaignPageRefsSchema = z.object({ campaign_page: z.object({ + hero: heroRefsSchema, blocks: discriminatedUnionArray( campaignPageBlockRefsItem.options ).nullable(), diff --git a/apps/scandic-web/server/routers/contentstack/campaignPage/query.ts b/apps/scandic-web/server/routers/contentstack/campaignPage/query.ts index 26f6b8eb8..18a26fb7a 100644 --- a/apps/scandic-web/server/routers/contentstack/campaignPage/query.ts +++ b/apps/scandic-web/server/routers/contentstack/campaignPage/query.ts @@ -46,7 +46,6 @@ export const campaignPageQueryRouter = router({ ttl: "max", } ) - if (!refsResponse.data) { const notFoundError = notFound(refsResponse) metricsGetCampaignPageRefs.noDataError() diff --git a/apps/scandic-web/server/routers/contentstack/schemas/pageLinks.ts b/apps/scandic-web/server/routers/contentstack/schemas/pageLinks.ts index 3e6ae93a6..61f4866e9 100644 --- a/apps/scandic-web/server/routers/contentstack/schemas/pageLinks.ts +++ b/apps/scandic-web/server/routers/contentstack/schemas/pageLinks.ts @@ -173,6 +173,7 @@ export function transformPageLink(data: Data) { title: data.title, url: removeMultipleSlashes(`/${data.system.locale}/${data.url}`), } + case ContentEnum.blocks.CollectionPage: case ContentEnum.blocks.ContentPage: case ContentEnum.blocks.LoyaltyPage: diff --git a/apps/scandic-web/types/trpc/routers/contentstack/campaignPage.ts b/apps/scandic-web/types/trpc/routers/contentstack/campaignPage.ts index f747eb8eb..c3dd08ae4 100644 --- a/apps/scandic-web/types/trpc/routers/contentstack/campaignPage.ts +++ b/apps/scandic-web/types/trpc/routers/contentstack/campaignPage.ts @@ -4,6 +4,7 @@ import type { blocksSchema, campaignPageRefsSchema, campaignPageSchema, + heroSchema, } from "@/server/routers/contentstack/campaignPage/output" import type { essentialsSchema } from "@/server/routers/contentstack/schemas/blocks/essentials" @@ -21,3 +22,5 @@ export interface CampaignPageRefs export type Block = z.output export type EssentialsBlock = z.output["essentials"] + +export type Hero = z.output diff --git a/packages/design-system/lib/components/Divider/divider.module.css b/packages/design-system/lib/components/Divider/divider.module.css index 626deb00b..435390806 100644 --- a/packages/design-system/lib/components/Divider/divider.module.css +++ b/packages/design-system/lib/components/Divider/divider.module.css @@ -36,3 +36,7 @@ .Border-Divider-Default { background-color: var(--Border-Divider-Default); } + +.Surface-Brand-Primary-1-OnSurface-Accent-Secondary { + background-color: var(--Surface-Brand-Primary-1-OnSurface-Accent-Secondary); +} diff --git a/packages/design-system/lib/components/Divider/variants.ts b/packages/design-system/lib/components/Divider/variants.ts index 311114e81..d39dba0f1 100644 --- a/packages/design-system/lib/components/Divider/variants.ts +++ b/packages/design-system/lib/components/Divider/variants.ts @@ -11,6 +11,8 @@ export const dividerVariants = cva(styles.divider, { white: styles.white, 'Border/Divider/Default': styles['Border-Divider-Default'], 'Border/Divider/Subtle': styles['Border-Divider-Subtle'], + 'Surface/Brand/Primary 1/OnSurface/Accent Secondary': + styles['Surface-Brand-Primary-1-OnSurface-Accent-Secondary'], }, variant: { horizontal: styles.horizontal,