Files
5chan/src/components/Post.jsx
T

137 lines
3.9 KiB
React
Raw Normal View History

2023-06-21 08:47:31 +02:00
import React, { useMemo } from 'react';
2023-04-21 16:38:14 +02:00
import ReactMarkdown from 'react-markdown';
2023-04-27 13:10:23 +02:00
import rehypeSanitize, { defaultSchema } from 'rehype-sanitize';
2023-04-23 18:53:47 +02:00
import breaks from 'remark-breaks';
2023-06-22 14:59:30 +02:00
import ForwardRefLink from './ForwardRefLink';
2023-04-21 16:57:08 +02:00
const Post = ({ content, postQuoteOnClick, postQuoteOnOver, postQuoteOnLeave, postQuoteRef }) => {
2023-08-18 13:47:41 +02:00
const doubleNewlineContent = content?.replace(/\n/g, ' \n\n');
2023-06-21 08:47:31 +02:00
const customSchema = useMemo(() => ({
...defaultSchema,
tagNames: [...defaultSchema.tagNames, 'div'],
attributes: {
...defaultSchema.attributes,
div: ['className'],
},
}), []);
2023-04-27 13:10:23 +02:00
2023-06-21 08:47:31 +02:00
const blockquoteToGreentext = () => (tree) => {
tree.children.forEach((node) => {
if (node.type === 'blockquote') {
node.children.forEach((child) => {
if (child.type === 'paragraph' && child.children.length > 0) {
const prefix = {
type: 'text',
value: '>',
};
child.children.unshift(prefix);
2023-06-19 15:56:18 +02:00
}
2023-06-21 08:47:31 +02:00
});
node.type = 'div';
node.data = {
hName: 'div',
hProperties: {
className: 'greentext',
},
};
2023-06-19 15:56:18 +02:00
}
});
2023-06-21 08:47:31 +02:00
};
2023-04-21 16:38:14 +02:00
const createQuotelink = (children, postQuoteOnClick, postQuoteOnOver, postQuoteOnLeave, postQuoteRef) => {
2023-06-22 17:29:46 +02:00
const patternC = "(c/[A-Za-z0-9]{46}|c/[A-Za-z0-9]{12})";
const patternP = "(p/([A-Za-z0-9]{52}|[A-Za-z0-9-.]*\\.eth))";
const patternU = "(u/([A-Za-z0-9]{52}|[A-Za-z0-9-.]*\\.eth))";
const patternPC = "(p/([A-Za-z0-9]{52}|[A-Za-z0-9-.]*\\.eth)/c/[A-Za-z0-9]{46})";
const regex = new RegExp(`${patternC}|${patternPC}|${patternU}|${patternP}`, 'g');
2023-06-22 18:12:15 +02:00
return children?.flatMap((child, i) => {
2023-06-22 17:29:46 +02:00
if (typeof child !== 'string') {
return child;
}
const parts = [];
let match;
let lastIndex = 0;
while ((match = regex.exec(child)) !== null) {
const matchedText = match[0];
const index = match.index;
if (index > lastIndex) {
parts.push(child.substring(lastIndex, index));
2023-06-21 08:47:31 +02:00
}
2023-06-22 17:29:46 +02:00
const cid = matchedText.replace('c/', '');
const linkRef = React.createRef();
let linkTo = () => {};
const linkTarget = matchedText.startsWith('u/') ? "_blank" : "_self";
if (matchedText.startsWith('u/')) {
2023-08-22 11:49:04 +02:00
linkTo = "#void";
2023-06-22 17:29:46 +02:00
} else if (matchedText.startsWith('p/') || matchedText.startsWith('p/')) {
linkTo = `/${matchedText}`;
}
parts.push(
<ForwardRefLink
key={`link-${i}-${matchedText}`}
className="quotelink"
to={linkTo}
target={linkTarget}
ref={linkRef}
setRefAndCid={(ref) => {
if (typeof postQuoteRef === 'function') {
postQuoteRef(cid, ref);
}
}}
onClick={() => {postQuoteOnClick(cid)}}
onMouseOver={() => {
postQuoteOnOver(cid);
}}
onMouseLeave={() => {
postQuoteOnLeave();
}}
>
{matchedText}
</ForwardRefLink>
);
lastIndex = index + matchedText.length;
}
if (lastIndex < child.length) {
parts.push(child.substring(lastIndex));
}
return parts;
2023-06-21 08:47:31 +02:00
});
};
2023-06-22 17:29:46 +02:00
2023-06-19 15:56:18 +02:00
2023-03-29 13:37:36 +02:00
2023-04-21 16:38:14 +02:00
return (
<ReactMarkdown
2023-04-25 15:26:46 +02:00
children={doubleNewlineContent}
2023-04-23 18:53:47 +02:00
remarkPlugins={[blockquoteToGreentext, breaks]}
2023-04-27 13:10:23 +02:00
rehypePlugins={[[rehypeSanitize, customSchema]]}
2023-04-21 16:38:14 +02:00
components={{
img: ({ src }) => <span>{src}</span>,
2023-05-02 13:28:32 +02:00
video: ({ src }) => <span>{src}</span>,
source: ({ src }) => <span>{src}</span>,
gif: ({ src }) => <span>{src}</span>,
p: ({ children }) => <div className='custom-paragraph'>
{createQuotelink(children, postQuoteOnClick, postQuoteOnOver, postQuoteOnLeave, postQuoteRef)}
</div>,
2023-04-21 16:38:14 +02:00
}}
/>
);
2023-03-29 13:37:36 +02:00
};
2023-06-19 15:56:18 +02:00
export default React.memo(Post);