diff --git a/web/src/labs/marked/marked.test.ts b/web/src/labs/marked/marked.test.ts
index 2f649f16a..7db8477c4 100644
--- a/web/src/labs/marked/marked.test.ts
+++ b/web/src/labs/marked/marked.test.ts
@@ -3,6 +3,38 @@ import { unescape } from "lodash-es";
import { marked } from ".";
describe("test marked parser", () => {
+ test("test markdown table", () => {
+ const tests = [
+ {
+ markdown: `| a | b | c |
+|---|---|---|
+| 1 | 2 | 3 |
+| 4 | 5 | 6 |`,
+ want: `
+
+
+ a | b | c |
+
+
+
+ 1 | 2 | 3 |
4 | 5 | 6 |
+
+
`,
+ },
+ {
+ markdown: `| a | b | c |
+| 1 | 2 | 3 |
+| 4 | 5 | 6 |`,
+ want: `| a | b | c |
+| 1 | 2 | 3 |
+| 4 | 5 | 6 |
`,
+ },
+ ];
+ for (const t of tests) {
+ expect(unescape(marked(t.markdown))).toBe(t.want);
+ }
+ });
+
test("parse code block", () => {
const tests = [
{
diff --git a/web/src/labs/marked/parser/Table.ts b/web/src/labs/marked/parser/Table.ts
new file mode 100644
index 000000000..050c8446a
--- /dev/null
+++ b/web/src/labs/marked/parser/Table.ts
@@ -0,0 +1,45 @@
+/**
+ * Match markdown table
+ * example:
+ * | a | b | c |
+ * |---|---|---|
+ * | 1 | 2 | 3 |
+ * | 4 | 5 | 6 |
+ */
+export const TABLE_REG = /^(\|.*\|)(?:(?:\n(?:\|-*)+\|))((?:\n\|.*\|)+)/;
+
+const renderer = (rawStr: string): string => {
+ const matchResult = rawStr.match(TABLE_REG);
+ if (!matchResult) {
+ return rawStr;
+ }
+ const tableHeader = matchResult[1]
+ .split("|")
+ .filter((str) => str !== "")
+ .map((str) => str.trim());
+ const tableBody = matchResult[2]
+ .trim()
+ .split("\n")
+ .map((str) =>
+ str
+ .split("|")
+ .filter((str) => str !== "")
+ .map((str) => str.trim())
+ );
+ return `
+
+
+ ${tableHeader.map((str) => `${str} | `).join("")}
+
+
+
+ ${tableBody.map((row) => `${row.map((str) => `${str} | `).join("")}
`).join("")}
+
+
`;
+};
+
+export default {
+ name: "table",
+ regex: TABLE_REG,
+ renderer,
+};
diff --git a/web/src/labs/marked/parser/index.ts b/web/src/labs/marked/parser/index.ts
index e679f485a..d1eb728bf 100644
--- a/web/src/labs/marked/parser/index.ts
+++ b/web/src/labs/marked/parser/index.ts
@@ -13,6 +13,7 @@ import Emphasis from "./Emphasis";
import PlainLink from "./PlainLink";
import InlineCode from "./InlineCode";
import PlainText from "./PlainText";
+import Table from "./Table";
export { CODE_BLOCK_REG } from "./CodeBlock";
export { TODO_LIST_REG } from "./TodoList";
@@ -21,8 +22,9 @@ export { TAG_REG } from "./Tag";
export { IMAGE_REG } from "./Image";
export { LINK_REG } from "./Link";
export { MARK_REG } from "./Mark";
+export { TABLE_REG } from "./Table";
// The order determines the order of execution.
-export const blockElementParserList = [CodeBlock, TodoList, DoneList, OrderedList, UnorderedList, Paragraph];
+export const blockElementParserList = [Table, CodeBlock, TodoList, DoneList, OrderedList, UnorderedList, Paragraph];
export const inlineElementParserList = [Image, Mark, Bold, Emphasis, Link, InlineCode, PlainLink, Tag, PlainText];
export const parserList = [...blockElementParserList, ...inlineElementParserList];
diff --git a/web/src/less/memo-content.less b/web/src/less/memo-content.less
index d5c4b0a1f..19b300f58 100644
--- a/web/src/less/memo-content.less
+++ b/web/src/less/memo-content.less
@@ -58,6 +58,18 @@
code {
@apply bg-gray-100 px-1 rounded text-sm font-mono leading-6 inline-block;
}
+
+ table {
+ @apply my-1 table-auto border-collapse border border-gray-300;
+
+ th {
+ @apply px-4 py-1 text-center border border-gray-300;
+ }
+
+ td {
+ @apply px-4 py-1 text-center border border-gray-300;
+ }
+ }
}
> .expand-btn-container {