diff --git a/apps/client/src/features/editor/components/common/file-upload-handler.tsx b/apps/client/src/features/editor/components/common/file-upload-handler.tsx
new file mode 100644
index 00000000..87c84bc2
--- /dev/null
+++ b/apps/client/src/features/editor/components/common/file-upload-handler.tsx
@@ -0,0 +1,45 @@
+import type { EditorView } from "@tiptap/pm/view";
+import { uploadImageAction } from "@/features/editor/components/image/upload-image-action.tsx";
+import { uploadVideoAction } from "@/features/editor/components/video/upload-video-action.tsx";
+
+export const handleFilePaste = (
+ view: EditorView,
+ event: ClipboardEvent,
+ pageId: string,
+) => {
+ if (event.clipboardData?.files.length) {
+ event.preventDefault();
+ const [file] = Array.from(event.clipboardData.files);
+ const pos = view.state.selection.from;
+
+ if (file) {
+ uploadImageAction(file, view, pos, pageId);
+ uploadVideoAction(file, view, pos, pageId);
+ }
+ return true;
+ }
+ return false;
+};
+
+export const handleFileDrop = (
+ view: EditorView,
+ event: DragEvent,
+ moved: boolean,
+ pageId: string,
+) => {
+ if (!moved && event.dataTransfer?.files.length) {
+ event.preventDefault();
+ const [file] = Array.from(event.dataTransfer.files);
+ const coordinates = view.posAtCoords({
+ left: event.clientX,
+ top: event.clientY,
+ });
+ // here we deduct 1 from the pos or else the image will create an extra node
+ if (file) {
+ uploadImageAction(file, view, coordinates?.pos ?? 0 - 1, pageId);
+ uploadVideoAction(file, view, coordinates?.pos ?? 0 - 1, pageId);
+ }
+ return true;
+ }
+ return false;
+};
diff --git a/apps/client/src/features/editor/components/image/image-view.tsx b/apps/client/src/features/editor/components/image/image-view.tsx
index 6d4051a2..378fa64b 100644
--- a/apps/client/src/features/editor/components/image/image-view.tsx
+++ b/apps/client/src/features/editor/components/image/image-view.tsx
@@ -1,7 +1,7 @@
import { NodeViewProps, NodeViewWrapper } from "@tiptap/react";
import { useMemo } from "react";
import { Image } from "@mantine/core";
-import { getBackendUrl } from "@/lib/config.ts";
+import { getFileUrl } from "@/lib/config.ts";
export default function ImageView(props: NodeViewProps) {
const { node, selected } = props;
@@ -23,9 +23,9 @@ export default function ImageView(props: NodeViewProps) {
>
diff --git a/apps/client/src/features/editor/components/image/upload-image-action.tsx b/apps/client/src/features/editor/components/image/upload-image-action.tsx
index d0a4e1f4..a23f2c17 100644
--- a/apps/client/src/features/editor/components/image/upload-image-action.tsx
+++ b/apps/client/src/features/editor/components/image/upload-image-action.tsx
@@ -4,7 +4,6 @@ import { uploadFile } from "@/features/page/services/page-service.ts";
export const uploadImageAction = handleImageUpload({
onUpload: async (file: File, pageId: string): Promise => {
try {
- console.log("dont upload");
return await uploadFile(file, pageId);
} catch (err) {
console.error("failed to upload image", err);
diff --git a/apps/client/src/features/editor/components/video/video-view.tsx b/apps/client/src/features/editor/components/video/video-view.tsx
index 1c8db942..b5feeb7e 100644
--- a/apps/client/src/features/editor/components/video/video-view.tsx
+++ b/apps/client/src/features/editor/components/video/video-view.tsx
@@ -1,6 +1,6 @@
import { NodeViewProps, NodeViewWrapper } from "@tiptap/react";
import { useMemo } from "react";
-import { getBackendUrl } from "@/lib/config.ts";
+import { getFileUrl } from "@/lib/config.ts";
export default function VideoView(props: NodeViewProps) {
const { node, selected } = props;
@@ -24,7 +24,7 @@ export default function VideoView(props: NodeViewProps) {
preload="metadata"
width={width}
controls
- src={getBackendUrl() + src}
+ src={getFileUrl(src)}
className={selected && "ProseMirror-selectednode"}
/>
diff --git a/apps/client/src/features/editor/page-editor.tsx b/apps/client/src/features/editor/page-editor.tsx
index c96369ff..0403682e 100644
--- a/apps/client/src/features/editor/page-editor.tsx
+++ b/apps/client/src/features/editor/page-editor.tsx
@@ -29,12 +29,15 @@ import EditorSkeleton from "@/features/editor/components/editor-skeleton";
import { EditorBubbleMenu } from "@/features/editor/components/bubble-menu/bubble-menu";
import TableCellMenu from "@/features/editor/components/table/table-cell-menu.tsx";
import TableMenu from "@/features/editor/components/table/table-menu.tsx";
-import { handleMediaDrop, handleMediaPaste } from "@docmost/editor-ext";
import ImageMenu from "@/features/editor/components/image/image-menu.tsx";
import CalloutMenu from "@/features/editor/components/callout/callout-menu.tsx";
import { uploadImageAction } from "@/features/editor/components/image/upload-image-action.tsx";
import { uploadVideoAction } from "@/features/editor/components/video/upload-video-action.tsx";
import VideoMenu from "@/features/editor/components/video/video-menu.tsx";
+import {
+ handleFileDrop,
+ handleFilePaste,
+} from "@/features/editor/components/common/file-upload-handler.tsx";
interface PageEditorProps {
pageId: string;
@@ -112,14 +115,9 @@ export default function PageEditor({ pageId, editable }: PageEditorProps) {
}
},
},
- handlePaste: (view, event) => {
- handleMediaPaste(view, event, uploadImageAction, pageId);
- handleMediaPaste(view, event, uploadVideoAction, pageId);
- },
- handleDrop: (view, event, _slice, moved) => {
- handleMediaDrop(view, event, moved, uploadImageAction, pageId);
- handleMediaDrop(view, event, moved, uploadVideoAction, pageId);
- },
+ handlePaste: (view, event) => handleFilePaste(view, event, pageId),
+ handleDrop: (view, event, _slice, moved) =>
+ handleFileDrop(view, event, moved, pageId),
},
onCreate({ editor }) {
if (editor) {
diff --git a/apps/client/src/features/editor/styles/media.css b/apps/client/src/features/editor/styles/media.css
index ef616d74..f288e3b0 100644
--- a/apps/client/src/features/editor/styles/media.css
+++ b/apps/client/src/features/editor/styles/media.css
@@ -5,6 +5,9 @@
}
.node-image, .node-video {
+ margin-top: 8px;
+ margin-bottom: 8px;
+
&.ProseMirror-selectednode {
outline: none;
}
diff --git a/apps/client/src/lib/config.ts b/apps/client/src/lib/config.ts
index 8383aa64..c7ff5448 100644
--- a/apps/client/src/lib/config.ts
+++ b/apps/client/src/lib/config.ts
@@ -42,3 +42,7 @@ export function getAvatarUrl(avatarUrl: string) {
export function getSpaceUrl(spaceSlug: string) {
return "/s/" + spaceSlug;
}
+
+export function getFileUrl(src: string) {
+ return src.startsWith("/files/") ? getBackendUrl() + src : src;
+}
diff --git a/packages/editor-ext/src/lib/image/image-upload.ts b/packages/editor-ext/src/lib/image/image-upload.ts
index fef472af..2c197e3a 100644
--- a/packages/editor-ext/src/lib/image/image-upload.ts
+++ b/packages/editor-ext/src/lib/image/image-upload.ts
@@ -6,9 +6,9 @@ import { MediaUploadOptions, UploadFn } from "../media-utils";
const uploadKey = new PluginKey("image-upload");
export const ImageUploadPlugin = ({
- placeHolderClass,
+ placeholderClass,
}: {
- placeHolderClass: string;
+ placeholderClass: string;
}) =>
new Plugin({
key: uploadKey,
@@ -27,7 +27,7 @@ export const ImageUploadPlugin = ({
const placeholder = document.createElement("div");
placeholder.setAttribute("class", "img-placeholder");
const image = document.createElement("img");
- image.setAttribute("class", placeHolderClass);
+ image.setAttribute("class", placeholderClass);
image.src = src;
placeholder.appendChild(image);
const deco = Decoration.widget(pos + 1, placeholder, {
diff --git a/packages/editor-ext/src/lib/image/image.ts b/packages/editor-ext/src/lib/image/image.ts
index 810ea376..63b0f1a0 100644
--- a/packages/editor-ext/src/lib/image/image.ts
+++ b/packages/editor-ext/src/lib/image/image.ts
@@ -141,7 +141,7 @@ export const TiptapImage = Image.extend({
addProseMirrorPlugins() {
return [
ImageUploadPlugin({
- placeHolderClass: "image-upload",
+ placeholderClass: "image-upload",
}),
];
},
diff --git a/packages/editor-ext/src/lib/media-utils.ts b/packages/editor-ext/src/lib/media-utils.ts
index 039dd406..82d57994 100644
--- a/packages/editor-ext/src/lib/media-utils.ts
+++ b/packages/editor-ext/src/lib/media-utils.ts
@@ -7,44 +7,6 @@ export type UploadFn = (
pageId: string,
) => void;
-export const handleMediaPaste = (
- view: EditorView,
- event: ClipboardEvent,
- uploadFn: UploadFn,
- pageId: string,
-) => {
- if (event.clipboardData?.files.length) {
- event.preventDefault();
- const [file] = Array.from(event.clipboardData.files);
- const pos = view.state.selection.from;
-
- if (file) uploadFn(file, view, pos, pageId);
- return true;
- }
- return false;
-};
-
-export const handleMediaDrop = (
- view: EditorView,
- event: DragEvent,
- moved: boolean,
- uploadFn: UploadFn,
- pageId: string,
-) => {
- if (!moved && event.dataTransfer?.files.length) {
- event.preventDefault();
- const [file] = Array.from(event.dataTransfer.files);
- const coordinates = view.posAtCoords({
- left: event.clientX,
- top: event.clientY,
- });
- // here we deduct 1 from the pos or else the image will create an extra node
- if (file) uploadFn(file, view, coordinates?.pos ?? 0 - 1, pageId);
- return true;
- }
- return false;
-};
-
export interface MediaUploadOptions {
validateFn?: (file: File) => void;
onUpload: (file: File, pageId: string) => Promise;
diff --git a/packages/editor-ext/src/lib/video/video-upload.ts b/packages/editor-ext/src/lib/video/video-upload.ts
index 168ce5e2..60e8bed2 100644
--- a/packages/editor-ext/src/lib/video/video-upload.ts
+++ b/packages/editor-ext/src/lib/video/video-upload.ts
@@ -6,9 +6,9 @@ import { MediaUploadOptions, UploadFn } from "../media-utils";
const uploadKey = new PluginKey("video-upload");
export const VideoUploadPlugin = ({
- placeHolderClass,
+ placeholderClass,
}: {
- placeHolderClass: string;
+ placeholderClass: string;
}) =>
new Plugin({
key: uploadKey,
@@ -27,7 +27,7 @@ export const VideoUploadPlugin = ({
const placeholder = document.createElement("div");
placeholder.setAttribute("class", "video-placeholder");
const video = document.createElement("video");
- video.setAttribute("class", placeHolderClass);
+ video.setAttribute("class", placeholderClass);
video.src = src;
placeholder.appendChild(video);
const deco = Decoration.widget(pos + 1, placeholder, {
diff --git a/packages/editor-ext/src/lib/video/video.ts b/packages/editor-ext/src/lib/video/video.ts
index 2599c45d..f3d543cd 100644
--- a/packages/editor-ext/src/lib/video/video.ts
+++ b/packages/editor-ext/src/lib/video/video.ts
@@ -28,8 +28,6 @@ declare module "@tiptap/core" {
}
}
-const VIDEO_INPUT_REGEX = /!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\)/;
-
export const TiptapVideo = Node.create({
name: "video",
@@ -123,23 +121,10 @@ export const TiptapVideo = Node.create({
return ReactNodeViewRenderer(this.options.view);
},
- addInputRules() {
- return [
- nodeInputRule({
- find: VIDEO_INPUT_REGEX,
- type: this.type,
- getAttributes: (match) => {
- const [, , src] = match;
- return { src };
- },
- }),
- ];
- },
-
addProseMirrorPlugins() {
return [
VideoUploadPlugin({
- placeHolderClass: "video-upload",
+ placeholderClass: "video-upload",
}),
];
},