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,
}),