Update MkUploadDialog.vue
This commit is contained in:
parent
d73904ff1f
commit
73157dd898
|
@ -16,11 +16,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div :class="$style.root" class="_gaps_s">
|
<div :class="$style.root" class="_gaps_s">
|
||||||
<MkSwitch v-model="compress">
|
|
||||||
<template #label>{{ i18n.ts.compress }}</template>
|
|
||||||
</MkSwitch>
|
|
||||||
<div :class="$style.items" class="_gaps_s">
|
<div :class="$style.items" class="_gaps_s">
|
||||||
<div v-for="ctx in items" :key="ctx.id" v-panel :class="$style.item" :style="{ '--p': ctx.progressValue !== null ? `${ctx.progressValue / ctx.progressMax * 100}%` : '0%' }">
|
<div v-for="ctx in items" :key="ctx.id" v-panel :class="[$style.item, ctx.waiting ? $style.itemWaiting : null]" :style="{ '--p': ctx.progressValue !== null ? `${ctx.progressValue / ctx.progressMax * 100}%` : '0%' }">
|
||||||
<div :class="$style.itemInner">
|
<div :class="$style.itemInner">
|
||||||
<div>
|
<div>
|
||||||
<MkButton :iconOnly="true" rounded><i class="ti ti-dots"></i></MkButton>
|
<MkButton :iconOnly="true" rounded><i class="ti ti-dots"></i></MkButton>
|
||||||
|
@ -41,18 +38,23 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<MkSwitch v-model="compress">
|
||||||
|
<template #label>{{ i18n.ts.compress }}</template>
|
||||||
|
</MkSwitch>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="_buttonsCenter">
|
<div class="_buttonsCenter">
|
||||||
<MkButton primary rounded @click="upload()"><i class="ti ti-upload"></i> {{ i18n.ts.upload }}</MkButton>
|
<MkButton v-if="uploadStarted" rounded @click=""><i class="ti ti-x"></i> {{ i18n.ts.cancel }}</MkButton>
|
||||||
|
<MkButton v-else primary rounded @click="upload()"><i class="ti ti-upload"></i> {{ i18n.ts.upload }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</MkModalWindow>
|
</MkModalWindow>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { markRaw, onMounted, ref, useTemplateRef } from 'vue';
|
import { markRaw, onMounted, ref, useTemplateRef, watch } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { readAndCompressImage } from '@misskey-dev/browser-image-resizer';
|
import { readAndCompressImage } from '@misskey-dev/browser-image-resizer';
|
||||||
|
@ -93,6 +95,7 @@ const items = ref([] as {
|
||||||
progressMax: number | null;
|
progressMax: number | null;
|
||||||
progressValue: number | null;
|
progressValue: number | null;
|
||||||
thumbnail: string;
|
thumbnail: string;
|
||||||
|
waiting: boolean;
|
||||||
uploading: boolean;
|
uploading: boolean;
|
||||||
uploaded: Misskey.entities.DriveFile | null;
|
uploaded: Misskey.entities.DriveFile | null;
|
||||||
file: File;
|
file: File;
|
||||||
|
@ -101,6 +104,14 @@ const items = ref([] as {
|
||||||
const dialog = useTemplateRef('dialog');
|
const dialog = useTemplateRef('dialog');
|
||||||
|
|
||||||
const compress = ref(true);
|
const compress = ref(true);
|
||||||
|
const uploadStarted = ref(false);
|
||||||
|
|
||||||
|
watch(items, () => {
|
||||||
|
if (uploadStarted.value && items.value.every(item => item.uploaded)) {
|
||||||
|
emit('done', items.value.map(item => item.uploaded!));
|
||||||
|
dialog.value?.close();
|
||||||
|
}
|
||||||
|
}, { deep: true });
|
||||||
|
|
||||||
function cancel() {
|
function cancel() {
|
||||||
// TODO: アップロードを中止しますか?
|
// TODO: アップロードを中止しますか?
|
||||||
|
@ -108,6 +119,8 @@ function cancel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function upload() {
|
function upload() {
|
||||||
|
uploadStarted.value = true;
|
||||||
|
|
||||||
for (const item of items.value) {
|
for (const item of items.value) {
|
||||||
if ((item.file.size > instance.maxFileSize) || (item.file.size > ($i.policies.maxFileSizeMb * 1024 * 1024))) {
|
if ((item.file.size > instance.maxFileSize) || (item.file.size > ($i.policies.maxFileSizeMb * 1024 * 1024))) {
|
||||||
alert({
|
alert({
|
||||||
|
@ -118,6 +131,8 @@ function upload() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
item.waiting = true;
|
||||||
|
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = async (): Promise<void> => {
|
reader.onload = async (): Promise<void> => {
|
||||||
const config = compress.value ? await getCompressionConfig(item.file) : undefined;
|
const config = compress.value ? await getCompressionConfig(item.file) : undefined;
|
||||||
|
@ -199,12 +214,14 @@ function upload() {
|
||||||
|
|
||||||
xhr.upload.onprogress = ev => {
|
xhr.upload.onprogress = ev => {
|
||||||
if (ev.lengthComputable) {
|
if (ev.lengthComputable) {
|
||||||
|
item.waiting = false;
|
||||||
item.progressMax = ev.total;
|
item.progressMax = ev.total;
|
||||||
item.progressValue = ev.loaded;
|
item.progressValue = ev.loaded;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.send(formData);
|
xhr.send(formData);
|
||||||
|
item.uploading = true;
|
||||||
};
|
};
|
||||||
reader.readAsArrayBuffer(item.file);
|
reader.readAsArrayBuffer(item.file);
|
||||||
}
|
}
|
||||||
|
@ -221,6 +238,8 @@ onMounted(() => {
|
||||||
progressMax: null,
|
progressMax: null,
|
||||||
progressValue: null,
|
progressValue: null,
|
||||||
thumbnail: window.URL.createObjectURL(file),
|
thumbnail: window.URL.createObjectURL(file),
|
||||||
|
waiting: false,
|
||||||
|
uploading: false,
|
||||||
uploaded: null,
|
uploaded: null,
|
||||||
file: markRaw(file),
|
file: markRaw(file),
|
||||||
});
|
});
|
||||||
|
@ -250,7 +269,30 @@ onMounted(() => {
|
||||||
width: var(--p);
|
width: var(--p);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: color(from var(--MI_THEME-accent) srgb r g b / 0.5);
|
background: color(from var(--MI_THEME-accent) srgb r g b / 0.5);
|
||||||
|
transition: width 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.itemWaiting {
|
||||||
|
&::after {
|
||||||
|
--c: color(from var(--MI_THEME-accent) srgb r g b / 0.25);
|
||||||
|
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(-45deg, transparent 25%, var(--c) 25%,var(--c) 50%, transparent 50%, transparent 75%, var(--c) 75%, var(--c));
|
||||||
|
background-size: 25px 25px;
|
||||||
|
animation: stripe .8s infinite linear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes stripe {
|
||||||
|
0% { background-position-x: 0; }
|
||||||
|
100% { background-position-x: -25px; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.itemInner {
|
.itemInner {
|
||||||
|
@ -259,7 +301,7 @@ onMounted(() => {
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.itemThumbnail {
|
.itemThumbnail {
|
||||||
|
|
Loading…
Reference in New Issue