markdown.tsx 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import ReactMarkdown from "react-markdown";
  2. import "katex/dist/katex.min.css";
  3. import RemarkMath from "remark-math";
  4. import RemarkBreaks from "remark-breaks";
  5. import RehypeKatex from "rehype-katex";
  6. import RemarkGfm from "remark-gfm";
  7. import SyntaxHighlighter from 'react-syntax-highlighter'
  8. import { atelierHeathLight } from 'react-syntax-highlighter/dist/esm/styles/hljs'
  9. import { useRef, useState, RefObject, useEffect } from "react";
  10. // import { copyToClipboard } from "../utils";
  11. export function PreCode(props: { children: any }) {
  12. const ref = useRef<HTMLPreElement>(null);
  13. return (
  14. <pre ref={ref}>
  15. <span
  16. className="copy-code-button"
  17. onClick={() => {
  18. if (ref.current) {
  19. const code = ref.current.innerText;
  20. // copyToClipboard(code);
  21. }
  22. }}
  23. ></span>
  24. {props.children}
  25. </pre>
  26. );
  27. }
  28. const useLazyLoad = (ref: RefObject<Element>): boolean => {
  29. const [isIntersecting, setIntersecting] = useState<boolean>(false);
  30. useEffect(() => {
  31. const observer = new IntersectionObserver(([entry]) => {
  32. if (entry.isIntersecting) {
  33. setIntersecting(true);
  34. observer.disconnect();
  35. }
  36. });
  37. if (ref.current) {
  38. observer.observe(ref.current);
  39. }
  40. return () => {
  41. observer.disconnect();
  42. };
  43. }, [ref]);
  44. return isIntersecting;
  45. };
  46. export function Markdown(props: { content: string }) {
  47. return (
  48. <div className="markdown-body">
  49. <ReactMarkdown
  50. remarkPlugins={[RemarkMath, RemarkGfm, RemarkBreaks]}
  51. rehypePlugins={[
  52. RehypeKatex,
  53. ]}
  54. components={{
  55. code({ node, inline, className, children, ...props }) {
  56. const match = /language-(\w+)/.exec(className || '')
  57. return !inline && match ? (
  58. <SyntaxHighlighter
  59. {...props}
  60. children={String(children).replace(/\n$/, '')}
  61. style={atelierHeathLight}
  62. language={match[1]}
  63. showLineNumbers
  64. PreTag="div"
  65. />
  66. ) : (
  67. <code {...props} className={className}>
  68. {children}
  69. </code>
  70. )
  71. }
  72. }}
  73. linkTarget={"_blank"}
  74. >
  75. {props.content}
  76. </ReactMarkdown>
  77. </div>
  78. );
  79. }