From 4637e64458b126387d7fddde726922491c39b88f Mon Sep 17 00:00:00 2001
From: Maximilian Kaske <56969857+mxkaske@users.noreply.github.com>
Date: Mon, 21 Aug 2023 21:31:02 +0200
Subject: [PATCH] chore: support markdown (#215)
* chore: support markdown
* fix: deps
* fix: remove log
---
apps/web/package.json | 3 +
apps/web/src/components/content/preview.tsx | 16 ++++++
.../src/components/forms/incident-form.tsx | 34 +++++++----
.../components/forms/incident-update-form.tsx | 34 +++++++----
apps/web/src/components/incidents/events.tsx | 24 +++++++-
apps/web/src/hooks/use-preprocessor.tsx | 31 ++++++++++
pnpm-lock.yaml | 56 +++++++++++++++++++
7 files changed, 175 insertions(+), 23 deletions(-)
create mode 100644 apps/web/src/components/content/preview.tsx
create mode 100644 apps/web/src/hooks/use-preprocessor.tsx
diff --git a/apps/web/package.json b/apps/web/package.json
index a48d062ec..56cc0e4b4 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -68,6 +68,9 @@
"react-tweet": "^3.1.1",
"reading-time": "1.5.0",
"rehype-pretty-code": "0.10.0",
+ "rehype-react": "7.2.0",
+ "remark-parse": "10.0.2",
+ "remark-rehype": "10.1.0",
"resend": "0.15.3",
"shiki": "0.14.3",
"stripe": "12.17.0",
diff --git a/apps/web/src/components/content/preview.tsx b/apps/web/src/components/content/preview.tsx
new file mode 100644
index 000000000..501414e67
--- /dev/null
+++ b/apps/web/src/components/content/preview.tsx
@@ -0,0 +1,16 @@
+"use client";
+
+import { useProcessor } from "@/hooks/use-preprocessor";
+
+interface Props {
+ md?: string;
+}
+
+export function Preview({ md }: Props) {
+ const Component = useProcessor(md || "");
+ return (
+
+ {Component}
+
+ );
+}
diff --git a/apps/web/src/components/forms/incident-form.tsx b/apps/web/src/components/forms/incident-form.tsx
index 4f1fd136e..49e89c215 100644
--- a/apps/web/src/components/forms/incident-form.tsx
+++ b/apps/web/src/components/forms/incident-form.tsx
@@ -1,4 +1,3 @@
-// move into @/components/forms/ later
"use client";
import * as React from "react";
@@ -14,6 +13,7 @@ import {
StatusEnum,
} from "@openstatus/db/src/schema";
+import { Preview } from "@/components/content/preview";
import { Icons } from "@/components/icons";
import { LoadingAnimation } from "@/components/loading-animation";
import { Button } from "@/components/ui/button";
@@ -30,6 +30,7 @@ import {
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Textarea } from "@/components/ui/textarea";
import { useToast } from "@/components/ui/use-toast";
import { statusDict } from "@/data/incidents-dictionary";
@@ -170,20 +171,31 @@ export function IncidentForm({
(
Message
-
-
-
+
+
+ Write
+ Preview
+
+
+
+
+
+
+
+
+
+
- Tell your user what's happening.
+ Tell your user what's happening. Supports markdown.
diff --git a/apps/web/src/components/forms/incident-update-form.tsx b/apps/web/src/components/forms/incident-update-form.tsx
index 7a2872b45..290753078 100644
--- a/apps/web/src/components/forms/incident-update-form.tsx
+++ b/apps/web/src/components/forms/incident-update-form.tsx
@@ -1,4 +1,3 @@
-// move into @/components/forms/ later
"use client";
import * as React from "react";
@@ -13,6 +12,7 @@ import {
StatusEnum,
} from "@openstatus/db/src/schema";
+import { Preview } from "@/components/content/preview";
import { Icons } from "@/components/icons";
import { LoadingAnimation } from "@/components/loading-animation";
import { Button } from "@/components/ui/button";
@@ -27,6 +27,7 @@ import {
FormMessage,
} from "@/components/ui/form";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Textarea } from "@/components/ui/textarea";
import { useToast } from "@/components/ui/use-toast";
import { statusDict } from "@/data/incidents-dictionary";
@@ -128,20 +129,31 @@ export function IncidentUpdateForm({
/>
(
Message
-
-
-
+
+
+ Write
+ Preview
+
+
+
+
+
+
+
+
+
+
- Tell your user what's happening.
+ Tell your user what's happening. Supports markdown.
diff --git a/apps/web/src/components/incidents/events.tsx b/apps/web/src/components/incidents/events.tsx
index 48b9273a9..3e7a45dcc 100644
--- a/apps/web/src/components/incidents/events.tsx
+++ b/apps/web/src/components/incidents/events.tsx
@@ -11,6 +11,7 @@ import { Icons } from "@/components/icons";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { statusDict } from "@/data/incidents-dictionary";
+import { useProcessor } from "@/hooks/use-preprocessor";
import { cn } from "@/lib/utils";
import { DeleteIncidentUpdateButtonIcon } from "../../app/app/(dashboard)/[workspaceSlug]/incidents/_components/delete-incident-update";
@@ -78,7 +79,8 @@ export function Events({
{label}
- {update.message}
+ {/* {update.message}
*/}
+
);
})}
@@ -93,3 +95,23 @@ export function Events({
);
}
+
+function EventMessage({
+ message,
+ className,
+}: {
+ message: string;
+ className?: string;
+}) {
+ const Component = useProcessor(message);
+ return (
+
+ {Component}
+
+ );
+}
diff --git a/apps/web/src/hooks/use-preprocessor.tsx b/apps/web/src/hooks/use-preprocessor.tsx
new file mode 100644
index 000000000..c0608b384
--- /dev/null
+++ b/apps/web/src/hooks/use-preprocessor.tsx
@@ -0,0 +1,31 @@
+import type { AnchorHTMLAttributes } from "react";
+import { createElement, Fragment, useEffect, useState } from "react";
+import rehypeReact from "rehype-react";
+import remarkParse from "remark-parse";
+import remarkRehype from "remark-rehype";
+import { unified } from "unified";
+
+export function useProcessor(text: string) {
+ const [Content, setContent] = useState(null);
+
+ useEffect(() => {
+ unified()
+ .use(remarkParse)
+ .use(remarkRehype)
+ .use(rehypeReact, {
+ createElement,
+ Fragment,
+ components: {
+ a: (props: AnchorHTMLAttributes) => {
+ return ;
+ },
+ },
+ })
+ .process(text)
+ .then((file) => {
+ setContent(file.result);
+ });
+ }, [text]);
+
+ return Content;
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 71da80ffa..e2be03fdd 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -249,6 +249,15 @@ importers:
rehype-pretty-code:
specifier: 0.10.0
version: 0.10.0(shiki@0.14.3)
+ rehype-react:
+ specifier: 7.2.0
+ version: 7.2.0(@types/react@18.2.12)
+ remark-parse:
+ specifier: 10.0.2
+ version: 10.0.2
+ remark-rehype:
+ specifier: 10.1.0
+ version: 10.1.0
resend:
specifier: 0.15.3
version: 0.15.3
@@ -2333,6 +2342,13 @@ packages:
read-yaml-file: 1.1.0
dev: false
+ /@mapbox/hast-util-table-cell-style@0.2.0:
+ resolution: {integrity: sha512-gqaTIGC8My3LVSnU38IwjHVKJC94HSonjvFHDk8/aSrApL8v4uWgm8zJkK7MJIIbHuNOr/+Mv2KkQKcxs6LEZA==}
+ engines: {node: '>=12'}
+ dependencies:
+ unist-util-visit: 1.4.1
+ dev: false
+
/@mdx-js/esbuild@2.3.0(esbuild@0.18.17):
resolution: {integrity: sha512-r/vsqsM0E+U4Wr0DK+0EfmABE/eg+8ITW4DjvYdh3ve/tK2safaqHArNnaqbOk1DjYGrhxtoXoGaM3BY8fGBTA==}
peerDependencies:
@@ -8056,6 +8072,17 @@ packages:
resolution: {integrity: sha512-7SW7ejyfnRxuOc7ptQHSf4LDoZaWOivfzqw+5rpcQku0nHfmicPKE51ra9BiRLAmT8+gGLestr1XroUkqdjL6w==}
dev: false
+ /hast-to-hyperscript@10.0.3:
+ resolution: {integrity: sha512-NuBoUStp4fRwmvlfbidlEiRSTk0gSHm+97q4Xn9CJ10HO+Py7nlTuDi6RhM1qLOureukGrCXLG7AAxaGqqyslQ==}
+ dependencies:
+ '@types/unist': 2.0.7
+ comma-separated-tokens: 2.0.3
+ property-information: 6.2.0
+ space-separated-tokens: 2.0.2
+ style-to-object: 0.4.2
+ web-namespaces: 2.0.1
+ dev: false
+
/hast-util-from-dom@4.2.0:
resolution: {integrity: sha512-t1RJW/OpJbCAJQeKi3Qrj1cAOLA0+av/iPFori112+0X7R3wng+jxLA+kXec8K4szqPRGI8vPxbbpEYvvpwaeQ==}
dependencies:
@@ -11241,6 +11268,19 @@ packages:
shiki: 0.14.3
dev: false
+ /rehype-react@7.2.0(@types/react@18.2.12):
+ resolution: {integrity: sha512-MHYyCHka+3TtzBMKtcuvVOBAbI1HrfoYA+XH9m7/rlrQQATCPwtJnPdkxKKcIGF8vc9mxqQja9r9f+FHItQeWg==}
+ peerDependencies:
+ '@types/react': '>=17'
+ dependencies:
+ '@mapbox/hast-util-table-cell-style': 0.2.0
+ '@types/hast': 2.3.5
+ '@types/react': 18.2.12
+ hast-to-hyperscript: 10.0.3
+ hast-util-whitespace: 2.0.1
+ unified: 10.1.2
+ dev: false
+
/rehype-slug@5.1.0:
resolution: {integrity: sha512-Gf91dJoXneiorNEnn+Phx97CO7oRMrpi+6r155tTxzGuLtm+QrI4cTwCa9e1rtePdL4i9tSO58PeSS6HWfgsiw==}
dependencies:
@@ -12572,6 +12612,10 @@ packages:
resolution: {integrity: sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==}
dev: false
+ /unist-util-is@3.0.0:
+ resolution: {integrity: sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==}
+ dev: false
+
/unist-util-is@5.2.1:
resolution: {integrity: sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==}
dependencies:
@@ -12615,6 +12659,12 @@ packages:
dependencies:
'@types/unist': 2.0.7
+ /unist-util-visit-parents@2.1.2:
+ resolution: {integrity: sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==}
+ dependencies:
+ unist-util-is: 3.0.0
+ dev: false
+
/unist-util-visit-parents@4.1.1:
resolution: {integrity: sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw==}
dependencies:
@@ -12635,6 +12685,12 @@ packages:
unist-util-is: 6.0.0
dev: false
+ /unist-util-visit@1.4.1:
+ resolution: {integrity: sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==}
+ dependencies:
+ unist-util-visit-parents: 2.1.2
+ dev: false
+
/unist-util-visit@3.1.0:
resolution: {integrity: sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA==}
dependencies:
--
2.51.2