From 5c4f082fd060eabfb487c30a8e34326ec1f54d68 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 26 May 2026 10:40:35 +0000 Subject: [PATCH] Support tables --- src/frontend/package.json | 1 + .../src/components/editors/NotesEditor.tsx | 135 +++++++++++++++++- src/frontend/yarn.lock | 5 + 3 files changed, 139 insertions(+), 2 deletions(-) diff --git a/src/frontend/package.json b/src/frontend/package.json index 7dca970377..00c73b5e8c 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -83,6 +83,7 @@ "@tiptap/core": "^3.23.6", "@tiptap/extension-image": "^3.23.6", "@tiptap/extension-link": "^3.23.6", + "@tiptap/extension-table": "^3.23.6", "@tiptap/pm": "^3.23.6", "@tiptap/react": "^3.23.6", "@tiptap/starter-kit": "^3.23.6", diff --git a/src/frontend/src/components/editors/NotesEditor.tsx b/src/frontend/src/components/editors/NotesEditor.tsx index a39fb8ddb2..ada6cab3fa 100644 --- a/src/frontend/src/components/editors/NotesEditor.tsx +++ b/src/frontend/src/components/editors/NotesEditor.tsx @@ -4,7 +4,8 @@ import '@mantine/tiptap/styles.css'; import { useHotkeys } from '@mantine/hooks'; import { notifications } from '@mantine/notifications'; import { useQuery } from '@tanstack/react-query'; -import { useEditor } from '@tiptap/react'; +import { TableKit } from '@tiptap/extension-table'; +import { useEditor, useEditorState } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; import DOMPurify from 'dompurify'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; @@ -35,12 +36,22 @@ import { Tooltip } from '@mantine/core'; import { + IconArrowMerge, IconCirclePlus, + IconColumnInsertLeft, + IconColumnInsertRight, + IconColumnRemove, IconDeviceFloppy, IconInfoCircle, IconPhoto, IconReload, - IconStar + IconRowInsertBottom, + IconRowInsertTop, + IconRowRemove, + IconStar, + IconTableOff, + IconTablePlus, + IconTableRow } from '@tabler/icons-react'; import { useShallow } from 'zustand/react/shallow'; import { formatDate } from '../../defaults/formatters'; @@ -150,6 +161,9 @@ export default function NotesEditor({ const src = await uploadFileRef.current(file); return { src, 'data-keep-ratio': true }; } + }), + TableKit.configure({ + table: { resizable: true, renderWrapper: true, cellMinWidth: 50 } }) ], content: '', @@ -233,6 +247,11 @@ export default function NotesEditor({ [user, modelType, notesQuery] ); + const isInTable = useEditorState({ + editor, + selector: ({ editor: e }) => e?.isActive('table') ?? false + }); + // Sync editor editable state when permissions change useEffect(() => { editor?.setEditable(canEdit); @@ -466,6 +485,118 @@ export default function NotesEditor({ )} + + + editor + ?.chain() + .focus() + .insertTable({ + rows: 3, + cols: 3, + withHeaderRow: true + }) + .run() + } + aria-label={t`Insert table`} + title={t`Insert table`} + > + + + + + )} + {canEdit && isInTable && ( + + + + editor?.chain().focus().addColumnBefore().run() + } + aria-label={t`Add column before`} + title={t`Add column before`} + > + + + + editor?.chain().focus().addColumnAfter().run() + } + aria-label={t`Add column after`} + title={t`Add column after`} + > + + + + editor?.chain().focus().deleteColumn().run() + } + aria-label={t`Delete column`} + title={t`Delete column`} + > + + + + + + editor?.chain().focus().addRowBefore().run() + } + aria-label={t`Add row before`} + title={t`Add row before`} + > + + + + editor?.chain().focus().addRowAfter().run() + } + aria-label={t`Add row after`} + title={t`Add row after`} + > + + + + editor?.chain().focus().deleteRow().run() + } + aria-label={t`Delete row`} + title={t`Delete row`} + > + + + + + + editor?.chain().focus().mergeOrSplit().run() + } + aria-label={t`Merge or split cells`} + title={t`Merge or split cells`} + > + + + + editor?.chain().focus().toggleHeaderRow().run() + } + aria-label={t`Toggle header row`} + title={t`Toggle header row`} + > + + + + + + editor?.chain().focus().deleteTable().run() + } + aria-label={t`Delete table`} + title={t`Delete table`} + > + + + )} diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock index f091761fe7..c631338144 100644 --- a/src/frontend/yarn.lock +++ b/src/frontend/yarn.lock @@ -2110,6 +2110,11 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-3.23.6.tgz#b68e8df11c8c24c82d8c292ff94bc962f3cec871" integrity sha512-oF7FEZ37f15aCe5kPgzGDYf/m+hr7VdQ/Ko/Hds/UM9pX7AG1fdtmRrl6wqkRqDM/incZaC/AQR2/Dpo2VCNGQ== +"@tiptap/extension-table@^3.23.6": + version "3.23.6" + resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-3.23.6.tgz#757a4d14f472fd4735ff5bab35da72402b0bced4" + integrity sha512-XbhZXjhsS6AP7ThoZxjAnNs+NiR81YRori25l6E+ORqB7quiPkIXOAi5h4AIpkn/CYIqze6ere11lWsYpDjtaQ== + "@tiptap/extension-text@^3.13.0": version "3.23.4" resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-3.23.4.tgz#1ab44d78d34c746f97100ff34cc28e0914231eaa"