chore(templates): migrate to new richtext component in website template (#9615)

In addition to requiring fewer files, it supports more nodes. If you
currently initialize a website template and want to use features such as
images or tables, they are not rendered. With this change that happens
automatically.

Credits to @AlessioGr for the [JSX
serializer](https://github.com/payloadcms/payload/pull/8795).

---------

Co-authored-by: Paul Popus <paul@nouance.io>
This commit is contained in:
Germán Jabloñski
2024-12-04 21:38:49 -03:00
committed by GitHub
parent 3d1305de5c
commit 89db8fb7f2
18 changed files with 1894 additions and 5386 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -58,7 +58,7 @@ export default async function Post({ params: paramsPromise }: Args) {
<div className="flex flex-col items-center gap-4 pt-8"> <div className="flex flex-col items-center gap-4 pt-8">
<div className="container"> <div className="container">
<RichText className="max-w-[48rem] mx-auto" content={post.content} enableGutter={false} /> <RichText className="max-w-[48rem] mx-auto" data={post.content} enableGutter={false} />
{post.relatedPosts && post.relatedPosts.length > 0 && ( {post.relatedPosts && post.relatedPosts.length > 0 && (
<RelatedPosts <RelatedPosts
className="mt-12 max-w-[52rem] lg:grid lg:grid-cols-subgrid col-start-1 col-span-3 grid-rows-[2fr]" className="mt-12 max-w-[52rem] lg:grid lg:grid-cols-subgrid col-start-1 col-span-3 grid-rows-[2fr]"

View File

@@ -22,43 +22,26 @@ import { default as default_1a7510af427896d367a49dbf838d2de6 } from '@/component
import { default as default_8a7ab0eb7ab5c511aba12e68480bfe5e } from '@/components/BeforeLogin' import { default as default_8a7ab0eb7ab5c511aba12e68480bfe5e } from '@/components/BeforeLogin'
export const importMap = { export const importMap = {
'@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell': "@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell": RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e,
RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e, "@payloadcms/richtext-lexical/rsc#RscEntryLexicalField": RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e,
'@payloadcms/richtext-lexical/rsc#RscEntryLexicalField': "@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient": InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e, "@payloadcms/richtext-lexical/client#FixedToolbarFeatureClient": FixedToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
'@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient': "@payloadcms/richtext-lexical/client#HeadingFeatureClient": HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/richtext-lexical/client#ParagraphFeatureClient": ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
'@payloadcms/richtext-lexical/client#FixedToolbarFeatureClient': "@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
FixedToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
'@payloadcms/richtext-lexical/client#HeadingFeatureClient': "@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/richtext-lexical/client#LinkFeatureClient": LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
'@payloadcms/richtext-lexical/client#ParagraphFeatureClient': "@payloadcms/plugin-seo/client#OverviewComponent": OverviewComponent_a8a977ebc872c5d5ea7ee689724c0860,
ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/plugin-seo/client#MetaTitleComponent": MetaTitleComponent_a8a977ebc872c5d5ea7ee689724c0860,
'@payloadcms/richtext-lexical/client#UnderlineFeatureClient': "@payloadcms/plugin-seo/client#MetaImageComponent": MetaImageComponent_a8a977ebc872c5d5ea7ee689724c0860,
UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/plugin-seo/client#MetaDescriptionComponent": MetaDescriptionComponent_a8a977ebc872c5d5ea7ee689724c0860,
'@payloadcms/richtext-lexical/client#BoldFeatureClient': "@payloadcms/plugin-seo/client#PreviewComponent": PreviewComponent_a8a977ebc872c5d5ea7ee689724c0860,
BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@/fields/slug/SlugComponent#SlugComponent": SlugComponent_92cc057d0a2abb4f6cf0307edf59f986,
'@payloadcms/richtext-lexical/client#ItalicFeatureClient': "@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient": HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/richtext-lexical/client#BlocksFeatureClient": BlocksFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
'@payloadcms/richtext-lexical/client#LinkFeatureClient': "@payloadcms/plugin-search/client#LinkToDoc": LinkToDoc_aead06e4cbf6b2620c5c51c9ab283634,
LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/plugin-search/client#ReindexButton": ReindexButton_aead06e4cbf6b2620c5c51c9ab283634,
'@payloadcms/plugin-seo/client#OverviewComponent': "@/components/BeforeDashboard#default": default_1a7510af427896d367a49dbf838d2de6,
OverviewComponent_a8a977ebc872c5d5ea7ee689724c0860, "@/components/BeforeLogin#default": default_8a7ab0eb7ab5c511aba12e68480bfe5e
'@payloadcms/plugin-seo/client#MetaTitleComponent':
MetaTitleComponent_a8a977ebc872c5d5ea7ee689724c0860,
'@payloadcms/plugin-seo/client#MetaImageComponent':
MetaImageComponent_a8a977ebc872c5d5ea7ee689724c0860,
'@payloadcms/plugin-seo/client#MetaDescriptionComponent':
MetaDescriptionComponent_a8a977ebc872c5d5ea7ee689724c0860,
'@payloadcms/plugin-seo/client#PreviewComponent':
PreviewComponent_a8a977ebc872c5d5ea7ee689724c0860,
'@/fields/slug/SlugComponent#SlugComponent': SlugComponent_92cc057d0a2abb4f6cf0307edf59f986,
'@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient':
HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
'@payloadcms/richtext-lexical/client#BlocksFeatureClient':
BlocksFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
'@payloadcms/plugin-search/client#LinkToDoc': LinkToDoc_aead06e4cbf6b2620c5c51c9ab283634,
'@payloadcms/plugin-search/client#ReindexButton': ReindexButton_aead06e4cbf6b2620c5c51c9ab283634,
'@/components/BeforeDashboard#default': default_1a7510af427896d367a49dbf838d2de6,
'@/components/BeforeLogin#default': default_8a7ab0eb7ab5c511aba12e68480bfe5e,
} }

View File

@@ -56,7 +56,7 @@ export const ArchiveBlock: React.FC<
<div className="my-16" id={`block-${id}`}> <div className="my-16" id={`block-${id}`}>
{introContent && ( {introContent && (
<div className="container mb-16"> <div className="container mb-16">
<RichText className="ml-0 max-w-[48rem]" content={introContent} enableGutter={false} /> <RichText className="ml-0 max-w-[48rem]" data={introContent} enableGutter={false} />
</div> </div>
)} )}
<CollectionArchive posts={posts} /> <CollectionArchive posts={posts} />

View File

@@ -19,7 +19,7 @@ export const BannerBlock: React.FC<Props> = ({ className, content, style }) => {
'border-warning bg-warning/30': style === 'warning', 'border-warning bg-warning/30': style === 'warning',
})} })}
> >
<RichText content={content} enableGutter={false} enableProse={false} /> <RichText data={content} enableGutter={false} enableProse={false} />
</div> </div>
</div> </div>
) )

View File

@@ -10,7 +10,7 @@ export const CallToActionBlock: React.FC<CTABlockProps> = ({ links, richText })
<div className="container"> <div className="container">
<div className="bg-card rounded border-border border p-4 flex flex-col gap-8 md:flex-row md:justify-between md:items-center"> <div className="bg-card rounded border-border border p-4 flex flex-col gap-8 md:flex-row md:justify-between md:items-center">
<div className="max-w-[48rem] flex items-center"> <div className="max-w-[48rem] flex items-center">
{richText && <RichText className="mb-0" content={richText} enableGutter={false} />} {richText && <RichText className="mb-0" data={richText} enableGutter={false} />}
</div> </div>
<div className="flex flex-col gap-8"> <div className="flex flex-col gap-8">
{(links || []).map(({ link }, i) => { {(links || []).map(({ link }, i) => {

View File

@@ -31,7 +31,7 @@ export const ContentBlock: React.FC<ContentBlockProps> = (props) => {
})} })}
key={index} key={index}
> >
{richText && <RichText content={richText} enableGutter={false} />} {richText && <RichText data={richText} enableGutter={false} />}
{enableLink && <CMSLink {...link} />} {enableLink && <CMSLink {...link} />}
</div> </div>

View File

@@ -6,6 +6,7 @@ import React, { useCallback, useState } from 'react'
import { useForm, FormProvider } from 'react-hook-form' import { useForm, FormProvider } from 'react-hook-form'
import RichText from '@/components/RichText' import RichText from '@/components/RichText'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical'
import { buildInitialFormState } from './buildInitialFormState' import { buildInitialFormState } from './buildInitialFormState'
import { fields } from './fields' import { fields } from './fields'
@@ -26,9 +27,7 @@ export type FormBlockType = {
blockType?: 'formBlock' blockType?: 'formBlock'
enableIntro: boolean enableIntro: boolean
form: FormType form: FormType
introContent?: { introContent?: SerializedEditorState
[k: string]: unknown
}[]
} }
export const FormBlock: React.FC< export const FormBlock: React.FC<
@@ -128,12 +127,12 @@ export const FormBlock: React.FC<
return ( return (
<div className="container lg:max-w-[48rem]"> <div className="container lg:max-w-[48rem]">
{enableIntro && introContent && !hasSubmitted && ( {enableIntro && introContent && !hasSubmitted && (
<RichText className="mb-8 lg:mb-12" content={introContent} enableGutter={false} /> <RichText className="mb-8 lg:mb-12" data={introContent} enableGutter={false} />
)} )}
<div className="p-4 lg:p-6 border border-border rounded-[0.8rem]"> <div className="p-4 lg:p-6 border border-border rounded-[0.8rem]">
<FormProvider {...formMethods}> <FormProvider {...formMethods}>
{!isLoading && hasSubmitted && confirmationType === 'message' && ( {!isLoading && hasSubmitted && confirmationType === 'message' && (
<RichText content={confirmationMessage} /> <RichText data={confirmationMessage} />
)} )}
{isLoading && !hasSubmitted && <p>Loading, please wait...</p>} {isLoading && !hasSubmitted && <p>Loading, please wait...</p>}
{error && <div>{`${error.status || '500'}: ${error.message || ''}`}</div>} {error && <div>{`${error.status || '500'}: ${error.message || ''}`}</div>}

View File

@@ -2,11 +2,12 @@ import RichText from '@/components/RichText'
import React from 'react' import React from 'react'
import { Width } from '../Width' import { Width } from '../Width'
import { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical'
export const Message: React.FC = ({ message }: { message: Record<string, any> }) => { export const Message: React.FC = ({ message }: { message: SerializedEditorState }) => {
return ( return (
<Width className="my-12" width="100"> <Width className="my-12" width="100">
{message && <RichText content={message} />} {message && <RichText data={message} />}
</Width> </Width>
) )
} }

View File

@@ -57,7 +57,7 @@ export const MediaBlock: React.FC<Props> = (props) => {
captionClassName, captionClassName,
)} )}
> >
<RichText content={caption} enableGutter={false} /> <RichText data={caption} enableGutter={false} />
</div> </div>
)} )}
</div> </div>

View File

@@ -17,7 +17,7 @@ export const RelatedPosts: React.FC<RelatedPostsProps> = (props) => {
return ( return (
<div className={clsx('container', className)}> <div className={clsx('container', className)}>
{introContent && <RichText content={introContent} enableGutter={false} />} {introContent && <RichText data={introContent} enableGutter={false} />}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-8 items-stretch"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-8 items-stretch">
{docs?.map((doc, index) => { {docs?.map((doc, index) => {

View File

@@ -1,27 +1,56 @@
import { cn } from '@/utilities/cn' import { MediaBlock } from '@/blocks/MediaBlock/Component'
import React from 'react' import { DefaultNodeTypes, SerializedBlockNode } from '@payloadcms/richtext-lexical'
import { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical'
import {
JSXConvertersFunction,
RichText as RichTextWithoutBlocks,
} from '@payloadcms/richtext-lexical/react'
import { serializeLexical } from './serialize' import { CodeBlock, CodeBlockProps } from '@/blocks/Code/Component'
import type {
BannerBlock as BannerBlockProps,
CallToActionBlock as CTABlockProps,
MediaBlock as MediaBlockProps,
} from '@/payload-types'
import { BannerBlock } from '@/blocks/Banner/Component'
import { CallToActionBlock } from '@/blocks/CallToAction/Component'
import { cn } from '@/utilities/cn'
type NodeTypes =
| DefaultNodeTypes
| SerializedBlockNode<CTABlockProps | MediaBlockProps | BannerBlockProps | CodeBlockProps>
const jsxConverters: JSXConvertersFunction<NodeTypes> = ({ defaultConverters }) => ({
...defaultConverters,
blocks: {
banner: ({ node }) => <BannerBlock className="col-start-2 mb-4" {...node.fields} />,
mediaBlock: ({ node }) => (
<MediaBlock
className="col-start-1 col-span-3"
imgClassName="m-0"
{...node.fields}
captionClassName="mx-auto max-w-[48rem]"
enableGutter={false}
disableInnerContainer={true}
/>
),
code: ({ node }) => <CodeBlock className="col-start-2" {...node.fields} />,
cta: ({ node }) => <CallToActionBlock {...node.fields} />,
},
})
type Props = { type Props = {
className?: string data: SerializedEditorState
content: Record<string, any>
enableGutter?: boolean enableGutter?: boolean
enableProse?: boolean enableProse?: boolean
} } & React.HTMLAttributes<HTMLDivElement>
const RichText: React.FC<Props> = ({
className,
content,
enableGutter = true,
enableProse = true,
}) => {
if (!content) {
return null
}
export default function RichText(props: Props) {
const { className, enableProse = true, enableGutter = true, ...rest } = props
return ( return (
<div <RichTextWithoutBlocks
converters={jsxConverters}
className={cn( className={cn(
{ {
'container ': enableGutter, 'container ': enableGutter,
@@ -30,14 +59,7 @@ const RichText: React.FC<Props> = ({
}, },
className, className,
)} )}
> {...rest}
{content && />
!Array.isArray(content) &&
typeof content === 'object' &&
'root' in content &&
serializeLexical({ nodes: content?.root?.children })}
</div>
) )
} }
export default RichText

View File

@@ -1,128 +0,0 @@
// @ts-nocheck
//This copy-and-pasted from lexical here: https://github.com/facebook/lexical/blob/c2ceee223f46543d12c574e62155e619f9a18a5d/packages/lexical/src/LexicalConstants.ts
import type { ElementFormatType, TextFormatType } from '@payloadcms/richtext-lexical/lexical'
import type {
TextDetailType,
TextModeType,
} from '@payloadcms/richtext-lexical/lexical/nodes/LexicalTextNode'
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
// DOM
export const DOM_ELEMENT_TYPE = 1
export const DOM_TEXT_TYPE = 3
// Reconciling
export const NO_DIRTY_NODES = 0
export const HAS_DIRTY_NODES = 1
export const FULL_RECONCILE = 2
// Text node modes
export const IS_NORMAL = 0
export const IS_TOKEN = 1
export const IS_SEGMENTED = 2
// IS_INERT = 3
// Text node formatting
export const IS_BOLD = 1
export const IS_ITALIC = 1 << 1
export const IS_STRIKETHROUGH = 1 << 2
export const IS_UNDERLINE = 1 << 3
export const IS_CODE = 1 << 4
export const IS_SUBSCRIPT = 1 << 5
export const IS_SUPERSCRIPT = 1 << 6
export const IS_HIGHLIGHT = 1 << 7
export const IS_ALL_FORMATTING =
IS_BOLD |
IS_ITALIC |
IS_STRIKETHROUGH |
IS_UNDERLINE |
IS_CODE |
IS_SUBSCRIPT |
IS_SUPERSCRIPT |
IS_HIGHLIGHT
// Text node details
export const IS_DIRECTIONLESS = 1
export const IS_UNMERGEABLE = 1 << 1
// Element node formatting
export const IS_ALIGN_LEFT = 1
export const IS_ALIGN_CENTER = 2
export const IS_ALIGN_RIGHT = 3
export const IS_ALIGN_JUSTIFY = 4
export const IS_ALIGN_START = 5
export const IS_ALIGN_END = 6
// Reconciliation
export const NON_BREAKING_SPACE = '\u00A0'
const ZERO_WIDTH_SPACE = '\u200b'
export const DOUBLE_LINE_BREAK = '\n\n'
// For FF, we need to use a non-breaking space, or it gets composition
// in a stuck state.
const RTL = '\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC'
const LTR =
'A-Za-z\u00C0-\u00D6\u00D8-\u00F6' +
'\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF\u200E\u2C00-\uFB1C' +
'\uFE00-\uFE6F\uFEFD-\uFFFF'
export const RTL_REGEX = new RegExp('^[^' + LTR + ']*[' + RTL + ']')
export const LTR_REGEX = new RegExp('^[^' + RTL + ']*[' + LTR + ']')
export const TEXT_TYPE_TO_FORMAT: Record<TextFormatType | string, number> = {
bold: IS_BOLD,
code: IS_CODE,
highlight: IS_HIGHLIGHT,
italic: IS_ITALIC,
strikethrough: IS_STRIKETHROUGH,
subscript: IS_SUBSCRIPT,
superscript: IS_SUPERSCRIPT,
underline: IS_UNDERLINE,
}
export const DETAIL_TYPE_TO_DETAIL: Record<TextDetailType | string, number> = {
directionless: IS_DIRECTIONLESS,
unmergeable: IS_UNMERGEABLE,
}
export const ELEMENT_TYPE_TO_FORMAT: Record<Exclude<ElementFormatType, ''>, number> = {
center: IS_ALIGN_CENTER,
end: IS_ALIGN_END,
justify: IS_ALIGN_JUSTIFY,
left: IS_ALIGN_LEFT,
right: IS_ALIGN_RIGHT,
start: IS_ALIGN_START,
}
export const ELEMENT_FORMAT_TO_TYPE: Record<number, ElementFormatType> = {
[IS_ALIGN_CENTER]: 'center',
[IS_ALIGN_END]: 'end',
[IS_ALIGN_JUSTIFY]: 'justify',
[IS_ALIGN_LEFT]: 'left',
[IS_ALIGN_RIGHT]: 'right',
[IS_ALIGN_START]: 'start',
}
export const TEXT_MODE_TO_TYPE: Record<TextModeType, 0 | 1 | 2> = {
normal: IS_NORMAL,
segmented: IS_SEGMENTED,
token: IS_TOKEN,
}
export const TEXT_TYPE_TO_MODE: Record<number, TextModeType> = {
[IS_NORMAL]: 'normal',
[IS_SEGMENTED]: 'segmented',
[IS_TOKEN]: 'token',
}

View File

@@ -1,209 +0,0 @@
import { BannerBlock } from '@/blocks/Banner/Component'
import { CallToActionBlock } from '@/blocks/CallToAction/Component'
import { CodeBlock, CodeBlockProps } from '@/blocks/Code/Component'
import { MediaBlock } from '@/blocks/MediaBlock/Component'
import React, { Fragment, JSX } from 'react'
import { CMSLink } from '@/components/Link'
import { DefaultNodeTypes, SerializedBlockNode } from '@payloadcms/richtext-lexical'
import type { BannerBlock as BannerBlockProps } from '@/payload-types'
import {
IS_BOLD,
IS_CODE,
IS_ITALIC,
IS_STRIKETHROUGH,
IS_SUBSCRIPT,
IS_SUPERSCRIPT,
IS_UNDERLINE,
} from './nodeFormat'
import type {
CallToActionBlock as CTABlockProps,
MediaBlock as MediaBlockProps,
} from '@/payload-types'
export type NodeTypes =
| DefaultNodeTypes
| SerializedBlockNode<CTABlockProps | MediaBlockProps | BannerBlockProps | CodeBlockProps>
type Props = {
nodes: NodeTypes[]
}
export function serializeLexical({ nodes }: Props): JSX.Element {
return (
<Fragment>
{nodes?.map((node, index): JSX.Element | null => {
if (node == null) {
return null
}
if (node.type === 'text') {
let text = <React.Fragment key={index}>{node.text}</React.Fragment>
if (node.format & IS_BOLD) {
text = <strong key={index}>{text}</strong>
}
if (node.format & IS_ITALIC) {
text = <em key={index}>{text}</em>
}
if (node.format & IS_STRIKETHROUGH) {
text = (
<span key={index} style={{ textDecoration: 'line-through' }}>
{text}
</span>
)
}
if (node.format & IS_UNDERLINE) {
text = (
<span key={index} style={{ textDecoration: 'underline' }}>
{text}
</span>
)
}
if (node.format & IS_CODE) {
text = <code key={index}>{node.text}</code>
}
if (node.format & IS_SUBSCRIPT) {
text = <sub key={index}>{text}</sub>
}
if (node.format & IS_SUPERSCRIPT) {
text = <sup key={index}>{text}</sup>
}
return text
}
// NOTE: Hacky fix for
// https://github.com/facebook/lexical/blob/d10c4e6e55261b2fdd7d1845aed46151d0f06a8c/packages/lexical-list/src/LexicalListItemNode.ts#L133
// which does not return checked: false (only true - i.e. there is no prop for false)
const serializedChildrenFn = (node: NodeTypes): JSX.Element | null => {
if (node.children == null) {
return null
} else {
if (node?.type === 'list' && node?.listType === 'check') {
for (const item of node.children) {
if ('checked' in item) {
if (!item?.checked) {
item.checked = false
}
}
}
}
return serializeLexical({ nodes: node.children as NodeTypes[] })
}
}
const serializedChildren = 'children' in node ? serializedChildrenFn(node) : ''
if (node.type === 'block') {
const block = node.fields
const blockType = block?.blockType
if (!block || !blockType) {
return null
}
switch (blockType) {
case 'cta':
return <CallToActionBlock key={index} {...block} />
case 'mediaBlock':
return (
<MediaBlock
className="col-start-1 col-span-3"
imgClassName="m-0"
key={index}
{...block}
captionClassName="mx-auto max-w-[48rem]"
enableGutter={false}
disableInnerContainer={true}
/>
)
case 'banner':
return <BannerBlock className="col-start-2 mb-4" key={index} {...block} />
case 'code':
return <CodeBlock className="col-start-2" key={index} {...block} />
default:
return null
}
} else {
switch (node.type) {
case 'linebreak': {
return <br className="col-start-2" key={index} />
}
case 'paragraph': {
return (
<p className="col-start-2" key={index}>
{serializedChildren}
</p>
)
}
case 'heading': {
const Tag = node?.tag
return (
<Tag className="col-start-2" key={index}>
{serializedChildren}
</Tag>
)
}
case 'list': {
const Tag = node?.tag
return (
<Tag className="list col-start-2" key={index}>
{serializedChildren}
</Tag>
)
}
case 'listitem': {
if (node?.checked != null) {
return (
<li
aria-checked={node.checked ? 'true' : 'false'}
className={` ${node.checked ? '' : ''}`}
key={index}
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
role="checkbox"
tabIndex={-1}
value={node?.value}
>
{serializedChildren}
</li>
)
} else {
return (
<li key={index} value={node?.value}>
{serializedChildren}
</li>
)
}
}
case 'quote': {
return (
<blockquote className="col-start-2" key={index}>
{serializedChildren}
</blockquote>
)
}
case 'link': {
const fields = node.fields
return (
<CMSLink
key={index}
newTab={Boolean(fields?.newTab)}
reference={fields.doc as any}
type={fields.linkType === 'internal' ? 'reference' : 'custom'}
url={fields.url}
>
{serializedChildren}
</CMSLink>
)
}
default:
return null
}
}
})}
</Fragment>
)
}

View File

@@ -22,7 +22,7 @@ export const HighImpactHero: React.FC<Page['hero']> = ({ links, media, richText
> >
<div className="container mb-8 z-10 relative flex items-center justify-center"> <div className="container mb-8 z-10 relative flex items-center justify-center">
<div className="max-w-[36.5rem] text-center"> <div className="max-w-[36.5rem] text-center">
{richText && <RichText className="mb-6" content={richText} enableGutter={false} />} {richText && <RichText className="mb-6" data={richText} enableGutter={false} />}
{Array.isArray(links) && links.length > 0 && ( {Array.isArray(links) && links.length > 0 && (
<ul className="flex justify-center gap-4"> <ul className="flex justify-center gap-4">
{links.map(({ link }, i) => { {links.map(({ link }, i) => {

View File

@@ -18,7 +18,7 @@ export const LowImpactHero: React.FC<LowImpactHeroType> = ({ children, richText
return ( return (
<div className="container mt-16"> <div className="container mt-16">
<div className="max-w-[48rem]"> <div className="max-w-[48rem]">
{children || (richText && <RichText content={richText} enableGutter={false} />)} {children || (richText && <RichText data={richText} enableGutter={false} />)}
</div> </div>
</div> </div>
) )

View File

@@ -10,7 +10,7 @@ export const MediumImpactHero: React.FC<Page['hero']> = ({ links, media, richTex
return ( return (
<div className=""> <div className="">
<div className="container mb-8"> <div className="container mb-8">
{richText && <RichText className="mb-6" content={richText} enableGutter={false} />} {richText && <RichText className="mb-6" data={richText} enableGutter={false} />}
{Array.isArray(links) && links.length > 0 && ( {Array.isArray(links) && links.length > 0 && (
<ul className="flex gap-4"> <ul className="flex gap-4">
@@ -36,7 +36,7 @@ export const MediumImpactHero: React.FC<Page['hero']> = ({ links, media, richTex
/> />
{media?.caption && ( {media?.caption && (
<div className="mt-3"> <div className="mt-3">
<RichText content={media.caption} enableGutter={false} /> <RichText data={media.caption} enableGutter={false} />
</div> </div>
)} )}
</div> </div>