mirror of
https://github.com/usememos/memos.git
synced 2025-04-03 12:21:15 +02:00
feat: implement table renderer
This commit is contained in:
parent
aecffe3402
commit
05c0aeb789
@ -63,6 +63,8 @@ func convertFromASTNode(rawNode ast.Node) *apiv2pb.Node {
|
|||||||
node.Node = &apiv2pb.Node_TaskListNode{TaskListNode: &apiv2pb.TaskListNode{Symbol: n.Symbol, Indent: int32(n.Indent), Complete: n.Complete, Children: children}}
|
node.Node = &apiv2pb.Node_TaskListNode{TaskListNode: &apiv2pb.TaskListNode{Symbol: n.Symbol, Indent: int32(n.Indent), Complete: n.Complete, Children: children}}
|
||||||
case *ast.MathBlock:
|
case *ast.MathBlock:
|
||||||
node.Node = &apiv2pb.Node_MathBlockNode{MathBlockNode: &apiv2pb.MathBlockNode{Content: n.Content}}
|
node.Node = &apiv2pb.Node_MathBlockNode{MathBlockNode: &apiv2pb.MathBlockNode{Content: n.Content}}
|
||||||
|
case *ast.Table:
|
||||||
|
node.Node = &apiv2pb.Node_TableNode{TableNode: convertTableFromASTNode(n)}
|
||||||
case *ast.Text:
|
case *ast.Text:
|
||||||
node.Node = &apiv2pb.Node_TextNode{TextNode: &apiv2pb.TextNode{Content: n.Content}}
|
node.Node = &apiv2pb.Node_TextNode{TextNode: &apiv2pb.TextNode{Content: n.Content}}
|
||||||
case *ast.Bold:
|
case *ast.Bold:
|
||||||
@ -134,6 +136,8 @@ func convertToASTNode(node *apiv2pb.Node) ast.Node {
|
|||||||
return &ast.TaskList{Symbol: n.TaskListNode.Symbol, Indent: int(n.TaskListNode.Indent), Complete: n.TaskListNode.Complete, Children: children}
|
return &ast.TaskList{Symbol: n.TaskListNode.Symbol, Indent: int(n.TaskListNode.Indent), Complete: n.TaskListNode.Complete, Children: children}
|
||||||
case *apiv2pb.Node_MathBlockNode:
|
case *apiv2pb.Node_MathBlockNode:
|
||||||
return &ast.MathBlock{Content: n.MathBlockNode.Content}
|
return &ast.MathBlock{Content: n.MathBlockNode.Content}
|
||||||
|
case *apiv2pb.Node_TableNode:
|
||||||
|
return convertTableToASTNode(node)
|
||||||
case *apiv2pb.Node_TextNode:
|
case *apiv2pb.Node_TextNode:
|
||||||
return &ast.Text{Content: n.TextNode.Content}
|
return &ast.Text{Content: n.TextNode.Content}
|
||||||
case *apiv2pb.Node_BoldNode:
|
case *apiv2pb.Node_BoldNode:
|
||||||
@ -166,6 +170,32 @@ func convertToASTNode(node *apiv2pb.Node) ast.Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func convertTableToASTNode(node *apiv2pb.Node) *ast.Table {
|
||||||
|
table := &ast.Table{
|
||||||
|
Header: node.GetTableNode().Header,
|
||||||
|
}
|
||||||
|
for _, d := range node.GetTableNode().Delimiter {
|
||||||
|
table.Delimiter = append(table.Delimiter, int(d))
|
||||||
|
}
|
||||||
|
for _, row := range node.GetTableNode().Rows {
|
||||||
|
table.Rows = append(table.Rows, row.Cells)
|
||||||
|
}
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertTableFromASTNode(node *ast.Table) *apiv2pb.TableNode {
|
||||||
|
table := &apiv2pb.TableNode{
|
||||||
|
Header: node.Header,
|
||||||
|
}
|
||||||
|
for _, d := range node.Delimiter {
|
||||||
|
table.Delimiter = append(table.Delimiter, int32(d))
|
||||||
|
}
|
||||||
|
for _, row := range node.Rows {
|
||||||
|
table.Rows = append(table.Rows, &apiv2pb.TableNode_Row{Cells: row})
|
||||||
|
}
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
|
||||||
func traverseASTNodes(nodes []ast.Node, fn func(ast.Node)) {
|
func traverseASTNodes(nodes []ast.Node, fn func(ast.Node)) {
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
fn(node)
|
fn(node)
|
||||||
|
@ -35,19 +35,20 @@ enum NodeType {
|
|||||||
UNORDERED_LIST = 8;
|
UNORDERED_LIST = 8;
|
||||||
TASK_LIST = 9;
|
TASK_LIST = 9;
|
||||||
MATH_BLOCK = 10;
|
MATH_BLOCK = 10;
|
||||||
TEXT = 11;
|
TABLE = 11;
|
||||||
BOLD = 12;
|
TEXT = 12;
|
||||||
ITALIC = 13;
|
BOLD = 13;
|
||||||
BOLD_ITALIC = 14;
|
ITALIC = 14;
|
||||||
CODE = 15;
|
BOLD_ITALIC = 15;
|
||||||
IMAGE = 16;
|
CODE = 16;
|
||||||
LINK = 17;
|
IMAGE = 17;
|
||||||
AUTO_LINK = 18;
|
LINK = 18;
|
||||||
TAG = 19;
|
AUTO_LINK = 19;
|
||||||
STRIKETHROUGH = 20;
|
TAG = 20;
|
||||||
ESCAPING_CHARACTER = 21;
|
STRIKETHROUGH = 21;
|
||||||
MATH = 22;
|
ESCAPING_CHARACTER = 22;
|
||||||
HIGHLIGHT = 23;
|
MATH = 23;
|
||||||
|
HIGHLIGHT = 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Node {
|
message Node {
|
||||||
@ -63,19 +64,20 @@ message Node {
|
|||||||
UnorderedListNode unordered_list_node = 9;
|
UnorderedListNode unordered_list_node = 9;
|
||||||
TaskListNode task_list_node = 10;
|
TaskListNode task_list_node = 10;
|
||||||
MathBlockNode math_block_node = 11;
|
MathBlockNode math_block_node = 11;
|
||||||
TextNode text_node = 12;
|
TableNode table_node = 12;
|
||||||
BoldNode bold_node = 13;
|
TextNode text_node = 13;
|
||||||
ItalicNode italic_node = 14;
|
BoldNode bold_node = 14;
|
||||||
BoldItalicNode bold_italic_node = 15;
|
ItalicNode italic_node = 15;
|
||||||
CodeNode code_node = 16;
|
BoldItalicNode bold_italic_node = 16;
|
||||||
ImageNode image_node = 17;
|
CodeNode code_node = 17;
|
||||||
LinkNode link_node = 18;
|
ImageNode image_node = 18;
|
||||||
AutoLinkNode auto_link_node = 19;
|
LinkNode link_node = 19;
|
||||||
TagNode tag_node = 20;
|
AutoLinkNode auto_link_node = 20;
|
||||||
StrikethroughNode strikethrough_node = 21;
|
TagNode tag_node = 21;
|
||||||
EscapingCharacterNode escaping_character_node = 22;
|
StrikethroughNode strikethrough_node = 22;
|
||||||
MathNode math_node = 23;
|
EscapingCharacterNode escaping_character_node = 23;
|
||||||
HighlightNode highlight_node = 24;
|
MathNode math_node = 24;
|
||||||
|
HighlightNode highlight_node = 25;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,6 +128,16 @@ message MathBlockNode {
|
|||||||
string content = 1;
|
string content = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message TableNode {
|
||||||
|
repeated string header = 1;
|
||||||
|
repeated int32 delimiter = 2;
|
||||||
|
|
||||||
|
message Row {
|
||||||
|
repeated string cells = 1;
|
||||||
|
}
|
||||||
|
repeated Row rows = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message TextNode {
|
message TextNode {
|
||||||
string content = 1;
|
string content = 1;
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,8 @@
|
|||||||
- [ParseMarkdownRequest](#memos-api-v2-ParseMarkdownRequest)
|
- [ParseMarkdownRequest](#memos-api-v2-ParseMarkdownRequest)
|
||||||
- [ParseMarkdownResponse](#memos-api-v2-ParseMarkdownResponse)
|
- [ParseMarkdownResponse](#memos-api-v2-ParseMarkdownResponse)
|
||||||
- [StrikethroughNode](#memos-api-v2-StrikethroughNode)
|
- [StrikethroughNode](#memos-api-v2-StrikethroughNode)
|
||||||
|
- [TableNode](#memos-api-v2-TableNode)
|
||||||
|
- [TableNode.Row](#memos-api-v2-TableNode-Row)
|
||||||
- [TagNode](#memos-api-v2-TagNode)
|
- [TagNode](#memos-api-v2-TagNode)
|
||||||
- [TaskListNode](#memos-api-v2-TaskListNode)
|
- [TaskListNode](#memos-api-v2-TaskListNode)
|
||||||
- [TextNode](#memos-api-v2-TextNode)
|
- [TextNode](#memos-api-v2-TextNode)
|
||||||
@ -1222,6 +1224,7 @@
|
|||||||
| unordered_list_node | [UnorderedListNode](#memos-api-v2-UnorderedListNode) | | |
|
| unordered_list_node | [UnorderedListNode](#memos-api-v2-UnorderedListNode) | | |
|
||||||
| task_list_node | [TaskListNode](#memos-api-v2-TaskListNode) | | |
|
| task_list_node | [TaskListNode](#memos-api-v2-TaskListNode) | | |
|
||||||
| math_block_node | [MathBlockNode](#memos-api-v2-MathBlockNode) | | |
|
| math_block_node | [MathBlockNode](#memos-api-v2-MathBlockNode) | | |
|
||||||
|
| table_node | [TableNode](#memos-api-v2-TableNode) | | |
|
||||||
| text_node | [TextNode](#memos-api-v2-TextNode) | | |
|
| text_node | [TextNode](#memos-api-v2-TextNode) | | |
|
||||||
| bold_node | [BoldNode](#memos-api-v2-BoldNode) | | |
|
| bold_node | [BoldNode](#memos-api-v2-BoldNode) | | |
|
||||||
| italic_node | [ItalicNode](#memos-api-v2-ItalicNode) | | |
|
| italic_node | [ItalicNode](#memos-api-v2-ItalicNode) | | |
|
||||||
@ -1318,6 +1321,38 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="memos-api-v2-TableNode"></a>
|
||||||
|
|
||||||
|
### TableNode
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| header | [string](#string) | repeated | |
|
||||||
|
| delimiter | [int32](#int32) | repeated | |
|
||||||
|
| rows | [TableNode.Row](#memos-api-v2-TableNode-Row) | repeated | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="memos-api-v2-TableNode-Row"></a>
|
||||||
|
|
||||||
|
### TableNode.Row
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| cells | [string](#string) | repeated | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="memos-api-v2-TagNode"></a>
|
<a name="memos-api-v2-TagNode"></a>
|
||||||
|
|
||||||
### TagNode
|
### TagNode
|
||||||
@ -1403,19 +1438,20 @@
|
|||||||
| UNORDERED_LIST | 8 | |
|
| UNORDERED_LIST | 8 | |
|
||||||
| TASK_LIST | 9 | |
|
| TASK_LIST | 9 | |
|
||||||
| MATH_BLOCK | 10 | |
|
| MATH_BLOCK | 10 | |
|
||||||
| TEXT | 11 | |
|
| TABLE | 11 | |
|
||||||
| BOLD | 12 | |
|
| TEXT | 12 | |
|
||||||
| ITALIC | 13 | |
|
| BOLD | 13 | |
|
||||||
| BOLD_ITALIC | 14 | |
|
| ITALIC | 14 | |
|
||||||
| CODE | 15 | |
|
| BOLD_ITALIC | 15 | |
|
||||||
| IMAGE | 16 | |
|
| CODE | 16 | |
|
||||||
| LINK | 17 | |
|
| IMAGE | 17 | |
|
||||||
| AUTO_LINK | 18 | |
|
| LINK | 18 | |
|
||||||
| TAG | 19 | |
|
| AUTO_LINK | 19 | |
|
||||||
| STRIKETHROUGH | 20 | |
|
| TAG | 20 | |
|
||||||
| ESCAPING_CHARACTER | 21 | |
|
| STRIKETHROUGH | 21 | |
|
||||||
| MATH | 22 | |
|
| ESCAPING_CHARACTER | 22 | |
|
||||||
| HIGHLIGHT | 23 | |
|
| MATH | 23 | |
|
||||||
|
| HIGHLIGHT | 24 | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,7 @@ import {
|
|||||||
OrderedListNode,
|
OrderedListNode,
|
||||||
ParagraphNode,
|
ParagraphNode,
|
||||||
StrikethroughNode,
|
StrikethroughNode,
|
||||||
|
TableNode,
|
||||||
TagNode,
|
TagNode,
|
||||||
TaskListNode,
|
TaskListNode,
|
||||||
TextNode,
|
TextNode,
|
||||||
@ -40,6 +41,7 @@ import Math from "./Math";
|
|||||||
import OrderedList from "./OrderedList";
|
import OrderedList from "./OrderedList";
|
||||||
import Paragraph from "./Paragraph";
|
import Paragraph from "./Paragraph";
|
||||||
import Strikethrough from "./Strikethrough";
|
import Strikethrough from "./Strikethrough";
|
||||||
|
import Table from "./Table";
|
||||||
import Tag from "./Tag";
|
import Tag from "./Tag";
|
||||||
import TaskList from "./TaskList";
|
import TaskList from "./TaskList";
|
||||||
import Text from "./Text";
|
import Text from "./Text";
|
||||||
@ -72,6 +74,8 @@ const Renderer: React.FC<Props> = ({ index, node }: Props) => {
|
|||||||
return <TaskList index={index} {...(node.taskListNode as TaskListNode)} />;
|
return <TaskList index={index} {...(node.taskListNode as TaskListNode)} />;
|
||||||
case NodeType.MATH_BLOCK:
|
case NodeType.MATH_BLOCK:
|
||||||
return <Math {...(node.mathBlockNode as MathNode)} block={true} />;
|
return <Math {...(node.mathBlockNode as MathNode)} block={true} />;
|
||||||
|
case NodeType.TABLE:
|
||||||
|
return <Table {...(node.tableNode as TableNode)} />;
|
||||||
case NodeType.TEXT:
|
case NodeType.TEXT:
|
||||||
return <Text {...(node.textNode as TextNode)} />;
|
return <Text {...(node.textNode as TextNode)} />;
|
||||||
case NodeType.BOLD:
|
case NodeType.BOLD:
|
||||||
|
35
web/src/components/MemoContent/Table.tsx
Normal file
35
web/src/components/MemoContent/Table.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { TableNode_Row } from "@/types/proto/api/v2/markdown_service";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
header: string[];
|
||||||
|
rows: TableNode_Row[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Table = ({ header, rows }: Props) => {
|
||||||
|
return (
|
||||||
|
<table className="w-auto max-w-full border border-gray-300 dark:border-zinc-600 divide-y divide-gray-300 dark:divide-zinc-600">
|
||||||
|
<thead className="text-sm font-semibold leading-5 text-left text-gray-900 dark:text-gray-400">
|
||||||
|
<tr className="divide-x divide-gray-300 dark:divide-zinc-600">
|
||||||
|
{header.map((h, i) => (
|
||||||
|
<th key={i} className="py-1 px-2">
|
||||||
|
{h}
|
||||||
|
</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="divide-y divide-gray-300 dark:divide-zinc-600 text-sm leading-5 text-left text-gray-900 dark:text-gray-400">
|
||||||
|
{rows.map((row, i) => (
|
||||||
|
<tr key={i} className="divide-x divide-gray-300 dark:divide-zinc-600">
|
||||||
|
{row.cells.map((r, j) => (
|
||||||
|
<td key={j} className="py-1 px-2">
|
||||||
|
{r}
|
||||||
|
</td>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Table;
|
Loading…
x
Reference in New Issue
Block a user