oxen-website/components/RichBody.tsx

146 lines
3.8 KiB
TypeScript
Raw Normal View History

2021-02-02 06:28:00 +01:00
/* eslint-disable react/display-name */
2021-02-12 06:37:44 +01:00
import { documentToPlainTextString } from '@contentful/rich-text-plain-text-renderer';
2021-02-02 06:28:00 +01:00
import { documentToReactComponents } from '@contentful/rich-text-react-renderer';
import {
AssetLinkBlock,
BLOCKS,
Document,
Heading1,
Heading2,
Heading3,
Heading4,
Hyperlink,
INLINES,
MARKS,
2021-02-18 04:07:53 +01:00
OrderedList,
2021-02-15 04:22:26 +01:00
Text,
2021-02-18 04:28:52 +01:00
UnorderedList,
2021-02-02 06:28:00 +01:00
} from '@contentful/rich-text-types';
2021-02-12 01:38:09 +01:00
import React, { ReactNode } from 'react';
2021-02-12 06:37:44 +01:00
import { CMS } from '../constants';
2021-02-15 04:22:26 +01:00
import { renderShortcode } from '../services/cms';
2021-02-12 01:38:09 +01:00
import { ArticleCallout } from './article/ArticleCallout';
2021-02-02 06:28:00 +01:00
const Bold = ({ children }) => (
<span className="font-semibold">{children}</span>
);
const Paragraph = ({ children }) => (
2021-02-11 01:38:40 +01:00
<p className="mb-3 font-sans tracking-wide">{children}</p>
2021-02-02 06:28:00 +01:00
);
const options = {
renderMark: {
[MARKS.BOLD]: text => <Bold>{text}</Bold>,
},
renderNode: {
2021-02-12 06:37:44 +01:00
[BLOCKS.PARAGRAPH]: (node, children) => {
// Grab shortcodes
// const children;
const plaintext = documentToPlainTextString(node);
const isShortcode = CMS.SHORTCODE_REGEX.test(plaintext);
2021-02-15 04:22:26 +01:00
2021-02-18 04:07:53 +01:00
return isShortcode ? (
renderShortcode(plaintext)
) : (
<Paragraph>{children}</Paragraph>
);
2021-02-02 06:28:00 +01:00
},
[BLOCKS.HEADING_1]: (node: Heading1) => {
const content = (node.content[0] as Text)?.value;
return (
2021-02-04 07:19:04 +01:00
<h1 className="mt-8 mb-4 text-4xl font-semibold font-prompt">
2021-02-02 06:28:00 +01:00
{content}
</h1>
);
},
[BLOCKS.HEADING_2]: (node: Heading2) => {
const content = (node.content[0] as Text)?.value;
return (
2021-02-11 01:38:40 +01:00
<h2 className="mt-8 mb-2 font-sans text-3xl font-semibold tracking-wide">
2021-02-02 06:28:00 +01:00
{content}
</h2>
);
},
[BLOCKS.HEADING_3]: (node: Heading3) => {
const content = (node.content[0] as Text)?.value;
return (
2021-02-11 01:38:40 +01:00
<h2 className="mt-6 mb-2 font-sans text-xl font-semibold">{content}</h2>
2021-02-02 06:28:00 +01:00
);
},
[BLOCKS.HEADING_4]: (node: Heading4) => {
const content = (node.content[0] as Text)?.value;
return (
2021-02-11 01:38:40 +01:00
<h2 className="mt-6 mb-2 font-sans text-lg font-bold">{content}</h2>
2021-02-02 06:28:00 +01:00
);
},
2021-02-12 01:38:09 +01:00
[BLOCKS.QUOTE]: (_node, children: ReactNode) => {
return (
<div className="mt-6">
<ArticleCallout bold indent>
<Paragraph>{children}</Paragraph>{' '}
</ArticleCallout>
</div>
);
},
2021-02-02 06:28:00 +01:00
[BLOCKS.EMBEDDED_ASSET]: (node: AssetLinkBlock) => {
2021-02-11 01:38:40 +01:00
const link = (node.data.target as any).fields.file.url.replace(
'//',
'http://',
);
2021-02-02 06:28:00 +01:00
2021-02-12 01:06:54 +01:00
return (
<div className="flex justify-center w-full mb-6">
<img
style={{ maxWidth: '800px' }}
className="object-cover w-full"
src={link}
/>
</div>
);
2021-02-02 06:28:00 +01:00
},
2021-02-18 04:28:52 +01:00
[BLOCKS.UL_LIST]: (node: UnorderedList, children: JSX.Element[]) => {
return (
<ul className="ml-6 list-disc">
{children.map(item => (
<li key={item.key}>{item}</li>
))}
</ul>
);
},
2021-02-18 04:07:53 +01:00
[BLOCKS.OL_LIST]: (node: OrderedList, children: JSX.Element[]) => {
return (
2021-02-18 04:28:52 +01:00
<ol className="list-decimal">
2021-02-18 04:07:53 +01:00
{children.map(item => (
<li key={item.key}>{item}</li>
))}
</ol>
);
},
2021-02-02 06:28:00 +01:00
[INLINES.HYPERLINK]: (node: Hyperlink) => {
const { content } = node;
return (
<a
2021-02-04 07:19:04 +01:00
className="cursor-pointer text-blue hover:underline"
2021-02-02 06:28:00 +01:00
href={node.data.uri}
2021-02-22 01:34:37 +01:00
target="_blank"
rel="noreferrer"
2021-02-02 06:28:00 +01:00
>
{content[0].value}
</a>
);
},
},
};
interface Props {
body: Document;
}
2021-02-04 07:19:04 +01:00
// Renders a rich text body
export function RichBody({ body }: Props) {
const RichBody = documentToReactComponents(body, options);
2021-02-02 06:28:00 +01:00
2021-02-12 01:06:54 +01:00
return <div className="text-primary">{RichBody}</div>;
2021-02-02 06:28:00 +01:00
}