replace el-progress

This commit is contained in:
pa
2026-01-13 11:14:00 +09:00
committed by Natsumi
parent 0daef0c220
commit f077fcfd51
10 changed files with 129 additions and 94 deletions

View File

@@ -345,17 +345,9 @@
:disabled="avatarDialog.galleryLoading" :disabled="avatarDialog.galleryLoading"
class="ml-1" class="ml-1"
@click="displayAvatarGalleryUpload"> @click="displayAvatarGalleryUpload">
<Spinner v-if="avatarDialog.galleryLoading" /> <Upload />
<Upload v-else />
{{ t('dialog.screenshot_metadata.upload') }} {{ t('dialog.screenshot_metadata.upload') }}
</Button> </Button>
<el-progress
v-if="avatarDialog.galleryLoading"
:show-text="false"
:indeterminate="true"
:percentage="100"
:stroke-width="3"
style="margin: 10px 0" />
<div class="mt-2 w-[80%] ml-20"> <div class="mt-2 w-[80%] ml-20">
<Carousel v-if="avatarDialog.galleryImages.length" class="w-full"> <Carousel v-if="avatarDialog.galleryImages.length" class="w-full">
<CarouselContent class="h-50"> <CarouselContent class="h-50">
@@ -543,7 +535,6 @@
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { ElMessageBox } from 'element-plus'; import { ElMessageBox } from 'element-plus';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
import { Spinner } from '@/components/ui/spinner';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -1092,14 +1083,17 @@
try { try {
avatarDialog.value.galleryLoading = true; avatarDialog.value.galleryLoading = true;
const base64Body = btoa(r.result.toString()); const base64Body = btoa(r.result.toString());
avatarRequest const uploadPromise = (async () => {
.uploadAvatarGalleryImage(base64Body, avatarDialog.value.id) const args = await avatarRequest.uploadAvatarGalleryImage(base64Body, avatarDialog.value.id);
.then(async (args) => { avatarDialog.value.galleryImages = await getAvatarGallery(avatarDialog.value.id);
toast.success(t('message.avatar_gallery.uploaded')); return args;
console.log(args); })();
avatarDialog.value.galleryImages = await getAvatarGallery(avatarDialog.value.id); toast.promise(uploadPromise, {
return args; loading: t('message.upload.loading'),
}) success: t('message.upload.success'),
error: t('message.upload.error')
});
uploadPromise
.catch((error) => { .catch((error) => {
console.error('Failed to upload image', error); console.error('Failed to upload image', error);
}) })

View File

@@ -13,13 +13,6 @@
accept="image/*" accept="image/*"
style="display: none" style="display: none"
@change="onFileChangeAvatarImage" /> @change="onFileChangeAvatarImage" />
<el-progress
v-if="changeAvatarImageDialogLoading"
:show-text="false"
:indeterminate="true"
:percentage="100"
:stroke-width="3"
style="margin-bottom: 12px" />
<span>{{ t('dialog.change_content_image.description') }}</span> <span>{{ t('dialog.change_content_image.description') }}</span>
<br /> <br />
<Button <Button
@@ -27,8 +20,7 @@
size="icon-sm" size="icon-sm"
:disabled="changeAvatarImageDialogLoading" :disabled="changeAvatarImageDialogLoading"
@click="uploadAvatarImage"> @click="uploadAvatarImage">
<Spinner v-if="changeAvatarImageDialogLoading" /> <Upload />
<Upload v-else />
{{ t('dialog.change_content_image.upload') }} {{ t('dialog.change_content_image.upload') }}
</Button> </Button>
<br /> <br />
@@ -41,7 +33,6 @@
<script setup> <script setup>
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Spinner } from '@/components/ui/spinner';
import { Upload } from '@element-plus/icons-vue'; import { Upload } from '@element-plus/icons-vue';
import { ref } from 'vue'; import { ref } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@@ -114,7 +105,7 @@
r.onerror = finalize; r.onerror = finalize;
r.onabort = finalize; r.onabort = finalize;
r.onload = async function () { r.onload = async function () {
try { const uploadPromise = (async () => {
const base64File = await resizeImageToFitLimits(btoa(r.result.toString())); const base64File = await resizeImageToFitLimits(btoa(r.result.toString()));
// 10MB // 10MB
if (LINUX) { if (LINUX) {
@@ -124,6 +115,14 @@
return; return;
} }
await initiateUploadLegacy(base64File, file); await initiateUploadLegacy(base64File, file);
})();
toast.promise(uploadPromise, {
loading: t('message.upload.loading'),
success: t('message.upload.success'),
error: t('message.upload.error')
});
try {
await uploadPromise;
} catch (error) { } catch (error) {
console.error('avatar image upload process failed:', error); console.error('avatar image upload process failed:', error);
} finally { } finally {
@@ -286,7 +285,6 @@
function avatarImageSet(args) { function avatarImageSet(args) {
changeAvatarImageDialogLoading.value = false; changeAvatarImageDialogLoading.value = false;
if (args.json.imageUrl === args.params.imageUrl) { if (args.json.imageUrl === args.params.imageUrl) {
toast.success(t('message.avatar.image_changed'));
emit('update:previousImageUrl', args.json.imageUrl); emit('update:previousImageUrl', args.json.imageUrl);
} else { } else {
$throw(0, 'avatar image change failed', args.params.imageUrl); $throw(0, 'avatar image change failed', args.params.imageUrl);
@@ -305,7 +303,6 @@
const ref = applyAvatar(avatarArgs.json); const ref = applyAvatar(avatarArgs.json);
changeAvatarImageDialogLoading.value = false; changeAvatarImageDialogLoading.value = false;
emit('update:previousImageUrl', ref.imageUrl); emit('update:previousImageUrl', ref.imageUrl);
toast.success(t('message.avatar.image_changed'));
// closeDialog(); // closeDialog();
} }

View File

@@ -8,7 +8,8 @@
width="400px"> width="400px">
<div v-loading="checkingForVRCXUpdate" style="margin-top: 15px"> <div v-loading="checkingForVRCXUpdate" style="margin-top: 15px">
<template v-if="updateInProgress"> <template v-if="updateInProgress">
<el-progress :percentage="updateProgress" :format="updateProgressText"></el-progress> <Progress :model-value="updateProgress" class="w-full" />
<div class="mt-2 text-xs" v-text="updateProgressText()"></div>
<br /> <br />
</template> </template>
<template v-else> <template v-else>
@@ -73,6 +74,7 @@
<script setup> <script setup>
import { nextTick, ref, watch } from 'vue'; import { nextTick, ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Progress } from '@/components/ui/progress';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';

View File

@@ -13,18 +13,10 @@
accept="image/*" accept="image/*"
style="display: none" style="display: none"
@change="onFileChangeWorldImage" /> @change="onFileChangeWorldImage" />
<el-progress
v-if="changeWorldImageDialogLoading"
:show-text="false"
:indeterminate="true"
:percentage="100"
:stroke-width="3"
style="margin-bottom: 12px" />
<span>{{ t('dialog.change_content_image.description') }}</span> <span>{{ t('dialog.change_content_image.description') }}</span>
<br /> <br />
<Button variant="outline" size="sm" :disabled="changeWorldImageDialogLoading" @click="uploadWorldImage"> <Button variant="outline" size="sm" :disabled="changeWorldImageDialogLoading" @click="uploadWorldImage">
<Spinner v-if="changeWorldImageDialogLoading" /> <Upload />
<Upload v-else />
{{ t('dialog.change_content_image.upload') }} {{ t('dialog.change_content_image.upload') }}
</Button> </Button>
<br /> <br />
@@ -37,7 +29,6 @@
<script setup> <script setup>
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Spinner } from '@/components/ui/spinner';
import { Upload } from '@element-plus/icons-vue'; import { Upload } from '@element-plus/icons-vue';
import { ref } from 'vue'; import { ref } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@@ -110,11 +101,19 @@
r.onerror = finalize; r.onerror = finalize;
r.onabort = finalize; r.onabort = finalize;
r.onload = async function () { r.onload = async function () {
try { const uploadPromise = (async () => {
const base64File = await resizeImageToFitLimits(btoa(r.result.toString())); const base64File = await resizeImageToFitLimits(btoa(r.result.toString()));
// 10MB // 10MB
await initiateUploadLegacy(base64File, file); await initiateUploadLegacy(base64File, file);
// await initiateUpload(base64File); // await initiateUpload(base64File);
})();
toast.promise(uploadPromise, {
loading: t('message.upload.loading'),
success: t('message.upload.success'),
error: t('message.upload.error')
});
try {
await uploadPromise;
} catch (error) { } catch (error) {
console.error('World image upload process failed:', error); console.error('World image upload process failed:', error);
} finally { } finally {
@@ -277,7 +276,6 @@
function worldImageSet(args) { function worldImageSet(args) {
changeWorldImageDialogLoading.value = false; changeWorldImageDialogLoading.value = false;
if (args.json.imageUrl === args.params.imageUrl) { if (args.json.imageUrl === args.params.imageUrl) {
toast.success(t('message.world.image_changed'));
emit('update:previousImageUrl', args.json.imageUrl); emit('update:previousImageUrl', args.json.imageUrl);
} else { } else {
$throw(0, 'World image change failed', args.params.imageUrl); $throw(0, 'World image change failed', args.params.imageUrl);
@@ -296,7 +294,6 @@
const ref = applyWorld(worldArgs.json); const ref = applyWorld(worldArgs.json);
changeWorldImageDialogLoading.value = false; changeWorldImageDialogLoading.value = false;
emit('update:previousImageUrl', ref.imageUrl); emit('update:previousImageUrl', ref.imageUrl);
toast.success(t('message.world.image_changed'));
// closeDialog(); // closeDialog();
} }

View File

@@ -0,0 +1,29 @@
<script setup>
import { ProgressIndicator, ProgressRoot } from 'reka-ui';
import { cn } from '@/lib/utils';
import { reactiveOmit } from '@vueuse/core';
const props = defineProps({
modelValue: { type: [Number, null], required: false, default: 0 },
max: { type: Number, required: false },
getValueLabel: { type: Function, required: false },
getValueText: { type: Function, required: false },
asChild: { type: Boolean, required: false },
as: { type: null, required: false },
class: { type: null, required: false }
});
const delegatedProps = reactiveOmit(props, 'class');
</script>
<template>
<ProgressRoot
data-slot="progress"
v-bind="delegatedProps"
:class="cn('bg-primary/20 relative h-2 w-full overflow-hidden rounded-full', props.class)">
<ProgressIndicator
data-slot="progress-indicator"
class="bg-primary h-full w-full flex-1 transition-all"
:style="`transform: translateX(-${100 - (props.modelValue ?? 0)}%);`" />
</ProgressRoot>
</template>

View File

@@ -0,0 +1 @@
export { default as Progress } from './Progress.vue';

View File

@@ -1971,6 +1971,11 @@
"already_last": "Already last image", "already_last": "Already last image",
"reordered": "Successfully reordered avatar gallery images" "reordered": "Successfully reordered avatar gallery images"
}, },
"upload": {
"loading": "Uploading",
"success": "Upload completed",
"error": "Upload failed"
},
"world": { "world": {
"image_changed": "World image changed", "image_changed": "World image changed",
"image_invalid": "Current world image invalid" "image_invalid": "Current world image invalid"

View File

@@ -35,7 +35,7 @@
<strong>{{ fetchState.processedFriends }} / {{ totalFriends }}</strong> <strong>{{ fetchState.processedFriends }} / {{ totalFriends }}</strong>
</div> </div>
<el-progress :percentage="progressPercent" :status="progressStatus" :stroke-width="14"> </el-progress> <Progress :model-value="progressPercent" class="h-3" />
</div> </div>
<div ref="chartRef" class="mutual-graph__canvas"></div> <div ref="chartRef" class="mutual-graph__canvas"></div>
@@ -144,6 +144,7 @@
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { ElMessageBox } from 'element-plus'; import { ElMessageBox } from 'element-plus';
import { Settings } from 'lucide-vue-next'; import { Settings } from 'lucide-vue-next';
import { Progress } from '@/components/ui/progress';
import { Spinner } from '@/components/ui/spinner'; import { Spinner } from '@/components/ui/spinner';
import { onBeforeRouteLeave } from 'vue-router'; import { onBeforeRouteLeave } from 'vue-router';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@@ -213,7 +214,6 @@
const progressPercent = computed(() => const progressPercent = computed(() =>
totalFriends.value ? Math.min(100, Math.round((fetchState.processedFriends / totalFriends.value) * 100)) : 0 totalFriends.value ? Math.min(100, Math.round((fetchState.processedFriends / totalFriends.value) * 100)) : 0
); );
const progressStatus = computed(() => (isFetching.value ? 'warning' : ''));
const forceDefaults = computed(() => const forceDefaults = computed(() =>
computeForceOptions(graphPayload.value?.nodes ?? [], graphPayload.value?.links ?? []) computeForceOptions(graphPayload.value?.nodes ?? [], graphPayload.value?.links ?? [])
); );

View File

@@ -241,10 +241,10 @@
:show-close="false" :show-close="false"
align-center> align-center>
<div style="margin-bottom: 10px" v-text="t('view.friend_list.load_dialog_message')"></div> <div style="margin-bottom: 10px" v-text="t('view.friend_list.load_dialog_message')"></div>
<el-progress <div class="flex items-center gap-2">
:percentage="friendsListLoadingPercent" <Progress :model-value="friendsListLoadingPercent" class="h-4 w-full" />
:text-inside="true" <span class="text-xs w-10 text-right">{{ friendsListLoadingPercent }}%</span>
:stroke-width="16"></el-progress> </div>
<div style="margin-top: 10px; text-align: right"> <div style="margin-top: 10px; text-align: right">
<span>{{ friendsListLoadingCurrent }} / {{ friendsListLoadingTotal }}</span> <span>{{ friendsListLoadingCurrent }} / {{ friendsListLoadingTotal }}</span>
</div> </div>
@@ -262,6 +262,7 @@
import { computed, nextTick, reactive, ref, watch } from 'vue'; import { computed, nextTick, reactive, ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupField } from '@/components/ui/input-group'; import { InputGroupField } from '@/components/ui/input-group';
import { Progress } from '@/components/ui/progress';
import { ElMessageBox } from 'element-plus'; import { ElMessageBox } from 'element-plus';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';

View File

@@ -6,13 +6,6 @@
</Button> </Button>
<span class="header">{{ t('dialog.gallery_icons.header') }}</span> <span class="header">{{ t('dialog.gallery_icons.header') }}</span>
</div> </div>
<el-progress
v-if="isUploading"
:show-text="false"
:indeterminate="true"
:percentage="100"
:stroke-width="3"
style="margin-bottom: 12px" />
<el-tabs> <el-tabs>
<el-tab-pane v-loading="galleryDialogGalleryLoading"> <el-tab-pane v-loading="galleryDialogGalleryLoading">
<template #label> <template #label>
@@ -680,13 +673,16 @@
r.onload = function () { r.onload = function () {
try { try {
const base64Body = btoa(r.result.toString()); const base64Body = btoa(r.result.toString());
vrcPlusImageRequest const uploadPromise = vrcPlusImageRequest.uploadGalleryImage(base64Body).then((args) => {
.uploadGalleryImage(base64Body) handleGalleryImageAdd(args);
.then((args) => { return args;
handleGalleryImageAdd(args); });
toast.success(t('message.gallery.uploaded')); toast.promise(uploadPromise, {
return args; loading: t('message.upload.loading'),
}) success: t('message.upload.success'),
error: t('message.upload.error')
});
uploadPromise
.catch((error) => { .catch((error) => {
console.error('Failed to upload', error); console.error('Failed to upload', error);
}) })
@@ -772,15 +768,18 @@
r.onload = function () { r.onload = function () {
try { try {
const base64Body = btoa(r.result.toString()); const base64Body = btoa(r.result.toString());
vrcPlusIconRequest const uploadPromise = vrcPlusIconRequest.uploadVRCPlusIcon(base64Body).then((args) => {
.uploadVRCPlusIcon(base64Body) if (Object.keys(VRCPlusIconsTable.value).length !== 0) {
.then((args) => { VRCPlusIconsTable.value.unshift(args.json);
if (Object.keys(VRCPlusIconsTable.value).length !== 0) { }
VRCPlusIconsTable.value.unshift(args.json); return args;
} });
toast.success(t('message.icon.uploaded')); toast.promise(uploadPromise, {
return args; loading: t('message.upload.loading'),
}) success: t('message.upload.success'),
error: t('message.upload.error')
});
uploadPromise
.catch((error) => { .catch((error) => {
console.error('Failed to upload VRC+ icon', error); console.error('Failed to upload VRC+ icon', error);
}) })
@@ -902,15 +901,18 @@
params.loopStyle = 'pingpong'; params.loopStyle = 'pingpong';
} }
const base64Body = btoa(r.result.toString()); const base64Body = btoa(r.result.toString());
vrcPlusImageRequest const uploadPromise = vrcPlusImageRequest.uploadEmoji(base64Body, params).then((args) => {
.uploadEmoji(base64Body, params) if (Object.keys(emojiTable.value).length !== 0) {
.then((args) => { emojiTable.value.unshift(args.json);
if (Object.keys(emojiTable.value).length !== 0) { }
emojiTable.value.unshift(args.json); return args;
} });
toast.success(t('message.emoji.uploaded')); toast.promise(uploadPromise, {
return args; loading: t('message.upload.loading'),
}) success: t('message.upload.success'),
error: t('message.upload.error')
});
uploadPromise
.catch((error) => { .catch((error) => {
console.error('Failed to upload', error); console.error('Failed to upload', error);
}) })
@@ -969,13 +971,16 @@
maskTag: 'square' maskTag: 'square'
}; };
const base64Body = btoa(r.result.toString()); const base64Body = btoa(r.result.toString());
vrcPlusImageRequest const uploadPromise = vrcPlusImageRequest.uploadSticker(base64Body, params).then((args) => {
.uploadSticker(base64Body, params) handleStickerAdd(args);
.then((args) => { return args;
handleStickerAdd(args); });
toast.success(t('message.sticker.uploaded')); toast.promise(uploadPromise, {
return args; loading: t('message.upload.loading'),
}) success: t('message.upload.success'),
error: t('message.upload.error')
});
uploadPromise
.catch((error) => { .catch((error) => {
console.error('Failed to upload', error); console.error('Failed to upload', error);
}) })
@@ -1041,16 +1046,20 @@
}; };
const base64Body = btoa(r.result.toString()); const base64Body = btoa(r.result.toString());
const cropWhiteBorder = printCropBorder.value; const cropWhiteBorder = printCropBorder.value;
vrcPlusImageRequest const uploadPromise = vrcPlusImageRequest
.uploadPrint(base64Body, cropWhiteBorder, params) .uploadPrint(base64Body, cropWhiteBorder, params)
.then((args) => { .then((args) => {
toast.success(t('message.print.uploaded'));
if (Object.keys(printTable.value).length !== 0) { if (Object.keys(printTable.value).length !== 0) {
printTable.value.unshift(args.json); printTable.value.unshift(args.json);
} }
return args; return args;
}) });
toast.promise(uploadPromise, {
loading: t('message.upload.loading'),
success: t('message.upload.success'),
error: t('message.upload.error')
});
uploadPromise
.catch((error) => { .catch((error) => {
console.error('Failed to upload', error); console.error('Failed to upload', error);
}) })