diff --git a/src/components/shared/tiptap/Tiptap.vue b/src/components/shared/tiptap/Tiptap.vue index 4bf26fb..7974e26 100644 --- a/src/components/shared/tiptap/Tiptap.vue +++ b/src/components/shared/tiptap/Tiptap.vue @@ -8,8 +8,12 @@ import TaskItem from '@tiptap/extension-task-item' import TaskList from '@tiptap/extension-task-list' import * as lowlight from 'lowlight' import mitt from 'mitt' +import { TauriEvent } from '@tauri-apps/api/event' +import { extname } from '@tauri-apps/api/path' +import { getType, insert } from './util' import { ImageBlock, Link, Video } from '@/extensions/tiptap/' +import { check, uploadByPath } from '@/modules/upload' const props = defineProps<{ content: string @@ -19,6 +23,7 @@ const props = defineProps<{ const { content: contentVModel } = useVModels(props) const { t } = useI18n() +const { warning } = useNotify() const previewEmitter = mitt<{ preview: { @@ -65,6 +70,37 @@ const editor = useEditor({ }, }) +useTauriListen<{ + paths: string[] +}>(TauriEvent.DROP, async (e) => { + if (!props.editable) + return + + if (!editor.value) + return + + const { paths } = e.payload + for (const path of paths) { + const ext = await extname(path) + if (!check(ext)) { + return warning({ + text: t('upload.invalidType', { + name: ext, + }), + }) + } + } + const list = await Promise.all(paths.map(async (path) => { + const src = await uploadByPath(path) + const ext = await extname(path) + return { + src, + type: getType(ext)!, + } + })) + insert(editor.value, list) +}) + const tiptapWrapper = ref() const previewUrl = ref('') const previewIndex = ref(0) diff --git a/src/components/shared/tiptap/Toolbar.vue b/src/components/shared/tiptap/Toolbar.vue index 84b6078..58394d0 100644 --- a/src/components/shared/tiptap/Toolbar.vue +++ b/src/components/shared/tiptap/Toolbar.vue @@ -2,6 +2,7 @@ import type { ChainedCommands, Editor } from '@tiptap/vue-3' import { open } from '@tauri-apps/plugin-dialog' +import { insert } from './util' import { uploadByPath, uploadExtension } from '@/modules/upload' interface DialogFilter { @@ -132,11 +133,9 @@ async function uploadImage() { if (!files.length) return - props.editor.commands.insertContent(files.map(src => ({ + insert(props.editor, files.map(src => ({ + src, type: 'imageBlock', - attrs: { - src, - }, }))) } @@ -148,11 +147,9 @@ async function uploadVideo() { if (!files.length) return - props.editor.commands.insertContent(files.map(src => ({ + insert(props.editor, files.map(src => ({ + src, type: 'video', - attrs: { - src, - }, }))) } diff --git a/src/components/shared/tiptap/util.ts b/src/components/shared/tiptap/util.ts new file mode 100644 index 0000000..d9b23f8 --- /dev/null +++ b/src/components/shared/tiptap/util.ts @@ -0,0 +1,22 @@ +import type { Editor } from '@tiptap/vue-3' +import { getType as getUploadType } from '@/modules/upload' + +export function insert(editor: Editor, list: Array<{ + src: string + type: string +}>) { + editor.commands.insertContent(list.map(({ type, src }) => ({ + type, + attrs: { + src, + }, + }))) +} + +export function getType(ext: string) { + const type = getUploadType(ext) + if (type == 'image') + return 'imageBlock' + else + return type +} diff --git a/src/locales/en-US.yaml b/src/locales/en-US.yaml index e6450c3..e664a6c 100644 --- a/src/locales/en-US.yaml +++ b/src/locales/en-US.yaml @@ -208,6 +208,7 @@ timelineGraph: upload: webImage: Unsupported image types filtered webVideo: Unsupported video types filtered + invalidType: Type {name} not supported widget: type: Type typeDesc: diff --git a/src/locales/zh-CN.yaml b/src/locales/zh-CN.yaml index 6f75aa9..65257bc 100644 --- a/src/locales/zh-CN.yaml +++ b/src/locales/zh-CN.yaml @@ -208,6 +208,7 @@ timelineGraph: upload: webImage: 已过滤不支持的图片类型 webVideo: 已过滤不支持的视频类型 + invalidType: 不支持{name}类型 widget: type: 类型 typeDesc: diff --git a/src/modules/upload/index.ts b/src/modules/upload/index.ts index 173e1af..5b54b2f 100644 --- a/src/modules/upload/index.ts +++ b/src/modules/upload/index.ts @@ -39,3 +39,20 @@ export const uploadExtension = { image: ['gif', 'jpeg', 'jpg', 'png', 'svg', 'webp'], video: ['mp4', 'webm'], } + +export function check(ext: string) { + const list = [...uploadExtension.image, ...uploadExtension.video] + return list.includes(ext.toLowerCase()) +} + +export function getType(ext: string) { + const extname = ext.toLowerCase() + for (const name of uploadExtension.image) { + if (extname == name) + return 'image' + } + for (const name of uploadExtension.video) { + if (extname == name) + return 'video' + } +}