diff --git a/app/globals.css b/app/globals.css
index 67624cbcf..5ec453db0 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -123,6 +123,7 @@ html,
body {
margin: 0;
padding: 0;
+ scroll-behavior: smooth;
}
body {
@@ -130,6 +131,16 @@ body {
overflow-x: hidden;
}
+body.overflow-hidden {
+ overflow: hidden;
+}
+@media screen and (min-width: 768px) {
+ body.overflow-hidden {
+ overflow: auto;
+ overflow-x: hidden;
+ }
+}
+
ul {
padding-inline-start: 0;
margin-block-start: 0;
diff --git a/components/Content/Blocks/TextCols/index.tsx b/components/Content/Blocks/TextCols/index.tsx
new file mode 100644
index 000000000..afcc6d0cf
--- /dev/null
+++ b/components/Content/Blocks/TextCols/index.tsx
@@ -0,0 +1,29 @@
+import JsonToHtml from "@/components/JsonToHtml"
+import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
+
+import { renderOptions } from "./renderOptions"
+
+import styles from "./textcols.module.css"
+
+import type { TextColsProps } from "@/types/components/content/blocks"
+
+export default function TextCols({ textCols }: TextColsProps) {
+ return (
+
+ {textCols.columns.map((col) => {
+ return (
+
+ )
+ })}
+
+ )
+}
diff --git a/components/Content/Blocks/TextCols/renderOptions.tsx b/components/Content/Blocks/TextCols/renderOptions.tsx
new file mode 100644
index 000000000..55582de95
--- /dev/null
+++ b/components/Content/Blocks/TextCols/renderOptions.tsx
@@ -0,0 +1,70 @@
+import Link from "@/components/TempDesignSystem/Link"
+
+import styles from "./textcols.module.css"
+
+import type { EmbedByUid } from "@/types/components/jsontohtml"
+import { RTEItemTypeEnum, RTETypeEnum } from "@/types/rte/enums"
+import type {
+ RTEDefaultNode,
+ RTENext,
+ RTENode,
+ RTERegularNode,
+} from "@/types/rte/node"
+import type { RenderOptions } from "@/types/rte/option"
+
+export const renderOptions: RenderOptions = {
+ [RTETypeEnum.p]: (
+ node: RTEDefaultNode,
+ embeds: EmbedByUid,
+ next: RTENext,
+ fullRenderOptions: RenderOptions
+ ) => {
+ return (
+
+ {next(node.children, embeds, fullRenderOptions)}
+
+ )
+ },
+ [RTETypeEnum.a]: (
+ node: RTERegularNode,
+ embeds: EmbedByUid,
+ next: RTENext,
+ fullRenderOptions: RenderOptions
+ ) => {
+ if (node.attrs.url) {
+ return (
+
+ {next(node.children, embeds, fullRenderOptions)}
+
+ )
+ }
+ return null
+ },
+ [RTETypeEnum.reference]: (
+ node: RTENode,
+ embeds: EmbedByUid,
+ next: RTENext,
+ fullRenderOptions: RenderOptions
+ ) => {
+ if ("attrs" in node) {
+ const type = node.attrs.type
+ if (type !== RTEItemTypeEnum.asset) {
+ const href = node.attrs?.locale
+ ? `/${node.attrs.locale}${node.attrs.href}`
+ : node.attrs.href
+ return (
+
+ {next(node.children, embeds, fullRenderOptions)}
+
+ )
+ }
+
+ return null
+ }
+ },
+}
diff --git a/components/Content/Blocks/TextCols/textcols.module.css b/components/Content/Blocks/TextCols/textcols.module.css
new file mode 100644
index 000000000..b3e9e2824
--- /dev/null
+++ b/components/Content/Blocks/TextCols/textcols.module.css
@@ -0,0 +1,40 @@
+.columns {
+ display: flex;
+ flex-direction: column;
+ gap: var(--Spacing-x3);
+ padding: var(--Spacing-x3) var(--Spacing-x4);
+}
+
+.column {
+ padding-bottom: var(--Spacing-x2);
+ border-bottom: 1px solid var(--Base-Border-Subtle);
+ gap: var(--Spacing-x1);
+ display: flex;
+ flex-direction: column;
+}
+
+.p {
+ color: var(--UI-Text-High-contrast);
+ line-height: var(--Spacing-x3);
+ margin: 0;
+}
+
+.a {
+ color: var(--Base-Text-High-contrast);
+}
+
+.text > section {
+ gap: 0;
+}
+
+@media (min-width: 768px) {
+ .columns {
+ flex-direction: row;
+ flex-wrap: wrap;
+ }
+
+ .column {
+ flex: 0 0 calc(50% - var(--Spacing-x3));
+ max-width: calc(50% - var(--Spacing-x3));
+ }
+}
diff --git a/components/Content/Blocks/index.tsx b/components/Content/Blocks/index.tsx
index 9c396ed11..77dabdfd1 100644
--- a/components/Content/Blocks/index.tsx
+++ b/components/Content/Blocks/index.tsx
@@ -3,6 +3,7 @@ import JsonToHtml from "@/components/JsonToHtml"
import Shortcuts from "@/components/MyPages/Blocks/Shortcuts"
import CardsGrid from "./CardsGrid"
+import TextCols from "./TextCols"
import type { BlocksProps } from "@/types/components/content/blocks"
import { ContentBlocksTypenameEnum } from "@/types/components/content/enums"
@@ -38,6 +39,8 @@ export function Blocks({ blocks }: BlocksProps) {
firstItem={firstItem}
/>
)
+ case ContentBlocksTypenameEnum.ContentPageBlocksTextCols:
+ return
default:
return null
}
diff --git a/components/LanguageSwitcher/index.tsx b/components/LanguageSwitcher/index.tsx
index 7a5ecb6b2..3d0543051 100644
--- a/components/LanguageSwitcher/index.tsx
+++ b/components/LanguageSwitcher/index.tsx
@@ -1,6 +1,5 @@
"use client"
-import { useEffect } from "react"
import { useIntl } from "react-intl"
import { languages } from "@/constants/languages"
@@ -28,12 +27,16 @@ export default function LanguageSwitcher({
}: LanguageSwitcherProps) {
const intl = useIntl()
const currentLanguage = useLang()
- const {
- toggleDropdown,
- isFooterLanguageSwitcherOpen,
- isHeaderLanguageSwitcherOpen,
- isHeaderLanguageSwitcherMobileOpen,
- } = useDropdownStore()
+ const toggleDropdown = useDropdownStore((state) => state.toggleDropdown)
+ const isFooterLanguageSwitcherOpen = useDropdownStore(
+ (state) => state.isFooterLanguageSwitcherOpen
+ )
+ const isHeaderLanguageSwitcherOpen = useDropdownStore(
+ (state) => state.isHeaderLanguageSwitcherOpen
+ )
+ const isHeaderLanguageSwitcherMobileOpen = useDropdownStore(
+ (state) => state.isHeaderLanguageSwitcherMobileOpen
+ )
const isFooter = type === LanguageSwitcherTypesEnum.Footer
const isHeader = !isFooter
@@ -58,17 +61,14 @@ export default function LanguageSwitcher({
}
})
- useEffect(() => {
- if (isFooter && isFooterLanguageSwitcherOpen) {
- document.body.style.overflow = "hidden"
- } else {
- document.body.style.overflow = ""
- }
+ function handleClick() {
+ const scrollPosition = window.scrollY
+ toggleDropdown(dropdownType)
- return () => {
- document.body.style.overflow = ""
- }
- }, [isFooter, isFooterLanguageSwitcherOpen])
+ requestAnimationFrame(() => {
+ window.scrollTo(0, scrollPosition)
+ })
+ }
const classNames = languageSwitcherVariants({ color, position })
@@ -82,7 +82,7 @@ export default function LanguageSwitcher({
? "Close language menu"
: "Open language menu",
})}
- onClick={() => toggleDropdown(dropdownType)}
+ onClick={handleClick}
>
{languages[currentLanguage]}
diff --git a/lib/graphql/Query/ContentPage.graphql b/lib/graphql/Query/ContentPage.graphql
index dec4b0d6f..e84612c0c 100644
--- a/lib/graphql/Query/ContentPage.graphql
+++ b/lib/graphql/Query/ContentPage.graphql
@@ -98,6 +98,28 @@ query GetContentPage($locale: String!, $uid: String!) {
}
}
}
+ ... on ContentPageBlocksTextCols {
+ __typename
+ text_cols {
+ columns {
+ title
+ text {
+ json
+ embedded_itemsConnection {
+ edges {
+ node {
+ __typename
+ ...LoyaltyPageLink
+ ...ContentPageLink
+ ...HotelPageLink
+ }
+ }
+ totalCount
+ }
+ }
+ }
+ }
+ }
}
title
header {
diff --git a/server/routers/contentstack/contentPage/output.ts b/server/routers/contentstack/contentPage/output.ts
index 1aa324041..21d7b1708 100644
--- a/server/routers/contentstack/contentPage/output.ts
+++ b/server/routers/contentstack/contentPage/output.ts
@@ -12,12 +12,8 @@ import {
SidebarDynamicComponentEnum,
SidebarTypenameEnum,
} from "@/types/components/content/enums"
-import { ImageVaultAsset } from "@/types/components/imageVault"
-import { Embeds } from "@/types/requests/embeds"
import { PageLinkEnum } from "@/types/requests/pageLinks"
import { RTEEmbedsEnum } from "@/types/requests/rte"
-import { EdgesWithTotalCount } from "@/types/requests/utils/edges"
-import { RTEDocument } from "@/types/rte/node"
// Block schemas
export const contentPageBlockTextContent = z.object({
@@ -135,11 +131,29 @@ export const contentPageCards = z.object({
}),
})
+export const contentPageTextCols = z.object({
+ __typename: z.literal(ContentBlocksTypenameEnum.ContentPageBlocksTextCols),
+ text_cols: z.object({
+ columns: z.array(
+ z.object({
+ title: z.string(),
+ text: z.object({
+ json: z.any(),
+ embedded_itemsConnection: z.object({
+ edges: z.array(z.any()),
+ totalCount: z.number(),
+ }),
+ }),
+ })
+ ),
+ }),
+})
const contentPageBlockItem = z.discriminatedUnion("__typename", [
contentPageBlockTextContent,
contentPageCards,
contentPageDynamicContent,
contentPageShortcuts,
+ contentPageTextCols,
])
export const contentPageSidebarTextContent = z.object({
diff --git a/server/trpc.ts b/server/trpc.ts
index 7a7a7f7ea..e3085f216 100644
--- a/server/trpc.ts
+++ b/server/trpc.ts
@@ -4,13 +4,13 @@ import { ZodError } from "zod"
import { env } from "@/env/server"
-import { type Context, createContext } from "./context"
import {
badRequestError,
internalServerError,
sessionExpiredError,
unauthorizedError,
} from "./errors/trpc"
+import { type Context, createContext } from "./context"
import { fetchServiceToken } from "./tokenManager"
import { transformer } from "./transformer"
diff --git a/stores/main-menu.ts b/stores/main-menu.ts
index 29e039e99..4ccbcb290 100644
--- a/stores/main-menu.ts
+++ b/stores/main-menu.ts
@@ -85,6 +85,11 @@ const useDropdownStore = create((set, get) => ({
state.isMyPagesMenuOpen = false
state.isHeaderLanguageSwitcherOpen = false
state.isHeaderLanguageSwitcherMobileOpen = false
+ if (state.isFooterLanguageSwitcherOpen) {
+ document.body.classList.add("overflow-hidden")
+ } else {
+ document.body.classList.remove("overflow-hidden")
+ }
break
}
})
diff --git a/types/components/content/blocks.ts b/types/components/content/blocks.ts
index a97ac9780..a29912359 100644
--- a/types/components/content/blocks.ts
+++ b/types/components/content/blocks.ts
@@ -7,6 +7,7 @@ import {
Block,
CardsGrid,
DynamicContent,
+ TextCols,
} from "@/types/trpc/routers/contentstack/contentPage"
export type BlocksProps = {
@@ -17,6 +18,10 @@ export type CardsGridProps = Pick & {
firstItem?: boolean
}
+export type TextColsProps = {
+ textCols: TextCols["text_cols"]
+}
+
export type DynamicContentProps = {
dynamicContent: DynamicContent["dynamic_content"]
firstItem: boolean
diff --git a/types/components/content/enums.ts b/types/components/content/enums.ts
index 3bc20ac48..cafb608fa 100644
--- a/types/components/content/enums.ts
+++ b/types/components/content/enums.ts
@@ -6,6 +6,7 @@ export enum ContentBlocksTypenameEnum {
ContentPageBlocksShortcuts = "ContentPageBlocksShortcuts",
ContentPageBlocksCardsGrid = "ContentPageBlocksCardsGrid",
ContentPageBlocksDynamicContent = "ContentPageBlocksDynamicContent",
+ ContentPageBlocksTextCols = "ContentPageBlocksTextCols",
}
export enum CardsGridEnum {
diff --git a/types/trpc/routers/contentstack/contentPage.ts b/types/trpc/routers/contentstack/contentPage.ts
index 4c3f27ce6..29eaf983e 100644
--- a/types/trpc/routers/contentstack/contentPage.ts
+++ b/types/trpc/routers/contentstack/contentPage.ts
@@ -9,6 +9,7 @@ import {
contentPageShortcuts,
contentPageSidebarDynamicContent,
contentPageSidebarTextContent,
+ contentPageTextCols,
loyaltyCardBlock,
validateContentPageRefsSchema,
validateContentPageSchema,
@@ -81,4 +82,22 @@ export type CardsGrid = Omit & {
}
export type CardsRaw = CardsGrid["cards_grid"]["cards"][number]
-export type Block = RteBlockContent | Shortcuts | CardsGrid | DynamicContent
+type TextColsRaw = z.infer
+export interface TextCols extends TextColsRaw {
+ textCols: {
+ columns: {
+ title: string
+ text: {
+ json: RTEDocument
+ embedded_itemsConnection: EdgesWithTotalCount
+ }
+ }[]
+ }
+}
+
+export type Block =
+ | RteBlockContent
+ | Shortcuts
+ | CardsGrid
+ | DynamicContent
+ | TextCols