From 09f3fe24fc046f2e1c1c68051c7238fcc3b7cc3f Mon Sep 17 00:00:00 2001 From: Marshall Ku Date: Fri, 23 Feb 2024 12:32:45 +0900 Subject: [PATCH] Add logics for parsing content in comments --- .../src/components/CommentBubble/index.tsx | 7 +- .../CommentContent/index.module.scss | 27 +++++ .../src/components/CommentContent/index.tsx | 99 +++++++++++++++++++ cspell.json | 1 + 4 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 apps/blog/src/components/CommentContent/index.module.scss create mode 100644 apps/blog/src/components/CommentContent/index.tsx diff --git a/apps/blog/src/components/CommentBubble/index.tsx b/apps/blog/src/components/CommentBubble/index.tsx index fba8b033..c9bdc3a0 100644 --- a/apps/blog/src/components/CommentBubble/index.tsx +++ b/apps/blog/src/components/CommentBubble/index.tsx @@ -1,8 +1,9 @@ import { classNames, formatDate } from "@marshallku/utils"; import { type Comment } from "#api"; -import styles from "./index.module.scss"; import CommentAvatar from "#components/CommentAvatar"; import Typography from "#components/Typography"; +import CommentContent from "#components/CommentContent"; +import styles from "./index.module.scss"; export interface CommentBubbleProps { data: Comment; @@ -27,8 +28,8 @@ function CommentBubble({ border, data: { name, url, body, createdAt, byPostAutho {name} - - {body} + + {formatDate(new Date(createdAt), "yyyy. MM. dd")} diff --git a/apps/blog/src/components/CommentContent/index.module.scss b/apps/blog/src/components/CommentContent/index.module.scss new file mode 100644 index 00000000..04cdc6a6 --- /dev/null +++ b/apps/blog/src/components/CommentContent/index.module.scss @@ -0,0 +1,27 @@ +.comment-content { + &__image, + &__video { + max-width: 100%; + height: auto; + } + + &__code { + font-family: "Fira Code", monospace; + font-size: 90%; + padding: 0.2em 0.4em; + border-radius: 4px; + overflow-x: auto; + background-color: color(background-dimmed); + } + + &__image, + &__video, + &__code, + p { + margin-bottom: 0.65em; + } + + a { + color: color(link); + } +} diff --git a/apps/blog/src/components/CommentContent/index.tsx b/apps/blog/src/components/CommentContent/index.tsx new file mode 100644 index 00000000..5ba1ba6b --- /dev/null +++ b/apps/blog/src/components/CommentContent/index.tsx @@ -0,0 +1,99 @@ +import { ReactNode } from "react"; +import { classNames } from "@marshallku/utils"; +import styles from "./index.module.scss"; + +export interface CommentContentProps { + content: string; +} + +const cx = classNames(styles, "comment-content"); + +const parseComponents = (content: string) => { + const components: ReactNode[] = []; + const lines = content.split("\n"); + + for (let i = 0, max = lines.length; i < max; ++i) { + const line = lines[i]; + + if (!line) { + continue; + } + + if (line.startsWith("```")) { + const code = []; + + for (++i; i < max; ++i) { + const line = lines[i]; + + if (line.startsWith("```")) { + components.push( +
+                            {code.join("\n")}
+                        
, + ); + break; + } + + code.push(line); + } + } else if (line.startsWith("![")) { + const alt = line.substring(2, line.indexOf("]")); + const src = line.substring(line.indexOf("(") + 1, line.indexOf(")")); + + components.push({alt}); + } else { + const parts = line.split(/(https?:\/\/[^\s]+|[\w.-]+@[\w.-]+\.\w+)/); + const children: ReactNode[] = []; + + for (let j = 0, max = parts.length; j < max; ++j) { + const part = parts[j]; + + if (!part) { + continue; + } + + if (part.match(/^https?:\/\//)) { + if (part.match(/\.(jpeg|jpg|gif|png)$/)) { + children.push(); + } else if (part.match(/\.mp4|webm$/)) { + children.push( +