diff --git a/web/src/components/markdown.tsx b/web/src/components/markdown.tsx index 3b545a8d..f3e3fdfb 100644 --- a/web/src/components/markdown.tsx +++ b/web/src/components/markdown.tsx @@ -1 +1,321 @@ -CN/a \ No newline at end of file +'use client'; + +import { cn } from '@/lib/utils'; +import { ImageIcon } from 'lucide-react'; +import Link from 'next/link'; +import { + JSX, + MouseEventHandler, + useCallback, + useEffect, + useMemo, + useState, +} from 'react'; +import ReactMarkdown from 'react-markdown'; +import rehypeHighlight from 'rehype-highlight'; +import rehypeHighlightLines from 'rehype-highlight-code-lines'; +import rehypeRaw from 'rehype-raw'; +import remarkDirective from 'remark-directive'; +import remarkFrontmatter from 'remark-frontmatter'; +import remarkGfm from 'remark-gfm'; +import remarkGithubAdmonitionsToDirectives from 'remark-github-admonitions-to-directives'; +import remarkHeaderId from 'remark-heading-id'; +import remarkMdxFrontmatter from 'remark-mdx-frontmatter'; +import { AnchorLink } from './anchor-link'; +import { ChartMermaid } from './chart-mermaid'; +import { Skeleton } from './ui/skeleton'; +import { Table, TableBody, TableCell, TableHeader, TableRow } from './ui/table'; +import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip'; + +import './markdown.css'; + +const securityLink = (props: JSX.IntrinsicElements['a']) => { + const target = props.href?.match(/^http/) ? '_blank' : '_self'; + const url = props.href?.replace(/\.md/, ''); + + const isNavLink = props.className?.includes('toc-link'); + return isNavLink ? ( + + + + + + {props.children} + + + ) : ( + + {props.children} + + ); +}; + +const unSecurityLink = (props: JSX.IntrinsicElements['a']) => { + const url = props.href?.replace(/\.md/, '') || '/'; + const isNavLink = props.className?.includes('toc-link'); + const handleLinkClick: MouseEventHandler = (e) => { + if (!url.match(/http/)) { + e.preventDefault(); + e.stopPropagation(); + } + }; + return isNavLink ? ( + + + + + + {props.children} + + + ) : ( + + {props.children} + + ); +}; + +export const CustomImage = ({ + src, + ...props +}: JSX.IntrinsicElements['img']) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [imageUrl, setImageUrl] = useState(); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const getImageSrc = useCallback(async () => { + if (typeof src !== 'string') return; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [path, queryString] = src.replace('asset://', '').split('?'); + }, [src]); + + useEffect(() => {}, []); + + return; + + return imageUrl ? ( + {props.alt} + ) : ( + + + + ); +}; + +export const mdComponents = { + h1: (props: JSX.IntrinsicElements['h1']) => ( +

+ {props.children} +

+ ), + h2: (props: JSX.IntrinsicElements['h2']) => ( +

+ {props.children} +

+ ), + h3: (props: JSX.IntrinsicElements['h3']) => ( +

+ {props.children} +

+ ), + h4: (props: JSX.IntrinsicElements['h4']) => ( +

+ {props.children} +

+ ), + h5: (props: JSX.IntrinsicElements['h5']) => ( +
+ {props.children} +
+ ), + h6: (props: JSX.IntrinsicElements['h6']) => ( +
+ {props.children} +
+ ), + p: (props: JSX.IntrinsicElements['p']) => ( +
{props.children}
+ ), + blockquote: ({ + className, + ...props + }: JSX.IntrinsicElements['blockquote']) => { + return ( +
+ {props.children} +
+ ); + }, + img: ({ src, ...props }: JSX.IntrinsicElements['img']) => { + if (!src) { + return ( + + + + ); + } else if (typeof src === 'string' && src.startsWith('asset://')) { + return ; + } else { + return ( + {props.alt} + ); + } + }, + pre: ({ className, ...props }: JSX.IntrinsicElements['pre']) => { + return ( +
+        {props.children}
+      
+ ); + }, + code: ({ className, ...props }: JSX.IntrinsicElements['code']) => { + const match = /language-(\w+)/.exec(className || ''); + const language = match?.[1]; + if (language) { + if (language === 'mermaid') { + return ( + + {typeof props.children === 'string' ? props.children : ''} + + ); + } else { + return ( + + {props.children} + + ); + } + } else { + return ( + + {props.children} + + ); + } + }, + ol: ({ className, ...props }: JSX.IntrinsicElements['ul']) => { + return ( +
    + {props.children} +
+ ); + }, + ul: ({ className, ...props }: JSX.IntrinsicElements['ul']) => { + return ( +
    {props.children}
+ ); + }, + li: ({ className, ...props }: JSX.IntrinsicElements['li']) => { + return ( +
  • {props.children}
  • + ); + }, + nav: (props: JSX.IntrinsicElements['nav']) => { + if (props.className === 'toc') { + return