mirror of
https://github.com/colanode/colanode.git
synced 2025-12-29 00:25:03 +01:00
Implement file node for editor
This commit is contained in:
@@ -15,12 +15,14 @@ import {
|
||||
TodoCommand,
|
||||
PageCommand,
|
||||
FolderCommand,
|
||||
FileCommand,
|
||||
} from '@/renderer/editor/commands';
|
||||
import {
|
||||
IdExtension,
|
||||
DocumentNode,
|
||||
PageNode,
|
||||
FolderNode,
|
||||
FileNode,
|
||||
TextNode,
|
||||
ParagraphNode,
|
||||
Heading1Node,
|
||||
@@ -93,6 +95,7 @@ export const DocumentEditor = ({
|
||||
DocumentNode,
|
||||
PageNode,
|
||||
FolderNode,
|
||||
FileNode,
|
||||
TextNode,
|
||||
ParagraphNode,
|
||||
Heading1Node,
|
||||
@@ -128,6 +131,7 @@ export const DocumentEditor = ({
|
||||
OrderedListCommand,
|
||||
DividerCommand,
|
||||
TodoCommand,
|
||||
FileCommand,
|
||||
FolderCommand,
|
||||
],
|
||||
context: {
|
||||
|
||||
51
desktop/src/renderer/editor/commands/file.tsx
Normal file
51
desktop/src/renderer/editor/commands/file.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { EditorCommand } from '@/types/editor';
|
||||
import { NodeTypes } from '@/lib/constants';
|
||||
|
||||
export const FileCommand: EditorCommand = {
|
||||
key: 'file',
|
||||
name: 'File',
|
||||
description: 'Insert a nested file',
|
||||
keywords: ['file', 'image', 'video', 'audio'],
|
||||
icon: 'file-text-line',
|
||||
disabled: false,
|
||||
async handler({ editor, range, context }) {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await window.neuron.openFileDialog({
|
||||
properties: ['openFile'],
|
||||
buttonLabel: 'Upload',
|
||||
title: 'Upload files to page',
|
||||
});
|
||||
|
||||
if (result.canceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { userId, documentId } = context;
|
||||
const output = await window.neuron.executeMutation({
|
||||
type: 'file_create',
|
||||
filePath: result.filePaths[0],
|
||||
userId,
|
||||
parentId: documentId,
|
||||
generateIndex: false,
|
||||
});
|
||||
|
||||
if (!output.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.insertContent({
|
||||
type: NodeTypes.File,
|
||||
attrs: {
|
||||
id: output.id,
|
||||
},
|
||||
})
|
||||
.run();
|
||||
},
|
||||
};
|
||||
@@ -10,6 +10,7 @@ import { ParagraphCommand } from '@/renderer/editor/commands/paragraph';
|
||||
import { TodoCommand } from '@/renderer/editor/commands/todo';
|
||||
import { PageCommand } from '@/renderer/editor/commands/page';
|
||||
import { FolderCommand } from '@/renderer/editor/commands/folder';
|
||||
import { FileCommand } from '@/renderer/editor/commands/file';
|
||||
import { EditorCommand, EditorCommandProps } from '@/types/editor';
|
||||
|
||||
export type { EditorCommand, EditorCommandProps };
|
||||
@@ -27,4 +28,5 @@ export {
|
||||
TodoCommand,
|
||||
PageCommand,
|
||||
FolderCommand,
|
||||
FileCommand,
|
||||
};
|
||||
|
||||
26
desktop/src/renderer/editor/extensions/file.tsx
Normal file
26
desktop/src/renderer/editor/extensions/file.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { mergeAttributes, Node } from '@tiptap/core';
|
||||
import { ReactNodeViewRenderer } from '@tiptap/react';
|
||||
import { FileNodeView } from '@/renderer/editor/views';
|
||||
|
||||
export const FileNode = Node.create({
|
||||
name: 'file',
|
||||
group: 'block',
|
||||
atom: true,
|
||||
defining: true,
|
||||
draggable: true,
|
||||
addAttributes() {
|
||||
return {
|
||||
id: {
|
||||
default: null,
|
||||
},
|
||||
};
|
||||
},
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return ['file', mergeAttributes(HTMLAttributes)];
|
||||
},
|
||||
addNodeView() {
|
||||
return ReactNodeViewRenderer(FileNodeView, {
|
||||
as: 'file',
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -32,6 +32,7 @@ import { TaskListNode } from '@/renderer/editor/extensions/task-list';
|
||||
import { TrailingNode } from '@/renderer/editor/extensions/trailing-node';
|
||||
import { PageNode } from '@/renderer/editor/extensions/page';
|
||||
import { FolderNode } from '@/renderer/editor/extensions/folder';
|
||||
import { FileNode } from '@/renderer/editor/extensions/file';
|
||||
|
||||
export {
|
||||
IdExtension,
|
||||
@@ -67,4 +68,5 @@ export {
|
||||
DropcursorExtension,
|
||||
PageNode,
|
||||
FolderNode,
|
||||
FileNode,
|
||||
};
|
||||
|
||||
37
desktop/src/renderer/editor/views/file.tsx
Normal file
37
desktop/src/renderer/editor/views/file.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
import { type NodeViewProps } from '@tiptap/core';
|
||||
import { NodeViewWrapper } from '@tiptap/react';
|
||||
import { useWorkspace } from '@/renderer/contexts/workspace';
|
||||
import { useQuery } from '@/renderer/hooks/use-query';
|
||||
import { FilePreview } from '@/renderer/components/files/file-preview';
|
||||
|
||||
export const FileNodeView = ({ node }: NodeViewProps) => {
|
||||
const workspace = useWorkspace();
|
||||
|
||||
const id = node.attrs.id;
|
||||
const { data } = useQuery({
|
||||
type: 'file_get',
|
||||
fileId: id,
|
||||
userId: workspace.userId,
|
||||
});
|
||||
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<NodeViewWrapper
|
||||
data-id={node.attrs.id}
|
||||
className="flex h-72 max-h-72 w-full cursor-pointer overflow-hidden rounded-md p-2 hover:bg-gray-100"
|
||||
onClick={() => {
|
||||
workspace.openModal(id);
|
||||
}}
|
||||
>
|
||||
<FilePreview file={data} />
|
||||
</NodeViewWrapper>
|
||||
);
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
import { CodeBlockNodeView } from '@/renderer/editor/views/code-block';
|
||||
import { PageNodeView } from '@/renderer/editor/views/page';
|
||||
import { FolderNodeView } from '@/renderer/editor/views/folder';
|
||||
import { FileNodeView } from '@/renderer/editor/views/file';
|
||||
|
||||
export { CodeBlockNodeView, PageNodeView, FolderNodeView };
|
||||
export { CodeBlockNodeView, PageNodeView, FolderNodeView, FileNodeView };
|
||||
|
||||
Reference in New Issue
Block a user