diff --git a/package.json b/package.json index 3ba8665..5bf68cb 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "@types/node": "^16.11.47", "@types/react": "^18.0.15", "@types/react-dom": "^18.0.6", + "@uiw/react-md-editor": "^3.18.1", "axios": "^0.27.2", "classnames": "^2.3.1", "formik": "^2.2.9", @@ -22,16 +23,20 @@ "react-dom": "^18.2.0", "react-hotkeys": "^2.0.0", "react-i18next": "^11.18.3", + "react-markdown": "^8.0.3", "react-redux": "^8.0.2", "react-router-dom": "^6.3.0", "react-scripts": "5.0.1", "react-scrollbars-custom": "^4.1.0", + "react-syntax-highlighter": "^15.5.0", + "remark-code-blocks": "^2.0.1", + "remark-gfm": "^3.0.1", "storybook-addon-pseudo-states": "^1.15.1", + "tailwindcss": "^3.1.7", "tsconfig-paths-webpack-plugin": "^4.0.0", "typescript": "^4.7.4", "web-vitals": "^2.1.4", - "yup": "^0.32.11", - "tailwindcss": "^3.1.7" + "yup": "^0.32.11" }, "scripts": { "dev-tools": "redux-devtools --hostname=localhost --port=8000", @@ -95,6 +100,7 @@ "@testing-library/react": "^13.3.0", "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.5.2", + "@types/react-syntax-highlighter": "^15.5.5", "autoprefixer": "^10.4.8", "babel-plugin-named-exports-order": "^0.0.2", "jest": "^28.1.3", diff --git a/src/components/Markdown.tsx b/src/components/Markdown.tsx new file mode 100644 index 0000000..5c5e4b9 --- /dev/null +++ b/src/components/Markdown.tsx @@ -0,0 +1,69 @@ +import React from "react"; + +/* -------------------------------------------------------------------------- */ +/* MarkDown */ +/* -------------------------------------------------------------------------- */ +import ReactMarkdown from "react-markdown"; +import remarkGfm from "remark-gfm"; + +/* -------------------------------------------------------------------------- */ +/* Components */ +/* -------------------------------------------------------------------------- */ +import Typography from "./typography/Typography"; +import Heading from "./typography/Heading"; +import Link from "./Link"; + +/* -------------------------------------------------------------------------- */ +/* Code */ +/* -------------------------------------------------------------------------- */ +import vsc from "react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus"; +import { darcula } from "react-syntax-highlighter/dist/esm/styles/prism"; +import docco from "react-syntax-highlighter/dist/esm/styles/prism"; +import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; + +export type Props = { + markdown: string; +}; + +const Markdown = ({ markdown }: Props) => { + return ( + <ReactMarkdown + remarkPlugins={[remarkGfm]} + children={markdown} + components={{ + h1: Heading, + h2: Typography, + a: (props) => { + return ( + <Link + href={props.href} + className="text-sky-600 font-bold text-base" + {...props} + > + {props.children} + </Link> + ); + }, + + code({ node, inline, className, children, ...props }) { + const match = /language-(\w+)/.exec(className || ""); + return !inline && match ? ( + <SyntaxHighlighter + children={String(children).replace(/\n$/, "")} + style={docco} + language={match[1]} + PreTag="div" + {...props} + /> + ) : ( + <code className={className} {...props}> + {children} + </code> + ); + }, + }} + /> + ); +}; + +export default Markdown;