From ba1e38c9fa39c717601f59ef0abe12d816646ef6 Mon Sep 17 00:00:00 2001 From: Der_Googler <54764558+DerGoogler@users.noreply.github.com> Date: Tue, 2 Jul 2024 16:08:30 +0200 Subject: [PATCH] part. support gfm alerts --- Website/src/components/Markdown/index.tsx | 125 +++++++++++++++++++++- 1 file changed, 123 insertions(+), 2 deletions(-) diff --git a/Website/src/components/Markdown/index.tsx b/Website/src/components/Markdown/index.tsx index 899ed44b..917ce81e 100644 --- a/Website/src/components/Markdown/index.tsx +++ b/Website/src/components/Markdown/index.tsx @@ -1,7 +1,7 @@ -import Markdown, { MarkdownToJSX, compiler } from "markdown-to-jsx"; +import Markdown, { MarkdownToJSX, RuleType, compiler } from "markdown-to-jsx"; import { Video } from "@Components/dapi/Video"; import React from "react"; -import { Alert, Divider, Paper, Stack, SxProps, Theme } from "@mui/material"; +import { Alert, AlertTitle, Divider, Paper, Stack, SxProps, Theme } from "@mui/material"; import styled from "@emotion/styled"; import hljs from "highlight.js"; import { Image } from "@Components/dapi/Image"; @@ -12,6 +12,61 @@ import { Code } from "@Components/dapi/Code"; import { Pre } from "@Components/dapi/Pre"; import { Anchor } from "@Components/dapi/Anchor"; +export type AlertType = { + title: string; + render: (content: React.ReactNode) => JSX.Element; +}; +const sx = { + mb: 2, +}; +export const admonitionTypes = { + "[!NOTE]": { + title: "Note", + render: (content: string) => ( + + Note + {content} + + ), + }, + "[!TIP]": { + title: "Tip", + render: (content: string) => ( + + Tip + {content} + + ), + }, + "[!IMPORTANT]": { + title: "Important", + render: (content: string) => ( + + Important + {content} + + ), + }, + "[!WARNING]": { + title: "Warning", + render: (content: string) => ( + + Warning + {content} + + ), + }, + "[!CAUTION]": { + title: "Caution", + render: (content: string) => ( + + Caution + {content} + + ), + }, +}; + type Props = { fetch?: string; children?: string; @@ -117,6 +172,72 @@ export const Markup = (props: Props) => { return React.createElement(type, props, ...children); } }, + renderRule(next, node, renderChildren, state) { + if (node.type != RuleType.blockQuote) return next(); + + const blockquote = node as MarkdownToJSX.BlockQuoteNode; + if (blockquote.children[0].type != RuleType.paragraph) return next(); + const paragraph = blockquote.children[0]; + if (paragraph.children[0].type != RuleType.text) return next(); + let text = paragraph.children.flatMap((p: any) => p.text).join(""); + + console.log(text); + + let title: string; + let admonitionType: AlertType | null = null; + // A link break after the title is explicitly required by GitHub + const titleEnd = text.indexOf("\n"); + if (titleEnd < 0) { + // But if the following one is a block, the newline would be trimmed by the upstream. + // To start a new block, a newline is required. + // So we just need to addtionally check if the following one is a block. + // The legacy title variant is not affected since it checks an inline and does not care about the newline. + + // Considering the reason why the paragraph ends here, the following one should be a children of the blockquote, which means it is always a block. + // So no more check is required. + title = text; + admonitionType = admonitionTypes[title]; + + console.log(admonitionType); + + if (!admonitionType) { + return next(); + } + + // No addtional inlines can exist in this paragraph for the title... + if (paragraph.children.length > 1) { + // Unless it is an inline break, which can be transformed to from 2 spaces with a newline. + if (paragraph.children.at(1)?.type == RuleType.breakLine) { + // When it is, we actually have already found the line break required by GitHub. + // So we just strip the additional `
` element. + // The title element will be removed later. + paragraph.children.splice(1, 1); + } else { + return next(); + } + } + // strip the title + paragraph.children.shift(); + } else { + const textBody = text.substring(titleEnd + 1); + title = text.substring(0, titleEnd); + // Handle whitespaces after the title. + // Whitespace characters are defined by GFM. + const m = /[ \t\v\f\r]+$/.exec(title); + if (m) { + title = title.substring(0, title.length - m[0].length); + } + + console.log(admonitionType); + + admonitionType = admonitionTypes[title]; + if (!admonitionType) return next(); + // Update the text body to remove the title + text = textBody; + } + + return admonitionType.render(text); + }, }} children={text} />