From 7f8ed733a3717a6d5ba330c56a4a5af86adfc351 Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Mon, 27 Apr 2026 01:54:59 +0100 Subject: [PATCH] =?UTF-8?q?feat(base):=20inline=20base=20embed=20=E2=80=94?= =?UTF-8?q?=20node=20registration,=20slash=20command,=20and=20renderer=20v?= =?UTF-8?q?iew?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/base-embed/base-embed-view.tsx | 48 +++++++++++++++++++ .../components/slash-menu/menu-items.ts | 20 ++++++++ .../features/editor/extensions/extensions.ts | 7 +++ 3 files changed, 75 insertions(+) create mode 100644 apps/client/src/features/editor/components/base-embed/base-embed-view.tsx diff --git a/apps/client/src/features/editor/components/base-embed/base-embed-view.tsx b/apps/client/src/features/editor/components/base-embed/base-embed-view.tsx new file mode 100644 index 000000000..c2f5e6359 --- /dev/null +++ b/apps/client/src/features/editor/components/base-embed/base-embed-view.tsx @@ -0,0 +1,48 @@ +import { NodeViewWrapper, NodeViewProps } from '@tiptap/react'; +import { Box, Text } from '@mantine/core'; +import { BaseTable } from '@/features/base/components/base-table'; +import { useBaseQuery } from '@/features/base/queries/base-query'; + +export function BaseEmbedView({ node }: NodeViewProps) { + const pageId = node.attrs.pageId as string | null; + + if (!pageId) { + return ( + + + Invalid base embed (missing page id) + + + ); + } + + const { isLoading, isError } = useBaseQuery(pageId); + + if (isLoading) { + return ( + + + Loading... + + + ); + } + + if (isError) { + return ( + + + You don't have access to this database. + + + ); + } + + return ( + + + + + + ); +} diff --git a/apps/client/src/features/editor/components/slash-menu/menu-items.ts b/apps/client/src/features/editor/components/slash-menu/menu-items.ts index 875e2efdd..d37a63cdb 100644 --- a/apps/client/src/features/editor/components/slash-menu/menu-items.ts +++ b/apps/client/src/features/editor/components/slash-menu/menu-items.ts @@ -52,6 +52,7 @@ import { VimeoIcon, YoutubeIcon, } from "@/components/icons"; +import api from "@/lib/api-client"; const CommandGroups: SlashMenuGroupedItemsType = { basic: [ @@ -477,6 +478,25 @@ const CommandGroups: SlashMenuGroupedItemsType = { editor.chain().focus().deleteRange(range).insertSubpages().run(); }, }, + { + title: "Database", + description: "Insert an inline database on this page", + searchTerms: ["database", "base", "table", "grid", "spreadsheet"], + icon: IconTable, + command: async ({ editor, range }: CommandProps) => { + // @ts-ignore + const parentPageId = editor.storage?.pageId as string | undefined; + if (!parentPageId) return; + + editor.chain().focus().deleteRange(range).run(); + + const res = await api.post<{ id: string }>("/bases/inline-embed", { + parentPageId, + }); + + editor.commands.insertBaseEmbed({ pageId: res.data.id }); + }, + }, { title: "2 Columns", description: "Split content into two columns.", diff --git a/apps/client/src/features/editor/extensions/extensions.ts b/apps/client/src/features/editor/extensions/extensions.ts index 1ad93308c..ecf68afea 100644 --- a/apps/client/src/features/editor/extensions/extensions.ts +++ b/apps/client/src/features/editor/extensions/extensions.ts @@ -52,6 +52,7 @@ import { Columns, Column, Status, + BaseEmbed as BaseEmbedNode, } from "@docmost/editor-ext"; import { randomElement, @@ -80,6 +81,7 @@ import ExcalidrawView from "@/features/editor/components/excalidraw/excalidraw-v import EmbedView from "@/features/editor/components/embed/embed-view.tsx"; import PdfView from "@/features/editor/components/pdf/pdf-view.tsx"; import SubpagesView from "@/features/editor/components/subpages/subpages-view.tsx"; +import { BaseEmbedView } from "@/features/editor/components/base-embed/base-embed-view.tsx"; import { common, createLowlight } from "lowlight"; import plaintext from "highlight.js/lib/languages/plaintext"; import powershell from "highlight.js/lib/languages/powershell"; @@ -351,6 +353,11 @@ export const mainExtensions = [ Status.configure({ view: StatusView, }), + BaseEmbedNode.extend({ + addNodeView() { + return ReactNodeViewRenderer(BaseEmbedView); + }, + }), MarkdownClipboard.configure({ transformPastedText: true, }),