replace ElMessageBox.prompt

This commit is contained in:
pa
2026-01-15 11:46:03 +09:00
committed by Natsumi
parent 87dc871578
commit fc13dca0a4
22 changed files with 413 additions and 408 deletions

View File

@@ -545,7 +545,6 @@
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/components/ui/carousel'; import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/components/ui/carousel';
import { computed, defineAsyncComponent, nextTick, ref, watch } from 'vue'; import { computed, defineAsyncComponent, nextTick, ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { ElMessageBox } from 'element-plus';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
import { TabsUnderline } from '@/components/ui/tabs'; import { TabsUnderline } from '@/components/ui/tabs';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@@ -925,18 +924,17 @@
} }
function promptChangeAvatarDescription(avatar) { function promptChangeAvatarDescription(avatar) {
ElMessageBox.prompt( modalStore
t('prompt.change_avatar_description.description'), .prompt({
t('prompt.change_avatar_description.header'), title: t('prompt.change_avatar_description.header'),
{ description: t('prompt.change_avatar_description.description'),
distinguishCancelAndClose: true, confirmText: t('prompt.change_avatar_description.ok'),
confirmButtonText: t('prompt.change_avatar_description.ok'), cancelText: t('prompt.change_avatar_description.cancel'),
cancelButtonText: t('prompt.change_avatar_description.cancel'),
inputValue: avatar.ref.description, inputValue: avatar.ref.description,
inputErrorMessage: t('prompt.change_avatar_description.input_error') errorMessage: t('prompt.change_avatar_description.input_error')
} })
) .then(({ ok, value }) => {
.then(({ value }) => { if (!ok) return;
if (value && value !== avatar.ref.description) { if (value && value !== avatar.ref.description) {
avatarRequest avatarRequest
.saveAvatar({ .saveAvatar({
@@ -954,14 +952,17 @@
} }
function promptRenameAvatar(avatar) { function promptRenameAvatar(avatar) {
ElMessageBox.prompt(t('prompt.rename_avatar.description'), t('prompt.rename_avatar.header'), { modalStore
distinguishCancelAndClose: true, .prompt({
confirmButtonText: t('prompt.rename_avatar.ok'), title: t('prompt.rename_avatar.header'),
cancelButtonText: t('prompt.rename_avatar.cancel'), description: t('prompt.rename_avatar.description'),
inputValue: avatar.ref.name, confirmText: t('prompt.rename_avatar.ok'),
inputErrorMessage: t('prompt.rename_avatar.input_error') cancelText: t('prompt.rename_avatar.cancel'),
}) inputValue: avatar.ref.name,
.then(({ value }) => { errorMessage: t('prompt.rename_avatar.input_error')
})
.then(({ ok, value }) => {
if (!ok) return;
if (value && value !== avatar.ref.name) { if (value && value !== avatar.ref.name) {
avatarRequest avatarRequest
.saveAvatar({ .saveAvatar({

View File

@@ -1304,6 +1304,7 @@
ArrowUp, ArrowUp,
Copy, Copy,
Download, Download,
DownloadIcon,
Eye, Eye,
Languages, Languages,
Loader2, Loader2,

View File

@@ -746,7 +746,6 @@
} from 'lucide-vue-next'; } from 'lucide-vue-next';
import { computed, defineAsyncComponent, nextTick, ref, watch } from 'vue'; import { computed, defineAsyncComponent, nextTick, ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { ElMessageBox } from 'element-plus';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
import { TabsUnderline } from '@/components/ui/tabs'; import { TabsUnderline } from '@/components/ui/tabs';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@@ -1120,14 +1119,17 @@
} }
function promptRenameWorld(world) { function promptRenameWorld(world) {
ElMessageBox.prompt(t('prompt.rename_world.description'), t('prompt.rename_world.header'), { modalStore
distinguishCancelAndClose: true, .prompt({
confirmButtonText: t('prompt.rename_world.ok'), title: t('prompt.rename_world.header'),
cancelButtonText: t('prompt.rename_world.cancel'), description: t('prompt.rename_world.description'),
inputValue: world.ref.name, confirmText: t('prompt.rename_world.ok'),
inputErrorMessage: t('prompt.rename_world.input_error') cancelText: t('prompt.rename_world.cancel'),
}) inputValue: world.ref.name,
.then(({ value }) => { errorMessage: t('prompt.rename_world.input_error')
})
.then(({ ok, value }) => {
if (!ok) return;
if (value && value !== world.ref.name) { if (value && value !== world.ref.name) {
worldRequest worldRequest
.saveWorld({ .saveWorld({
@@ -1143,18 +1145,17 @@
.catch(() => {}); .catch(() => {});
} }
function promptChangeWorldDescription(world) { function promptChangeWorldDescription(world) {
ElMessageBox.prompt( modalStore
t('prompt.change_world_description.description'), .prompt({
t('prompt.change_world_description.header'), title: t('prompt.change_world_description.header'),
{ description: t('prompt.change_world_description.description'),
distinguishCancelAndClose: true, confirmText: t('prompt.change_world_description.ok'),
confirmButtonText: t('prompt.change_world_description.ok'), cancelText: t('prompt.change_world_description.cancel'),
cancelButtonText: t('prompt.change_world_description.cancel'),
inputValue: world.ref.description, inputValue: world.ref.description,
inputErrorMessage: t('prompt.change_world_description.input_error') errorMessage: t('prompt.change_world_description.input_error')
} })
) .then(({ ok, value }) => {
.then(({ value }) => { if (!ok) return;
if (value && value !== world.ref.description) { if (value && value !== world.ref.description) {
worldRequest worldRequest
.saveWorld({ .saveWorld({
@@ -1171,15 +1172,18 @@
} }
function promptChangeWorldCapacity(world) { function promptChangeWorldCapacity(world) {
ElMessageBox.prompt(t('prompt.change_world_capacity.description'), t('prompt.change_world_capacity.header'), { modalStore
distinguishCancelAndClose: true, .prompt({
confirmButtonText: t('prompt.change_world_capacity.ok'), title: t('prompt.change_world_capacity.header'),
cancelButtonText: t('prompt.change_world_capacity.cancel'), description: t('prompt.change_world_capacity.description'),
inputValue: world.ref.capacity, confirmText: t('prompt.change_world_capacity.ok'),
inputPattern: /\d+$/, cancelText: t('prompt.change_world_capacity.cancel'),
inputErrorMessage: t('prompt.change_world_capacity.input_error') inputValue: world.ref.capacity,
}) pattern: /\d+$/,
.then(({ value }) => { errorMessage: t('prompt.change_world_capacity.input_error')
})
.then(({ ok, value }) => {
if (!ok) return;
if (value && value !== world.ref.capacity) { if (value && value !== world.ref.capacity) {
worldRequest worldRequest
.saveWorld({ .saveWorld({
@@ -1196,19 +1200,18 @@
} }
function promptChangeWorldRecommendedCapacity(world) { function promptChangeWorldRecommendedCapacity(world) {
ElMessageBox.prompt( modalStore
t('prompt.change_world_recommended_capacity.description'), .prompt({
t('prompt.change_world_recommended_capacity.header'), title: t('prompt.change_world_recommended_capacity.header'),
{ description: t('prompt.change_world_recommended_capacity.description'),
distinguishCancelAndClose: true, confirmText: t('prompt.change_world_capacity.ok'),
confirmButtonText: t('prompt.change_world_capacity.ok'), cancelText: t('prompt.change_world_capacity.cancel'),
cancelButtonText: t('prompt.change_world_capacity.cancel'),
inputValue: world.ref.recommendedCapacity, inputValue: world.ref.recommendedCapacity,
inputPattern: /\d+$/, pattern: /\d+$/,
inputErrorMessage: t('prompt.change_world_recommended_capacity.input_error') errorMessage: t('prompt.change_world_recommended_capacity.input_error')
} })
) .then(({ ok, value }) => {
.then(({ value }) => { if (!ok) return;
if (value && value !== world.ref.recommendedCapacity) { if (value && value !== world.ref.recommendedCapacity) {
worldRequest worldRequest
.saveWorld({ .saveWorld({
@@ -1225,14 +1228,17 @@
} }
function promptChangeWorldYouTubePreview(world) { function promptChangeWorldYouTubePreview(world) {
ElMessageBox.prompt(t('prompt.change_world_preview.description'), t('prompt.change_world_preview.header'), { modalStore
distinguishCancelAndClose: true, .prompt({
confirmButtonText: t('prompt.change_world_preview.ok'), title: t('prompt.change_world_preview.header'),
cancelButtonText: t('prompt.change_world_preview.cancel'), description: t('prompt.change_world_preview.description'),
inputValue: world.ref.previewYoutubeId, confirmText: t('prompt.change_world_preview.ok'),
inputErrorMessage: t('prompt.change_world_preview.input_error') cancelText: t('prompt.change_world_preview.cancel'),
}) inputValue: world.ref.previewYoutubeId,
.then(({ value }) => { errorMessage: t('prompt.change_world_preview.input_error')
})
.then(({ ok, value }) => {
if (!ok) return;
if (value && value !== world.ref.previewYoutubeId) { if (value && value !== world.ref.previewYoutubeId) {
let processedValue = value; let processedValue = value;
if (value.length > 11) { if (value.length > 11) {

View File

@@ -40,7 +40,7 @@
v-bind="{ ...$attrs, ...forwarded }" v-bind="{ ...$attrs, ...forwarded }"
:class=" :class="
cn( cn(
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg', 'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-10000 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
props.class props.class
) )
"> ">

View File

@@ -19,7 +19,7 @@
v-bind="delegatedProps" v-bind="delegatedProps"
:class=" :class="
cn( cn(
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-10000 bg-black/80',
props.class props.class
) )
"> ">

View File

@@ -32,11 +32,11 @@
<template> <template>
<DialogPortal> <DialogPortal>
<DialogOverlay <DialogOverlay
class="fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"> class="fixed inset-0 z-10000 grid place-items-center overflow-y-auto bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0">
<DialogContent <DialogContent
:class=" :class="
cn( cn(
'relative z-50 grid w-full max-w-lg my-8 gap-4 border border-border bg-background p-6 shadow-lg duration-200 sm:rounded-lg md:w-full', 'relative z-10000 grid w-full max-w-lg my-8 gap-4 border border-border bg-background p-6 shadow-lg duration-200 sm:rounded-lg md:w-full',
props.class props.class
) )
" "

View File

@@ -7,7 +7,7 @@
DialogHeader, DialogHeader,
DialogTitle DialogTitle
} from '@/components/ui/dialog'; } from '@/components/ui/dialog';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; import { FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@@ -61,7 +61,7 @@
event.preventDefault(); event.preventDefault();
return; return;
} }
modalStore.handlePromptDismiss(values.value.value ?? ''); modalStore.handlePromptDismiss(values.value ?? '');
} }
function onPointerDownOutside(event) { function onPointerDownOutside(event) {
@@ -69,7 +69,7 @@
event.preventDefault(); event.preventDefault();
return; return;
} }
modalStore.handlePromptDismiss(values.value.value ?? ''); modalStore.handlePromptDismiss(values.value ?? '');
} }
function onInteractOutside(event) { function onInteractOutside(event) {
@@ -77,20 +77,21 @@
event.preventDefault(); event.preventDefault();
return; return;
} }
modalStore.handlePromptDismiss(values.value.value ?? ''); modalStore.handlePromptDismiss(values.value ?? '');
} }
function handleCancel() { function handleCancel() {
modalStore.handlePromptCancel(values.value.value ?? ''); modalStore.handlePromptCancel(values.value ?? '');
} }
watch( watch(
promptOpen, [promptOpen, promptInputValue],
(open) => { ([open, inputValue]) => {
if (open) { if (open) {
setValues({ value: promptInputValue.value ?? '' }); setValues({ value: inputValue ?? '' });
return; return;
} }
resetForm({ resetForm({
values: { values: {
value: '' value: ''
@@ -108,7 +109,7 @@
@escapeKeyDown="onEscapeKeyDown" @escapeKeyDown="onEscapeKeyDown"
@pointerDownOutside="onPointerDownOutside" @pointerDownOutside="onPointerDownOutside"
@interactOutside="onInteractOutside"> @interactOutside="onInteractOutside">
<Form @submit="onSubmit"> <form @submit="onSubmit">
<DialogHeader> <DialogHeader>
<DialogTitle>{{ promptTitle }}</DialogTitle> <DialogTitle>{{ promptTitle }}</DialogTitle>
<DialogDescription>{{ promptDescription }}</DialogDescription> <DialogDescription>{{ promptDescription }}</DialogDescription>
@@ -132,7 +133,7 @@
{{ promptOkText }} {{ promptOkText }}
</Button> </Button>
</DialogFooter> </DialogFooter>
</Form> </form>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</template> </template>

View File

@@ -43,7 +43,7 @@
v-bind="{ ...$attrs, ...forwardedProps }" v-bind="{ ...$attrs, ...forwardedProps }"
:class=" :class="
cn( cn(
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-64 rounded-md border p-4 shadow-md outline-hidden', 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-10000 w-64 rounded-md border p-4 shadow-md outline-hidden',
props.class props.class
) )
"> ">

View File

@@ -11,7 +11,6 @@
const emits = defineEmits(['update:modelValue']); const emits = defineEmits(['update:modelValue']);
const modelValue = useVModel(props, 'modelValue', emits, { const modelValue = useVModel(props, 'modelValue', emits, {
passive: true,
defaultValue: props.defaultValue defaultValue: props.defaultValue
}); });
</script> </script>

View File

@@ -1,5 +1,4 @@
import { reactive, ref, watch } from 'vue'; import { reactive, ref, watch } from 'vue';
import { ElMessageBox } from 'element-plus';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -255,15 +254,21 @@ export const useAuthStore = defineStore('Auth', () => {
if (advancedSettingsStore.enablePrimaryPassword) { if (advancedSettingsStore.enablePrimaryPassword) {
enablePrimaryPasswordDialog.value.visible = true; enablePrimaryPasswordDialog.value.visible = true;
} else { } else {
ElMessageBox.prompt( modalStore
t('prompt.primary_password.description'), .prompt({
t('prompt.primary_password.header'), title: t('prompt.primary_password.header'),
{ description: t('prompt.primary_password.description'),
inputType: 'password', pattern: /[\s\S]{1,32}/
inputPattern: /[\s\S]{1,32}/ })
} .then(async ({ ok, value }) => {
) if (!ok) {
.then(async ({ value }) => { advancedSettingsStore.enablePrimaryPassword = true;
advancedSettingsStore.setEnablePrimaryPasswordConfigRepository(
true
);
return;
}
const savedCredentials = JSON.parse( const savedCredentials = JSON.parse(
await configRepository.getString( await configRepository.getString(
'savedCredentials', 'savedCredentials',
@@ -299,7 +304,8 @@ export const useAuthStore = defineStore('Auth', () => {
}); });
} }
}) })
.catch(async () => { .catch((err) => {
console.error(err);
advancedSettingsStore.enablePrimaryPassword = true; advancedSettingsStore.enablePrimaryPassword = true;
advancedSettingsStore.setEnablePrimaryPasswordConfigRepository( advancedSettingsStore.setEnablePrimaryPasswordConfigRepository(
true true
@@ -378,16 +384,19 @@ export const useAuthStore = defineStore('Auth', () => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!advancedSettingsStore.enablePrimaryPassword) { if (!advancedSettingsStore.enablePrimaryPassword) {
resolve(args.password); resolve(args.password);
return;
} }
ElMessageBox.prompt( modalStore
t('prompt.primary_password.description'), .prompt({
t('prompt.primary_password.header'), title: t('prompt.primary_password.header'),
{ description: t('prompt.primary_password.description'),
inputType: 'password', pattern: /[\s\S]{1,32}/
inputPattern: /[\s\S]{1,32}/ })
} .then(({ ok, value }) => {
) if (!ok) {
.then(({ value }) => { reject(new Error('primary password prompt cancelled'));
return;
}
security security
.decrypt(args.password, value) .decrypt(args.password, value)
.then(resolve) .then(resolve)
@@ -536,15 +545,16 @@ export const useAuthStore = defineStore('Auth', () => {
loginForm.value.saveCredentials && loginForm.value.saveCredentials &&
advancedSettingsStore.enablePrimaryPassword advancedSettingsStore.enablePrimaryPassword
) { ) {
ElMessageBox.prompt( modalStore
t('prompt.primary_password.description'), .prompt({
t('prompt.primary_password.header'), title: t('prompt.primary_password.header'),
{ description: t(
inputType: 'password', 'prompt.primary_password.description'
inputPattern: /[\s\S]{1,32}/ ),
} pattern: /[\s\S]{1,32}/
) })
.then(async ({ value }) => { .then(async ({ ok, value }) => {
if (!ok) return;
const savedCredentials = JSON.parse( const savedCredentials = JSON.parse(
await configRepository.getString( await configRepository.getString(
'savedCredentials' 'savedCredentials'
@@ -613,41 +623,39 @@ export const useAuthStore = defineStore('Auth', () => {
} }
AppApi.FlashWindow(); AppApi.FlashWindow();
twoFactorAuthDialogVisible.value = true; twoFactorAuthDialogVisible.value = true;
ElMessageBox.prompt( modalStore
t('prompt.totp.description'), .prompt({
t('prompt.totp.header'), title: t('prompt.totp.header'),
{ description: t('prompt.totp.description'),
distinguishCancelAndClose: true, cancelText: t('prompt.totp.use_otp'),
cancelButtonText: t('prompt.totp.use_otp'), confirmText: t('prompt.totp.verify'),
confirmButtonText: t('prompt.totp.verify'), pattern: /^[0-9]{6}$/,
inputPlaceholder: t('prompt.totp.input_placeholder'), errorMessage: t('prompt.totp.input_error')
inputPattern: /^[0-9]{6}$/,
inputErrorMessage: t('prompt.totp.input_error'),
beforeClose: (action, instance, done) => {
twoFactorAuthDialogVisible.value = false;
if (action === 'cancel') {
promptOTP();
}
done();
}
}
)
.then(({ value, action }) => {
if (action === 'confirm') {
authRequest
.verifyTOTP({
code: value.trim()
})
.catch((err) => {
console.error(err);
clearCookiesTryLogin();
})
.then(() => {
userStore.getCurrentUser();
});
}
}) })
.catch(() => {}); .then(({ ok, reason, value }) => {
twoFactorAuthDialogVisible.value = false;
if (reason === 'cancel') {
promptOTP();
return;
}
if (!ok) return;
authRequest
.verifyTOTP({
code: value.trim()
})
.catch((err) => {
console.error(err);
clearCookiesTryLogin();
})
.then(() => {
userStore.getCurrentUser();
});
})
.catch(() => {
twoFactorAuthDialogVisible.value = false;
});
} }
function promptOTP() { function promptOTP() {
@@ -655,41 +663,39 @@ export const useAuthStore = defineStore('Auth', () => {
return; return;
} }
twoFactorAuthDialogVisible.value = true; twoFactorAuthDialogVisible.value = true;
ElMessageBox.prompt( modalStore
t('prompt.otp.description'), .prompt({
t('prompt.otp.header'), title: t('prompt.otp.header'),
{ description: t('prompt.otp.description'),
distinguishCancelAndClose: true, cancelText: t('prompt.otp.use_totp'),
cancelButtonText: t('prompt.otp.use_totp'), confirmText: t('prompt.otp.verify'),
confirmButtonText: t('prompt.otp.verify'), pattern: /^[a-z0-9]{4}-[a-z0-9]{4}$/,
inputPlaceholder: t('prompt.otp.input_placeholder'), errorMessage: t('prompt.otp.input_error')
inputPattern: /^[a-z0-9]{4}-[a-z0-9]{4}$/,
inputErrorMessage: t('prompt.otp.input_error'),
beforeClose: (action, instance, done) => {
twoFactorAuthDialogVisible.value = false;
if (action === 'cancel') {
promptTOTP();
}
done();
}
}
)
.then(({ value, action }) => {
if (action === 'confirm') {
authRequest
.verifyOTP({
code: value.trim()
})
.catch((err) => {
console.error(err);
clearCookiesTryLogin();
})
.then(() => {
userStore.getCurrentUser();
});
}
}) })
.catch(() => {}); .then(({ ok, reason, value }) => {
twoFactorAuthDialogVisible.value = false;
if (reason === 'cancel') {
promptTOTP();
return;
}
if (!ok) return;
authRequest
.verifyOTP({
code: value.trim()
})
.catch((err) => {
console.error(err);
clearCookiesTryLogin();
})
.then(() => {
userStore.getCurrentUser();
});
})
.catch(() => {
twoFactorAuthDialogVisible.value = false;
});
} }
function promptEmailOTP() { function promptEmailOTP() {
@@ -698,42 +704,39 @@ export const useAuthStore = defineStore('Auth', () => {
} }
AppApi.FlashWindow(); AppApi.FlashWindow();
twoFactorAuthDialogVisible.value = true; twoFactorAuthDialogVisible.value = true;
ElMessageBox.prompt( modalStore
t('prompt.email_otp.description'), .prompt({
t('prompt.email_otp.header'), title: t('prompt.email_otp.header'),
{ description: t('prompt.email_otp.description'),
distinguishCancelAndClose: true, cancelText: t('prompt.email_otp.resend'),
cancelButtonText: t('prompt.email_otp.resend'), confirmText: t('prompt.email_otp.verify'),
confirmButtonText: t('prompt.email_otp.verify'), pattern: /^[0-9]{6}$/,
inputPlaceholder: t('prompt.email_otp.input_placeholder'), errorMessage: t('prompt.email_otp.input_error')
inputPattern: /^[0-9]{6}$/,
inputErrorMessage: t('prompt.email_otp.input_error'),
beforeClose: (action, instance, done) => {
twoFactorAuthDialogVisible.value = false;
if (action === 'cancel') {
resendEmail2fa();
return;
}
done();
}
}
)
.then(({ value, action }) => {
if (action === 'confirm') {
authRequest
.verifyEmailOTP({
code: value.trim()
})
.catch((err) => {
console.error(err);
promptEmailOTP();
})
.then(() => {
userStore.getCurrentUser();
});
}
}) })
.catch(() => {}); .then(({ ok, reason, value }) => {
twoFactorAuthDialogVisible.value = false;
if (reason === 'cancel') {
resendEmail2fa();
return;
}
if (!ok) return;
authRequest
.verifyEmailOTP({
code: value.trim()
})
.catch((err) => {
console.error(err);
promptEmailOTP();
})
.then(() => {
userStore.getCurrentUser();
});
})
.catch(() => {
twoFactorAuthDialogVisible.value = false;
});
} }
/** /**

View File

@@ -1,5 +1,4 @@
import { computed, reactive, ref } from 'vue'; import { computed, reactive, ref } from 'vue';
import { ElMessageBox } from 'element-plus';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -24,6 +23,7 @@ import { useFriendStore } from './friend';
import { useGameLogStore } from './gameLog'; import { useGameLogStore } from './gameLog';
import { useInstanceStore } from './instance'; import { useInstanceStore } from './instance';
import { useLocationStore } from './location'; import { useLocationStore } from './location';
import { useModalStore } from './modal';
import { useNotificationStore } from './notification'; import { useNotificationStore } from './notification';
import { useSharedFeedStore } from './sharedFeed'; import { useSharedFeedStore } from './sharedFeed';
import { useUserStore } from './user'; import { useUserStore } from './user';
@@ -39,6 +39,7 @@ export const usePhotonStore = defineStore('Photon', () => {
const friendStore = useFriendStore(); const friendStore = useFriendStore();
const instanceStore = useInstanceStore(); const instanceStore = useInstanceStore();
const gameLogStore = useGameLogStore(); const gameLogStore = useGameLogStore();
const modalStore = useModalStore();
const notificationStore = useNotificationStore(); const notificationStore = useNotificationStore();
const locationStore = useLocationStore(); const locationStore = useLocationStore();
const sharedFeedStore = useSharedFeedStore(); const sharedFeedStore = useSharedFeedStore();
@@ -440,24 +441,21 @@ export const usePhotonStore = defineStore('Photon', () => {
} }
function promptPhotonOverlayMessageTimeout() { function promptPhotonOverlayMessageTimeout() {
ElMessageBox.prompt( modalStore
t('prompt.overlay_message_timeout.description'), .prompt({
t('prompt.overlay_message_timeout.header'), title: t('prompt.overlay_message_timeout.header'),
{ description: t('prompt.overlay_message_timeout.description'),
distinguishCancelAndClose: true, confirmText: t('prompt.overlay_message_timeout.ok'),
confirmButtonText: t('prompt.overlay_message_timeout.ok'), cancelText: t('prompt.overlay_message_timeout.cancel'),
cancelButtonText: t('prompt.overlay_message_timeout.cancel'),
inputValue: ( inputValue: (
state.photonOverlayMessageTimeout / 1000 state.photonOverlayMessageTimeout / 1000
).toString(), ).toString(),
inputPattern: /\d+$/, pattern: /\d+$/,
inputErrorMessage: t( errorMessage: t('prompt.overlay_message_timeout.input_error')
'prompt.overlay_message_timeout.input_error' })
) .then(({ ok, value }) => {
} if (!ok) return;
) if (value && !isNaN(Number(value))) {
.then(({ value, action }) => {
if (action === 'confirm' && value && !isNaN(Number(value))) {
state.photonOverlayMessageTimeout = Math.trunc( state.photonOverlayMessageTimeout = Math.trunc(
Number(value) * 1000 Number(value) * 1000
); );
@@ -468,22 +466,21 @@ export const usePhotonStore = defineStore('Photon', () => {
} }
function promptPhotonLobbyTimeoutThreshold() { function promptPhotonLobbyTimeoutThreshold() {
ElMessageBox.prompt( modalStore
t('prompt.photon_lobby_timeout.description'), .prompt({
t('prompt.photon_lobby_timeout.header'), title: t('prompt.photon_lobby_timeout.header'),
{ description: t('prompt.photon_lobby_timeout.description'),
distinguishCancelAndClose: true, confirmText: t('prompt.photon_lobby_timeout.ok'),
confirmButtonText: t('prompt.photon_lobby_timeout.ok'), cancelText: t('prompt.photon_lobby_timeout.cancel'),
cancelButtonText: t('prompt.photon_lobby_timeout.cancel'),
inputValue: ( inputValue: (
state.photonLobbyTimeoutThreshold / 1000 state.photonLobbyTimeoutThreshold / 1000
).toString(), ).toString(),
inputPattern: /\d+$/, pattern: /\d+$/,
inputErrorMessage: t('prompt.photon_lobby_timeout.input_error') errorMessage: t('prompt.photon_lobby_timeout.input_error')
} })
) .then(({ ok, value }) => {
.then(({ value, action }) => { if (!ok) return;
if (action === 'confirm' && value && !isNaN(Number(value))) { if (value && !isNaN(Number(value))) {
state.photonLobbyTimeoutThreshold = Math.trunc( state.photonLobbyTimeoutThreshold = Math.trunc(
Number(value) * 1000 Number(value) * 1000
); );

View File

@@ -1,5 +1,4 @@
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { ElMessageBox } from 'element-plus';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -13,6 +12,7 @@ import { useAppearanceSettingsStore } from './settings/appearance';
import { useAvatarStore } from './avatar'; import { useAvatarStore } from './avatar';
import { useFriendStore } from './friend'; import { useFriendStore } from './friend';
import { useGroupStore } from './group'; import { useGroupStore } from './group';
import { useModalStore } from './modal';
import { useUserStore } from './user'; import { useUserStore } from './user';
import { useWorldStore } from './world'; import { useWorldStore } from './world';
import { watchState } from '../service/watchState'; import { watchState } from '../service/watchState';
@@ -25,6 +25,7 @@ export const useSearchStore = defineStore('Search', () => {
const worldStore = useWorldStore(); const worldStore = useWorldStore();
const avatarStore = useAvatarStore(); const avatarStore = useAvatarStore();
const groupStore = useGroupStore(); const groupStore = useGroupStore();
const modalStore = useModalStore();
const { t } = useI18n(); const { t } = useI18n();
const searchText = ref(''); const searchText = ref('');
@@ -350,22 +351,20 @@ export const useSearchStore = defineStore('Search', () => {
async function promptOmniDirectDialog() { async function promptOmniDirectDialog() {
if (directAccessPrompt.value) return; if (directAccessPrompt.value) return;
directAccessPrompt.value = ElMessageBox.prompt( // Element Plus: prompt(message, title, options)
t('prompt.direct_access_omni.description'), directAccessPrompt.value = modalStore.prompt({
t('prompt.direct_access_omni.header'), title: t('prompt.direct_access_omni.header'),
{ description: t('prompt.direct_access_omni.description'),
distinguishCancelAndClose: true, confirmText: t('prompt.direct_access_omni.ok'),
confirmButtonText: t('prompt.direct_access_omni.ok'), cancelText: t('prompt.direct_access_omni.cancel'),
cancelButtonText: t('prompt.direct_access_omni.cancel'), pattern: /\S+/,
inputPattern: /\S+/, errorMessage: t('prompt.direct_access_omni.input_error')
inputErrorMessage: t('prompt.direct_access_omni.input_error') });
}
);
try { try {
const { value, action } = await directAccessPrompt.value; const { ok, value } = await directAccessPrompt.value;
if (action === 'confirm' && value) { if (ok && value) {
const input = value.trim(); const input = value.trim();
if (!directAccessParse(input)) { if (!directAccessParse(input)) {
toast.error(t('prompt.direct_access_omni.message.error')); toast.error(t('prompt.direct_access_omni.message.error'));

View File

@@ -1,5 +1,4 @@
import { reactive, ref, watch } from 'vue'; import { reactive, ref, watch } from 'vue';
import { ElMessageBox } from 'element-plus';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -855,23 +854,22 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => {
} }
function promptAutoClearVRCXCacheFrequency() { function promptAutoClearVRCXCacheFrequency() {
ElMessageBox.prompt( modalStore
t('prompt.auto_clear_cache.description'), .prompt({
t('prompt.auto_clear_cache.header'), title: t('prompt.auto_clear_cache.header'),
{ description: t('prompt.auto_clear_cache.description'),
distinguishCancelAndClose: true, confirmText: t('prompt.auto_clear_cache.ok'),
confirmButtonText: t('prompt.auto_clear_cache.ok'), cancelText: t('prompt.auto_clear_cache.cancel'),
cancelButtonText: t('prompt.auto_clear_cache.cancel'),
inputValue: ( inputValue: (
vrcxStore.clearVRCXCacheFrequency / vrcxStore.clearVRCXCacheFrequency /
3600 / 3600 /
2 2
).toString(), ).toString(),
inputPattern: /\d+$/, pattern: /\d+$/,
inputErrorMessage: t('prompt.auto_clear_cache.input_error') errorMessage: t('prompt.auto_clear_cache.input_error')
} })
) .then(async ({ ok, value }) => {
.then(async ({ value }) => { if (!ok) return;
if (value && !isNaN(parseInt(value, 10))) { if (value && !isNaN(parseInt(value, 10))) {
vrcxStore.clearVRCXCacheFrequency = Math.trunc( vrcxStore.clearVRCXCacheFrequency = Math.trunc(
parseInt(value, 10) * 3600 * 2 parseInt(value, 10) * 3600 * 2

View File

@@ -1,5 +1,4 @@
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { ElMessageBox } from 'element-plus';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
@@ -17,6 +16,7 @@ import { loadLocalizedStrings } from '../../plugin';
import { useElementTheme } from '../../composables/useElementTheme'; import { useElementTheme } from '../../composables/useElementTheme';
import { useFeedStore } from '../feed'; import { useFeedStore } from '../feed';
import { useGameLogStore } from '../gameLog'; import { useGameLogStore } from '../gameLog';
import { useModalStore } from '../modal';
import { useUiStore } from '../ui'; import { useUiStore } from '../ui';
import { useUserStore } from '../user'; import { useUserStore } from '../user';
import { useVrStore } from '../vr'; import { useVrStore } from '../vr';
@@ -36,6 +36,7 @@ export const useAppearanceSettingsStore = defineStore(
const userStore = useUserStore(); const userStore = useUserStore();
const router = useRouter(); const router = useRouter();
const uiStore = useUiStore(); const uiStore = useUiStore();
const modalStore = useModalStore();
const { t, locale } = useI18n(); const { t, locale } = useI18n();
@@ -746,19 +747,18 @@ export const useAppearanceSettingsStore = defineStore(
} }
function promptMaxTableSizeDialog() { function promptMaxTableSizeDialog() {
ElMessageBox.prompt( modalStore
t('prompt.change_table_size.description'), .prompt({
t('prompt.change_table_size.header'), title: t('prompt.change_table_size.header'),
{ description: t('prompt.change_table_size.description'),
distinguishCancelAndClose: true, confirmText: t('prompt.change_table_size.save'),
confirmButtonText: t('prompt.change_table_size.save'), cancelText: t('prompt.change_table_size.cancel'),
cancelButtonText: t('prompt.change_table_size.cancel'),
inputValue: vrcxStore.maxTableSize.toString(), inputValue: vrcxStore.maxTableSize.toString(),
inputPattern: /\d+$/, pattern: /\d+$/,
inputErrorMessage: t('prompt.change_table_size.input_error') errorMessage: t('prompt.change_table_size.input_error')
} })
) .then(async ({ ok, value }) => {
.then(async ({ value }) => { if (!ok) return;
if (value) { if (value) {
let processedValue = Number(value); let processedValue = Number(value);
if (processedValue > 10000) { if (processedValue > 10000) {

View File

@@ -1,9 +1,9 @@
import { ElMessageBox } from 'element-plus';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { ref } from 'vue'; import { ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useFriendStore } from '../friend'; import { useFriendStore } from '../friend';
import { useModalStore } from '../modal';
import { useVRCXUpdaterStore } from '../vrcxUpdater'; import { useVRCXUpdaterStore } from '../vrcxUpdater';
import { useVrcxStore } from '../vrcx'; import { useVrcxStore } from '../vrcx';
@@ -15,6 +15,7 @@ export const useGeneralSettingsStore = defineStore('GeneralSettings', () => {
const vrcxStore = useVrcxStore(); const vrcxStore = useVrcxStore();
const VRCXUpdaterStore = useVRCXUpdaterStore(); const VRCXUpdaterStore = useVRCXUpdaterStore();
const friendStore = useFriendStore(); const friendStore = useFriendStore();
const modalStore = useModalStore();
const { t } = useI18n(); const { t } = useI18n();
@@ -231,32 +232,32 @@ export const useGeneralSettingsStore = defineStore('GeneralSettings', () => {
} }
function promptProxySettings() { function promptProxySettings() {
ElMessageBox.prompt( // Element Plus: prompt(message, title, options)
t('prompt.proxy_settings.description'), modalStore
t('prompt.proxy_settings.header'), .prompt({
{ title: t('prompt.proxy_settings.header'),
distinguishCancelAndClose: true, description: t('prompt.proxy_settings.description'),
confirmButtonText: t('prompt.proxy_settings.restart'), confirmText: t('prompt.proxy_settings.restart'),
cancelButtonText: t('prompt.proxy_settings.close'), cancelText: t('prompt.proxy_settings.close'),
inputValue: vrcxStore.proxyServer, inputValue: vrcxStore.proxyServer
inputPlaceholder: t('prompt.proxy_settings.placeholder')
}
)
.then(async ({ value }) => {
vrcxStore.proxyServer = value;
await VRCXStorage.Set(
'VRCX_ProxyServer',
vrcxStore.proxyServer
);
await VRCXStorage.Save();
await new Promise((resolve) => {
workerTimers.setTimeout(resolve, 100);
});
const { restartVRCX } = VRCXUpdaterStore;
const isUpgrade = false;
restartVRCX(isUpgrade);
}) })
.catch(async () => { .then(async ({ ok, value }) => {
if (ok) {
vrcxStore.proxyServer = value;
await VRCXStorage.Set(
'VRCX_ProxyServer',
vrcxStore.proxyServer
);
await VRCXStorage.Save();
await new Promise((resolve) => {
workerTimers.setTimeout(resolve, 100);
});
const { restartVRCX } = VRCXUpdaterStore;
const isUpgrade = false;
restartVRCX(isUpgrade);
return;
}
// User clicked close/cancel, still save the value but don't restart // User clicked close/cancel, still save the value but don't restart
if (vrcxStore.proxyServer !== undefined) { if (vrcxStore.proxyServer !== undefined) {
await VRCXStorage.Set( await VRCXStorage.Set(
@@ -268,6 +269,9 @@ export const useGeneralSettingsStore = defineStore('GeneralSettings', () => {
workerTimers.setTimeout(resolve, 100); workerTimers.setTimeout(resolve, 100);
}); });
} }
})
.catch((err) => {
console.error(err);
}); });
} }

View File

@@ -1,9 +1,9 @@
import { ElMessageBox } from 'element-plus';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { ref } from 'vue'; import { ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { sharedFeedFiltersDefaults } from '../../shared/constants'; import { sharedFeedFiltersDefaults } from '../../shared/constants';
import { useModalStore } from '../modal';
import { useVrStore } from '../vr'; import { useVrStore } from '../vr';
import configRepository from '../../service/config'; import configRepository from '../../service/config';
@@ -12,6 +12,7 @@ export const useNotificationsSettingsStore = defineStore(
'NotificationsSettings', 'NotificationsSettings',
() => { () => {
const vrStore = useVrStore(); const vrStore = useVrStore();
const modalStore = useModalStore();
const { t } = useI18n(); const { t } = useI18n();
@@ -410,21 +411,18 @@ export const useNotificationsSettingsStore = defineStore(
} }
function promptNotificationTimeout() { function promptNotificationTimeout() {
ElMessageBox.prompt( modalStore
t('prompt.notification_timeout.description'), .prompt({
t('prompt.notification_timeout.header'), title: t('prompt.notification_timeout.header'),
{ description: t('prompt.notification_timeout.description'),
distinguishCancelAndClose: true, confirmText: t('prompt.notification_timeout.ok'),
confirmButtonText: t('prompt.notification_timeout.ok'), cancelText: t('prompt.notification_timeout.cancel'),
cancelButtonText: t('prompt.notification_timeout.cancel'),
inputValue: notificationTimeout.value / 1000, inputValue: notificationTimeout.value / 1000,
inputPattern: /\d+$/, pattern: /\d+$/,
inputErrorMessage: t( errorMessage: t('prompt.notification_timeout.input_error')
'prompt.notification_timeout.input_error' })
) .then(async ({ ok, value }) => {
} if (!ok) return;
)
.then(async ({ value }) => {
if (value && !isNaN(value)) { if (value && !isNaN(value)) {
notificationTimeout.value = Math.trunc( notificationTimeout.value = Math.trunc(
Number(value) * 1000 Number(value) * 1000

View File

@@ -529,7 +529,6 @@
import { ArrowUpDown, Check, Ellipsis, Loader, MoreHorizontal, Plus, RefreshCcw, RefreshCw } from 'lucide-vue-next'; import { ArrowUpDown, Check, Ellipsis, Loader, MoreHorizontal, Plus, RefreshCcw, RefreshCw } from 'lucide-vue-next';
import { InputGroupField, InputGroupSearch } from '@/components/ui/input-group'; import { InputGroupField, InputGroupSearch } from '@/components/ui/input-group';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { ElMessageBox } from 'element-plus';
import { Spinner } from '@/components/ui/spinner'; import { Spinner } from '@/components/ui/spinner';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
@@ -1344,19 +1343,18 @@
function changeFavoriteGroupName(group) { function changeFavoriteGroupName(group) {
const currentName = group.displayName || group.name; const currentName = group.displayName || group.name;
ElMessageBox.prompt( modalStore
t('prompt.change_favorite_group_name.description'), .prompt({
t('prompt.change_favorite_group_name.header'), title: t('prompt.change_favorite_group_name.header'),
{ description: t('prompt.change_favorite_group_name.description'),
confirmButtonText: t('prompt.change_favorite_group_name.change'), confirmText: t('prompt.change_favorite_group_name.change'),
cancelButtonText: t('prompt.change_favorite_group_name.cancel'), cancelText: t('prompt.change_favorite_group_name.cancel'),
inputPlaceholder: t('prompt.change_favorite_group_name.input_placeholder'), pattern: /\S+/,
inputPattern: /\S+/,
inputValue: currentName, inputValue: currentName,
inputErrorMessage: t('prompt.change_favorite_group_name.input_error') errorMessage: t('prompt.change_favorite_group_name.input_error')
} })
) .then(({ ok, value }) => {
.then(({ value }) => { if (!ok) return;
const newName = value.trim(); const newName = value.trim();
if (!newName || newName === currentName) { if (!newName || newName === currentName) {
return; return;
@@ -1419,19 +1417,18 @@
} }
function promptLocalAvatarFavoriteGroupRename(group) { function promptLocalAvatarFavoriteGroupRename(group) {
ElMessageBox.prompt( modalStore
t('prompt.local_favorite_group_rename.description'), .prompt({
t('prompt.local_favorite_group_rename.header'), title: t('prompt.local_favorite_group_rename.header'),
{ description: t('prompt.local_favorite_group_rename.description'),
distinguishCancelAndClose: true, confirmText: t('prompt.local_favorite_group_rename.save'),
confirmButtonText: t('prompt.local_favorite_group_rename.save'), cancelText: t('prompt.local_favorite_group_rename.cancel'),
cancelButtonText: t('prompt.local_favorite_group_rename.cancel'), pattern: /\S+/,
inputPattern: /\S+/, errorMessage: t('prompt.local_favorite_group_rename.input_error'),
inputErrorMessage: t('prompt.local_favorite_group_rename.input_error'),
inputValue: group inputValue: group
} })
) .then(({ ok, value }) => {
.then(({ value }) => { if (!ok) return;
if (value) { if (value) {
renameLocalAvatarFavoriteGroup(value, group); renameLocalAvatarFavoriteGroup(value, group);
nextTick(() => { nextTick(() => {

View File

@@ -312,7 +312,6 @@
import { computed, nextTick, onBeforeMount, onMounted, onUnmounted, ref, watch } from 'vue'; import { computed, nextTick, onBeforeMount, onMounted, onUnmounted, ref, watch } from 'vue';
import { ArrowUpDown, Check, Ellipsis, MoreHorizontal, RefreshCw } from 'lucide-vue-next'; import { ArrowUpDown, Check, Ellipsis, MoreHorizontal, RefreshCw } from 'lucide-vue-next';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { ElMessageBox } from 'element-plus';
import { InputGroupSearch } from '@/components/ui/input-group'; import { InputGroupSearch } from '@/components/ui/input-group';
import { Spinner } from '@/components/ui/spinner'; import { Spinner } from '@/components/ui/spinner';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@@ -809,19 +808,18 @@
function changeFavoriteGroupName(group) { function changeFavoriteGroupName(group) {
const currentName = group.displayName || group.name; const currentName = group.displayName || group.name;
ElMessageBox.prompt( modalStore
t('prompt.change_favorite_group_name.description'), .prompt({
t('prompt.change_favorite_group_name.header'), title: t('prompt.change_favorite_group_name.header'),
{ description: t('prompt.change_favorite_group_name.description'),
confirmButtonText: t('prompt.change_favorite_group_name.change'), confirmText: t('prompt.change_favorite_group_name.change'),
cancelButtonText: t('prompt.change_favorite_group_name.cancel'), cancelText: t('prompt.change_favorite_group_name.cancel'),
inputPlaceholder: t('prompt.change_favorite_group_name.input_placeholder'), pattern: /\S+/,
inputPattern: /\S+/,
inputValue: currentName, inputValue: currentName,
inputErrorMessage: t('prompt.change_favorite_group_name.input_error') errorMessage: t('prompt.change_favorite_group_name.input_error')
} })
) .then(({ ok, value }) => {
.then(({ value }) => { if (!ok) return;
const newName = value.trim(); const newName = value.trim();
if (!newName || newName === currentName) { if (!newName || newName === currentName) {
return; return;

View File

@@ -440,7 +440,6 @@
import { ArrowUpDown, Ellipsis, MoreHorizontal, Plus, RefreshCcw, RefreshCw } from 'lucide-vue-next'; import { ArrowUpDown, Ellipsis, MoreHorizontal, Plus, RefreshCcw, RefreshCw } from 'lucide-vue-next';
import { InputGroupField, InputGroupSearch } from '@/components/ui/input-group'; import { InputGroupField, InputGroupSearch } from '@/components/ui/input-group';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { ElMessageBox } from 'element-plus';
import { Spinner } from '@/components/ui/spinner'; import { Spinner } from '@/components/ui/spinner';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
@@ -1145,19 +1144,18 @@
} }
function promptLocalWorldFavoriteGroupRename(group) { function promptLocalWorldFavoriteGroupRename(group) {
ElMessageBox.prompt( modalStore
t('prompt.local_favorite_group_rename.description'), .prompt({
t('prompt.local_favorite_group_rename.header'), title: t('prompt.local_favorite_group_rename.header'),
{ description: t('prompt.local_favorite_group_rename.description'),
distinguishCancelAndClose: true, confirmText: t('prompt.local_favorite_group_rename.save'),
confirmButtonText: t('prompt.local_favorite_group_rename.save'), cancelText: t('prompt.local_favorite_group_rename.cancel'),
cancelButtonText: t('prompt.local_favorite_group_rename.cancel'), pattern: /\S+/,
inputPattern: /\S+/, errorMessage: t('prompt.local_favorite_group_rename.input_error'),
inputErrorMessage: t('prompt.local_favorite_group_rename.input_error'),
inputValue: group inputValue: group
} })
) .then(({ ok, value }) => {
.then(({ value }) => { if (!ok) return;
if (value) { if (value) {
renameLocalWorldFavoriteGroup(value, group); renameLocalWorldFavoriteGroup(value, group);
nextTick(() => { nextTick(() => {
@@ -1238,19 +1236,18 @@
function changeFavoriteGroupName(group) { function changeFavoriteGroupName(group) {
const currentName = group.displayName || group.name; const currentName = group.displayName || group.name;
ElMessageBox.prompt( modalStore
t('prompt.change_favorite_group_name.description'), .prompt({
t('prompt.change_favorite_group_name.header'), title: t('prompt.change_favorite_group_name.header'),
{ description: t('prompt.change_favorite_group_name.description'),
confirmButtonText: t('prompt.change_favorite_group_name.change'), confirmText: t('prompt.change_favorite_group_name.change'),
cancelButtonText: t('prompt.change_favorite_group_name.cancel'), cancelText: t('prompt.change_favorite_group_name.cancel'),
inputPlaceholder: t('prompt.change_favorite_group_name.input_placeholder'), pattern: /\S+/,
inputPattern: /\S+/,
inputValue: currentName, inputValue: currentName,
inputErrorMessage: t('prompt.change_favorite_group_name.input_error') errorMessage: t('prompt.change_favorite_group_name.input_error')
} })
) .then(({ ok, value }) => {
.then(({ value }) => { if (!ok) return;
const newName = value.trim(); const newName = value.trim();
if (!newName || newName === currentName) { if (!newName || newName === currentName) {
return; return;

View File

@@ -88,7 +88,7 @@ function DetailCell({ row, isPrevious, onShowAvatar, onShowGroup, onShowWorld, o
></i> ></i>
</TooltipWrapper> </TooltipWrapper>
<span> <span>
<ArrowRight / /> <ArrowRight />
</span> </span>
<TooltipWrapper <TooltipWrapper
side="top" side="top"
@@ -126,7 +126,7 @@ function DetailCell({ row, isPrevious, onShowAvatar, onShowGroup, onShowWorld, o
{r.previousGroupName || r.previousGroupId} {r.previousGroupName || r.previousGroupId}
</span> </span>
<span> <span>
<ArrowRight / /> <ArrowRight />
</span> </span>
<span <span
class="x-link" class="x-link"
@@ -179,7 +179,6 @@ function DetailCell({ row, isPrevious, onShowAvatar, onShowGroup, onShowWorld, o
Android&nbsp; Android&nbsp;
</span> </span>
) : null} ) : null}
<span <span
class="x-link" class="x-link"
onClick={(e) => { onClick={(e) => {
@@ -192,7 +191,7 @@ function DetailCell({ row, isPrevious, onShowAvatar, onShowGroup, onShowWorld, o
&nbsp; &nbsp;
{!r.inCache ? ( {!r.inCache ? (
<span style="color: #aaa"> <span style="color: #aaa">
<Download / /> <Download />
&nbsp; &nbsp;
</span> </span>
) : null} ) : null}

View File

@@ -50,7 +50,6 @@
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { DataTableLayout } from '@/components/ui/data-table'; import { DataTableLayout } from '@/components/ui/data-table';
import { ElMessageBox } from 'element-plus';
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';
@@ -178,12 +177,16 @@
} }
function promptVrcRegistryBackupName() { function promptVrcRegistryBackupName() {
ElMessageBox.prompt('Enter a name for the backup', 'Backup Name', { modalStore
inputPattern: /\S+/, .prompt({
inputErrorMessage: 'Name is required', title: 'Backup Name',
inputValue: 'Backup' description: 'Enter a name for the backup',
}) inputValue: 'Backup',
.then(({ value }) => { pattern: /\S+/,
errorMessage: 'Name is required'
})
.then(({ ok, value }) => {
if (!ok) return;
handleBackupVrcRegistry(value); handleBackupVrcRegistry(value);
}) })
.catch(() => {}); .catch(() => {});

View File

@@ -580,7 +580,6 @@
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { ButtonGroup } from '@/components/ui/button-group'; import { ButtonGroup } from '@/components/ui/button-group';
import { Checkbox } from '@/components/ui/checkbox'; import { Checkbox } from '@/components/ui/checkbox';
import { ElMessageBox } from 'element-plus';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
import { TabsUnderline } from '@/components/ui/tabs'; import { TabsUnderline } from '@/components/ui/tabs';
import { VirtualCombobox } from '@/components/ui/virtual-combobox'; import { VirtualCombobox } from '@/components/ui/virtual-combobox';
@@ -597,7 +596,7 @@
openExternalLink openExternalLink
} from '../../shared/utils'; } from '../../shared/utils';
import { inventoryRequest, miscRequest, userRequest, vrcPlusIconRequest, vrcPlusImageRequest } from '../../api'; import { inventoryRequest, miscRequest, userRequest, vrcPlusIconRequest, vrcPlusImageRequest } from '../../api';
import { useAdvancedSettingsStore, useAuthStore, useGalleryStore, useUserStore } from '../../stores'; import { useAdvancedSettingsStore, useAuthStore, useGalleryStore, useModalStore, useUserStore } from '../../stores';
import { emojiAnimationStyleList, emojiAnimationStyleUrl } from '../../shared/constants'; import { emojiAnimationStyleList, emojiAnimationStyleUrl } from '../../shared/constants';
import { AppDebug } from '../../service/appConfig'; import { AppDebug } from '../../service/appConfig';
import { handleImageUploadInput } from '../../shared/utils/imageUpload'; import { handleImageUploadInput } from '../../shared/utils/imageUpload';
@@ -606,6 +605,7 @@
const { t } = useI18n(); const { t } = useI18n();
const router = useRouter(); const router = useRouter();
const modalStore = useModalStore();
const { const {
galleryTable, galleryTable,
@@ -1161,11 +1161,15 @@
} }
async function redeemReward() { async function redeemReward() {
ElMessageBox.prompt(t('prompt.redeem.description'), t('prompt.redeem.header'), { modalStore
confirmButtonText: t('prompt.redeem.redeem'), .prompt({
cancelButtonText: t('prompt.redeem.cancel') title: t('prompt.redeem.header'),
}) description: t('prompt.redeem.description'),
.then(({ value }) => { confirmText: t('prompt.redeem.redeem'),
cancelText: t('prompt.redeem.cancel')
})
.then(({ ok, value }) => {
if (!ok) return;
if (value) { if (value) {
inventoryRequest inventoryRequest
.redeemReward({ .redeemReward({