import React, { useMemo, useState } from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import supersub from 'remark-supersub'; import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'; import styles from './markdown.module.css'; import { useTranslation } from 'react-i18next'; import { getLinkMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils'; import CommentMedia from '../comment-media'; interface MarkdownProps { content: string; } const MAX_LENGTH_FOR_GFM = 10000; // remarkGfm lags with large content const blockquoteToGreentext = () => (tree: any) => { tree.children.forEach((node: any) => { if (node.type === 'blockquote') { node.children.forEach((child: any) => { if (child.type === 'paragraph' && child.children.length > 0) { const prefix = { type: 'text', value: '>', }; child.children.unshift(prefix); } }); node.type = 'div'; node.data = { hName: 'div', hProperties: { className: 'greentext', }, }; } }); }; const Markdown = ({ content }: MarkdownProps) => { const remarkPlugins: any[] = [[supersub]]; if (content && content.length <= MAX_LENGTH_FOR_GFM) { remarkPlugins.push([remarkGfm, { singleTilde: false }]); } const customSchema = useMemo( () => ({ ...defaultSchema, tagNames: [...(defaultSchema.tagNames || []), 'div'], attributes: { ...defaultSchema.attributes, div: ['className'], }, }), [], ); remarkPlugins.push([blockquoteToGreentext]); const { t } = useTranslation(); const [showMedia, setShowMedia] = useState(false); return ( {src}, video: ({ src }) => {src}, iframe: ({ src }) => {src}, source: ({ src }) => {src}, hr: () => (

), a: ({ href, children }) => { if (href) { const linkMediaInfo = getLinkMediaInfo(href); if (getHasThumbnail(linkMediaInfo, href)) { return ( <> {children} {' '} [ setShowMedia(!showMedia)}> {showMedia ? t('remove') : t('embed')} ] {showMedia && ( <>
)} ); } else { return ( {children} ); } } }, }} />
); }; export default React.memo(Markdown);