|
@@ -1,25 +1,112 @@
|
|
|
<script setup lang="ts">
|
|
|
-import { defineProps } from "vue";
|
|
|
+import { ref, inject, type Ref } from "vue";
|
|
|
import { VideoCamera } from "@element-plus/icons-vue";
|
|
|
-import { NormalToolbar } from "md-editor-v3";
|
|
|
+import { DropdownToolbar } from "md-editor-v3";
|
|
|
+import { Link } from "@element-plus/icons-vue";
|
|
|
+import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
|
+import { v4 as uuid4 } from "uuid";
|
|
|
+
|
|
|
+const prefix = "md-editor";
|
|
|
+
|
|
|
+const s3 = inject<InstanceType<typeof S3Client>>("s3");
|
|
|
+const editorLoading = inject<Ref<boolean>>("editorLoading");
|
|
|
|
|
|
const props = defineProps<{
|
|
|
insert?: Function;
|
|
|
}>();
|
|
|
|
|
|
-const onClick = () => {
|
|
|
- console.log("video");
|
|
|
- // TODO
|
|
|
- // emitHandler('video');
|
|
|
+const showDropdown = ref(false);
|
|
|
+const showDialog = ref(false);
|
|
|
+
|
|
|
+const linkInput = ref("");
|
|
|
+
|
|
|
+const onClickMenuLink = () => {
|
|
|
+ showDropdown.value = false;
|
|
|
+ showDialog.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+const selectFile = (contentType: string, multiple: boolean) => {
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ let input = document.createElement("input");
|
|
|
+ input.type = "file";
|
|
|
+ input.multiple = multiple;
|
|
|
+ input.accept = contentType;
|
|
|
+
|
|
|
+ input.onchange = (_) => {
|
|
|
+ let files = Array.from(input.files);
|
|
|
+ if (multiple) resolve(files);
|
|
|
+ else resolve(files[0]);
|
|
|
+ };
|
|
|
+
|
|
|
+ input.click();
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const onClickMenuSelect = async () => {
|
|
|
+ showDropdown.value = false;
|
|
|
+ const file = await selectFile("video/*", false);
|
|
|
+
|
|
|
+ const key = `${uuid4()}::${file.name}`;
|
|
|
+ const command = new PutObjectCommand({
|
|
|
+ Bucket: import.meta.env.VITE_DOCS_MEDIA_BUCKET,
|
|
|
+ Key: key,
|
|
|
+ Body: file,
|
|
|
+ ACL: "public-read",
|
|
|
+ });
|
|
|
+ editorLoading!.value = true;
|
|
|
+ await s3!.send(command);
|
|
|
+ editorLoading!.value = false;
|
|
|
+ insert(
|
|
|
+ `https://${import.meta.env.VITE_DOCS_MEDIA_BUCKET}.s3.amazonaws.com/${key}`
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+const onConfirmDialog = async () => {
|
|
|
+ // FIXME check link format?
|
|
|
+ await insert(linkInput.value);
|
|
|
+ linkInput.value = "";
|
|
|
+ showDialog.value = false;
|
|
|
+};
|
|
|
+
|
|
|
+const insert = (url: string) => {
|
|
|
+ // TEST
|
|
|
+ // const url = `https://woolyss.com/f/av1-opus-sita.webm`;
|
|
|
props.insert?.(() => ({
|
|
|
- targetValue: "hello video",
|
|
|
+ targetValue: `<video src="${url}" width="100%" controls></video>`,
|
|
|
}));
|
|
|
};
|
|
|
</script>
|
|
|
<template>
|
|
|
- <NormalToolbar title="video" @onClick="onClick">
|
|
|
+ <DropdownToolbar title="video" :visible="showDropdown" :onChange="(v) => (showDropdown = v)">
|
|
|
<template #trigger>
|
|
|
<VideoCamera width="18" />
|
|
|
</template>
|
|
|
- </NormalToolbar>
|
|
|
+ <template #overlay>
|
|
|
+ <ul :class="`${prefix}-menu`">
|
|
|
+ <li :class="`${prefix}-menu-item ${prefix}-menu-item-title`" @click="onClickMenuLink">
|
|
|
+ 输入链接
|
|
|
+ </li>
|
|
|
+ <li :class="`${prefix}-menu-item ${prefix}-menu-item-title`" @click="onClickMenuSelect">
|
|
|
+ 选择文件
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </template>
|
|
|
+ </DropdownToolbar>
|
|
|
+ <el-dialog v-model="showDialog" title="添加视频">
|
|
|
+ <div>
|
|
|
+ <el-input v-model="linkInput" placeholder="https://woolyss.com/f/av1-opus-sita.webm">
|
|
|
+ <template #prepend>
|
|
|
+ <el-icon>
|
|
|
+ <Link />
|
|
|
+ </el-icon>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ </div>
|
|
|
+ <template #footer>
|
|
|
+ <div>
|
|
|
+ <el-button @click="showDialog = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="onConfirmDialog"> 确认 </el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
</template>
|