Skip to content

Commit

Permalink
Add support for GitHub's admonitions
Browse files Browse the repository at this point in the history
  • Loading branch information
damianstasik committed Sep 6, 2024
1 parent d8d3cde commit 113a716
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 2 deletions.
17 changes: 17 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@tanstack/react-query-devtools": "^5.53.2",
"@types/react": "^18.3.5",
"@types/react-dom": "^18.3.0",
"@types/react-is": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.20",
"clsx": "^2.1.1",
Expand All @@ -37,6 +38,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-helmet-async": "^2.0.5",
"react-is": "^18.3.1",
"react-router-dom": "^6.26.1",
"react-virtuoso": "^4.10.2",
"rehype-raw": "^7.0.0",
Expand Down
104 changes: 104 additions & 0 deletions frontend/src/components/Markdown/Blockquote.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import clsx from "clsx";
import { BlockquoteHTMLAttributes, ReactNode } from "react";
import { isElement } from "react-is";

const WARNING_MARK = "[!WARNING]";
const IMPORTANT_MARK = "[!DANGER]";
const NOTE_MARK = "[!NOTE]";
const TIP_MARK = "[!TIP]";
const CAUTION_MARK = "[!CAUTION]";

function getAdmonitionClassName(prefix: string) {
switch (prefix) {
case NOTE_MARK:
return "bg-sky-100 text-sky-800 dark:bg-sky-950 dark:text-sky-100";
case CAUTION_MARK:
return "bg-red-100 text-red-800 dark:bg-red-950 dark:text-red-100";
case WARNING_MARK:
return "bg-yellow-100 text-yellow-800 dark:bg-yellow-950 dark:text-yellow-100";
case TIP_MARK:
return "bg-green-100 text-green-800 dark:bg-green-950 dark:text-green-100";
case IMPORTANT_MARK:
return "bg-purple-100 text-purple-800 dark:bg-purple-950 dark:text-purple-100";
}
}

function getAdmonitionTitle(prefix: string) {
switch (prefix) {
case NOTE_MARK:
return "Note";
case CAUTION_MARK:
return "Caution";
case WARNING_MARK:
return "Warning";
case TIP_MARK:
return "Tip";
case IMPORTANT_MARK:
return "Important";
}
}

function getAdmonitionMatch(children: ReactNode) {
if (!Array.isArray(children)) {
return null;
}

for (let i = 0; i < children.length; i++) {
const child = children[i];

if (!isElement(child)) {
continue;
}

const type = child.props.children;

if (typeof type !== "string") {
continue;
}

switch (type) {
case WARNING_MARK:
case CAUTION_MARK:
case NOTE_MARK:
case TIP_MARK:
case IMPORTANT_MARK:
return {
prefix: type,
content: children.slice(i + 1),
};
}
}

return null;
}

export function MarkdownBlockquote({
children,
}: BlockquoteHTMLAttributes<HTMLQuoteElement>) {
const admonitionMatch = getAdmonitionMatch(children);

if (admonitionMatch) {
const { prefix, content } = admonitionMatch;
const className = getAdmonitionClassName(prefix);
const title = getAdmonitionTitle(prefix);

return (
<div
role="alert"
className={clsx(
"mt-5 px-3 py-2 first:mt-0 [&>h6]:mt-4 [&>p]:mt-2 [li>&:first-child]:mt-0",
className,
)}
>
<strong className="font-semibold">{title}</strong>
{content}
</div>
);
}

return (
<blockquote className="mt-5 flex flex-col border-l-2 border-gray-500 pl-5">
{children}
</blockquote>
);
}
17 changes: 17 additions & 0 deletions frontend/src/components/Markdown/H4.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { HTMLAttributes } from "react";
import { HeadingLink } from "../HeadingLink";

export function MarkdownH4({
children,
id,
}: HTMLAttributes<HTMLHeadingElement>) {
return (
<h6
className="group mt-8 scroll-mt-5 break-words text-lg font-bold first:mt-0"
id={id}
>
{children}
{id && <HeadingLink id={id} label={children as string} />}
</h6>
);
}
2 changes: 0 additions & 2 deletions frontend/src/components/Markdown/P.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ function getAdmonitionClassName(prefix: string) {
return "bg-red-100 text-red-800 dark:bg-red-950 dark:text-red-100";
case WARNING_MARK:
return "bg-yellow-100 text-yellow-800 dark:bg-yellow-950 dark:text-yellow-100";
default:
return "";
}
}

Expand Down
4 changes: 4 additions & 0 deletions frontend/src/components/Markdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import { MarkdownTh } from "./Th";
import { MarkdownImg } from "./Img";
import { MarkdownOl } from "./Ol";
import { MarkdownHr } from "./Hr";
import { MarkdownBlockquote } from "./Blockquote";
import { MarkdownH4 } from "./H4";

const production: Options = {
development: false,
Expand All @@ -38,6 +40,7 @@ const production: Options = {
h1: MarkdownH1,
h2: MarkdownH2,
h3: MarkdownH3,
h4: MarkdownH4,
p: MarkdownP,
code: MarkdownCode,
pre: MarkdownPre,
Expand All @@ -47,6 +50,7 @@ const production: Options = {
img: MarkdownImg,
ol: MarkdownOl,
hr: MarkdownHr,
blockquote: MarkdownBlockquote,
},
};

Expand Down

0 comments on commit 113a716

Please sign in to comment.