church-website/src/components/Text/converters.tsx
2026-06-05 11:37:33 +02:00

88 lines
2.6 KiB
TypeScript

import type { JSXConvertersFunction } from '@payloadcms/richtext-lexical/react'
import { LinkJSXConverter } from '@payloadcms/richtext-lexical/react'
import type { SerializedLinkNode } from '@payloadcms/richtext-lexical'
import Image from 'next/image'
import { Button } from '@/components/Button/Button'
import { getPhoto } from '@/utils/dto/gallery'
type LinkFields = SerializedLinkNode['fields'] & {
appearance?: 'link' | 'button'
}
// Maps an internal Payload document to its public URL based on collection slug.
const internalDocToHref = ({ linkNode }: { linkNode: SerializedLinkNode }): string => {
const { doc } = linkNode.fields
if (!doc?.value || typeof doc.value !== 'object') return '#'
const document = doc.value as Record<string, unknown>
switch (doc.relationTo) {
case 'group':
return `/gruppe/${document.slug ?? document.id}`
case 'event':
return `/veranstaltungen/${document.id}`
case 'worship':
return `/gottesdienst/${document.id}`
case 'pages':
return `/${document.slug ?? ''}`
case 'parish':
return `/gemeinde/${document.slug ?? document.id}`
case 'blog':
return `/blog/${document.id}`
default:
return '#'
}
}
const linkConverters = LinkJSXConverter({ internalDocToHref })
export const jsxConverters: JSXConvertersFunction = ({ defaultConverters }) => ({
...defaultConverters,
...linkConverters,
// Render uploaded media at the "gallery" size (500px tall, variable width).
upload: ({ node }) => {
if (node.relationTo !== 'media' || typeof node.value !== 'object') {
return null
}
const photo = getPhoto('gallery', node.value)
if (!photo) return null
return (
<Image
src={photo.src}
width={photo.width}
height={photo.height}
alt={node.value.alt}
unoptimized={true}
/>
)
},
link: (args) => {
const { node, nodesToJSX } = args
const fields = node.fields as LinkFields
// Normal link → delegate to the internalDocToHref-aware link converter.
if (fields?.appearance !== 'button') {
const linkConverter = linkConverters.link
return typeof linkConverter === 'function' ? linkConverter(args) : linkConverter
}
// Button link → resolve href using internalDocToHref for internal links.
const href =
fields.linkType === 'internal'
? internalDocToHref({ linkNode: node })
: (fields.url ?? '#')
return (
<Button
href={href}
size="md"
schema="contrast"
target={fields.newTab ? '_blank' : '_self'}
>
{nodesToJSX({ nodes: node.children })}
</Button>
)
},
})