Implement database block for the editor

This commit is contained in:
Hakan Shehu
2025-01-22 13:07:38 +01:00
parent e266da2450
commit 1b584b4b51
11 changed files with 127 additions and 5 deletions

View File

@@ -29,7 +29,7 @@ export class DatabaseCreateMutationHandler
type: 'database',
name: input.name,
avatar: input.avatar,
parentId: input.spaceId,
parentId: input.parentId,
fields: {
[fieldId]: {
id: fieldId,
@@ -51,7 +51,7 @@ export class DatabaseCreateMutationHandler
await workspace.entries.createEntry({
id: databaseId,
attributes,
parentId: input.spaceId,
parentId: input.parentId,
});
return {

View File

@@ -53,7 +53,7 @@ export const DatabaseCreateDialog = ({
mutate({
input: {
type: 'database_create',
spaceId: spaceId,
parentId: spaceId,
name: values.name,
avatar: values.avatar,
accountId: workspace.accountId,

View File

@@ -24,6 +24,7 @@ import {
PageCommand,
ParagraphCommand,
TodoCommand,
DatabaseCommand,
} from '@/renderer/editor/commands';
import {
BlockquoteNode,
@@ -59,6 +60,7 @@ import {
TextNode,
TrailingNode,
UnderlineMark,
DatabaseNode,
} from '@/renderer/editor/extensions';
import { ToolbarMenu, ActionMenu } from '@/renderer/editor/menus';
@@ -138,6 +140,7 @@ export const DocumentEditor = ({
LinkMark,
DeleteControlExtension,
DropcursorExtension,
DatabaseNode,
CommanderExtension.configure({
commands: [
ParagraphCommand,
@@ -149,6 +152,7 @@ export const DocumentEditor = ({
BulletListCommand,
CodeBlockCommand,
OrderedListCommand,
DatabaseCommand,
DividerCommand,
TodoCommand,
FileCommand,

View File

@@ -0,0 +1,42 @@
import { Database } from 'lucide-react';
import { EditorCommand } from '@/shared/types/editor';
export const DatabaseCommand: EditorCommand = {
key: 'database',
name: 'Database',
description: 'Insert a nested database',
keywords: ['database'],
icon: Database,
disabled: false,
async handler({ editor, range, context }) {
if (context == null) {
return;
}
const { accountId, workspaceId, documentId } = context;
const output = await window.colanode.executeMutation({
type: 'database_create',
name: 'Untitled',
accountId,
workspaceId,
parentId: documentId,
});
if (!output.success) {
return;
}
editor
.chain()
.focus()
.deleteRange(range)
.insertContent({
type: 'database',
attrs: {
id: output.output.id,
},
})
.run();
},
};

View File

@@ -12,6 +12,7 @@ import { PageCommand } from '@/renderer/editor/commands/page';
import { ParagraphCommand } from '@/renderer/editor/commands/paragraph';
import { TodoCommand } from '@/renderer/editor/commands/todo';
import { EditorCommand, EditorCommandProps } from '@/shared/types/editor';
import { DatabaseCommand } from '@/renderer/editor/commands/database';
export type { EditorCommand, EditorCommandProps };
@@ -29,4 +30,5 @@ export {
PageCommand,
ParagraphCommand,
TodoCommand,
DatabaseCommand,
};

View File

@@ -0,0 +1,27 @@
import { mergeAttributes, Node } from '@tiptap/core';
import { ReactNodeViewRenderer } from '@tiptap/react';
import { DatabaseNodeView } from '@/renderer/editor/views';
export const DatabaseNode = Node.create({
name: 'database',
group: 'block',
atom: true,
defining: true,
draggable: true,
addAttributes() {
return {
id: {
default: null,
},
};
},
renderHTML({ HTMLAttributes }) {
return ['page', mergeAttributes(HTMLAttributes)];
},
addNodeView() {
return ReactNodeViewRenderer(DatabaseNodeView, {
as: 'database',
});
},
});

View File

@@ -34,6 +34,7 @@ import { TabKeymapExtension } from '@/renderer/editor/extensions/tab-keymap';
import { TaskItemNode } from '@/renderer/editor/extensions/task-item';
import { TaskListNode } from '@/renderer/editor/extensions/task-list';
import { TrailingNode } from '@/renderer/editor/extensions/trailing-node';
import { DatabaseNode } from '@/renderer/editor/extensions/database';
export {
BlockquoteNode,
@@ -71,4 +72,5 @@ export {
TextNode,
TrailingNode,
UnderlineMark,
DatabaseNode,
};

View File

@@ -0,0 +1,44 @@
import { type NodeViewProps } from '@tiptap/core';
import { NodeViewWrapper } from '@tiptap/react';
import { Avatar } from '@/renderer/components/avatars/avatar';
import { useWorkspace } from '@/renderer/contexts/workspace';
import { useQuery } from '@/renderer/hooks/use-query';
export const DatabaseNodeView = ({ node }: NodeViewProps) => {
const workspace = useWorkspace();
const id = node.attrs.id;
const { data } = useQuery({
type: 'entry_get',
entryId: id,
accountId: workspace.accountId,
workspaceId: workspace.id,
});
if (!id) {
return null;
}
if (data?.attributes.type !== 'database') {
return null;
}
const name = data.attributes.name ?? 'Unnamed';
const avatar = data?.attributes.avatar;
return (
<NodeViewWrapper
data-id={node.attrs.id}
className="my-0.5 flex h-12 w-full cursor-pointer flex-row items-center gap-1 rounded-md bg-gray-50 p-2 hover:bg-gray-100"
onClick={() => {
workspace.openInMain(id);
}}
>
<Avatar size="small" id={id} name={name} avatar={avatar} />
<div role="presentation" className="flex-grow">
{name}
</div>
</NodeViewWrapper>
);
};

View File

@@ -3,9 +3,11 @@ import { FileNodeView } from '@/renderer/editor/views/file';
import { FilePlaceholderNodeView } from '@/renderer/editor/views/file-placeholder';
import { FolderNodeView } from '@/renderer/editor/views/folder';
import { PageNodeView } from '@/renderer/editor/views/page';
import { DatabaseNodeView } from '@/renderer/editor/views/database';
export {
CodeBlockNodeView,
DatabaseNodeView,
FileNodeView,
FilePlaceholderNodeView,
FolderNodeView,

View File

@@ -2,7 +2,7 @@ export type DatabaseCreateMutationInput = {
type: 'database_create';
accountId: string;
workspaceId: string;
spaceId: string;
parentId: string;
name: string;
avatar?: string | null;
};

View File

@@ -5,7 +5,6 @@ export type PageCreateMutationInput = {
parentId: string;
avatar?: string | null;
name: string;
generateIndex: boolean;
};
export type PageCreateMutationOutput = {