Merged develop into feat/hotel-pages-intro-section
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
padding-left: var(--Spacing-x0);
|
||||
padding-right: var(--Spacing-x0);
|
||||
position: relative;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.blocks {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useRouter } from "next/navigation"
|
||||
|
||||
import { Button } from "@scandic-hotels/design-system/current"
|
||||
|
||||
import { renderOptions as currentRenderOptions } from "@/components/Current/currentRenderOptions"
|
||||
import Image from "@/components/Image"
|
||||
import JsonToHtml from "@/components/JsonToHtml"
|
||||
|
||||
@@ -44,7 +45,7 @@ export default function Puff({
|
||||
<JsonToHtml
|
||||
embeds={[]}
|
||||
nodes={text.json.children}
|
||||
renderOptions={renderOptions}
|
||||
renderOptions={{ ...currentRenderOptions, ...renderOptions }}
|
||||
/>
|
||||
<div>
|
||||
<Button onPress={onClick}>{link.title || title}</Button>
|
||||
@@ -73,7 +74,7 @@ export default function Puff({
|
||||
<JsonToHtml
|
||||
embeds={[]}
|
||||
nodes={text.json.children}
|
||||
renderOptions={renderOptions}
|
||||
renderOptions={{ ...currentRenderOptions, ...renderOptions }}
|
||||
/>
|
||||
</section>
|
||||
</article>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import JsonToHtml from "@/components/JsonToHtml"
|
||||
|
||||
import { renderOptions } from "./../currentRenderOptions"
|
||||
|
||||
import type { TextProps } from "@/types/components/current/blocks/text"
|
||||
|
||||
export default function Text({ text }: TextProps) {
|
||||
@@ -7,6 +9,7 @@ export default function Text({ text }: TextProps) {
|
||||
<JsonToHtml
|
||||
embeds={text.content.embedded_itemsConnection.edges}
|
||||
nodes={text.content.json.children}
|
||||
renderOptions={renderOptions}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import JsonToHtml from "@/components/JsonToHtml"
|
||||
|
||||
import { renderOptions as currentRenderOptions } from "./../currentRenderOptions"
|
||||
import Breadcrumbs from "./Breadcrumbs"
|
||||
import { renderOptions } from "./renderOptions"
|
||||
|
||||
@@ -27,7 +28,7 @@ export default function Preamble({
|
||||
<JsonToHtml
|
||||
embeds={preamble.text.embedded_itemsConnection.edges}
|
||||
nodes={preamble.text.json.children}
|
||||
renderOptions={renderOptions}
|
||||
renderOptions={{ ...currentRenderOptions, ...renderOptions }}
|
||||
/>
|
||||
) : null}
|
||||
</section>
|
||||
|
||||
6
components/Current/currentRenderOptions.module.css
Normal file
6
components/Current/currentRenderOptions.module.css
Normal file
@@ -0,0 +1,6 @@
|
||||
.image {
|
||||
height: auto;
|
||||
margin-bottom: var(--Spacing-x2);
|
||||
max-width: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
474
components/Current/currentRenderOptions.tsx
Normal file
474
components/Current/currentRenderOptions.tsx
Normal file
@@ -0,0 +1,474 @@
|
||||
import Image from "@/components/Image"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
|
||||
import styles from "./currentRenderOptions.module.css"
|
||||
|
||||
import type { EmbedByUid } from "@/types/components/jsontohtml"
|
||||
import { EmbedEnum } from "@/types/requests/utils/embeds"
|
||||
import type { Attributes } from "@/types/rte/attrs"
|
||||
import { RTEItemTypeEnum, RTETypeEnum } from "@/types/rte/enums"
|
||||
import type {
|
||||
RTEDefaultNode,
|
||||
RTENext,
|
||||
RTENode,
|
||||
RTERegularNode,
|
||||
} from "@/types/rte/node"
|
||||
import { RTEMarkType } from "@/types/rte/node"
|
||||
import type { RenderOptions } from "@/types/rte/option"
|
||||
|
||||
function extractPossibleAttributes(attrs: Attributes | undefined) {
|
||||
if (!attrs) return {}
|
||||
const props: Record<string, any> = {}
|
||||
if (attrs.id) {
|
||||
props.id = attrs.id
|
||||
}
|
||||
|
||||
if (attrs.class) {
|
||||
props.className = attrs.class
|
||||
} else if (attrs["class-name"]) {
|
||||
props.className = attrs["class-name"]
|
||||
} else if (attrs.classname) {
|
||||
props.className = attrs.classname
|
||||
} else if (attrs?.style?.["text-align"]) {
|
||||
props.style = {
|
||||
textAlign: attrs?.style?.["text-align"],
|
||||
}
|
||||
}
|
||||
|
||||
return props
|
||||
}
|
||||
|
||||
export const renderOptions: RenderOptions = {
|
||||
[RTETypeEnum.a]: (
|
||||
node: RTERegularNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
if (node.attrs.url) {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<a
|
||||
{...props}
|
||||
href={node.attrs.url}
|
||||
target={node.attrs.target ?? "_blank"}
|
||||
key={node.uid}
|
||||
>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
return null
|
||||
},
|
||||
|
||||
[RTETypeEnum.blockquote]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<blockquote key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</blockquote>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.code]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<code key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</code>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.embed]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
if (node.attrs.src) {
|
||||
props.src = node.attrs.src
|
||||
}
|
||||
if (node.attrs.url) {
|
||||
props.src = node.attrs.url
|
||||
}
|
||||
if (!props.src) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<iframe key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</iframe>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.h1]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<h1 key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</h1>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.h2]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<h2 key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</h2>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.h3]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<h3 key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</h3>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.h4]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<h4 key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</h4>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.h5]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<h5 key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</h5>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.h6]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<h6 key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</h6>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.hr]: () => {
|
||||
return <hr />
|
||||
},
|
||||
|
||||
[RTETypeEnum.li]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<li key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</li>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.ol]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<ol key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</ol>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.p]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<p {...props} key={node.uid}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</p>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.reference]: (
|
||||
node: RTENode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
if ("attrs" in node) {
|
||||
const type = node.attrs.type
|
||||
if (type === RTEItemTypeEnum.asset) {
|
||||
const image = embeds?.[node?.attrs?.["asset-uid"]]
|
||||
if (image?.node.__typename === EmbedEnum.SysAsset) {
|
||||
const alt = image?.node?.title ?? node.attrs.alt
|
||||
const alignment = node.attrs?.style?.["text-align"]
|
||||
? {
|
||||
alignSelf: node.attrs?.style?.["text-align"],
|
||||
}
|
||||
: {}
|
||||
return (
|
||||
<Image
|
||||
key={node.uid}
|
||||
alt={alt}
|
||||
className={styles.image}
|
||||
height={image.node.dimension.height}
|
||||
src={image?.node?.url}
|
||||
width={image.node.dimension.width}
|
||||
style={alignment}
|
||||
/>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
const href = node.attrs?.locale
|
||||
? `/${node.attrs.locale}${node.attrs.href}`
|
||||
: node.attrs.href
|
||||
return (
|
||||
<Link {...props} href={href} key={node.uid}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
},
|
||||
|
||||
[RTETypeEnum.table]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<table key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</table>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.thead]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<thead key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</thead>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.tbody]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<tbody key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</tbody>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.tfoot]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<tfoot key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</tfoot>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.tr]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<tr key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</tr>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.th]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<th key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</th>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.td]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<td key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</td>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.ul]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<ul key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</ul>
|
||||
)
|
||||
},
|
||||
|
||||
/** TextNode wrappers */
|
||||
[RTEMarkType.bold]: (children: React.ReactNode) => {
|
||||
return <strong>{children}</strong>
|
||||
},
|
||||
|
||||
[RTEMarkType.italic]: (children: React.ReactNode) => {
|
||||
return <em>{children}</em>
|
||||
},
|
||||
|
||||
[RTEMarkType.underline]: (children: React.ReactNode) => {
|
||||
return <u>{children}</u>
|
||||
},
|
||||
|
||||
[RTEMarkType.strikethrough]: (children: React.ReactNode) => {
|
||||
return <s>{children}</s>
|
||||
},
|
||||
|
||||
[RTEMarkType.inlineCode]: (children: React.ReactNode) => {
|
||||
return <span>{children}</span>
|
||||
},
|
||||
|
||||
[RTEMarkType.subscript]: (children: React.ReactNode) => {
|
||||
return <sub>{children}</sub>
|
||||
},
|
||||
|
||||
[RTEMarkType.superscript]: (children: React.ReactNode) => {
|
||||
return <sup>{children}</sup>
|
||||
},
|
||||
|
||||
[RTEMarkType.break]: (children: React.ReactNode) => {
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
{children}
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
||||
[RTEMarkType.classnameOrId]: (
|
||||
children: React.ReactNode,
|
||||
className?: string,
|
||||
id?: string
|
||||
) => {
|
||||
let props = {
|
||||
className,
|
||||
id,
|
||||
}
|
||||
if (!className) {
|
||||
delete props.className
|
||||
}
|
||||
if (!id) {
|
||||
delete props.id
|
||||
}
|
||||
return (
|
||||
<span key={id} {...props}>
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
|
||||
/**
|
||||
* Contentstack can return something called `default` as seen here in their
|
||||
* own SDK (https://github.com/contentstack/contentstack-utils-javascript/blob/master/src/options/default-node-options.ts#L89)
|
||||
*/
|
||||
default: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
return next(node.children, embeds, fullRenderOptions)
|
||||
},
|
||||
}
|
||||
24
components/ImageContainer/imageContainer.module.css
Normal file
24
components/ImageContainer/imageContainer.module.css
Normal file
@@ -0,0 +1,24 @@
|
||||
.container {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x2);
|
||||
width: 100%;
|
||||
grid-template-columns: auto;
|
||||
}
|
||||
|
||||
.image {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
height: 365px;
|
||||
object-fit: cover;
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.container {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
.image {
|
||||
margin: var(--Spacing-x1) var(--Spacing-x0);
|
||||
}
|
||||
}
|
||||
36
components/ImageContainer/index.tsx
Normal file
36
components/ImageContainer/index.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import Image from "../Image"
|
||||
import Caption from "../TempDesignSystem/Text/Caption"
|
||||
|
||||
import styles from "./imageContainer.module.css"
|
||||
|
||||
import type { ImageContainerProps } from "@/types/components/imageContainer"
|
||||
|
||||
export default function ImageContainer({
|
||||
leftImage,
|
||||
rightImage,
|
||||
}: ImageContainerProps) {
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<article>
|
||||
<Image
|
||||
className={styles.image}
|
||||
src={leftImage.url}
|
||||
height={365}
|
||||
width={600}
|
||||
alt={leftImage.meta.alt || leftImage.title}
|
||||
/>
|
||||
<Caption>{leftImage.meta.caption}</Caption>
|
||||
</article>
|
||||
<article>
|
||||
<Image
|
||||
className={styles.image}
|
||||
src={rightImage.url}
|
||||
height={365}
|
||||
width={600}
|
||||
alt={rightImage.meta.alt || rightImage.title}
|
||||
/>
|
||||
<Caption>{leftImage.meta.caption}</Caption>
|
||||
</article>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import { nodesToHtml } from "./utils"
|
||||
|
||||
import styles from "./jsontohtml.module.css"
|
||||
|
||||
import type { JsonToHtmlProps } from "@/types/components/jsontohtml"
|
||||
|
||||
export default function JsonToHtml({
|
||||
@@ -10,5 +12,9 @@ export default function JsonToHtml({
|
||||
if (!Array.isArray(nodes) || !nodes.length) {
|
||||
return null
|
||||
}
|
||||
return <>{nodesToHtml(nodes, embeds, renderOptions).filter(Boolean)}</>
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
{nodesToHtml(nodes, embeds, renderOptions).filter(Boolean)}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,60 @@
|
||||
.image {
|
||||
height: auto;
|
||||
margin-bottom: var(--Spacing-x2);
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
height: 365px;
|
||||
object-fit: cover;
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
margin: var(--Spacing-x1) var(--Spacing-x0);
|
||||
}
|
||||
|
||||
.ul,
|
||||
.ol {
|
||||
padding: var(--Spacing-x2) var(--Spacing-x0);
|
||||
display: grid;
|
||||
gap: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.ol:has(li:nth-last-child(n + 4)),
|
||||
.ul:has(li:nth-last-child(n + 4)) {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-auto-flow: column;
|
||||
}
|
||||
|
||||
.ol > li::marker {
|
||||
color: var(--Primary-Light-On-Surface-Accent);
|
||||
}
|
||||
|
||||
.ul:has(.heart),
|
||||
.ul:has(.check) {
|
||||
list-style: none;
|
||||
}
|
||||
.li:has(.heart),
|
||||
.li:has(.check) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.li:not(:has(.heart), :has(.check)) {
|
||||
margin-left: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.li:has(.heart):before {
|
||||
content: url("/_static/icons/heart.svg");
|
||||
position: relative;
|
||||
margin-right: var(--Spacing-x1);
|
||||
height: 8px;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.li:has(.check)::before {
|
||||
content: url("/_static/icons/check-ring.svg");
|
||||
position: relative;
|
||||
margin-right: var(--Spacing-x1);
|
||||
height: 8px;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: "grid";
|
||||
gap: var(--Spacing-x3);
|
||||
max-width: 1197px;
|
||||
}
|
||||
|
||||
@@ -1,17 +1,34 @@
|
||||
import Image from "@/components/Image"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import { insertResponseToImageVaultAsset } from "@/utils/imageVault"
|
||||
|
||||
import ImageContainer from "../ImageContainer"
|
||||
import Divider from "../TempDesignSystem/Divider"
|
||||
import BiroScript from "../TempDesignSystem/Text/BiroScript"
|
||||
import Body from "../TempDesignSystem/Text/Body"
|
||||
import Caption from "../TempDesignSystem/Text/Caption"
|
||||
import Footnote from "../TempDesignSystem/Text/Footnote"
|
||||
import Subtitle from "../TempDesignSystem/Text/Subtitle"
|
||||
import Title from "../TempDesignSystem/Text/Title"
|
||||
import { hasAvailableParagraphFormat, hasAvailableULFormat } from "./utils"
|
||||
|
||||
import styles from "./jsontohtml.module.css"
|
||||
|
||||
import type { EmbedByUid } from "@/types/components/jsontohtml"
|
||||
import { EmbedEnum } from "@/types/requests/utils/embeds"
|
||||
import type { Attributes } from "@/types/rte/attrs"
|
||||
import { RTEItemTypeEnum, RTETypeEnum } from "@/types/rte/enums"
|
||||
import type { Attributes, RTEImageVaultAttrs } from "@/types/rte/attrs"
|
||||
import {
|
||||
AvailableParagraphFormatEnum,
|
||||
RTEItemTypeEnum,
|
||||
RTETypeEnum,
|
||||
} from "@/types/rte/enums"
|
||||
import type {
|
||||
RTEDefaultNode,
|
||||
RTEImageNode,
|
||||
RTENext,
|
||||
RTENode,
|
||||
RTERegularNode,
|
||||
RTETextNode,
|
||||
} from "@/types/rte/node"
|
||||
import { RTEMarkType } from "@/types/rte/node"
|
||||
import type { RenderOptions } from "@/types/rte/option"
|
||||
@@ -48,14 +65,16 @@ export const renderOptions: RenderOptions = {
|
||||
if (node.attrs.url) {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<a
|
||||
<Link
|
||||
{...props}
|
||||
href={node.attrs.url}
|
||||
target={node.attrs.target ?? "_blank"}
|
||||
key={node.uid}
|
||||
target={node.attrs.target ?? "_blank"}
|
||||
variant="underscored"
|
||||
color="burgundy"
|
||||
>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
return null
|
||||
@@ -69,9 +88,9 @@ export const renderOptions: RenderOptions = {
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<blockquote key={node.uid} {...props}>
|
||||
<BiroScript key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</blockquote>
|
||||
</BiroScript>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -120,9 +139,9 @@ export const renderOptions: RenderOptions = {
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<h1 key={node.uid} {...props}>
|
||||
<Title key={node.uid} {...props} level="h1">
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</h1>
|
||||
</Title>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -134,9 +153,9 @@ export const renderOptions: RenderOptions = {
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<h2 key={node.uid} {...props}>
|
||||
<Title key={node.uid} {...props} level="h2">
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</h2>
|
||||
</Title>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -148,9 +167,9 @@ export const renderOptions: RenderOptions = {
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<h3 key={node.uid} {...props}>
|
||||
<Title key={node.uid} {...props} level="h3">
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</h3>
|
||||
</Title>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -162,9 +181,9 @@ export const renderOptions: RenderOptions = {
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<h4 key={node.uid} {...props}>
|
||||
<Title key={node.uid} {...props} level="h4">
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</h4>
|
||||
</Title>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -176,28 +195,14 @@ export const renderOptions: RenderOptions = {
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<h5 key={node.uid} {...props}>
|
||||
<Title key={node.uid} {...props} level="h5">
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</h5>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.h6]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<h6 key={node.uid} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</h6>
|
||||
</Title>
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.hr]: () => {
|
||||
return <hr />
|
||||
return <Divider />
|
||||
},
|
||||
|
||||
[RTETypeEnum.li]: (
|
||||
@@ -208,7 +213,7 @@ export const renderOptions: RenderOptions = {
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
return (
|
||||
<li key={node.uid} {...props}>
|
||||
<li key={node.uid} {...props} className={styles.li}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</li>
|
||||
)
|
||||
@@ -221,8 +226,26 @@ export const renderOptions: RenderOptions = {
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
|
||||
// Set the number of rows dynamically to create even rows for each column. We want the li:s
|
||||
// to flow with the column, so therefore this is needed.
|
||||
let numberOfRows: number | undefined
|
||||
if (node.children.length > 4) {
|
||||
const half = node.children.length / 2
|
||||
numberOfRows = Math.ceil(half)
|
||||
}
|
||||
|
||||
return (
|
||||
<ol key={node.uid} {...props}>
|
||||
<ol
|
||||
key={node.uid}
|
||||
{...props}
|
||||
className={styles.ol}
|
||||
style={
|
||||
numberOfRows
|
||||
? { gridTemplateRows: `repeat(${numberOfRows}, auto)` }
|
||||
: {}
|
||||
}
|
||||
>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</ol>
|
||||
)
|
||||
@@ -235,10 +258,21 @@ export const renderOptions: RenderOptions = {
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
|
||||
const hasFormat = node.children.some((item) =>
|
||||
hasAvailableParagraphFormat((item as RTETextNode)?.classname)
|
||||
)
|
||||
|
||||
// If a child node has an available format as className, we wrap it in a
|
||||
// span and render the children with the correct component
|
||||
if (hasFormat) {
|
||||
return next(node.children, embeds, fullRenderOptions)
|
||||
}
|
||||
|
||||
return (
|
||||
<p {...props} key={node.uid}>
|
||||
<Body {...props} key={node.uid}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</p>
|
||||
</Body>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -254,32 +288,78 @@ export const renderOptions: RenderOptions = {
|
||||
const image = embeds?.[node?.attrs?.["asset-uid"]]
|
||||
if (image?.node.__typename === EmbedEnum.SysAsset) {
|
||||
const alt = image?.node?.title ?? node.attrs.alt
|
||||
const alignment = node.attrs?.style?.["text-align"]
|
||||
? {
|
||||
alignSelf: node.attrs?.style?.["text-align"],
|
||||
}
|
||||
: {}
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
props.className = styles.image
|
||||
return (
|
||||
<Image
|
||||
key={node.uid}
|
||||
alt={alt}
|
||||
className={styles.image}
|
||||
height={image.node.dimension.height}
|
||||
src={image?.node?.url}
|
||||
width={image.node.dimension.width}
|
||||
style={alignment}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
const href = node.attrs?.locale
|
||||
? `/${node.attrs.locale}${node.attrs.href}`
|
||||
: node.attrs.href
|
||||
} else if (type === RTEItemTypeEnum.entry) {
|
||||
const entry = embeds?.[node?.attrs?.["entry-uid"]]
|
||||
|
||||
if (entry?.node.__typename === EmbedEnum.ImageContainer) {
|
||||
const leftImage = insertResponseToImageVaultAsset(
|
||||
entry.node.image_left
|
||||
)
|
||||
const rightImage = insertResponseToImageVaultAsset(
|
||||
entry.node.image_right
|
||||
)
|
||||
return (
|
||||
<ImageContainer leftImage={leftImage} rightImage={rightImage} />
|
||||
)
|
||||
} else {
|
||||
// If entry is not an ImageContainer, it is a page and we return it as a link
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
const href = node.attrs?.locale
|
||||
? `/${node.attrs.locale}${node.attrs.href}`
|
||||
: node.attrs.href
|
||||
return (
|
||||
<Link
|
||||
{...props}
|
||||
href={href}
|
||||
key={node.uid}
|
||||
variant="underscored"
|
||||
color="burgundy"
|
||||
>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
},
|
||||
|
||||
[RTETypeEnum.ImageVault]: (node: RTEImageNode) => {
|
||||
if ("attrs" in node) {
|
||||
const type = node.type
|
||||
if (type === RTETypeEnum.ImageVault) {
|
||||
const attrs = node.attrs as RTEImageVaultAttrs
|
||||
const image = insertResponseToImageVaultAsset(attrs)
|
||||
const alt = image.meta.alt ?? image.title
|
||||
|
||||
const width = parseInt(attrs.width.replaceAll("px", ""))
|
||||
const props = extractPossibleAttributes(attrs)
|
||||
return (
|
||||
<Link {...props} href={href} key={node.uid}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</Link>
|
||||
<section key={node.uid}>
|
||||
<Image
|
||||
alt={alt}
|
||||
className={styles.image}
|
||||
height={365}
|
||||
src={image.url}
|
||||
width={width}
|
||||
{...props}
|
||||
/>
|
||||
<Caption>{image.meta.caption}</Caption>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -343,6 +423,15 @@ export const renderOptions: RenderOptions = {
|
||||
)
|
||||
},
|
||||
|
||||
[RTETypeEnum.fragment]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
next: RTENext,
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
return <>{next(node.children, embeds, fullRenderOptions)}</>
|
||||
},
|
||||
|
||||
[RTETypeEnum.tr]: (
|
||||
node: RTEDefaultNode,
|
||||
embeds: EmbedByUid,
|
||||
@@ -392,8 +481,26 @@ export const renderOptions: RenderOptions = {
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const props = extractPossibleAttributes(node.attrs)
|
||||
|
||||
// Set the number of rows dynamically to create even rows for each column. We want the li:s
|
||||
// to flow with the column, so therefore this is needed.
|
||||
let numberOfRows: number | undefined
|
||||
if (node.children.length > 4) {
|
||||
const half = node.children.length / 2
|
||||
numberOfRows = Math.ceil(half)
|
||||
}
|
||||
|
||||
return (
|
||||
<ul key={node.uid} {...props}>
|
||||
<ul
|
||||
key={node.uid}
|
||||
{...props}
|
||||
className={styles.ul}
|
||||
style={
|
||||
numberOfRows
|
||||
? { gridTemplateRows: `repeat(${numberOfRows}, auto)` }
|
||||
: {}
|
||||
}
|
||||
>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</ul>
|
||||
)
|
||||
@@ -452,6 +559,62 @@ export const renderOptions: RenderOptions = {
|
||||
if (!id) {
|
||||
delete props.id
|
||||
}
|
||||
|
||||
if (className) {
|
||||
if (hasAvailableULFormat(className)) {
|
||||
// @ts-ignore: We want to set css modules classNames even if it does not correspond
|
||||
// to an existing class in the module style sheet. Due to our css modules plugin for
|
||||
// typescript, we cannot do this without the ts-ignore
|
||||
props.className = styles[className]
|
||||
}
|
||||
}
|
||||
|
||||
if (className === AvailableParagraphFormatEnum.footnote) {
|
||||
return (
|
||||
<Footnote key={id} {...props}>
|
||||
{children}
|
||||
</Footnote>
|
||||
)
|
||||
}
|
||||
|
||||
if (className === AvailableParagraphFormatEnum.caption) {
|
||||
return (
|
||||
<Caption key={id} {...props}>
|
||||
{children}
|
||||
</Caption>
|
||||
)
|
||||
}
|
||||
|
||||
if (className === AvailableParagraphFormatEnum["script-1"]) {
|
||||
return (
|
||||
<BiroScript key={id} type="one" {...props}>
|
||||
{children}
|
||||
</BiroScript>
|
||||
)
|
||||
}
|
||||
|
||||
if (className === AvailableParagraphFormatEnum["script-2"]) {
|
||||
return (
|
||||
<BiroScript key={id} type="two" {...props}>
|
||||
{children}
|
||||
</BiroScript>
|
||||
)
|
||||
}
|
||||
|
||||
if (className === AvailableParagraphFormatEnum["subtitle-1"]) {
|
||||
return (
|
||||
<Subtitle key={id} {...props}>
|
||||
{children}
|
||||
</Subtitle>
|
||||
)
|
||||
}
|
||||
if (className === AvailableParagraphFormatEnum["subtitle-2"]) {
|
||||
return (
|
||||
<Subtitle key={id} {...props}>
|
||||
{children}
|
||||
</Subtitle>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<span key={id} {...props}>
|
||||
{children}
|
||||
|
||||
@@ -3,7 +3,11 @@ import { renderOptions } from "./renderOptions"
|
||||
import type { EmbedByUid } from "@/types/components/jsontohtml"
|
||||
import type { Embeds } from "@/types/requests/embeds"
|
||||
import type { Node } from "@/types/requests/utils/edges"
|
||||
import { RTETypeEnum } from "@/types/rte/enums"
|
||||
import {
|
||||
AvailableParagraphFormatEnum,
|
||||
AvailableULFormatEnum,
|
||||
RTETypeEnum,
|
||||
} from "@/types/rte/enums"
|
||||
import type {
|
||||
RTENode,
|
||||
RTERenderOptionComponent,
|
||||
@@ -74,7 +78,6 @@ export function textNodeToHtml(
|
||||
if (node.bold) {
|
||||
text = (fullRenderOptions[RTEMarkType.bold] as RTERenderMark)(text)
|
||||
}
|
||||
|
||||
return text
|
||||
}
|
||||
|
||||
@@ -86,6 +89,20 @@ function next(
|
||||
return nodeChildrenToHtml(nodes, embeds, fullRenderOptions)
|
||||
}
|
||||
|
||||
export function hasAvailableParagraphFormat(className?: string) {
|
||||
if (!className) {
|
||||
return false
|
||||
}
|
||||
return Object.keys(AvailableParagraphFormatEnum).includes(className)
|
||||
}
|
||||
|
||||
export function hasAvailableULFormat(className?: string) {
|
||||
if (!className) {
|
||||
return false
|
||||
}
|
||||
return Object.keys(AvailableULFormatEnum).includes(className)
|
||||
}
|
||||
|
||||
export function nodeToHtml(
|
||||
node: RTENode,
|
||||
embeds: EmbedByUid,
|
||||
|
||||
@@ -44,7 +44,7 @@ export default async function ContactRow({ contact }: ContactRowProps) {
|
||||
<Link
|
||||
className={styles.link}
|
||||
href={openableLink}
|
||||
variant="myPage"
|
||||
variant="underscored"
|
||||
color="burgundy"
|
||||
size="small"
|
||||
>
|
||||
|
||||
@@ -18,7 +18,7 @@ export default function SectionLink({ link, variant }: SectionLinkProps) {
|
||||
className={classNames}
|
||||
color="burgundy"
|
||||
href={link.href}
|
||||
variant="myPage"
|
||||
variant="underscored"
|
||||
>
|
||||
<ArrowRight color="burgundy" className={styles.icon} />
|
||||
{link.text}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
gap: var(--Spacing-x-half);
|
||||
}
|
||||
|
||||
.myPage {
|
||||
.underscored {
|
||||
font-family: var(--typography-Body-Underlined-fontFamily);
|
||||
font-size: var(--typography-Body-Underlined-fontSize);
|
||||
font-weight: var(--typography-Body-Underlined-fontWeight);
|
||||
|
||||
@@ -23,7 +23,7 @@ export const linkVariants = cva(styles.link, {
|
||||
breadcrumb: styles.breadcrumb,
|
||||
default: styles.default,
|
||||
icon: styles.icon,
|
||||
myPage: styles.myPage,
|
||||
underscored: styles.underscored,
|
||||
myPageMobileDropdown: styles.myPageMobileDropdown,
|
||||
shortcut: styles.shortcut,
|
||||
sidebar: styles.sidebar,
|
||||
|
||||
@@ -49,7 +49,7 @@ export default function LoyaltyCard({
|
||||
color="burgundy"
|
||||
href={link.href}
|
||||
target={link.openInNewTab ? "_blank" : undefined}
|
||||
variant="myPage"
|
||||
variant="underscored"
|
||||
>
|
||||
<ArrowRight
|
||||
color="burgundy"
|
||||
|
||||
@@ -32,7 +32,6 @@ const config = {
|
||||
defaultVariants: {
|
||||
color: "burgundy",
|
||||
textAlign: "left",
|
||||
textTransform: "uppercase",
|
||||
type: "h1",
|
||||
},
|
||||
} as const
|
||||
|
||||
@@ -70,6 +70,15 @@ query GetLoyaltyPage($locale: String!, $uid: String!) {
|
||||
__typename
|
||||
...LoyaltyPageLink
|
||||
...ContentPageLink
|
||||
...Image
|
||||
... on ImageContainer {
|
||||
title
|
||||
image_left
|
||||
image_right
|
||||
system {
|
||||
uid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
totalCount
|
||||
@@ -223,6 +232,12 @@ query GetLoyaltyPageRefs($locale: String!, $uid: String!) {
|
||||
...System
|
||||
}
|
||||
}
|
||||
... on ImageContainer {
|
||||
__typename
|
||||
system {
|
||||
...System
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
8
public/_static/icons/check-ring.svg
Normal file
8
public/_static/icons/check-ring.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_5625_32337" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="16" height="16">
|
||||
<rect width="16" height="16" fill="#D9D9D9"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_5625_32337)">
|
||||
<path d="M7.08333 9.21667L5.65738 7.79072C5.53579 7.66913 5.38889 7.60833 5.21667 7.60833C5.04444 7.60833 4.89722 7.66944 4.775 7.79167C4.65278 7.91389 4.59167 8.06111 4.59167 8.23333C4.59167 8.40556 4.6518 8.5518 4.77207 8.67207L6.64167 10.5417C6.76742 10.6694 6.91414 10.7333 7.08182 10.7333C7.2495 10.7333 7.39722 10.6694 7.525 10.5417L11.225 6.84167C11.3472 6.71944 11.4083 6.57222 11.4083 6.4C11.4083 6.22778 11.3472 6.08056 11.225 5.95833C11.1028 5.83611 10.9556 5.775 10.7833 5.775C10.6111 5.775 10.4646 5.83538 10.3439 5.95613L7.08333 9.21667ZM8 14.5C7.10103 14.5 6.25623 14.3291 5.46558 13.9873C4.67493 13.6455 3.98717 13.1816 3.4023 12.5956C2.81743 12.0097 2.35417 11.3217 2.0125 10.5319C1.67083 9.74202 1.5 8.89806 1.5 8C1.5 7.10103 1.67091 6.25623 2.01272 5.46558C2.35453 4.67493 2.81842 3.98717 3.40438 3.4023C3.99035 2.81743 4.67826 2.35417 5.46812 2.0125C6.25798 1.67083 7.10194 1.5 8 1.5C8.89897 1.5 9.74377 1.67091 10.5344 2.01272C11.3251 2.35453 12.0128 2.81842 12.5977 3.40438C13.1826 3.99035 13.6458 4.67826 13.9875 5.46812C14.3292 6.25798 14.5 7.10194 14.5 8C14.5 8.89897 14.3291 9.74377 13.9873 10.5344C13.6455 11.3251 13.1816 12.0128 12.5956 12.5977C12.0097 13.1826 11.3217 13.6458 10.5319 13.9875C9.74202 14.3292 8.89806 14.5 8 14.5ZM8 13.25C9.46111 13.25 10.7014 12.7403 11.7208 11.7208C12.7403 10.7014 13.25 9.46111 13.25 8C13.25 6.53889 12.7403 5.29861 11.7208 4.27917C10.7014 3.25972 9.46111 2.75 8 2.75C6.53889 2.75 5.29861 3.25972 4.27917 4.27917C3.25972 5.29861 2.75 6.53889 2.75 8C2.75 9.46111 3.25972 10.7014 4.27917 11.7208C5.29861 12.7403 6.53889 13.25 8 13.25Z" fill="#B05B65"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
8
public/_static/icons/heart.svg
Normal file
8
public/_static/icons/heart.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_5625_32301" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="16" height="16">
|
||||
<rect width="16" height="16" fill="#D9D9D9"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_5625_32301)">
|
||||
<path d="M7.99994 13.4171L7.23327 12.7255C6.14142 11.7524 5.24068 10.9189 4.53105 10.2249C3.82142 9.53081 3.26225 8.91489 2.85354 8.37709C2.44481 7.8393 2.16148 7.34774 2.00353 6.90241C1.84558 6.45708 1.7666 6.00088 1.7666 5.53379C1.7666 4.57813 2.09435 3.77255 2.74985 3.11704C3.40536 2.46154 4.21095 2.13379 5.1666 2.13379C5.70314 2.13379 6.22338 2.25046 6.72734 2.48379C7.23129 2.71712 7.65549 3.05046 7.99994 3.48379C8.36105 3.05046 8.78882 2.71712 9.28327 2.48379C9.77771 2.25046 10.2944 2.13379 10.8333 2.13379C11.7889 2.13379 12.5945 2.46154 13.25 3.11704C13.9055 3.77255 14.2333 4.57813 14.2333 5.53379C14.2333 6.00088 14.1571 6.45153 14.0047 6.88574C13.8523 7.31996 13.5717 7.80319 13.163 8.33542C12.7543 8.86767 12.1923 9.48637 11.4772 10.1915C10.762 10.8967 9.84734 11.7524 8.73327 12.7588L7.99994 13.4171Z" fill="#B05B65"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -13,6 +13,7 @@ import {
|
||||
} from "@/types/components/loyalty/enums"
|
||||
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"
|
||||
|
||||
@@ -272,6 +273,20 @@ const pageConnectionRefs = z.object({
|
||||
),
|
||||
})
|
||||
|
||||
const rteConnectionRefs = z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
__typename: z.nativeEnum(RTEEmbedsEnum),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
const cardBlockRefs = z.object({
|
||||
__typename: z.literal(LoyaltyCardsGridEnum.Card),
|
||||
primary_button: z
|
||||
@@ -349,7 +364,7 @@ const loyaltyPageBlockTextContentRefs = z.object({
|
||||
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent),
|
||||
content: z.object({
|
||||
content: z.object({
|
||||
embedded_itemsConnection: pageConnectionRefs,
|
||||
embedded_itemsConnection: rteConnectionRefs,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
@@ -365,7 +380,7 @@ const loyaltyPageSidebarTextContentRef = z.object({
|
||||
__typename: z.literal(SidebarTypenameEnum.LoyaltyPageSidebarContent),
|
||||
content: z.object({
|
||||
content: z.object({
|
||||
embedded_itemsConnection: pageConnectionRefs,
|
||||
embedded_itemsConnection: rteConnectionRefs,
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
6
types/components/imageContainer.ts
Normal file
6
types/components/imageContainer.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { ImageVaultAsset } from "./imageVaultImage"
|
||||
|
||||
export type ImageContainerProps = {
|
||||
leftImage: ImageVaultAsset
|
||||
rightImage: ImageVaultAsset
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { ImageContainer } from "./imageContainer"
|
||||
import type { SysAsset } from "./utils/asset"
|
||||
|
||||
export type Embeds = SysAsset
|
||||
export type Embeds = SysAsset | ImageContainer
|
||||
|
||||
14
types/requests/imageContainer.ts
Normal file
14
types/requests/imageContainer.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { InsertResponse } from "../components/imageVaultImage"
|
||||
import { EmbedEnum } from "./utils/embeds"
|
||||
import { Typename } from "./utils/typename"
|
||||
|
||||
export type ImageContainer = Typename<
|
||||
{
|
||||
image_left: InsertResponse
|
||||
image_right: InsertResponse
|
||||
system: {
|
||||
uid: string
|
||||
}
|
||||
},
|
||||
EmbedEnum.ImageContainer
|
||||
>
|
||||
6
types/requests/rte.ts
Normal file
6
types/requests/rte.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export enum RTEEmbedsEnum {
|
||||
AccountPage = "AccountPage",
|
||||
ContentPage = "ContentPage",
|
||||
LoyaltyPage = "LoyaltyPage",
|
||||
ImageContainer = "ImageContainer",
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
export enum EmbedEnum {
|
||||
CurrentBlocksPage = "CurrentBlocksPage",
|
||||
SysAsset = "SysAsset",
|
||||
ImageContainer = "ImageContainer",
|
||||
LoyaltyPage = "LoyaltyPage",
|
||||
AccountPage = "AccountPage",
|
||||
ContentPage = "ContentPage",
|
||||
}
|
||||
|
||||
export type Embed = keyof typeof EmbedEnum
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { InsertResponse } from "../components/imageVaultImage"
|
||||
import { RTEItemTypeEnum } from "./enums"
|
||||
import type { EmbedTypesEnum, RTEItemType } from "./enums"
|
||||
|
||||
import type { Lang } from "@/constants/languages"
|
||||
import type { EmbedTypesEnum, RTEItemType } from "./enums"
|
||||
|
||||
export interface Attributes {
|
||||
[key: string]: any
|
||||
@@ -36,3 +38,9 @@ export interface RTELinkAttrs extends Attributes {
|
||||
target: HTMLAnchorElement["target"]
|
||||
type: RTEItemTypeEnum.entry
|
||||
}
|
||||
|
||||
export interface RTEImageVaultAttrs extends Attributes, InsertResponse {
|
||||
height: string
|
||||
width: string
|
||||
style: string[]
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ export enum RTETypeEnum {
|
||||
thead = "thead",
|
||||
tr = "tr",
|
||||
ul = "ul",
|
||||
ImageVault = "ImageVault",
|
||||
fragment = "fragment",
|
||||
}
|
||||
|
||||
export type RTEType = keyof typeof RTETypeEnum
|
||||
@@ -46,3 +48,17 @@ export enum RTEItemTypeEnum {
|
||||
}
|
||||
|
||||
export type RTEItemType = keyof typeof RTEItemTypeEnum
|
||||
|
||||
export enum AvailableParagraphFormatEnum {
|
||||
"script-1" = "script-1",
|
||||
"script-2" = "script-2",
|
||||
"footnote" = "footnote",
|
||||
"caption" = "caption",
|
||||
"subtitle-1" = "subtitle-1",
|
||||
"subtitle-2" = "subtitle-2",
|
||||
}
|
||||
|
||||
export enum AvailableULFormatEnum {
|
||||
"heart" = "heart",
|
||||
"check" = "check",
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
Attributes,
|
||||
RTEAnchorAttrs,
|
||||
RTEAssetAttrs,
|
||||
RTEImageVaultAttrs,
|
||||
RTELinkAttrs,
|
||||
} from "./attrs"
|
||||
import type { RenderOptions } from "./option"
|
||||
@@ -36,6 +37,11 @@ export interface RTEReferenceLinkNode extends RTEDefaultNode {
|
||||
attrs: RTELinkAttrs
|
||||
}
|
||||
|
||||
export interface RTEImageVaultNode extends RTEDefaultNode {
|
||||
attrs: RTEImageVaultAttrs
|
||||
type: RTETypeEnum.ImageVault
|
||||
}
|
||||
|
||||
export enum RTEMarkType {
|
||||
bold = "bold",
|
||||
break = "break",
|
||||
@@ -58,9 +64,11 @@ export type RTETextNode = RTETextNodeOptionalKeys & {
|
||||
text: string
|
||||
}
|
||||
|
||||
export type RTERegularNode = RTEDefaultNode | RTEAnchorNode
|
||||
export type RTERegularNode = RTEDefaultNode | RTEAnchorNode | RTEImageVaultNode
|
||||
|
||||
export type RTEReferenceNode = RTEDefaultNode | RTEAnchorNode
|
||||
export type RTEImageNode = RTEDefaultNode | RTEImageVaultNode
|
||||
|
||||
export type RTEReferenceNode = RTEAnchorNode
|
||||
|
||||
export type RTENode = RTERegularNode | RTEReferenceNode | RTETextNode
|
||||
|
||||
|
||||
Reference in New Issue
Block a user