Skip to content

Commit 581b6de

Browse files
authored
Merge pull request #29 from caido-community/ae-issue-26-md-tables-and-commands
2 parents e9292d0 + 992aa82 commit 581b6de

File tree

8 files changed

+670
-69
lines changed

8 files changed

+670
-69
lines changed

packages/frontend/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
"@tiptap/extension-image": "^2.12.0",
1212
"@tiptap/extension-mention": "^2.12.0",
1313
"@tiptap/extension-placeholder": "^2.12.0",
14+
"@tiptap/extension-table": "^2.27.1",
15+
"@tiptap/extension-table-cell": "^2.27.1",
16+
"@tiptap/extension-table-header": "^2.27.1",
17+
"@tiptap/extension-table-row": "^2.27.1",
1418
"@tiptap/pm": "^2.12.0",
1519
"@tiptap/starter-kit": "^2.12.0",
1620
"@tiptap/vue-3": "^2.12.0",

packages/frontend/src/components/content/editor/NoteEditor.vue

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@
77
autocapitalize="off"
88
class="editor-wrapper"
99
/>
10+
<TableMenu v-if="editor" :editor="editor" />
1011
<SearchUI v-if="editor" :editor="editor" />
1112
</div>
1213
</template>
1314
<script setup lang="ts">
1415
import { Image as ImageExtension } from "@tiptap/extension-image";
1516
import { Placeholder } from "@tiptap/extension-placeholder";
17+
import Table from "@tiptap/extension-table";
18+
import TableCell from "@tiptap/extension-table-cell";
19+
import TableHeader from "@tiptap/extension-table-header";
20+
import TableRow from "@tiptap/extension-table-row";
1621
import { type Slice } from "@tiptap/pm/model";
1722
import { type EditorView } from "@tiptap/pm/view";
1823
import { StarterKit } from "@tiptap/starter-kit";
@@ -29,6 +34,8 @@ import { createSessionMention } from "./extensions/mentions/mention-request";
2934
import createSuggestion from "./extensions/mentions/suggestion";
3035
import { Search } from "./extensions/search";
3136
import SearchUI from "./extensions/search/SearchUI.vue";
37+
import { SlashCommands } from "./extensions/slash-commands";
38+
import TableMenu from "./TableMenu.vue";
3239
3340
import { useSDK } from "@/plugins/sdk";
3441
import { useNotesStore } from "@/stores/notes";
@@ -169,6 +176,16 @@ const editor = useEditor({
169176
class: "caido-image",
170177
},
171178
}),
179+
Table.configure({
180+
resizable: true,
181+
HTMLAttributes: {
182+
class: "notes-table",
183+
},
184+
}),
185+
TableRow,
186+
TableHeader,
187+
TableCell,
188+
SlashCommands,
172189
],
173190
editorProps: {
174191
attributes: {
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<script setup lang="ts">
2+
import { BubbleMenu, type Editor } from "@tiptap/vue-3";
3+
4+
const props = defineProps<{
5+
editor: Editor;
6+
}>();
7+
8+
const shouldShowMenu = () => {
9+
if (!props.editor.isActive("table")) return false;
10+
return (
11+
props.editor.isActive("tableCell") || props.editor.isActive("tableHeader")
12+
);
13+
};
14+
15+
const addColumnBefore = () => {
16+
props.editor.chain().focus().addColumnBefore().run();
17+
};
18+
19+
const addColumnAfter = () => {
20+
props.editor.chain().focus().addColumnAfter().run();
21+
};
22+
23+
const deleteColumn = () => {
24+
props.editor.chain().focus().deleteColumn().run();
25+
};
26+
27+
const addRowBefore = () => {
28+
props.editor.chain().focus().addRowBefore().run();
29+
};
30+
31+
const addRowAfter = () => {
32+
props.editor.chain().focus().addRowAfter().run();
33+
};
34+
35+
const deleteRow = () => {
36+
props.editor.chain().focus().deleteRow().run();
37+
};
38+
39+
const deleteTable = () => {
40+
props.editor.chain().focus().deleteTable().run();
41+
};
42+
</script>
43+
44+
<template>
45+
<BubbleMenu
46+
:editor="editor"
47+
:tippy-options="{ duration: 100, placement: 'top' }"
48+
:should-show="shouldShowMenu"
49+
class="table-menu"
50+
>
51+
<button title="Add column left" @click="addColumnBefore">+Col</button>
52+
<button title="Add column right" @click="addColumnAfter">Col+</button>
53+
<button title="Delete column" class="del" @click="deleteColumn">−Col</button>
54+
<span class="sep"></span>
55+
<button title="Add row above" @click="addRowBefore">+Row</button>
56+
<button title="Add row below" @click="addRowAfter">Row+</button>
57+
<button title="Delete row" class="del" @click="deleteRow">−Row</button>
58+
<span class="sep"></span>
59+
<button title="Delete table" class="del" @click="deleteTable">
60+
<i class="fas fa-trash"></i>
61+
</button>
62+
</BubbleMenu>
63+
</template>
64+
65+
<style scoped>
66+
.table-menu {
67+
display: flex;
68+
align-items: center;
69+
gap: 2px;
70+
background: #27272a;
71+
border: 1px solid #52525b;
72+
border-radius: 6px;
73+
padding: 4px 6px;
74+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
75+
}
76+
77+
.sep {
78+
width: 1px;
79+
height: 16px;
80+
background: #52525b;
81+
margin: 0 4px;
82+
}
83+
84+
button {
85+
padding: 3px 6px;
86+
background: transparent;
87+
border: none;
88+
border-radius: 3px;
89+
color: #a1a1aa;
90+
cursor: pointer;
91+
font-size: 11px;
92+
font-weight: 500;
93+
}
94+
95+
button:hover {
96+
background: #3f3f46;
97+
color: #e5e5e5;
98+
}
99+
100+
button.del {
101+
color: #f87171;
102+
}
103+
104+
button.del:hover {
105+
background: rgba(248, 113, 113, 0.15);
106+
}
107+
108+
button i {
109+
font-size: 12px;
110+
}
111+
</style>

packages/frontend/src/components/content/editor/editor.css

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,70 @@
103103
background-color: rgba(99, 102, 241, 0.5);
104104
outline: 1px solid rgba(99, 102, 241, 0.8);
105105
}
106+
107+
.tiptap table,
108+
.notes-table {
109+
border-collapse: collapse;
110+
margin: 1rem 0;
111+
width: 100%;
112+
table-layout: fixed;
113+
}
114+
115+
.tiptap table td,
116+
.tiptap table th,
117+
.notes-table td,
118+
.notes-table th {
119+
border: 1px solid #52525b;
120+
padding: 0.5rem 0.75rem;
121+
position: relative;
122+
vertical-align: top;
123+
box-sizing: border-box;
124+
}
125+
126+
.tiptap table th,
127+
.notes-table th {
128+
background-color: #27272a;
129+
font-weight: 600;
130+
text-align: left;
131+
}
132+
133+
.tiptap table td,
134+
.notes-table td {
135+
background-color: #18181b;
136+
}
137+
138+
.tiptap table .selectedCell,
139+
.notes-table .selectedCell {
140+
background-color: rgba(99, 102, 241, 0.2);
141+
}
142+
143+
.tiptap table .selectedCell::after,
144+
.notes-table .selectedCell::after {
145+
content: "";
146+
position: absolute;
147+
inset: 0;
148+
pointer-events: none;
149+
border: 2px solid rgba(99, 102, 241, 0.6);
150+
}
151+
152+
.tiptap .column-resize-handle {
153+
position: absolute;
154+
right: -2px;
155+
top: 0;
156+
bottom: -2px;
157+
width: 4px;
158+
background-color: #6366f1;
159+
pointer-events: none;
160+
}
161+
162+
.tiptap table p,
163+
.notes-table p {
164+
margin: 0;
165+
}
166+
167+
.tiptap .tableWrapper {
168+
overflow-x: auto;
169+
margin: 1rem 0;
170+
width: 100%;
171+
max-width: 100%;
172+
}

0 commit comments

Comments
 (0)