Spaces:
Sleeping
Sleeping
File size: 2,214 Bytes
052672d 0fd8446 052672d f80b091 052672d 0fd8446 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
import { FC, memo } from 'react';
import ReactMarkdown, { Options } from 'react-markdown';
import Img from '../ui/Img';
import remarkGfm from 'remark-gfm';
import remarkMath from 'remark-math';
import rehypeRaw from 'rehype-raw';
import { CodeBlock } from '../ui/CodeBlock';
export const MemoizedReactMarkdown: FC<Options> = memo(
ReactMarkdown,
(prevProps, nextProps) =>
prevProps.children === nextProps.children &&
prevProps.className === nextProps.className,
);
export const Markdown: React.FC<{
content: string;
}> = ({ content }) => {
return (
<>
<MemoizedReactMarkdown
className="break-words overflow-auto"
remarkPlugins={[remarkGfm, remarkMath]}
rehypePlugins={[rehypeRaw] as any}
components={{
p({ children, ...props }) {
if (
props.node.children.some(
child => child.type === 'element' && child.tagName === 'img',
)
) {
return (
<p className="flex flex-wrap gap-2 items-start">{children}</p>
);
}
return <p className="mb-2 whitespace-pre-line">{children}</p>;
},
img(props) {
if (props.src?.endsWith('.mp4')) {
return (
<video src={props.src} controls width={500} height={500} />
);
}
return (
<Img
src={props.src ?? '/landing.png'}
alt={props.alt ?? 'answer-image'}
quality={100}
sizes="(min-width: 66em) 15vw,
(min-width: 44em) 20vw,
100vw"
/>
);
},
code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '');
return (
<CodeBlock
key={Math.random()}
language={(match && match[1]) || ''}
value={String(children).replace(/\n$/, '')}
{...props}
/>
);
},
}}
>
{content}
</MemoizedReactMarkdown>
</>
);
};
|