diff --git a/web/src/components/Editor/Editor.tsx b/web/src/components/Editor/Editor.tsx index 79848a6d..fe45188f 100644 --- a/web/src/components/Editor/Editor.tsx +++ b/web/src/components/Editor/Editor.tsx @@ -1,6 +1,8 @@ import { forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef } from "react"; import TinyUndo from "tiny-undo"; +import toastHelper from "../Toast"; import appContext from "../../stores/appContext"; +import resourceService from "../../services/resourceService"; import { storage } from "../../helpers/storage"; import useRefresh from "../../hooks/useRefresh"; import Only from "../common/OnlyWhen"; @@ -46,10 +48,50 @@ const Editor = forwardRef((props: Props, ref: React.ForwardedRef { - if (initialContent && editorRef.current) { + if (!editorRef.current) { + return; + } + + if (initialContent) { editorRef.current.value = initialContent; refresh(); } + + const handlePasteEvent = async (event: ClipboardEvent) => { + if (event.clipboardData && event.clipboardData.files.length > 0) { + const file = event.clipboardData.files[0]; + const { type } = file; + + if (!type.startsWith("image")) { + return; + } + + event.preventDefault(); + + try { + if (!editorRef.current) { + return; + } + + const resource = await resourceService.upload(file); + const url = `https://memos.justsven.top/r/${resource.id}/${resource.filename}`; + + const prevValue = editorRef.current.value; + editorRef.current.value = + prevValue.slice(0, editorRef.current.selectionStart) + url + prevValue.slice(editorRef.current.selectionStart); + handleContentChangeCallback(editorRef.current.value); + refresh(); + } catch (error: any) { + toastHelper.error(error); + } + } + }; + + editorRef.current.addEventListener("paste", handlePasteEvent); + + return () => { + editorRef.current?.removeEventListener("paste", handlePasteEvent); + }; }, []); useEffect(() => { @@ -102,7 +144,8 @@ const Editor = forwardRef((props: Props, ref: React.ForwardedRef({ method: "PUT", url: "/api/resource/", data: formData, diff --git a/web/src/services/resourceService.ts b/web/src/services/resourceService.ts new file mode 100644 index 00000000..2ccc188a --- /dev/null +++ b/web/src/services/resourceService.ts @@ -0,0 +1,28 @@ +import api from "../helpers/api"; + +class ResourceService { + /** + * Upload resource file to server, + * @param file file + * @returns resource: id, filename + */ + public async upload(file: File) { + const { name: filename, size } = file; + + if (size > 5 << 20) { + return Promise.reject("超过最大文件大小 5Mb"); + } + + const formData = new FormData(); + + formData.append("file", file, filename); + + const { data } = await api.uploadFile(formData); + + return data; + } +} + +const resourceService = new ResourceService(); + +export default resourceService; diff --git a/web/src/types/models.d.ts b/web/src/types/models.d.ts index 04142978..82a0d19c 100644 --- a/web/src/types/models.d.ts +++ b/web/src/types/models.d.ts @@ -20,4 +20,12 @@ declare namespace Model { querystring: string; pinnedAt: string; } + + interface Resource { + id: string; + filename: string; + type: string; + size: string; + createdAt: string; + } }