How to retain indents and line ends with code field #7605
Replies: 1 comment
-
I managed to solve this, by adding the code snippet leaf to the richtext editor. import type { RichTextLeaf } from '@payloadcms/richtext-slate/dist/types'
const defaultLeaves: RichTextLeaf[] = ['bold', 'italic', 'underline', 'code']
export default defaultLeaves After that you should update your Richtext component to handle code strings. import React, { Fragment } from 'react'
import escapeHTML from 'escape-html'
import { Text } from 'slate'
import CodeBlock from '../CodeBlock'
import { Label } from '../Label'
import { LargeBody } from '../LargeBody'
import { CMSLink } from '../Link'
// eslint-disable-next-line no-use-before-define
type Children = Leaf[]
type Leaf = {
type: string
value?: {
url: string
alt: string
}
children?: Children
url?: string
[key: string]: unknown
}
const serialize = (children?: Children): React.ReactNode[] =>
children?.map((node, i) => {
if (Text.isText(node)) {
let text = <span dangerouslySetInnerHTML={{ __html: escapeHTML(node.text) }} />
if (node.bold) {
text = <strong key={i}>{text}</strong>
}
if (node.italic) {
text = <em key={i}>{text}</em>
}
if (node.underline) {
text = (
<span style={{ textDecoration: 'underline' }} key={i}>
{text}
</span>
)
}
if (node.strikethrough) {
text = (
<span style={{ textDecoration: 'line-through' }} key={i}>
{text}
</span>
)
}
if (node.code) {
return <CodeBlock key={i} text={node.text} />
}
return <Fragment key={i}>{text}</Fragment>
}
if (!node) {
return null
}
switch (node.type) {
case 'h1':
return <h1 key={i}>{serialize(node?.children)}</h1>
case 'h2':
return <h2 key={i}>{serialize(node?.children)}</h2>
case 'h3':
return <h3 key={i}>{serialize(node?.children)}</h3>
case 'h4':
return <h4 key={i}>{serialize(node?.children)}</h4>
case 'h5':
return <h5 key={i}>{serialize(node?.children)}</h5>
case 'h6':
return <h6 key={i}>{serialize(node?.children)}</h6>
case 'quote':
return <blockquote key={i}>{serialize(node?.children)}</blockquote>
case 'ul':
return <ul key={i}>{serialize(node?.children)}</ul>
case 'ol':
return <ol key={i}>{serialize(node.children)}</ol>
case 'li':
return <li key={i}>{serialize(node.children)}</li>
case 'link':
return (
<CMSLink
key={i}
type={node.linkType === 'internal' ? 'reference' : 'custom'}
url={node.url}
reference={node.doc as any}
newTab={Boolean(node?.newTab)}
>
{serialize(node?.children)}
</CMSLink>
)
case 'label':
return <Label key={i}>{serialize(node?.children)}</Label>
case 'large-body': {
return <LargeBody key={i}>{serialize(node?.children)}</LargeBody>
}
default: {
const containsBlockLevelElement = node.children?.some(child => child.code === true)
if (containsBlockLevelElement) {
return <Fragment key={i}>{serialize(node?.children)}</Fragment>
}
return <p key={i}>{serialize(node?.children)}</p>
}
}
}) || []
export default serialize Here is my codeblock implementation: 'use client'
import React, { useState } from 'react'
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
import { detectLanguage } from '../../_utilities/determineLanguage'
import classes from './index.module.scss'
const CodeBlock = ({ text }) => {
const [isCopied, setIsCopied] = useState(false)
const codeString = text.replaceAll(/\/n/g, '\n').replaceAll('>', '>').replaceAll('<', '<')
const copyToClipboard = async () => {
try {
await navigator.clipboard.writeText(codeString)
setIsCopied(true)
setTimeout(() => setIsCopied(false), 2000)
} catch (err) {}
}
const language = detectLanguage(codeString)
return (
<div className={classes.codeBlock}>
<button
onClick={copyToClipboard}
className={classes.copyButton}
style={{
backgroundColor: isCopied ? '#4CAF50' : '#b5c942',
}}
>
{isCopied ? 'Copied!' : 'Copy Code'}
</button>
<SyntaxHighlighter language={language} style={vscDarkPlus} showLineNumbers={true}>
{codeString}
</SyntaxHighlighter>
</div>
)
}
export default CodeBlock |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi,
I want to use the code field to create code snippets that I can use in my content.
I used this documentation. But it seems to store the text as a pain string with no regards for the line endings.
My field config looks like this:
I would also be ok to use a custom element for slate editor. But I couldn't find a usefull example for that one as well.
Thnx in advance
Beta Was this translation helpful? Give feedback.
All reactions