feat(base): inline base embed — node registration, slash command, and renderer view

This commit is contained in:
Philipinho
2026-04-27 01:54:59 +01:00
parent 3826e5a50d
commit 7f8ed733a3
3 changed files with 75 additions and 0 deletions
@@ -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 (
<NodeViewWrapper>
<Box p="md">
<Text c="red">Invalid base embed (missing page id)</Text>
</Box>
</NodeViewWrapper>
);
}
const { isLoading, isError } = useBaseQuery(pageId);
if (isLoading) {
return (
<NodeViewWrapper>
<Box p="md">
<Text c="dimmed">Loading...</Text>
</Box>
</NodeViewWrapper>
);
}
if (isError) {
return (
<NodeViewWrapper>
<Box p="md" bg="gray.0" style={{ borderRadius: 8 }}>
<Text c="dimmed">You don't have access to this database.</Text>
</Box>
</NodeViewWrapper>
);
}
return (
<NodeViewWrapper>
<Box style={{ minHeight: 200 }}>
<BaseTable pageId={pageId} />
</Box>
</NodeViewWrapper>
);
}
@@ -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.",
@@ -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,
}),