replace el-dialog

This commit is contained in:
pa
2026-01-15 15:33:20 +09:00
committed by Natsumi
parent fc13dca0a4
commit 3b47d3a0eb
67 changed files with 7034 additions and 6769 deletions

View File

@@ -1,11 +1,9 @@
<template> <template>
<el-dialog <Dialog v-model:open="avatarDialog.visible">
:z-index="avatarDialogIndex" <DialogContent
class="x-dialog x-avatar-dialog" class="x-dialog x-avatar-dialog sm:max-w-235 translate-y-0"
v-model="avatarDialog.visible" style="top: 10vh"
:show-close="false" :show-close-button="false">
top="10vh"
width="940px">
<div v-loading="avatarDialog.loading"> <div v-loading="avatarDialog.loading">
<div style="display: flex"> <div style="display: flex">
<img <img
@@ -108,9 +106,11 @@
variant="outline" variant="outline"
style="margin-right: 5px; margin-top: 5px" style="margin-right: 5px; margin-top: 5px"
>Styles >Styles
<span v-if="avatarDialog.ref.styles.primary" :class="['x-grey', 'x-tag-border-left']">{{ <span
avatarDialog.ref.styles.primary v-if="avatarDialog.ref.styles.primary"
}}</span> :class="['x-grey', 'x-tag-border-left']"
>{{ avatarDialog.ref.styles.primary }}</span
>
<span <span
v-if="avatarDialog.ref.styles.secondary" v-if="avatarDialog.ref.styles.secondary"
:class="['x-grey', 'x-tag-border-left']" :class="['x-grey', 'x-tag-border-left']"
@@ -355,7 +355,9 @@
<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">
<CarouselItem v-for="imageUrl in avatarDialog.galleryImages" :key="imageUrl"> <CarouselItem
v-for="imageUrl in avatarDialog.galleryImages"
:key="imageUrl">
<div class="relative h-50 w-full"> <div class="relative h-50 w-full">
<img <img
:src="imageUrl" :src="imageUrl"
@@ -397,7 +399,9 @@
</div> </div>
<div class="x-friend-item" style="width: 100%; cursor: default"> <div class="x-friend-item" style="width: 100%; cursor: default">
<div class="detail"> <div class="detail">
<span class="name" style="margin-bottom: 5px">{{ t('dialog.avatar.info.memo') }}</span> <span class="name" style="margin-bottom: 5px">{{
t('dialog.avatar.info.memo')
}}</span>
<InputGroupTextareaField <InputGroupTextareaField
v-model="memo" v-model="memo"
class="extra" class="extra"
@@ -439,7 +443,9 @@
<div class="x-friend-item" style="cursor: default"> <div class="x-friend-item" style="cursor: default">
<div class="detail"> <div class="detail">
<span class="name">{{ t('dialog.avatar.info.created_at') }}</span> <span class="name">{{ t('dialog.avatar.info.created_at') }}</span>
<span class="extra">{{ formatDateFilter(avatarDialog.ref.created_at, 'long') }}</span> <span class="extra">{{
formatDateFilter(avatarDialog.ref.created_at, 'long')
}}</span>
</div> </div>
</div> </div>
<div class="x-friend-item" style="cursor: default"> <div class="x-friend-item" style="cursor: default">
@@ -478,7 +484,10 @@
<div class="x-friend-item" style="width: 100%; cursor: default"> <div class="x-friend-item" style="width: 100%; cursor: default">
<div class="detail"> <div class="detail">
<span class="name">{{ t('dialog.avatar.info.platform') }}</span> <span class="name">{{ t('dialog.avatar.info.platform') }}</span>
<span v-if="avatarDialogPlatform" class="extra" v-text="avatarDialogPlatform"></span> <span
v-if="avatarDialogPlatform"
class="extra"
v-text="avatarDialogPlatform"></span>
<span v-else class="extra">-</span> <span v-else class="extra">-</span>
</div> </div>
</div> </div>
@@ -509,7 +518,6 @@
show-icon /> show-icon />
</template> </template>
</TabsUnderline> </TabsUnderline>
</div>
<template v-if="avatarDialog.visible"> <template v-if="avatarDialog.visible">
<SetAvatarTagsDialog v-model:setAvatarTagsDialog="setAvatarTagsDialog" /> <SetAvatarTagsDialog v-model:setAvatarTagsDialog="setAvatarTagsDialog" />
<SetAvatarStylesDialog v-model:setAvatarStylesDialog="setAvatarStylesDialog" /> <SetAvatarStylesDialog v-model:setAvatarStylesDialog="setAvatarStylesDialog" />
@@ -517,7 +525,9 @@
v-model:changeAvatarImageDialogVisible="changeAvatarImageDialogVisible" v-model:changeAvatarImageDialogVisible="changeAvatarImageDialogVisible"
v-model:previousImageUrl="previousImageUrl" /> v-model:previousImageUrl="previousImageUrl" />
</template> </template>
</el-dialog> </div>
</DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
@@ -544,6 +554,7 @@
} from 'lucide-vue-next'; } from 'lucide-vue-next';
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 { Dialog, DialogContent } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
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';
@@ -557,9 +568,7 @@
commaNumber, commaNumber,
copyToClipboard, copyToClipboard,
downloadAndSaveJson, downloadAndSaveJson,
extractFileId,
formatDateFilter, formatDateFilter,
moveArrayItem,
openExternalLink, openExternalLink,
openFolderGeneric, openFolderGeneric,
replaceVrcPackageUrl, replaceVrcPackageUrl,
@@ -581,11 +590,11 @@
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger DropdownMenuTrigger
} from '../../ui/dropdown-menu'; } from '../../ui/dropdown-menu';
import { avatarModerationRequest, avatarRequest, favoriteRequest, miscRequest } from '../../../api'; import { avatarModerationRequest, avatarRequest, favoriteRequest } from '../../../api';
import { formatJsonVars, getNextDialogIndex } from '../../../shared/utils/base/ui';
import { AppDebug } from '../../../service/appConfig.js'; import { AppDebug } from '../../../service/appConfig.js';
import { Badge } from '../../ui/badge'; import { Badge } from '../../ui/badge';
import { database } from '../../../service/database'; import { database } from '../../../service/database';
import { formatJsonVars } from '../../../shared/utils/base/ui';
import { handleImageUploadInput } from '../../../shared/utils/imageUpload'; import { handleImageUploadInput } from '../../../shared/utils/imageUpload';
const ChangeAvatarImageDialog = defineAsyncComponent(() => import('./ChangeAvatarImageDialog.vue')); const ChangeAvatarImageDialog = defineAsyncComponent(() => import('./ChangeAvatarImageDialog.vue'));
@@ -612,7 +621,6 @@
{ value: 'JSON', label: t('dialog.avatar.json.header') } { value: 'JSON', label: t('dialog.avatar.json.header') }
]); ]);
const avatarDialogIndex = ref(2000);
const avatarDialogLastActiveTab = ref('Info'); const avatarDialogLastActiveTab = ref('Info');
const changeAvatarImageDialogVisible = ref(false); const changeAvatarImageDialogVisible = ref(false);
const previousImageUrl = ref(''); const previousImageUrl = ref('');
@@ -677,9 +685,6 @@
() => avatarDialog.value.loading, () => avatarDialog.value.loading,
() => { () => {
if (avatarDialog.value.visible) { if (avatarDialog.value.visible) {
nextTick(() => {
avatarDialogIndex.value = getNextDialogIndex();
});
handleDialogOpen(); handleDialogOpen();
!avatarDialog.value.loading && loadLastActiveTab(); !avatarDialog.value.loading && loadLastActiveTab();
} }
@@ -1126,44 +1131,4 @@
resetLoading(); resetLoading();
} }
} }
function reorderAvatarGalleryImage(imageUrl, direction) {
const fileId = extractFileId(imageUrl);
let fileIds = [];
avatarDialog.value.ref.gallery.forEach((item) => {
fileIds.push(extractFileId(item.id));
});
const index = fileIds.indexOf(fileId);
if (index === -1) {
toast.error(t('message.avatar_gallery.not_found'));
return;
}
if (direction === -1 && index === 0) {
toast.warning(t('message.avatar_gallery.already_first'));
return;
}
if (direction === 1 && index === fileIds.length - 1) {
toast.warning(t('message.avatar_gallery.already_last'));
return;
}
if (direction === -1) {
moveArrayItem(fileIds, index, index - 1);
} else {
moveArrayItem(fileIds, index, index + 1);
}
avatarRequest.setAvatarGalleryOrder(fileIds).then(async (args) => {
toast.success(t('message.avatar_gallery.reordered'));
avatarDialog.value.galleryImages = await getAvatarGallery(avatarDialog.value.id);
return args;
});
}
function deleteAvatarGalleryImage(imageUrl) {
const fileId = extractFileId(imageUrl);
miscRequest.deleteFile(fileId).then((args) => {
toast.success(t('message.avatar_gallery.deleted'));
getAvatarGallery(avatarDialog.value.id);
return args;
});
}
</script> </script>

View File

@@ -1,11 +1,14 @@
<template> <template>
<el-dialog <Dialog
class="x-dialog" :open="changeAvatarImageDialogVisible"
:model-value="changeAvatarImageDialogVisible" @update:open="(open) => {
:title="t('dialog.change_content_image.avatar')" if (!open) closeDialog();
width="850px" }">
append-to-body <DialogContent class="x-dialog sm:max-w-212.5">
@close="closeDialog"> <DialogHeader>
<DialogTitle>{{ t('dialog.change_content_image.avatar') }}</DialogTitle>
</DialogHeader>
<div> <div>
<input <input
id="AvatarImageUploadButton" id="AvatarImageUploadButton"
@@ -28,11 +31,13 @@
<img :src="previousImageUrl" class="img-size" loading="lazy" /> <img :src="previousImageUrl" class="img-size" loading="lazy" />
</div> </div>
</div> </div>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Upload } from 'lucide-vue-next'; import { Upload } from 'lucide-vue-next';
import { ref } from 'vue'; import { ref } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';

View File

@@ -1,12 +1,14 @@
<template> <template>
<el-dialog <Dialog
ref="setAvatarStylesDialog" :open="setAvatarStylesDialog.visible"
class="x-dialog" @update:open="(open) => {
:model-value="setAvatarStylesDialog.visible" if (!open) closeSetAvatarStylesDialog();
:title="t('dialog.set_avatar_styles.header')" }">
width="400px" <DialogContent class="x-dialog sm:max-w-100">
append-to-body <DialogHeader>
@close="closeSetAvatarStylesDialog"> <DialogTitle>{{ t('dialog.set_avatar_styles.header') }}</DialogTitle>
</DialogHeader>
<template v-if="setAvatarStylesDialog.visible"> <template v-if="setAvatarStylesDialog.visible">
<div> <div>
<span>{{ t('dialog.set_avatar_styles.primary_style') }}</span> <span>{{ t('dialog.set_avatar_styles.primary_style') }}</span>
@@ -66,19 +68,21 @@
@update:modelValue="(v) => updateDialog({ authorTags: v })" /> @update:modelValue="(v) => updateDialog({ authorTags: v })" />
</template> </template>
<template #footer> <DialogFooter>
<Button variant="secondary" class="mr-2" @click="closeSetAvatarStylesDialog">{{ <Button variant="secondary" class="mr-2" @click="closeSetAvatarStylesDialog">{{
t('dialog.set_avatar_styles.cancel') t('dialog.set_avatar_styles.cancel')
}}</Button> }}</Button>
<Button @click="saveSetAvatarStylesDialog"> <Button @click="saveSetAvatarStylesDialog">
{{ t('dialog.set_avatar_styles.save') }} {{ t('dialog.set_avatar_styles.save') }}
</Button> </Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';

View File

@@ -1,15 +1,21 @@
<template> <template>
<el-dialog <Dialog
ref="setAvatarTagsDialog" :open="setAvatarTagsDialog.visible"
class="x-dialog" @update:open="
:model-value="setAvatarTagsDialog.visible" (open) => {
@close="closeSetAvatarTagsDialog" if (!open) closeSetAvatarTagsDialog();
:title="t('dialog.set_avatar_tags.header')" }
width="780px" ">
append-to-body> <DialogContent class="x-dialog sm:max-w-195">
<DialogHeader>
<DialogTitle>{{ t('dialog.set_avatar_tags.header') }}</DialogTitle>
</DialogHeader>
<template v-if="setAvatarTagsDialog.visible"> <template v-if="setAvatarTagsDialog.visible">
<label class="inline-flex items-center gap-2"> <label class="inline-flex items-center gap-2">
<Checkbox v-model="setAvatarTagsDialog.contentHorror" @update:modelValue="updateSelectedAvatarTags" /> <Checkbox
v-model="setAvatarTagsDialog.contentHorror"
@update:modelValue="updateSelectedAvatarTags" />
<span>{{ t('dialog.set_avatar_tags.content_horror') }}</span> <span>{{ t('dialog.set_avatar_tags.content_horror') }}</span>
</label> </label>
<label class="inline-flex items-center gap-2"> <label class="inline-flex items-center gap-2">
@@ -17,11 +23,15 @@
<span>{{ t('dialog.set_avatar_tags.content_gore') }}</span> <span>{{ t('dialog.set_avatar_tags.content_gore') }}</span>
</label> </label>
<label class="inline-flex items-center gap-2"> <label class="inline-flex items-center gap-2">
<Checkbox v-model="setAvatarTagsDialog.contentViolence" @update:modelValue="updateSelectedAvatarTags" /> <Checkbox
v-model="setAvatarTagsDialog.contentViolence"
@update:modelValue="updateSelectedAvatarTags" />
<span>{{ t('dialog.set_avatar_tags.content_violence') }}</span> <span>{{ t('dialog.set_avatar_tags.content_violence') }}</span>
</label> </label>
<label class="inline-flex items-center gap-2"> <label class="inline-flex items-center gap-2">
<Checkbox v-model="setAvatarTagsDialog.contentAdult" @update:modelValue="updateSelectedAvatarTags" /> <Checkbox
v-model="setAvatarTagsDialog.contentAdult"
@update:modelValue="updateSelectedAvatarTags" />
<span>{{ t('dialog.set_avatar_tags.content_adult') }}</span> <span>{{ t('dialog.set_avatar_tags.content_adult') }}</span>
</label> </label>
<label class="inline-flex items-center gap-2"> <label class="inline-flex items-center gap-2">
@@ -87,16 +97,19 @@
</div> </div>
</div> </div>
</template> </template>
<template #footer>
<DialogFooter>
<Button variant="secondary" class="mr-2" @click="closeSetAvatarTagsDialog">{{ <Button variant="secondary" class="mr-2" @click="closeSetAvatarTagsDialog">{{
t('dialog.set_avatar_tags.cancel') t('dialog.set_avatar_tags.cancel')
}}</Button> }}</Button>
<Button @click="saveSetAvatarTagsDialog">{{ t('dialog.set_avatar_tags.save') }}</Button> <Button @click="saveSetAvatarTagsDialog">{{ t('dialog.set_avatar_tags.save') }}</Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox'; import { Checkbox } from '@/components/ui/checkbox';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';

View File

@@ -1,5 +1,9 @@
<template> <template>
<el-dialog :z-index="favoriteDialogIndex" v-model="isVisible" :title="t('dialog.favorite.header')" width="300px"> <Dialog v-model:open="isVisible">
<DialogContent>
<DialogHeader>
<DialogTitle>{{ t('dialog.favorite.header') }}</DialogTitle>
</DialogHeader>
<div v-loading="loading"> <div v-loading="loading">
<span style="display: block; text-align: center">{{ t('dialog.favorite.vrchat_favorites') }}</span> <span style="display: block; text-align: center">{{ t('dialog.favorite.vrchat_favorites') }}</span>
<template v-if="favoriteDialog.currentGroup && favoriteDialog.currentGroup.key"> <template v-if="favoriteDialog.currentGroup && favoriteDialog.currentGroup.key">
@@ -67,13 +71,15 @@
</Button> </Button>
</template> </template>
</div> </div>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { computed, nextTick, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Check } from 'lucide-vue-next'; import { Check } from 'lucide-vue-next';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -81,7 +87,6 @@
import { useFavoriteStore, useUserStore } from '../../stores'; import { useFavoriteStore, useUserStore } from '../../stores';
import { favoriteRequest } from '../../api'; import { favoriteRequest } from '../../api';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
const { t } = useI18n(); const { t } = useI18n();
@@ -107,7 +112,6 @@
} = favoriteStore; } = favoriteStore;
const { isLocalUserVrcPlusSupporter } = storeToRefs(useUserStore()); const { isLocalUserVrcPlusSupporter } = storeToRefs(useUserStore());
const favoriteDialogIndex = ref(2000);
const groups = ref([]); const groups = ref([]);
const loading = ref(false); const loading = ref(false);
@@ -123,9 +127,6 @@
(value) => { (value) => {
if (value) { if (value) {
initFavoriteDialog(); initFavoriteDialog();
nextTick(() => {
favoriteDialogIndex.value = getNextDialogIndex();
});
} }
} }
); );

View File

@@ -1,11 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="visible" @update:open="(open) => (open ? null : handleClose())">
:model-value="visible" <DialogContent class="custom-nav-dialog">
class="custom-nav-dialog" <DialogHeader>
:title="t('nav_menu.custom_nav.dialog_title')" <DialogTitle>{{ t('nav_menu.custom_nav.dialog_title') }}</DialogTitle>
width="600px" </DialogHeader>
@close="handleClose"
destroy-on-close>
<div class="custom-nav-dialog__list" v-if="localLayout.length"> <div class="custom-nav-dialog__list" v-if="localLayout.length">
<div <div
v-for="(entry, index) in localLayout" v-for="(entry, index) in localLayout"
@@ -90,7 +88,7 @@
type="warning" type="warning"
:closable="false" :closable="false"
:title="t('nav_menu.custom_nav.invalid_folder')" /> :title="t('nav_menu.custom_nav.invalid_folder')" />
<template #footer> <DialogFooter>
<div class="custom-nav-dialog__footer"> <div class="custom-nav-dialog__footer">
<div class="custom-nav-dialog__footer-left"> <div class="custom-nav-dialog__footer-left">
<Button variant="outline" @click="openFolderEditor()"> <Button variant="outline" @click="openFolderEditor()">
@@ -109,15 +107,21 @@
</Button> </Button>
</div> </div>
</div> </div>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
<el-dialog <Dialog v-model:open="folderEditor.visible">
v-model="folderEditor.visible" <DialogContent class="folder-editor-dialog">
class="folder-editor-dialog" <DialogHeader>
:title="folderEditor.isEditing ? t('nav_menu.custom_nav.edit_folder') : t('nav_menu.custom_nav.add_folder')" <DialogTitle>
width="900px" {{
destroy-on-close> folderEditor.isEditing
? t('nav_menu.custom_nav.edit_folder')
: t('nav_menu.custom_nav.add_folder')
}}
</DialogTitle>
</DialogHeader>
<div class="folder-editor"> <div class="folder-editor">
<div class="folder-editor__form"> <div class="folder-editor__form">
<InputGroupField <InputGroupField
@@ -189,7 +193,7 @@
</div> </div>
</div> </div>
</div> </div>
<template #footer> <DialogFooter>
<div class="folder-editor__footer"> <div class="folder-editor__footer">
<Button <Button
variant="destructive" variant="destructive"
@@ -206,13 +210,15 @@
{{ t('nav_menu.custom_nav.save') }} {{ t('nav_menu.custom_nav.save') }}
</Button> </Button>
</div> </div>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { computed, reactive, ref, watch } from 'vue'; import { computed, reactive, ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import dayjs from 'dayjs'; import dayjs from 'dayjs';

View File

@@ -1,10 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="gallerySelectDialog.visible">
class="x-dialog" <DialogContent class="x-dialog w-full sm:max-w-none">
v-model="gallerySelectDialog.visible" <DialogHeader>
:title="t('dialog.gallery_select.header')" <DialogTitle>{{ t('dialog.gallery_select.header') }}</DialogTitle>
width="100%" </DialogHeader>
append-to-body>
<div> <div>
<span>{{ t('dialog.gallery_select.gallery') }}</span> <span>{{ t('dialog.gallery_select.gallery') }}</span>
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{ galleryTable.length }}/64</span> <span style="color: #909399; font-size: 12px; margin-left: 5px">{{ galleryTable.length }}/64</span>
@@ -43,19 +43,24 @@
<div <div
v-if="image.versions[image.versions.length - 1].file.url" v-if="image.versions[image.versions.length - 1].file.url"
class="vrcplus-icon" class="vrcplus-icon"
@click="selectImageGallerySelect(image.versions[image.versions.length - 1].file.url, image.id)"> @click="
selectImageGallerySelect(image.versions[image.versions.length - 1].file.url, image.id)
">
<img <img
:src="image.versions[image.versions.length - 1].file.url" :src="image.versions[image.versions.length - 1].file.url"
class="avatar" class="avatar"
loading="lazy" /></div loading="lazy" />
></template> </div>
</template>
</div> </div>
</div> </div>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { X, RefreshCw, Upload } from 'lucide-vue-next'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { RefreshCw, Upload, X } from 'lucide-vue-next';
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 { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';

View File

@@ -1,12 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="groupDialog.visible">
:z-index="groupDialogIndex" <DialogContent
v-model="groupDialog.visible" class="x-dialog x-group-dialog group-body translate-y-0 sm:max-w-235"
:show-close="false" :show-close-button="false"
top="10vh" style="top: 10vh">
width="940px" <div v-loading="groupDialog.loading">
class="x-dialog x-group-dialog">
<div v-loading="groupDialog.loading" class="group-body">
<div style="display: flex"> <div style="display: flex">
<img <img
:src="groupDialog.ref.iconUrl" :src="groupDialog.ref.iconUrl"
@@ -153,7 +151,10 @@
<Star /> <Star />
</Button> </Button>
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-else side="top" :content="t('dialog.group.actions.represent_tooltip')"> <TooltipWrapper
v-else
side="top"
:content="t('dialog.group.actions.represent_tooltip')">
<span> <span>
<Button <Button
class="rounded-full mr-2" class="rounded-full mr-2"
@@ -167,7 +168,9 @@
</TooltipWrapper> </TooltipWrapper>
</template> </template>
<template v-else-if="groupDialog.ref.myMember?.membershipStatus === 'requested'"> <template v-else-if="groupDialog.ref.myMember?.membershipStatus === 'requested'">
<TooltipWrapper side="top" :content="t('dialog.group.actions.cancel_join_request_tooltip')"> <TooltipWrapper
side="top"
:content="t('dialog.group.actions.cancel_join_request_tooltip')">
<span> <span>
<Button <Button
class="rounded-full mr-2" class="rounded-full mr-2"
@@ -233,7 +236,9 @@
<Button <Button
class="rounded-full" class="rounded-full"
:variant=" :variant="
groupDialog.ref.membershipStatus === 'userblocked' ? 'destructive' : 'outline' groupDialog.ref.membershipStatus === 'userblocked'
? 'destructive'
: 'outline'
" "
size="icon-lg"> size="icon-lg">
<MoreHorizontal /> <MoreHorizontal />
@@ -283,7 +288,9 @@
{{ t('dialog.group.actions.moderation_tools') }} {{ t('dialog.group.actions.moderation_tools') }}
</DropdownMenuItem> </DropdownMenuItem>
<template <template
v-if="groupDialog.ref.myMember && groupDialog.ref.privacy === 'default'"> v-if="
groupDialog.ref.myMember && groupDialog.ref.privacy === 'default'
">
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItem @click="groupDialogCommand('Visibility Everyone')"> <DropdownMenuItem @click="groupDialogCommand('Visibility Everyone')">
<Eye class="size-4" /> <Eye class="size-4" />
@@ -345,7 +352,13 @@
<img <img
:src="groupDialog.ref.bannerUrl" :src="groupDialog.ref.bannerUrl"
class="x-link" class="x-link"
style="flex: none; width: 100%; aspect-ratio: 6/1; object-fit: cover; border-radius: 4px" style="
flex: none;
width: 100%;
aspect-ratio: 6/1;
object-fit: cover;
border-radius: 4px;
"
@click="showFullscreenImageDialog(groupDialog.ref.bannerUrl)" @click="showFullscreenImageDialog(groupDialog.ref.bannerUrl)"
loading="lazy" /> loading="lazy" />
</div> </div>
@@ -443,8 +456,12 @@
<template #content> <template #content>
<span>{{ t('dialog.group.posts.visibility') }}</span> <span>{{ t('dialog.group.posts.visibility') }}</span>
<br /> <br />
<template v-for="roleId in groupDialog.announcement.roleIds" :key="roleId"> <template
<template v-for="role in groupDialog.ref.roles" :key="roleId + role.id" v-for="roleId in groupDialog.announcement.roleIds"
:key="roleId">
<template
v-for="role in groupDialog.ref.roles"
:key="roleId + role.id"
><span v-if="role.id === roleId" v-text="role.name" ><span v-if="role.id === roleId" v-text="role.name"
/></template> /></template>
<span <span
@@ -469,7 +486,9 @@
<template #content> <template #content>
<span <span
>{{ t('dialog.group.posts.created_at') }} >{{ t('dialog.group.posts.created_at') }}
{{ formatDateFilter(groupDialog.announcement.createdAt, 'long') }}</span {{
formatDateFilter(groupDialog.announcement.createdAt, 'long')
}}</span
> >
<template <template
v-if=" v-if="
@@ -487,17 +506,23 @@
</template> </template>
<Timer :epoch="Date.parse(groupDialog.announcement.updatedAt)" /> <Timer :epoch="Date.parse(groupDialog.announcement.updatedAt)" />
</TooltipWrapper> </TooltipWrapper>
<template v-if="hasGroupPermission(groupDialog.ref, 'group-announcement-manage')"> <template
v-if="hasGroupPermission(groupDialog.ref, 'group-announcement-manage')">
<TooltipWrapper side="top" :content="t('dialog.group.posts.edit_tooltip')"> <TooltipWrapper side="top" :content="t('dialog.group.posts.edit_tooltip')">
<Button <Button
size="sm" size="sm"
variant="ghost" variant="ghost"
style="margin-left: 5px; padding: 0" style="margin-left: 5px; padding: 0"
@click=" @click="
showGroupPostEditDialog(groupDialog.id, groupDialog.announcement) showGroupPostEditDialog(
groupDialog.id,
groupDialog.announcement
)
"></Button> "></Button>
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper side="top" :content="t('dialog.group.posts.delete_tooltip')"> <TooltipWrapper
side="top"
:content="t('dialog.group.posts.delete_tooltip')">
<Button <Button
size="sm" size="sm"
variant="ghost" variant="ghost"
@@ -668,10 +693,14 @@
<span class="name">{{ t('dialog.group.info.roles') }}</span> <span class="name">{{ t('dialog.group.info.roles') }}</span>
<span v-if="groupDialog.memberRoles.length === 0" class="extra"> - </span> <span v-if="groupDialog.memberRoles.length === 0" class="extra"> - </span>
<span v-else class="extra"> <span v-else class="extra">
<template v-for="(role, rIndex) in groupDialog.memberRoles" :key="rIndex"> <template
v-for="(role, rIndex) in groupDialog.memberRoles"
:key="rIndex">
<TooltipWrapper side="top"> <TooltipWrapper side="top">
<template #content> <template #content>
<span>{{ t('dialog.group.info.role') }} {{ role.name }}</span> <span
>{{ t('dialog.group.info.role') }} {{ role.name }}</span
>
<br /> <br />
<span <span
>{{ t('dialog.group.info.role_description') }} >{{ t('dialog.group.info.role_description') }}
@@ -770,7 +799,9 @@
><span v-if="role.id === roleId" v-text="role.name" /> ><span v-if="role.id === roleId" v-text="role.name" />
</template> </template>
<template <template
v-if="post.roleIds.indexOf(roleId) < post.roleIds.length - 1" v-if="
post.roleIds.indexOf(roleId) < post.roleIds.length - 1
"
><span>,&nbsp;</span></template ><span>,&nbsp;</span></template
> >
</template> </template>
@@ -800,7 +831,9 @@
</TooltipWrapper> </TooltipWrapper>
<template <template
v-if="hasGroupPermission(groupDialog.ref, 'group-announcement-manage')"> v-if="hasGroupPermission(groupDialog.ref, 'group-announcement-manage')">
<TooltipWrapper side="top" :content="t('dialog.group.posts.edit_tooltip')"> <TooltipWrapper
side="top"
:content="t('dialog.group.posts.edit_tooltip')">
<Button <Button
size="icon-sm" size="icon-sm"
class="h-6 w-6 text-xs text-muted-foreground hover:text-foreground" class="h-6 w-6 text-xs text-muted-foreground hover:text-foreground"
@@ -858,7 +891,9 @@
<span <span
v-if="groupDialog.memberSearch.length" v-if="groupDialog.memberSearch.length"
style="font-size: 14px; margin-left: 5px; margin-right: 5px" style="font-size: 14px; margin-left: 5px; margin-right: 5px"
>{{ groupDialog.memberSearchResults.length }}/{{ groupDialog.ref.memberCount }}</span >{{ groupDialog.memberSearchResults.length }}/{{
groupDialog.ref.memberCount
}}</span
> >
<span v-else style="font-size: 14px; margin-left: 5px; margin-right: 5px" <span v-else style="font-size: 14px; margin-left: 5px; margin-right: 5px"
>{{ groupDialog.members.length }}/{{ groupDialog.ref.memberCount }}</span >{{ groupDialog.members.length }}/{{ groupDialog.ref.memberCount }}</span
@@ -929,7 +964,8 @@
:style="{ color: user.user?.$userColour }" :style="{ color: user.user?.$userColour }"
v-text="user.user?.displayName" /> v-text="user.user?.displayName" />
<span class="extra"> <span class="extra">
<template v-if="hasGroupPermission(groupDialog.ref, 'group-members-manage')"> <template
v-if="hasGroupPermission(groupDialog.ref, 'group-members-manage')">
<TooltipWrapper <TooltipWrapper
v-if="user.isRepresenting" v-if="user.isRepresenting"
side="top" side="top"
@@ -990,7 +1026,8 @@
:style="{ color: user.user?.$userColour }" :style="{ color: user.user?.$userColour }"
v-text="user.user?.displayName" /> v-text="user.user?.displayName" />
<span class="extra"> <span class="extra">
<template v-if="hasGroupPermission(groupDialog.ref, 'group-members-manage')"> <template
v-if="hasGroupPermission(groupDialog.ref, 'group-members-manage')">
<TooltipWrapper <TooltipWrapper
v-if="user.isRepresenting" v-if="user.isRepresenting"
side="top" side="top"
@@ -1065,7 +1102,10 @@
:key="`label-${index}`" :key="`label-${index}`"
v-slot:[`label-${index}`]> v-slot:[`label-${index}`]>
<span style="font-weight: bold; font-size: 16px" v-text="gallery.name" /> <span style="font-weight: bold; font-size: 16px" v-text="gallery.name" />
<i class="x-status-icon" style="margin-left: 5px" :class="groupGalleryStatus(gallery)" /> <i
class="x-status-icon"
style="margin-left: 5px"
:class="groupGalleryStatus(gallery)" />
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{ <span style="color: #909399; font-size: 12px; margin-left: 5px">{{
groupDialog.galleries[gallery.id] ? groupDialog.galleries[gallery.id].length : 0 groupDialog.galleries[gallery.id] ? groupDialog.galleries[gallery.id].length : 0
}}</span> }}</span>
@@ -1121,11 +1161,12 @@
</template> </template>
</TabsUnderline> </TabsUnderline>
</div> </div>
</DialogContent>
<GroupPostEditDialog :dialog-data="groupPostEditDialog" :selected-gallery-file="selectedGalleryFile" /> <GroupPostEditDialog :dialog-data="groupPostEditDialog" :selected-gallery-file="selectedGalleryFile" />
<PreviousInstancesGroupDialog <PreviousInstancesGroupDialog
:previous-instances-group-dialog="previousInstancesGroupDialog" :previous-instances-group-dialog="previousInstancesGroupDialog"
:current-user="currentUser" /> :current-user="currentUser" />
</el-dialog> </Dialog>
</template> </template>
<script setup> <script setup>
@@ -1154,6 +1195,7 @@
} from 'lucide-vue-next'; } from 'lucide-vue-next';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { computed, nextTick, reactive, ref, watch } from 'vue'; import { computed, nextTick, reactive, ref, watch } from 'vue';
import { Dialog, DialogContent } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card'; import { Card } from '@/components/ui/card';
import { InputGroupField } from '@/components/ui/input-group'; import { InputGroupField } from '@/components/ui/input-group';
@@ -1197,9 +1239,9 @@
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger DropdownMenuTrigger
} from '../../ui/dropdown-menu'; } from '../../ui/dropdown-menu';
import { formatJsonVars, getNextDialogIndex } from '../../../shared/utils/base/ui';
import { groupDialogFilterOptions, groupDialogSortingOptions } from '../../../shared/constants'; import { groupDialogFilterOptions, groupDialogSortingOptions } from '../../../shared/constants';
import { Badge } from '../../ui/badge'; import { Badge } from '../../ui/badge';
import { formatJsonVars } from '../../../shared/utils/base/ui';
import { groupRequest } from '../../../api'; import { groupRequest } from '../../../api';
import GroupCalendarEventCard from '../../../views/Tools/components/GroupCalendarEventCard.vue'; import GroupCalendarEventCard from '../../../views/Tools/components/GroupCalendarEventCard.vue';
@@ -1246,7 +1288,6 @@
const { isDarkMode } = storeToRefs(useAppearanceSettingsStore()); const { isDarkMode } = storeToRefs(useAppearanceSettingsStore());
const groupDialogLastActiveTab = ref('Info'); const groupDialogLastActiveTab = ref('Info');
const groupDialogIndex = ref(2000);
const isGroupMembersDone = ref(false); const isGroupMembersDone = ref(false);
const isGroupMembersLoading = ref(false); const isGroupMembersLoading = ref(false);
const groupDialogGalleryCurrentName = ref('0'); const groupDialogGalleryCurrentName = ref('0');
@@ -1376,17 +1417,6 @@
}); });
}); });
watch(
() => groupDialog.value.loading,
() => {
if (groupDialog.value.visible) {
nextTick(() => {
groupDialogIndex.value = getNextDialogIndex();
});
}
}
);
watch( watch(
() => groupDialog.value.isGetGroupDialogGroupLoading, () => groupDialog.value.isGetGroupDialogGroupLoading,
(val) => { (val) => {

View File

@@ -1,10 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="groupMemberModeration.visible">
class="x-dialog" <DialogContent class="x-dialog max-w-none w-[90vw]">
v-model="groupMemberModeration.visible" <DialogHeader>
:title="t('dialog.group_member_moderation.header')" <DialogTitle>{{ t('dialog.group_member_moderation.header') }}</DialogTitle>
append-to-body </DialogHeader>
width="90vw">
<div> <div>
<h3>{{ groupMemberModeration.groupRef.name }}</h3> <h3>{{ groupMemberModeration.groupRef.name }}</h3>
<TabsUnderline <TabsUnderline
@@ -47,7 +47,10 @@
Boolean( Boolean(
isGroupMembersLoading || isGroupMembersLoading ||
memberSearch.length || memberSearch.length ||
!hasGroupPermission(groupMemberModeration.groupRef, 'group-bans-manage') !hasGroupPermission(
groupMemberModeration.groupRef,
'group-bans-manage'
)
) )
" "
@click.stop> @click.stop>
@@ -66,7 +69,9 @@
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
<span class="ml-2" style="margin-right: 5px">{{ t('dialog.group.members.filter') }}</span> <span class="ml-2" style="margin-right: 5px">{{
t('dialog.group.members.filter')
}}</span>
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger <DropdownMenuTrigger
as-child as-child
@@ -84,7 +89,10 @@
Boolean( Boolean(
isGroupMembersLoading || isGroupMembersLoading ||
memberSearch.length || memberSearch.length ||
!hasGroupPermission(groupMemberModeration.groupRef, 'group-bans-manage') !hasGroupPermission(
groupMemberModeration.groupRef,
'group-bans-manage'
)
) )
" "
@click.stop> @click.stop>
@@ -102,7 +110,9 @@
{{ t(item.name) }} {{ t(item.name) }}
</DropdownMenuItem> </DropdownMenuItem>
<template v-for="role in groupMemberModeration.groupRef.roles" :key="role.name"> <template v-for="role in groupMemberModeration.groupRef.roles" :key="role.name">
<DropdownMenuItem v-if="!role.defaultRole" @click="setGroupMemberFilter(role)"> <DropdownMenuItem
v-if="!role.defaultRole"
@click="setGroupMemberFilter(role)">
{{ t(role.name) }} {{ t(role.name) }}
</DropdownMenuItem> </DropdownMenuItem>
</template> </template>
@@ -216,7 +226,10 @@
:disabled=" :disabled="
Boolean( Boolean(
progressCurrent || progressCurrent ||
!hasGroupPermission(groupMemberModeration.groupRef, 'group-invites-manage') !hasGroupPermission(
groupMemberModeration.groupRef,
'group-invites-manage'
)
) )
" "
@click="groupMembersDeleteSentInvite" @click="groupMembersDeleteSentInvite"
@@ -240,7 +253,10 @@
:disabled=" :disabled="
Boolean( Boolean(
progressCurrent || progressCurrent ||
!hasGroupPermission(groupMemberModeration.groupRef, 'group-invites-manage') !hasGroupPermission(
groupMemberModeration.groupRef,
'group-invites-manage'
)
) )
" "
class="mr-2" class="mr-2"
@@ -252,7 +268,10 @@
:disabled=" :disabled="
Boolean( Boolean(
progressCurrent || progressCurrent ||
!hasGroupPermission(groupMemberModeration.groupRef, 'group-invites-manage') !hasGroupPermission(
groupMemberModeration.groupRef,
'group-invites-manage'
)
) )
" "
class="mr-2" class="mr-2"
@@ -264,7 +283,10 @@
:disabled=" :disabled="
Boolean( Boolean(
progressCurrent || progressCurrent ||
!hasGroupPermission(groupMemberModeration.groupRef, 'group-invites-manage') !hasGroupPermission(
groupMemberModeration.groupRef,
'group-invites-manage'
)
) )
" "
@click="groupMembersBlockJoinRequest" @click="groupMembersBlockJoinRequest"
@@ -288,7 +310,10 @@
:disabled=" :disabled="
Boolean( Boolean(
progressCurrent || progressCurrent ||
!hasGroupPermission(groupMemberModeration.groupRef, 'group-invites-manage') !hasGroupPermission(
groupMemberModeration.groupRef,
'group-invites-manage'
)
) )
" "
@click="groupMembersDeleteBlockedRequest" @click="groupMembersDeleteBlockedRequest"
@@ -318,7 +343,8 @@
<div> <div>
<Select v-model="selectedAuditLogTypes" multiple> <Select v-model="selectedAuditLogTypes" multiple>
<SelectTrigger style="margin: 10px 0; width: 250px"> <SelectTrigger style="margin: 10px 0; width: 250px">
<SelectValue :placeholder="t('dialog.group_member_moderation.filter_type')" /> <SelectValue
:placeholder="t('dialog.group_member_moderation.filter_type')" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem <SelectItem
@@ -394,7 +420,9 @@
</template> </template>
<AlertTriangle style="margin-left: 3px; display: inline-block" /> <AlertTriangle style="margin-left: 3px; display: inline-block" />
</TooltipWrapper> </TooltipWrapper>
<span v-text="user.user?.displayName || user.userId" style="font-weight: bold; margin-left: 5px"></span> <span
v-text="user.user?.displayName || user.userId"
style="font-weight: bold; margin-left: 5px"></span>
<button <button
type="button" type="button"
style=" style="
@@ -430,7 +458,10 @@
<SelectValue :placeholder="t('dialog.group_member_moderation.choose_roles_placeholder')" /> <SelectValue :placeholder="t('dialog.group_member_moderation.choose_roles_placeholder')" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem v-for="role in groupMemberModeration.groupRef.roles" :key="role.id" :value="role.id"> <SelectItem
v-for="role in groupMemberModeration.groupRef.roles"
:key="role.id"
:value="role.id">
{{ role.name }} {{ role.name }}
</SelectItem> </SelectItem>
</SelectContent> </SelectContent>
@@ -490,7 +521,8 @@
variant="outline" variant="outline"
:disabled=" :disabled="
Boolean( Boolean(
progressCurrent || !hasGroupPermission(groupMemberModeration.groupRef, 'group-bans-manage') progressCurrent ||
!hasGroupPermission(groupMemberModeration.groupRef, 'group-bans-manage')
) )
" "
@click="groupMembersBan" @click="groupMembersBan"
@@ -500,7 +532,8 @@
variant="outline" variant="outline"
:disabled=" :disabled="
Boolean( Boolean(
progressCurrent || !hasGroupPermission(groupMemberModeration.groupRef, 'group-bans-manage') progressCurrent ||
!hasGroupPermission(groupMemberModeration.groupRef, 'group-bans-manage')
) )
" "
@click="groupMembersUnban" @click="groupMembersUnban"
@@ -519,14 +552,17 @@
> >
</div> </div>
</div> </div>
<group-member-moderation-export-dialog <group-member-moderation-export-dialog
v-model:isGroupLogsExportDialogVisible="isGroupLogsExportDialogVisible" v-model:isGroupLogsExportDialogVisible="isGroupLogsExportDialogVisible"
:group-logs-moderation-table="groupLogsModerationTable" /> :group-logs-moderation-table="groupLogsModerationTable" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { AlertTriangle, ArrowDown, Loader2, RefreshCw, Trash2, X } from 'lucide-vue-next'; import { AlertTriangle, ArrowDown, Loader2, RefreshCw, Trash2, X } from 'lucide-vue-next';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, reactive, ref, watch } from 'vue'; import { computed, reactive, ref, watch } from 'vue';
import { InputGroupField, InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupField, InputGroupTextareaField } from '@/components/ui/input-group';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';

View File

@@ -1,11 +1,16 @@
<template> <template>
<el-dialog <Dialog
class="x-dialog" :open="isGroupLogsExportDialogVisible"
:model-value="isGroupLogsExportDialogVisible" @update:open="
:title="t('dialog.group_member_moderation.export_logs')" (open) => {
width="650px" if (!open) setIsGroupLogsExportDialogVisible();
append-to-body }
@close="setIsGroupLogsExportDialogVisible"> ">
<DialogContent class="x-dialog sm:max-w-162.5">
<DialogHeader>
<DialogTitle>{{ t('dialog.group_member_moderation.export_logs') }}</DialogTitle>
</DialogHeader>
<div style="margin-bottom: 10px" class="flex flex-col gap-2"> <div style="margin-bottom: 10px" class="flex flex-col gap-2">
<label <label
v-for="option in checkGroupsLogsExportLogsOptions" v-for="option in checkGroupsLogsExportLogsOptions"
@@ -25,10 +30,12 @@
style="margin-top: 15px" style="margin-top: 15px"
input-class="resize-none" input-class="resize-none"
@click="handleCopyGroupLogsExportContent" /> @click="handleCopyGroupLogsExportContent" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { Checkbox } from '@/components/ui/checkbox'; import { Checkbox } from '@/components/ui/checkbox';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';

View File

@@ -1,9 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="groupPostEditDialog.visible">
v-model="groupPostEditDialog.visible" <DialogContent class="sm:max-w-162.5">
:title="t('dialog.group_post_edit.header')" <DialogHeader>
width="650px" <DialogTitle>{{ t('dialog.group_post_edit.header') }}</DialogTitle>
append-to-body> </DialogHeader>
<div v-if="groupPostEditDialog.visible"> <div v-if="groupPostEditDialog.visible">
<FieldGroup class="gap-4"> <FieldGroup class="gap-4">
<Field> <Field>
@@ -55,7 +56,9 @@
<FieldContent> <FieldContent>
<Select <Select
multiple multiple
:model-value="Array.isArray(groupPostEditDialog.roleIds) ? groupPostEditDialog.roleIds : []" :model-value="
Array.isArray(groupPostEditDialog.roleIds) ? groupPostEditDialog.roleIds : []
"
@update:modelValue="handleRoleIdsChange"> @update:modelValue="handleRoleIdsChange">
<SelectTrigger size="sm" class="w-full"> <SelectTrigger size="sm" class="w-full">
<SelectValue> <SelectValue>
@@ -84,7 +87,13 @@
<div style="display: inline-block; flex: none; margin-right: 5px"> <div style="display: inline-block; flex: none; margin-right: 5px">
<img <img
:src="gallerySelectDialog.selectedImageUrl" :src="gallerySelectDialog.selectedImageUrl"
style="flex: none; width: 60px; height: 60px; border-radius: 4px; object-fit: cover" style="
flex: none;
width: 60px;
height: 60px;
border-radius: 4px;
object-fit: cover;
"
@click="showFullscreenImageDialog(gallerySelectDialog.selectedImageUrl)" @click="showFullscreenImageDialog(gallerySelectDialog.selectedImageUrl)"
loading="lazy" /> loading="lazy" />
<Button <Button
@@ -105,7 +114,8 @@
</Field> </Field>
</FieldGroup> </FieldGroup>
</div> </div>
<template #footer>
<DialogFooter>
<div class="flex gap-2"> <div class="flex gap-2">
<Button variant="secondary" @click="groupPostEditDialog.visible = false"> <Button variant="secondary" @click="groupPostEditDialog.visible = false">
{{ t('dialog.group_post_edit.cancel') }} {{ t('dialog.group_post_edit.cancel') }}
@@ -117,15 +127,18 @@
{{ t('dialog.group_post_edit.create_post') }} {{ t('dialog.group_post_edit.create_post') }}
</Button> </Button>
</div> </div>
</template> </DialogFooter>
<GallerySelectDialog <GallerySelectDialog
:gallery-select-dialog="gallerySelectDialog" :gallery-select-dialog="gallerySelectDialog"
:gallery-table="galleryTable" :gallery-table="galleryTable"
@refresh-gallery-table="refreshGalleryTable" /> @refresh-gallery-table="refreshGalleryTable" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field'; import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field';
import { InputGroupField, InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupField, InputGroupTextareaField } from '@/components/ui/input-group';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';

View File

@@ -1,11 +1,16 @@
<template> <template>
<el-dialog <Dialog
class="x-dialog" :open="editAndSendInviteDialog.visible"
:model-value="editAndSendInviteDialog.visible" @update:open="
:title="t('dialog.edit_send_invite_message.header')" (open) => {
width="400px" if (!open) cancelEditAndSendInvite();
append-to-body }
@close="cancelEditAndSendInvite"> ">
<DialogContent class="x-dialog sm:max-w-100">
<DialogHeader>
<DialogTitle>{{ t('dialog.edit_send_invite_message.header') }}</DialogTitle>
</DialogHeader>
<div style="font-size: 12px"> <div style="font-size: 12px">
<span>{{ t('dialog.edit_send_invite_message.description') }}</span> <span>{{ t('dialog.edit_send_invite_message.description') }}</span>
</div> </div>
@@ -18,18 +23,20 @@
placeholder="" placeholder=""
show-count /> show-count />
<template #footer> <DialogFooter>
<Button variant="secondary" class="mr-2" @click="cancelEditAndSendInvite"> <Button variant="secondary" class="mr-2" @click="cancelEditAndSendInvite">
{{ t('dialog.edit_send_invite_message.cancel') }} {{ t('dialog.edit_send_invite_message.cancel') }}
</Button> </Button>
<Button @click="saveEditAndSendInvite" :disabled="!editAndSendInviteDialog.newMessage"> <Button @click="saveEditAndSendInvite" :disabled="!editAndSendInviteDialog.newMessage">
{{ t('dialog.edit_send_invite_message.send') }} {{ t('dialog.edit_send_invite_message.send') }}
</Button> </Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';

View File

@@ -1,11 +1,16 @@
<template> <template>
<el-dialog <Dialog
class="x-dialog" :open="inviteDialog.visible"
:model-value="inviteDialog.visible" @update:open="
@close="closeInviteDialog" (open) => {
:title="t('dialog.invite.header')" if (!open) closeInviteDialog();
width="500px" }
append-to-body> ">
<DialogContent class="x-dialog sm:max-w-125">
<DialogHeader>
<DialogTitle>{{ t('dialog.invite.header') }}</DialogTitle>
</DialogHeader>
<div v-if="inviteDialog.visible" v-loading="inviteDialog.loading"> <div v-if="inviteDialog.visible" v-loading="inviteDialog.loading">
<Location :location="inviteDialog.worldId" :link="false" /> <Location :location="inviteDialog.worldId" :link="false" />
<br /> <br />
@@ -63,7 +68,7 @@
</div> </div>
</div> </div>
<template #footer> <DialogFooter>
<Button <Button
variant="secondary" variant="secondary"
class="mr-2" class="mr-2"
@@ -74,16 +79,19 @@
<Button :disabled="inviteDialog.loading || !inviteDialog.userIds.length" @click="sendInvite">{{ <Button :disabled="inviteDialog.loading || !inviteDialog.userIds.length" @click="sendInvite">{{
t('dialog.invite.invite') t('dialog.invite.invite')
}}</Button> }}</Button>
</template> </DialogFooter>
</DialogContent>
<SendInviteDialog <SendInviteDialog
v-model:sendInviteDialogVisible="sendInviteDialogVisible" v-model:sendInviteDialogVisible="sendInviteDialogVisible"
v-model:sendInviteDialog="sendInviteDialog" v-model:sendInviteDialog="sendInviteDialog"
:invite-dialog="inviteDialog" :invite-dialog="inviteDialog"
@closeInviteDialog="closeInviteDialog" /> @closeInviteDialog="closeInviteDialog" />
</el-dialog> </Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Check as CheckIcon } from 'lucide-vue-next'; import { Check as CheckIcon } from 'lucide-vue-next';

View File

@@ -1,27 +1,35 @@
<template> <template>
<el-dialog <Dialog
class="x-dialog" :open="isSendInviteConfirmDialogVisible"
:model-value="isSendInviteConfirmDialogVisible" @update:open="
:title="t('dialog.invite_message.header')" (open) => {
width="400px" if (!open) cancelInviteConfirm();
append-to-body }
@close="cancelInviteConfirm"> ">
<DialogContent class="x-dialog sm:max-w-100">
<DialogHeader>
<DialogTitle>{{ t('dialog.invite_message.header') }}</DialogTitle>
</DialogHeader>
<div style="font-size: 12px"> <div style="font-size: 12px">
<span>{{ t('dialog.invite_message.confirmation') }}</span> <span>{{ t('dialog.invite_message.confirmation') }}</span>
</div> </div>
<template #footer> <DialogFooter>
<Button variant="secondary" @click="cancelInviteConfirm"> <Button variant="secondary" @click="cancelInviteConfirm">
{{ t('dialog.invite_message.cancel') }} {{ t('dialog.invite_message.cancel') }}
</Button> </Button>
<Button @click="sendInviteConfirm"> <Button @click="sendInviteConfirm">
{{ t('dialog.invite_message.confirm') }} {{ t('dialog.invite_message.confirm') }}
</Button> </Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
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';

View File

@@ -1,11 +1,16 @@
<template> <template>
<el-dialog <Dialog
class="x-dialog" :open="sendInviteDialogVisible"
:model-value="sendInviteDialogVisible" @update:open="
:title="t('dialog.invite_message.header')" (open) => {
width="800px" if (!open) cancelSendInvite();
append-to-body }
@close="cancelSendInvite"> ">
<DialogContent class="x-dialog sm:max-w-200">
<DialogHeader>
<DialogTitle>{{ t('dialog.invite_message.header') }}</DialogTitle>
</DialogHeader>
<template v-if="isLocalUserVrcPlusSupporter"> <template v-if="isLocalUserVrcPlusSupporter">
<!-- <template v-if="gallerySelectDialog.selectedFileId">--> <!-- <template v-if="gallerySelectDialog.selectedFileId">-->
<!-- <div style="display: inline-block; flex: none; margin-right: 5px">--> <!-- <div style="display: inline-block; flex: none; margin-right: 5px">-->
@@ -42,14 +47,16 @@
:show-pagination="false" :show-pagination="false"
:on-row-click="handleInviteMessageRowClick" /> :on-row-click="handleInviteMessageRowClick" />
<template #footer> <DialogFooter>
<Button variant="secondary" @click="cancelSendInvite"> <Button variant="secondary" @click="cancelSendInvite">
{{ t('dialog.invite_message.cancel') }} {{ t('dialog.invite_message.cancel') }}
</Button> </Button>
<Button variant="outline" @click="refreshInviteMessageTableData('message')"> <Button variant="outline" @click="refreshInviteMessageTableData('message')">
{{ t('dialog.invite_message.refresh') }} {{ t('dialog.invite_message.refresh') }}
</Button> </Button>
</template> </DialogFooter>
</DialogContent>
<SendInviteConfirmDialog <SendInviteConfirmDialog
v-model:isSendInviteConfirmDialogVisible="isSendInviteConfirmDialogVisible" v-model:isSendInviteConfirmDialogVisible="isSendInviteConfirmDialogVisible"
:sendInviteDialog="sendInviteDialog" :sendInviteDialog="sendInviteDialog"
@@ -62,10 +69,11 @@
@update:sendInviteDialog="emit('update:sendInviteDialog', $event)" @update:sendInviteDialog="emit('update:sendInviteDialog', $event)"
:invite-dialog="inviteDialog" :invite-dialog="inviteDialog"
@closeInviteDialog="closeInviteDialog" /> @closeInviteDialog="closeInviteDialog" />
</el-dialog> </Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref } from 'vue'; import { computed, ref } 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';

View File

@@ -1,10 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="inviteGroupDialog.visible">
:z-index="inviteGroupDialogIndex" <DialogContent class="sm:max-w-112.5">
v-model="inviteGroupDialog.visible" <DialogHeader>
:title="t('dialog.invite_to_group.header')" <DialogTitle>{{ t('dialog.invite_to_group.header') }}</DialogTitle>
width="450px" </DialogHeader>
append-to-body>
<div v-if="inviteGroupDialog.visible" v-loading="inviteGroupDialog.loading"> <div v-if="inviteGroupDialog.visible" v-loading="inviteGroupDialog.loading">
<span>{{ t('dialog.invite_to_group.description') }}</span> <span>{{ t('dialog.invite_to_group.description') }}</span>
<br /> <br />
@@ -65,19 +65,24 @@
</VirtualCombobox> </VirtualCombobox>
</div> </div>
</div> </div>
<template #footer>
<DialogFooter>
<Button <Button
:disabled="inviteGroupDialog.loading || !inviteGroupDialog.userIds.length || !inviteGroupDialog.groupId" :disabled="
inviteGroupDialog.loading || !inviteGroupDialog.userIds.length || !inviteGroupDialog.groupId
"
@click="sendGroupInvite"> @click="sendGroupInvite">
{{ t('dialog.invite_to_group.invite') }} {{ t('dialog.invite_to_group.invite') }}
</Button> </Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { computed, nextTick, ref, watch } from 'vue'; import { computed, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Check as CheckIcon } from 'lucide-vue-next'; import { Check as CheckIcon } from 'lucide-vue-next';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
@@ -87,7 +92,6 @@
import { useFriendStore, useGroupStore, useModalStore } from '../../stores'; import { useFriendStore, useGroupStore, useModalStore } from '../../stores';
import { groupRequest, userRequest } from '../../api'; import { groupRequest, userRequest } from '../../api';
import { VirtualCombobox } from '../ui/virtual-combobox'; import { VirtualCombobox } from '../ui/virtual-combobox';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
import configRepository from '../../service/config'; import configRepository from '../../service/config';
@@ -109,8 +113,6 @@
} }
); );
const inviteGroupDialogIndex = ref(2000);
const groupsWithInvitePermission = computed(() => { const groupsWithInvitePermission = computed(() => {
return Array.from(currentUserGroups.value.values()).filter((group) => return Array.from(currentUserGroups.value.values()).filter((group) =>
hasGroupPermission(group, 'group-invites-manage') hasGroupPermission(group, 'group-invites-manage')
@@ -223,9 +225,6 @@
); );
function initDialog() { function initDialog() {
nextTick(() => {
inviteGroupDialogIndex.value = getNextDialogIndex();
});
const D = inviteGroupDialog.value; const D = inviteGroupDialog.value;
if (D.groupId) { if (D.groupId) {
groupRequest groupRequest

View File

@@ -1,5 +1,9 @@
<template> <template>
<el-dialog :z-index="launchDialogIndex" v-model="isVisible" :title="t('dialog.launch.header')" width="450px"> <Dialog v-model:open="isVisible">
<DialogContent>
<DialogHeader>
<DialogTitle>{{ t('dialog.launch.header') }}</DialogTitle>
</DialogHeader>
<FieldGroup class="gap-4"> <FieldGroup class="gap-4">
<Field> <Field>
<FieldLabel>{{ t('dialog.launch.url') }}</FieldLabel> <FieldLabel>{{ t('dialog.launch.url') }}</FieldLabel>
@@ -63,8 +67,7 @@
</FieldContent> </FieldContent>
</Field> </Field>
</FieldGroup> </FieldGroup>
<template #footer> <DialogFooter>
<div class="flex justify-end">
<Button <Button
class="mr-1.5" class="mr-1.5"
variant="outline" variant="outline"
@@ -117,14 +120,16 @@
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
</ButtonGroup> </ButtonGroup>
</div> </DialogFooter>
</template>
<InviteDialog :invite-dialog="inviteDialog" @closeInviteDialog="closeInviteDialog" /> <InviteDialog :invite-dialog="inviteDialog" @closeInviteDialog="closeInviteDialog" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'; import { computed, onBeforeUnmount, ref, watch } from 'vue';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
@@ -150,7 +155,6 @@
} from '../../stores'; } from '../../stores';
import { checkCanInvite, getLaunchURL, isRealInstance, parseLocation } from '../../shared/utils'; import { checkCanInvite, getLaunchURL, isRealInstance, parseLocation } from '../../shared/utils';
import { instanceRequest, worldRequest } from '../../api'; import { instanceRequest, worldRequest } from '../../api';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
import InviteDialog from './InviteDialog/InviteDialog.vue'; import InviteDialog from './InviteDialog/InviteDialog.vue';
import configRepository from '../../service/config'; import configRepository from '../../service/config';
@@ -171,8 +175,6 @@
launchDialog.value.desktop ? t('dialog.launch.start_as_desktop') : t('dialog.launch.launch') launchDialog.value.desktop ? t('dialog.launch.start_as_desktop') : t('dialog.launch.launch')
); );
const launchDialogIndex = ref(2000);
let launchAsDesktopTimeoutId; let launchAsDesktopTimeoutId;
onBeforeUnmount(() => { onBeforeUnmount(() => {
@@ -312,9 +314,6 @@
if (!isRealInstance(tag)) { if (!isRealInstance(tag)) {
return; return;
} }
nextTick(() => {
launchDialogIndex.value = getNextDialogIndex();
});
const D = launchDialog.value; const D = launchDialog.value;
D.tag = tag; D.tag = tag;
D.secureOrShortName = shortName; D.secureOrShortName = shortName;

View File

@@ -1,10 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="moderateGroupDialog.visible">
:z-index="moderateGroupDialogIndex" <DialogContent class="sm:max-w-112.5">
v-model="moderateGroupDialog.visible" <DialogHeader>
:title="t('dialog.moderate_group.header')" <DialogTitle>{{ t('dialog.moderate_group.header') }}</DialogTitle>
width="450px" </DialogHeader>
append-to-body>
<div v-if="moderateGroupDialog.visible"> <div v-if="moderateGroupDialog.visible">
<div class="x-friend-item" style="cursor: default"> <div class="x-friend-item" style="cursor: default">
<div class="avatar"> <div class="avatar">
@@ -38,7 +38,8 @@
</VirtualCombobox> </VirtualCombobox>
</div> </div>
</div> </div>
<template #footer>
<DialogFooter>
<Button <Button
:disabled="!moderateGroupDialog.userId || !moderateGroupDialog.groupId" :disabled="!moderateGroupDialog.userId || !moderateGroupDialog.groupId"
@click=" @click="
@@ -47,20 +48,21 @@
"> ">
{{ t('dialog.moderate_group.moderation_tools') }} {{ t('dialog.moderate_group.moderation_tools') }}
</Button> </Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { computed, nextTick, ref, watch } from 'vue'; import { computed, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { groupRequest, userRequest } from '../../api'; import { groupRequest, userRequest } from '../../api';
import { hasGroupModerationPermission, userImage } from '../../shared/utils'; import { hasGroupModerationPermission, userImage } from '../../shared/utils';
import { VirtualCombobox } from '../ui/virtual-combobox'; import { VirtualCombobox } from '../ui/virtual-combobox';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
import { useGroupStore } from '../../stores'; import { useGroupStore } from '../../stores';
const { currentUserGroups, moderateGroupDialog } = storeToRefs(useGroupStore()); const { currentUserGroups, moderateGroupDialog } = storeToRefs(useGroupStore());
@@ -99,12 +101,7 @@
} }
); );
const moderateGroupDialogIndex = ref(2000);
function initDialog() { function initDialog() {
nextTick(() => {
moderateGroupDialogIndex.value = getNextDialogIndex();
});
const D = moderateGroupDialog.value; const D = moderateGroupDialog.value;
if (D.groupId) { if (D.groupId) {
groupRequest groupRequest

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog v-model:open="newInstanceDialog.visible">
:z-index="newInstanceDialogIndex" <DialogContent>
v-model="newInstanceDialog.visible" <DialogHeader>
:title="t('dialog.new_instance.header')" <DialogTitle>{{ t('dialog.new_instance.header') }}</DialogTitle>
width="650px" </DialogHeader>
append-to-body>
<TabsUnderline <TabsUnderline
v-model="newInstanceDialog.selectedTab" v-model="newInstanceDialog.selectedTab"
:items="newInstanceTabs" :items="newInstanceTabs"
@@ -435,7 +434,7 @@
</FieldGroup> </FieldGroup>
</template> </template>
</TabsUnderline> </TabsUnderline>
<template v-if="newInstanceDialog.selectedTab === 'Normal'" #footer> <DialogFooter v-if="newInstanceDialog.selectedTab === 'Normal'">
<template v-if="newInstanceDialog.instanceCreated"> <template v-if="newInstanceDialog.instanceCreated">
<Button variant="outline" class="mr-2" @click="copyInstanceUrl(newInstanceDialog.location)">{{ <Button variant="outline" class="mr-2" @click="copyInstanceUrl(newInstanceDialog.location)">{{
t('dialog.new_instance.copy_url') t('dialog.new_instance.copy_url')
@@ -473,8 +472,8 @@
<template v-else> <template v-else>
<Button @click="handleCreateNewInstance">{{ t('dialog.new_instance.create_instance') }}</Button> <Button @click="handleCreateNewInstance">{{ t('dialog.new_instance.create_instance') }}</Button>
</template> </template>
</template> </DialogFooter>
<template v-else-if="newInstanceDialog.selectedTab === 'Legacy'" #footer> <DialogFooter v-else-if="newInstanceDialog.selectedTab === 'Legacy'">
<Button variant="outline" class="mr-2" @click="copyInstanceUrl(newInstanceDialog.location)">{{ <Button variant="outline" class="mr-2" @click="copyInstanceUrl(newInstanceDialog.location)">{{
t('dialog.new_instance.copy_url') t('dialog.new_instance.copy_url')
}}</Button> }}</Button>
@@ -506,14 +505,17 @@
t('dialog.new_instance.launch') t('dialog.new_instance.launch')
}}</Button> }}</Button>
</template> </template>
</template> </DialogFooter>
</DialogContent>
<InviteDialog :invite-dialog="inviteDialog" @closeInviteDialog="closeInviteDialog" /> <InviteDialog :invite-dialog="inviteDialog" @closeInviteDialog="closeInviteDialog" />
</el-dialog> </Dialog>
</template> </template>
<script setup> <script setup>
import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field'; import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field';
import { computed, nextTick, ref, watch } from 'vue'; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Check as CheckIcon } from 'lucide-vue-next'; import { Check as CheckIcon } from 'lucide-vue-next';
import { Checkbox } from '@/components/ui/checkbox'; import { Checkbox } from '@/components/ui/checkbox';
@@ -545,7 +547,6 @@
import { groupRequest, instanceRequest, worldRequest } from '../../api'; import { groupRequest, instanceRequest, worldRequest } from '../../api';
import { ToggleGroup, ToggleGroupItem } from '../ui/toggle-group'; import { ToggleGroup, ToggleGroupItem } from '../ui/toggle-group';
import { VirtualCombobox } from '../ui/virtual-combobox'; import { VirtualCombobox } from '../ui/virtual-combobox';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
import InviteDialog from './InviteDialog/InviteDialog.vue'; import InviteDialog from './InviteDialog/InviteDialog.vue';
import configRepository from '../../service/config'; import configRepository from '../../service/config';
@@ -572,8 +573,6 @@
const { currentUser, isLocalUserVrcPlusSupporter } = storeToRefs(useUserStore()); const { currentUser, isLocalUserVrcPlusSupporter } = storeToRefs(useUserStore());
const { canOpenInstanceInGame } = useInviteStore(); const { canOpenInstanceInGame } = useInviteStore();
const newInstanceDialogIndex = ref(2000);
const newInstanceDialog = ref({ const newInstanceDialog = ref({
visible: false, visible: false,
// loading: false, // loading: false,
@@ -778,9 +777,6 @@
if (!isRealInstance(tag)) { if (!isRealInstance(tag)) {
return; return;
} }
nextTick(() => {
newInstanceDialogIndex.value = getNextDialogIndex();
});
const D = newInstanceDialog.value; const D = newInstanceDialog.value;
const L = parseLocation(tag); const L = parseLocation(tag);
if (D.worldId === L.worldId) { if (D.worldId === L.worldId) {

View File

@@ -1,10 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="isVisible">
:z-index="previousInstancesGroupDialogIndex" <DialogContent class="sm:max-w-250">
v-model="isVisible" <DialogHeader>
:title="t('dialog.previous_instances.header')" <DialogTitle>{{ t('dialog.previous_instances.header') }}</DialogTitle>
width="1000px" </DialogHeader>
append-to-body>
<DataTableLayout <DataTableLayout
class="min-w-0 w-full" class="min-w-0 w-full"
:table="table" :table="table"
@@ -24,11 +24,13 @@
</div> </div>
</template> </template>
</DataTableLayout> </DataTableLayout>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { computed, nextTick, ref, watch } from 'vue'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref, watch } from 'vue';
import { InputGroupField } from '@/components/ui/input-group'; import { InputGroupField } from '@/components/ui/input-group';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -44,7 +46,6 @@
import { DataTableLayout } from '../../ui/data-table'; import { DataTableLayout } from '../../ui/data-table';
import { createColumns } from './previousInstancesGroupColumns.jsx'; import { createColumns } from './previousInstancesGroupColumns.jsx';
import { database } from '../../../service/database'; import { database } from '../../../service/database';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable'; import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
const { showPreviousInstancesInfoDialog } = useInstanceStore(); const { showPreviousInstancesInfoDialog } = useInstanceStore();
@@ -52,7 +53,6 @@
const { stringComparer } = storeToRefs(useSearchStore()); const { stringComparer } = storeToRefs(useSearchStore());
const { t } = useI18n(); const { t } = useI18n();
const previousInstancesGroupDialogIndex = ref(2000);
const loading = ref(false); const loading = ref(false);
const modalStore = useModalStore(); const modalStore = useModalStore();
@@ -140,9 +140,6 @@
() => props.previousInstancesGroupDialog.openFlg, () => props.previousInstancesGroupDialog.openFlg,
() => { () => {
if (props.previousInstancesGroupDialog.visible) { if (props.previousInstancesGroupDialog.visible) {
nextTick(() => {
previousInstancesGroupDialogIndex.value = getNextDialogIndex();
});
refreshPreviousInstancesGroupTable(); refreshPreviousInstancesGroupTable();
} }
} }

View File

@@ -1,12 +1,16 @@
<template> <template>
<el-dialog <Dialog
:z-index="previousInstancesInfoDialogIndex" :open="previousInstancesInfoDialogVisible"
:model-value="previousInstancesInfoDialogVisible" @update:open="
:title="t('dialog.previous_instances.info')" (open) => {
width="800px" if (!open) closeDialog();
:fullscreen="fullscreen" }
destroy-on-close ">
@close="closeDialog"> <DialogContent class="sm:max-w-200">
<DialogHeader>
<DialogTitle>{{ t('dialog.previous_instances.info') }}</DialogTitle>
</DialogHeader>
<DataTableLayout <DataTableLayout
class="min-w-0 w-full" class="min-w-0 w-full"
:table="table" :table="table"
@@ -26,10 +30,12 @@
</div> </div>
</template> </template>
</DataTableLayout> </DataTableLayout>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, nextTick, ref, watch } from 'vue'; import { computed, nextTick, ref, watch } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -40,7 +46,6 @@
import { InputGroupField } from '../../../components/ui/input-group'; import { InputGroupField } from '../../../components/ui/input-group';
import { createColumns } from './previousInstancesInfoColumns.jsx'; import { createColumns } from './previousInstancesInfoColumns.jsx';
import { database } from '../../../service/database'; import { database } from '../../../service/database';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable'; import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
const { lookupUser } = useUserStore(); const { lookupUser } = useUserStore();
@@ -49,8 +54,6 @@
const { gameLogIsFriend, gameLogIsFavorite } = useGameLogStore(); const { gameLogIsFriend, gameLogIsFavorite } = useGameLogStore();
const { t } = useI18n(); const { t } = useI18n();
const previousInstancesInfoDialogIndex = ref(2000);
const loading = ref(false); const loading = ref(false);
const rawRows = ref([]); const rawRows = ref([]);
const search = ref(''); const search = ref('');
@@ -147,7 +150,6 @@
); );
function init() { function init() {
previousInstancesInfoDialogIndex.value = getNextDialogIndex();
loading.value = true; loading.value = true;
location.value = parseLocation(previousInstancesInfoDialogInstanceId.value); location.value = parseLocation(previousInstancesInfoDialogInstanceId.value);
} }

View File

@@ -1,10 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="isVisible">
:z-index="previousInstancesWorldDialogIndex" <DialogContent class="sm:max-w-250">
v-model="isVisible" <DialogHeader>
:title="t('dialog.previous_instances.header')" <DialogTitle>{{ t('dialog.previous_instances.header') }}</DialogTitle>
width="1000px" </DialogHeader>
append-to-body>
<DataTableLayout <DataTableLayout
class="min-w-0 w-full" class="min-w-0 w-full"
:table="table" :table="table"
@@ -25,11 +25,13 @@
</div> </div>
</template> </template>
</DataTableLayout> </DataTableLayout>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { computed, nextTick, ref, watch } from 'vue'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref, watch } from 'vue';
import { InputGroupField } from '@/components/ui/input-group'; import { InputGroupField } from '@/components/ui/input-group';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -52,7 +54,6 @@
import { DataTableLayout } from '../../ui/data-table'; import { DataTableLayout } from '../../ui/data-table';
import { createColumns } from './previousInstancesWorldColumns.jsx'; import { createColumns } from './previousInstancesWorldColumns.jsx';
import { database } from '../../../service/database'; import { database } from '../../../service/database';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable'; import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
const { t } = useI18n(); const { t } = useI18n();
@@ -79,7 +80,6 @@
const pageSize = ref(10); const pageSize = ref(10);
const tableStyle = { maxHeight: '400px' }; const tableStyle = { maxHeight: '400px' };
const loading = ref(false); const loading = ref(false);
const previousInstancesWorldDialogIndex = ref(2000);
const isVisible = computed({ const isVisible = computed({
get: () => props.previousInstancesWorldDialog.visible, get: () => props.previousInstancesWorldDialog.visible,
@@ -188,9 +188,6 @@
() => props.previousInstancesWorldDialog.openFlg, () => props.previousInstancesWorldDialog.openFlg,
() => { () => {
if (props.previousInstancesWorldDialog.visible) { if (props.previousInstancesWorldDialog.visible) {
nextTick(() => {
previousInstancesWorldDialogIndex.value = getNextDialogIndex();
});
refreshPreviousInstancesWorldTable(); refreshPreviousInstancesWorldTable();
} }
} }

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog v-model:open="sendBoopDialog.visible">
class="x-dialog" <DialogContent>
v-model="sendBoopDialog.visible" <DialogHeader>
:title="t('dialog.boop_dialog.header')" <DialogTitle>{{ t('dialog.boop_dialog.header') }}</DialogTitle>
width="450px" </DialogHeader>
@close="closeDialog">
<span>{{ displayName }}</span> <span>{{ displayName }}</span>
<br /> <br />
@@ -58,7 +57,7 @@
</div> </div>
</div> </div>
<template #footer> <DialogFooter>
<Button size="sm" variant="outline" class="mr-2" @click="showGalleryPage">{{ <Button size="sm" variant="outline" class="mr-2" @click="showGalleryPage">{{
t('dialog.boop_dialog.emoji_manager') t('dialog.boop_dialog.emoji_manager')
}}</Button> }}</Button>
@@ -68,14 +67,16 @@
<Button size="sm" :disabled="!sendBoopDialog.userId" @click="sendBoop">{{ <Button size="sm" :disabled="!sendBoopDialog.userId" @click="sendBoop">{{
t('dialog.boop_dialog.send') t('dialog.boop_dialog.send')
}}</Button> }}</Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
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 { Check as CheckIcon } from 'lucide-vue-next'; import { Check as CheckIcon } from 'lucide-vue-next';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';

View File

@@ -1,10 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="bioDialog.visible">
class="x-dialog" <DialogContent class="x-dialog sm:max-w-150">
v-model="bioDialog.visible" <DialogHeader>
:title="t('dialog.bio.header')" <DialogTitle>{{ t('dialog.bio.header') }}</DialogTitle>
width="600px" </DialogHeader>
append-to-body>
<div v-loading="bioDialog.loading"> <div v-loading="bioDialog.loading">
<InputGroupTextareaField <InputGroupTextareaField
v-model="bioDialog.bio" v-model="bioDialog.bio"
@@ -42,15 +42,17 @@
</Button> </Button>
</div> </div>
<template #footer> <DialogFooter>
<Button :disabled="bioDialog.loading" @click="saveBio"> <Button :disabled="bioDialog.loading" @click="saveBio">
{{ t('dialog.bio.update') }} {{ t('dialog.bio.update') }}
</Button> </Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { InputGroupAction, InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupAction, InputGroupTextareaField } from '@/components/ui/input-group';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Trash2 } from 'lucide-vue-next'; import { Trash2 } from 'lucide-vue-next';

View File

@@ -1,13 +1,16 @@
<template> <template>
<el-dialog <Dialog
class="x-dialog" :open="props.visible"
:model-value="props.visible" @update:open="
title="Edit Note And Memo" (open) => {
:show-close="false" if (!open) cancel();
top="30vh" }
width="500px" ">
append-to-body <DialogContent class="x-dialog sm:max-w-125 translate-y-0" style="top: 30vh" :show-close-button="false">
@close="cancel"> <DialogHeader>
<DialogTitle>Edit Note And Memo</DialogTitle>
</DialogHeader>
<template v-if="!hideUserNotes || (hideUserNotes && hideUserMemos)"> <template v-if="!hideUserNotes || (hideUserNotes && hideUserMemos)">
<span class="name my-2">{{ t('dialog.user.info.note') }}</span> <span class="name my-2">{{ t('dialog.user.info.note') }}</span>
<br /> <br />
@@ -30,16 +33,17 @@
:placeholder="t('dialog.user.info.memo_placeholder')" :placeholder="t('dialog.user.info.memo_placeholder')"
input-class="resize-none min-h-0" /> input-class="resize-none min-h-0" />
</template> </template>
<template #footer>
<div class="dialog-footer"> <DialogFooter>
<Button variant="secondary" @click="cancel" class="mr-2">Cancel</Button> <Button variant="secondary" @click="cancel" class="mr-2">Cancel</Button>
<Button @click="saveChanges">Confirm</Button> <Button @click="saveChanges">Confirm</Button>
</div> </DialogFooter>
</template> </DialogContent>
</el-dialog> </Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';

View File

@@ -1,10 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="languageDialog.visible">
class="x-dialog" <DialogContent class="x-dialog sm:max-w-100">
v-model="languageDialog.visible" <DialogHeader>
:title="t('dialog.language.header')" <DialogTitle>{{ t('dialog.language.header') }}</DialogTitle>
width="400px" </DialogHeader>
append-to-body>
<div v-loading="languageDialog.loading"> <div v-loading="languageDialog.loading">
<div v-for="item in currentUser.$languages" :key="item.key" style="margin: 6px 0"> <div v-for="item in currentUser.$languages" :key="item.key" style="margin: 6px 0">
<Badge variant="outline" style="margin-right: 5px"> <Badge variant="outline" style="margin-right: 5px">
@@ -32,7 +32,9 @@
</div> </div>
<Select <Select
:model-value="selectedLanguageToAdd" :model-value="selectedLanguageToAdd"
:disabled="languageDialog.loading || (currentUser.$languages && currentUser.$languages.length === 3)" :disabled="
languageDialog.loading || (currentUser.$languages && currentUser.$languages.length === 3)
"
@update:modelValue="handleAddUserLanguage"> @update:modelValue="handleAddUserLanguage">
<SelectTrigger size="sm" style="margin-top: 14px"> <SelectTrigger size="sm" style="margin-top: 14px">
<SelectValue :placeholder="t('dialog.language.select_language')" /> <SelectValue :placeholder="t('dialog.language.select_language')" />
@@ -54,10 +56,12 @@
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { X } from 'lucide-vue-next'; import { X } from 'lucide-vue-next';
import { ref } from 'vue'; import { ref } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';

View File

@@ -1,10 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="isVisible">
:z-index="previousInstancesUserDialogIndex" <DialogContent class="sm:max-w-250">
v-model="isVisible" <DialogHeader>
:title="t('dialog.previous_instances.header')" <DialogTitle>{{ t('dialog.previous_instances.header') }}</DialogTitle>
width="1000px" </DialogHeader>
append-to-body>
<DataTableLayout <DataTableLayout
class="min-w-0 w-full" class="min-w-0 w-full"
:table="table" :table="table"
@@ -25,11 +25,13 @@
</div> </div>
</template> </template>
</DataTableLayout> </DataTableLayout>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { computed, nextTick, ref, watch } from 'vue'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref, watch } from 'vue';
import { InputGroupField } from '@/components/ui/input-group'; import { InputGroupField } from '@/components/ui/input-group';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -52,7 +54,6 @@
import { DataTableLayout } from '../../ui/data-table'; import { DataTableLayout } from '../../ui/data-table';
import { createColumns } from './previousInstancesUserColumns.jsx'; import { createColumns } from './previousInstancesUserColumns.jsx';
import { database } from '../../../service/database'; import { database } from '../../../service/database';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable'; import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
const props = defineProps({ const props = defineProps({
@@ -90,8 +91,6 @@
const vrcxStore = useVrcxStore(); const vrcxStore = useVrcxStore();
const { t } = useI18n(); const { t } = useI18n();
const previousInstancesUserDialogIndex = ref(2000);
const isVisible = computed({ const isVisible = computed({
get: () => props.previousInstancesUserDialog.visible, get: () => props.previousInstancesUserDialog.visible,
set: (value) => { set: (value) => {
@@ -178,9 +177,6 @@
() => props.previousInstancesUserDialog.openFlg, () => props.previousInstancesUserDialog.openFlg,
() => { () => {
if (props.previousInstancesUserDialog.visible) { if (props.previousInstancesUserDialog.visible) {
nextTick(() => {
previousInstancesUserDialogIndex.value = getNextDialogIndex();
});
refreshPreviousInstancesUserTable(); refreshPreviousInstancesUserTable();
} }
} }

View File

@@ -1,10 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="pronounsDialog.visible">
class="x-dialog" <DialogContent class="x-dialog sm:max-w-150">
v-model="pronounsDialog.visible" <DialogHeader>
:title="t('dialog.pronouns.header')" <DialogTitle>{{ t('dialog.pronouns.header') }}</DialogTitle>
width="600px" </DialogHeader>
append-to-body>
<div v-loading="pronounsDialog.loading"> <div v-loading="pronounsDialog.loading">
<InputGroupTextareaField <InputGroupTextareaField
v-model="pronounsDialog.pronouns" v-model="pronounsDialog.pronouns"
@@ -13,15 +13,18 @@
:placeholder="t('dialog.pronouns.pronouns_placeholder')" :placeholder="t('dialog.pronouns.pronouns_placeholder')"
show-count /> show-count />
</div> </div>
<template #footer>
<DialogFooter>
<Button :disabled="pronounsDialog.loading" @click="savePronouns"> <Button :disabled="pronounsDialog.loading" @click="savePronouns">
{{ t('dialog.pronouns.update') }} {{ t('dialog.pronouns.update') }}
</Button> </Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';

View File

@@ -1,11 +1,16 @@
<template> <template>
<el-dialog <Dialog
class="x-dialog" :open="sendInviteRequestDialogVisible"
:model-value="sendInviteRequestDialogVisible" @update:open="
:title="t('dialog.invite_request_message.header')" (open) => {
width="800px" if (!open) cancelSendInviteRequest();
append-to-body }
@close="cancelSendInviteRequest"> ">
<DialogContent class="x-dialog sm:max-w-200">
<DialogHeader>
<DialogTitle>{{ t('dialog.invite_request_message.header') }}</DialogTitle>
</DialogHeader>
<template v-if="isLocalUserVrcPlusSupporter"> <template v-if="isLocalUserVrcPlusSupporter">
<input class="inviteImageUploadButton" type="file" accept="image/*" @change="inviteImageUpload" /> <input class="inviteImageUploadButton" type="file" accept="image/*" @change="inviteImageUpload" />
</template> </template>
@@ -17,14 +22,16 @@
:show-pagination="false" :show-pagination="false"
:on-row-click="handleInviteRequestMessageRowClick" /> :on-row-click="handleInviteRequestMessageRowClick" />
<template #footer> <DialogFooter>
<Button variant="secondary" class="mr-2" @click="cancelSendInviteRequest">{{ <Button variant="secondary" class="mr-2" @click="cancelSendInviteRequest">{{
t('dialog.invite_request_message.cancel') t('dialog.invite_request_message.cancel')
}}</Button> }}</Button>
<Button @click="refreshInviteMessageTableData('request')">{{ <Button @click="refreshInviteMessageTableData('request')">{{
t('dialog.invite_request_message.refresh') t('dialog.invite_request_message.refresh')
}}</Button> }}</Button>
</template> </DialogFooter>
</DialogContent>
<SendInviteConfirmDialog <SendInviteConfirmDialog
v-model:isSendInviteConfirmDialogVisible="isSendInviteConfirmDialogVisible" v-model:isSendInviteConfirmDialogVisible="isSendInviteConfirmDialogVisible"
:sendInviteDialog="sendInviteDialog" :sendInviteDialog="sendInviteDialog"
@@ -37,10 +44,11 @@
@update:sendInviteDialog="emit('update:sendInviteDialog', $event)" @update:sendInviteDialog="emit('update:sendInviteDialog', $event)"
:invite-dialog="inviteDialog" :invite-dialog="inviteDialog"
@closeInviteDialog="closeInviteDialog" /> @closeInviteDialog="closeInviteDialog" />
</el-dialog> </Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref } from 'vue'; import { computed, ref } 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';

View File

@@ -1,10 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="socialStatusDialog.visible">
class="x-dialog" <DialogContent class="x-dialog sm:max-w-100">
v-model="socialStatusDialog.visible" <DialogHeader>
:title="t('dialog.social_status.header')" <DialogTitle>{{ t('dialog.social_status.header') }}</DialogTitle>
append-to-body </DialogHeader>
width="400px">
<div v-loading="socialStatusDialog.loading"> <div v-loading="socialStatusDialog.loading">
<Select :model-value="socialStatusDialog.status" @update:modelValue="handleSocialStatusChange"> <Select :model-value="socialStatusDialog.status" @update:modelValue="handleSocialStatusChange">
<SelectTrigger size="sm" style="margin-top: 10px; width: 100%"> <SelectTrigger size="sm" style="margin-top: 10px; width: 100%">
@@ -72,25 +72,27 @@
@click="setSocialStatusFromHistory(item)"> @click="setSocialStatusFromHistory(item)">
{{ item.status }} {{ item.status }}
</div> </div>
</CollapsibleContent> </CollapsibleContent></Collapsible
</Collapsible> >
</div> </div>
<template #footer> <DialogFooter>
<Button :disabled="socialStatusDialog.loading" @click="saveSocialStatus"> <Button :disabled="socialStatusDialog.loading" @click="saveSocialStatus">
{{ t('dialog.social_status.update') }} {{ t('dialog.social_status.update') }}
</Button> </Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupField } from '@/components/ui/input-group';
import { ChevronsUpDown } from 'lucide-vue-next'; import { ChevronsUpDown } from 'lucide-vue-next';
import { InputGroupField } from '@/components/ui/input-group';
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';

View File

@@ -1,12 +1,16 @@
<template> <template>
<el-dialog <Dialog v-model:open="userDialog.visible">
:z-index="userDialogIndex" <DialogContent
class="x-dialog x-user-dialog" class="x-dialog x-user-dialog sm:max-w-235 translate-y-0"
v-model="userDialog.visible" style="top: 10vh"
:show-close="false" :show-close-button="false">
top="10vh"
width="940px">
<div v-loading="userDialog.loading"> <div v-loading="userDialog.loading">
<DialogHeader class="sr-only">
<DialogTitle>{{
userDialog.ref?.displayName || userDialog.id || t('dialog.user.info.header')
}}</DialogTitle>
<DialogDescription>{{ getUserStateText(userDialog.ref || {}) }}</DialogDescription>
</DialogHeader>
<UserSummaryHeader <UserSummaryHeader
:get-user-state-text="getUserStateText" :get-user-state-text="getUserStateText"
:copy-user-display-name="copyUserDisplayName" :copy-user-display-name="copyUserDisplayName"
@@ -169,7 +173,8 @@
style="display: inline-block" /> style="display: inline-block" />
<TooltipWrapper <TooltipWrapper
v-if=" v-if="
userDialog.ref.profilePicOverride && !userDialog.ref.currentAvatarImageUrl userDialog.ref.profilePicOverride &&
!userDialog.ref.currentAvatarImageUrl
" "
side="top" side="top"
:content="t('dialog.user.info.vrcplus_hides_avatar')"> :content="t('dialog.user.info.vrcplus_hides_avatar')">
@@ -303,7 +308,9 @@
style="display: flex; justify-content: space-between; align-items: center"> style="display: flex; justify-content: space-between; align-items: center">
<div> <div>
{{ t('dialog.user.info.join_count') }} {{ t('dialog.user.info.join_count') }}
<TooltipWrapper side="top" :content="t('dialog.user.info.accuracy_notice')"> <TooltipWrapper
side="top"
:content="t('dialog.user.info.accuracy_notice')">
<AlertTriangle style="margin-left: 3px" /> <AlertTriangle style="margin-left: 3px" />
</TooltipWrapper> </TooltipWrapper>
</div> </div>
@@ -341,7 +348,9 @@
<div class="detail"> <div class="detail">
<span class="name"> <span class="name">
{{ t('dialog.user.info.play_time') }} {{ t('dialog.user.info.play_time') }}
<TooltipWrapper side="top" :content="t('dialog.user.info.accuracy_notice')"> <TooltipWrapper
side="top"
:content="t('dialog.user.info.accuracy_notice')">
<AlertTriangle style="margin-left: 3px" /> <AlertTriangle style="margin-left: 3px" />
</TooltipWrapper> </TooltipWrapper>
</span> </span>
@@ -424,7 +433,9 @@
<AlertTriangle style="margin-left: 3px" /> <AlertTriangle style="margin-left: 3px" />
</TooltipWrapper> </TooltipWrapper>
</span> </span>
<span class="extra">{{ formatDateFilter(userDialog.dateFriended, 'long') }}</span> <span class="extra">{{
formatDateFilter(userDialog.dateFriended, 'long')
}}</span>
</div> </div>
</TooltipWrapper> </TooltipWrapper>
</div> </div>
@@ -552,7 +563,9 @@
</div> </div>
</template> </template>
<template v-if="userDialog.id !== currentUser.id && !currentUser.hasSharedConnectionsOptOut" #mutual> <template
v-if="userDialog.id !== currentUser.id && !currentUser.hasSharedConnectionsOptOut"
#mutual>
<div style="display: flex; align-items: center; justify-content: space-between"> <div style="display: flex; align-items: center; justify-content: space-between">
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
<Button <Button
@@ -640,7 +653,11 @@
}}</span> }}</span>
<template v-if="userDialogGroupEditMode"> <template v-if="userDialogGroupEditMode">
<span <span
style="margin-left: 10px; color: var(--el-text-color-secondary); font-size: 10px" style="
margin-left: 10px;
color: var(--el-text-color-secondary);
font-size: 10px;
"
>{{ t('dialog.user.groups.hold_shift') }}</span >{{ t('dialog.user.groups.hold_shift') }}</span
> >
</template> </template>
@@ -688,10 +705,17 @@
</div> </div>
<div v-loading="userDialog.isGroupsLoading" style="margin-top: 10px"> <div v-loading="userDialog.isGroupsLoading" style="margin-top: 10px">
<template v-if="userDialogGroupEditMode"> <template v-if="userDialogGroupEditMode">
<div class="x-friend-list" style="margin-top: 10px; margin-bottom: 15px; max-height: unset"> <div
class="x-friend-list"
style="margin-top: 10px; margin-bottom: 15px; max-height: unset">
<!-- Bulk actions dropdown (shown only in edit mode) --> <!-- Bulk actions dropdown (shown only in edit mode) -->
<Select :model-value="bulkGroupActionValue" @update:modelValue="handleBulkGroupAction"> <Select
<SelectTrigger size="sm" style="margin-right: 5px; margin-bottom: 5px" @click.stop> :model-value="bulkGroupActionValue"
@update:modelValue="handleBulkGroupAction">
<SelectTrigger
size="sm"
style="margin-right: 5px; margin-bottom: 5px"
@click.stop>
<SelectValue :placeholder="t('dialog.group.actions.manage_selected')" /> <SelectValue :placeholder="t('dialog.group.actions.manage_selected')" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -793,7 +817,9 @@
:content="t('dialog.group.members.representing')"> :content="t('dialog.group.members.representing')">
<Tag style="margin-right: 5px" /> <Tag style="margin-right: 5px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="group.myMember?.visibility !== 'visible'" side="top"> <TooltipWrapper
v-if="group.myMember?.visibility !== 'visible'"
side="top">
<template #content> <template #content>
<span <span
>{{ t('dialog.group.members.visibility') }} >{{ t('dialog.group.members.visibility') }}
@@ -848,7 +874,9 @@
{{ t('dialog.group.tags.unsubscribed') }}</span {{ t('dialog.group.tags.unsubscribed') }}</span
> >
</Button> --> </Button> -->
<TooltipWrapper side="right" :content="t('dialog.user.groups.leave_group_tooltip')"> <TooltipWrapper
side="right"
:content="t('dialog.user.groups.leave_group_tooltip')">
<Button <Button
class="rounded-full h-6 w-6" class="rounded-full h-6 w-6"
size="icon-sm" size="icon-sm"
@@ -876,7 +904,8 @@
<span style="font-weight: bold; font-size: 16px">{{ <span style="font-weight: bold; font-size: 16px">{{
t('dialog.user.groups.own_groups') t('dialog.user.groups.own_groups')
}}</span> }}</span>
<span style="color: var(--el-text-color-secondary); font-size: 12px; margin-left: 5px" <span
style="color: var(--el-text-color-secondary); font-size: 12px; margin-left: 5px"
>{{ userGroups.ownGroups.length }}/{{ >{{ userGroups.ownGroups.length }}/{{
cachedConfig?.constants?.GROUPS?.MAX_OWNED cachedConfig?.constants?.GROUPS?.MAX_OWNED
}}</span }}</span
@@ -901,7 +930,9 @@
:content="t('dialog.group.members.representing')"> :content="t('dialog.group.members.representing')">
<Tag style="margin-right: 5px" /> <Tag style="margin-right: 5px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="group.memberVisibility !== 'visible'" side="top"> <TooltipWrapper
v-if="group.memberVisibility !== 'visible'"
side="top">
<template #content> <template #content>
<span <span
>{{ t('dialog.group.members.visibility') }} >{{ t('dialog.group.members.visibility') }}
@@ -944,7 +975,9 @@
:content="t('dialog.group.members.representing')"> :content="t('dialog.group.members.representing')">
<Tag style="margin-right: 5px" /> <Tag style="margin-right: 5px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="group.memberVisibility !== 'visible'" side="top"> <TooltipWrapper
v-if="group.memberVisibility !== 'visible'"
side="top">
<template #content> <template #content>
<span <span
>{{ t('dialog.group.members.visibility') }} >{{ t('dialog.group.members.visibility') }}
@@ -963,7 +996,12 @@
<span style="font-weight: bold; font-size: 16px">{{ <span style="font-weight: bold; font-size: 16px">{{
t('dialog.user.groups.groups') t('dialog.user.groups.groups')
}}</span> }}</span>
<span style="color: var(--el-text-color-secondary); font-size: 12px; margin-left: 5px"> <span
style="
color: var(--el-text-color-secondary);
font-size: 12px;
margin-left: 5px;
">
{{ userGroups.remainingGroups.length }} {{ userGroups.remainingGroups.length }}
<template v-if="currentUser.id === userDialog.id"> <template v-if="currentUser.id === userDialog.id">
/ /
@@ -995,7 +1033,9 @@
:content="t('dialog.group.members.representing')"> :content="t('dialog.group.members.representing')">
<Tag style="margin-right: 5px" /> <Tag style="margin-right: 5px" />
</TooltipWrapper> </TooltipWrapper>
<TooltipWrapper v-if="group.memberVisibility !== 'visible'" side="top"> <TooltipWrapper
v-if="group.memberVisibility !== 'visible'"
side="top">
<template #content> <template #content>
<span <span
>{{ t('dialog.group.members.visibility') }} >{{ t('dialog.group.members.visibility') }}
@@ -1119,7 +1159,11 @@
</i> </i>
<span style="font-weight: bold; font-size: 14px" v-text="list[0]"></span> <span style="font-weight: bold; font-size: 14px" v-text="list[0]"></span>
<span <span
style="color: var(--el-text-color-secondary); font-size: 10px; margin-left: 5px" style="
color: var(--el-text-color-secondary);
font-size: 10px;
margin-left: 5px;
"
>{{ list[2].length }}/{{ favoriteLimits.maxFavoritesPerGroup.world }}</span >{{ list[2].length }}/{{ favoriteLimits.maxFavoritesPerGroup.world }}</span
> >
</span> </span>
@@ -1130,7 +1174,12 @@
v-slot:[String(index)]> v-slot:[String(index)]>
<div <div
class="x-friend-list" class="x-friend-list"
style="margin-top: 10px; margin-bottom: 15px; min-height: 60px; max-height: none"> style="
margin-top: 10px;
margin-bottom: 15px;
min-height: 60px;
max-height: none;
">
<div <div
v-for="world in list[2]" v-for="world in list[2]"
:key="world.favoriteId" :key="world.favoriteId"
@@ -1141,7 +1190,9 @@
</div> </div>
<div class="detail"> <div class="detail">
<span class="name" v-text="world.name"></span> <span class="name" v-text="world.name"></span>
<span v-if="world.occupants" class="extra">({{ world.occupants }})</span> <span v-if="world.occupants" class="extra"
>({{ world.occupants }})</span
>
</div> </div>
</div> </div>
</div> </div>
@@ -1214,12 +1265,18 @@
@update:modelValue="(value) => (userDialog.avatarReleaseStatus = value)"> @update:modelValue="(value) => (userDialog.avatarReleaseStatus = value)">
<SelectTrigger size="sm" @click.stop> <SelectTrigger size="sm" @click.stop>
<SelectValue <SelectValue
:placeholder="t(`dialog.user.avatars.${userDialog.avatarReleaseStatus}`)" /> :placeholder="
t(`dialog.user.avatars.${userDialog.avatarReleaseStatus}`)
" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="all">{{ t('dialog.user.avatars.all') }}</SelectItem> <SelectItem value="all">{{ t('dialog.user.avatars.all') }}</SelectItem>
<SelectItem value="public">{{ t('dialog.user.avatars.public') }}</SelectItem> <SelectItem value="public">{{
<SelectItem value="private">{{ t('dialog.user.avatars.private') }}</SelectItem> t('dialog.user.avatars.public')
}}</SelectItem>
<SelectItem value="private">{{
t('dialog.user.avatars.private')
}}</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
</template> </template>
@@ -1232,7 +1289,10 @@
class="x-friend-item x-friend-item-border" class="x-friend-item x-friend-item-border"
@click="showAvatarDialog(avatar.id)"> @click="showAvatarDialog(avatar.id)">
<div class="avatar"> <div class="avatar">
<img v-if="avatar.thumbnailImageUrl" :src="avatar.thumbnailImageUrl" loading="lazy" /> <img
v-if="avatar.thumbnailImageUrl"
:src="avatar.thumbnailImageUrl"
loading="lazy" />
</div> </div>
<div class="detail"> <div class="detail">
<span class="name" v-text="avatar.name"></span> <span class="name" v-text="avatar.name"></span>
@@ -1276,7 +1336,6 @@
show-icon /> show-icon />
</template> </template>
</TabsUnderline> </TabsUnderline>
</div>
<SendInviteDialog <SendInviteDialog
v-model:sendInviteDialogVisible="sendInviteDialogVisible" v-model:sendInviteDialogVisible="sendInviteDialogVisible"
v-model:sendInviteDialog="sendInviteDialog" v-model:sendInviteDialog="sendInviteDialog"
@@ -1294,7 +1353,9 @@
<PronounsDialog :pronouns-dialog="pronounsDialog" /> <PronounsDialog :pronouns-dialog="pronounsDialog" />
<ModerateGroupDialog /> <ModerateGroupDialog />
<EditNoteAndMemoDialog v-model:visible="isEditNoteAndMemoDialogVisible" /> <EditNoteAndMemoDialog v-model:visible="isEditNoteAndMemoDialogVisible" />
</el-dialog> </div>
</DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
@@ -1316,6 +1377,7 @@
Tag, Tag,
Trash2 Trash2
} from 'lucide-vue-next'; } from 'lucide-vue-next';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { computed, defineAsyncComponent, nextTick, ref, watch } from 'vue'; import { computed, defineAsyncComponent, nextTick, ref, watch } from 'vue';
import { import {
@@ -1386,7 +1448,6 @@
import { userDialogGroupSortingOptions, userDialogMutualFriendSortingOptions } from '../../../shared/constants'; import { userDialogGroupSortingOptions, userDialogMutualFriendSortingOptions } from '../../../shared/constants';
import { userDialogWorldOrderOptions, userDialogWorldSortingOptions } from '../../../shared/constants/'; import { userDialogWorldOrderOptions, userDialogWorldSortingOptions } from '../../../shared/constants/';
import { database } from '../../../service/database'; import { database } from '../../../service/database';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import SendInviteDialog from '../InviteDialog/SendInviteDialog.vue'; import SendInviteDialog from '../InviteDialog/SendInviteDialog.vue';
import UserSummaryHeader from './UserSummaryHeader.vue'; import UserSummaryHeader from './UserSummaryHeader.vue';
@@ -1470,9 +1531,6 @@
() => userDialog.value.loading, () => userDialog.value.loading,
() => { () => {
if (userDialog.value.visible) { if (userDialog.value.visible) {
nextTick(() => {
userDialogIndex.value = getNextDialogIndex();
});
!userDialog.value.loading && loadLastActiveTab(); !userDialog.value.loading && loadLastActiveTab();
if (userDialog.value.id !== bioCache.value.userId) { if (userDialog.value.id !== bioCache.value.userId) {
bioCache.value = { bioCache.value = {
@@ -1484,8 +1542,6 @@
} }
); );
const userDialogIndex = ref(2000);
const userDialogGroupEditMode = ref(false); // whether edit mode is active const userDialogGroupEditMode = ref(false); // whether edit mode is active
const userDialogGroupEditGroups = ref([]); // editable group list const userDialogGroupEditGroups = ref([]); // editable group list
const userDialogGroupAllSelected = ref(false); const userDialogGroupAllSelected = ref(false);

View File

@@ -1,11 +1,9 @@
<template> <template>
<el-dialog <Dialog v-model:open="VRCXUpdateDialog.visible">
:z-index="VRCXUpdateDialogIndex" <DialogContent>
class="x-dialog" <DialogHeader>
v-model="VRCXUpdateDialog.visible" <DialogTitle>{{ t('dialog.vrcx_updater.header') }}</DialogTitle>
:title="t('dialog.vrcx_updater.header')" </DialogHeader>
append-to-body
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">
<Progress :model-value="updateProgress" class="w-full" /> <Progress :model-value="updateProgress" class="w-full" />
@@ -63,7 +61,7 @@
</template> </template>
</div> </div>
<template #footer> <DialogFooter>
<Button variant="secondary" class="mr-2" v-if="updateInProgress" @click="cancelUpdate"> <Button variant="secondary" class="mr-2" v-if="updateInProgress" @click="cancelUpdate">
{{ t('dialog.vrcx_updater.cancel') }} {{ t('dialog.vrcx_updater.cancel') }}
</Button> </Button>
@@ -77,15 +75,16 @@
<Button variant="default" v-if="!updateInProgress && pendingVRCXInstall" @click="restartVRCX(true)"> <Button variant="default" v-if="!updateInProgress && pendingVRCXInstall" @click="restartVRCX(true)">
{{ t('dialog.vrcx_updater.install') }} {{ t('dialog.vrcx_updater.install') }}
</Button> </Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field'; import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { nextTick, ref, watch } from 'vue'; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { AlertCircle } from 'lucide-vue-next'; import { AlertCircle } from 'lucide-vue-next';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Progress } from '@/components/ui/progress'; import { Progress } from '@/components/ui/progress';
@@ -93,7 +92,6 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
import { useVRCXUpdaterStore } from '../../stores'; import { useVRCXUpdaterStore } from '../../stores';
const VRCXUpdaterStore = useVRCXUpdaterStore(); const VRCXUpdaterStore = useVRCXUpdaterStore();
@@ -111,7 +109,6 @@
const { t } = useI18n(); const { t } = useI18n();
const VRCXUpdateDialogIndex = ref(2000);
const handleBranchChange = (value) => { const handleBranchChange = (value) => {
if (!value || value === branch.value) { if (!value || value === branch.value) {
return; return;
@@ -119,15 +116,4 @@
branch.value = value; branch.value = value;
loadBranchVersions(); loadBranchVersions();
}; };
watch(
() => VRCXUpdateDialog,
(newVal) => {
if (newVal.value.visible) {
nextTick(() => {
VRCXUpdateDialogIndex.value = getNextDialogIndex();
});
}
}
);
</script> </script>

View File

@@ -1,11 +1,16 @@
<template> <template>
<el-dialog <Dialog
class="x-dialog" :open="changeWorldImageDialogVisible"
:model-value="changeWorldImageDialogVisible" @update:open="
:title="t('dialog.change_content_image.world')" (open) => {
width="850px" if (!open) closeDialog();
append-to-body }
@close="closeDialog"> ">
<DialogContent class="x-dialog sm:max-w-212.5">
<DialogHeader>
<DialogTitle>{{ t('dialog.change_content_image.world') }}</DialogTitle>
</DialogHeader>
<div> <div>
<input <input
id="WorldImageUploadButton" id="WorldImageUploadButton"
@@ -24,10 +29,12 @@
<img :src="previousImageUrl" class="img-size" loading="lazy" /> <img :src="previousImageUrl" class="img-size" loading="lazy" />
</div> </div>
</div> </div>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Upload } from 'lucide-vue-next'; import { Upload } from 'lucide-vue-next';
import { ref } from 'vue'; import { ref } from 'vue';

View File

@@ -1,10 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="isVisible">
v-model="isVisible" <DialogContent class="sm:max-w-100">
:title="t('dialog.set_world_tags.header')" <DialogHeader>
width="400px" <DialogTitle>{{ t('dialog.set_world_tags.header') }}</DialogTitle>
destroy-on-close </DialogHeader>
append-to-body>
<label class="inline-flex items-center gap-2"> <label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.avatarScalingDisabled" /> <Checkbox v-model="setWorldTagsDialog.avatarScalingDisabled" />
<span>{{ t('dialog.set_world_tags.avatar_scaling_disabled') }}</span> <span>{{ t('dialog.set_world_tags.avatar_scaling_disabled') }}</span>
@@ -88,7 +88,8 @@
<Checkbox v-model="setWorldTagsDialog.thirdPerson" /> <Checkbox v-model="setWorldTagsDialog.thirdPerson" />
<span>{{ t('dialog.new_instance.content_third_person') }}</span> <span>{{ t('dialog.new_instance.content_third_person') }}</span>
</label> </label>
<template #footer>
<DialogFooter>
<div class="flex gap-2"> <div class="flex gap-2">
<Button variant="secondary" @click="isVisible = false"> <Button variant="secondary" @click="isVisible = false">
{{ t('dialog.set_world_tags.cancel') }} {{ t('dialog.set_world_tags.cancel') }}
@@ -97,11 +98,13 @@
{{ t('dialog.set_world_tags.save') }} {{ t('dialog.set_world_tags.save') }}
</Button> </Button>
</div> </div>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
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 { Checkbox } from '@/components/ui/checkbox'; import { Checkbox } from '@/components/ui/checkbox';

View File

@@ -1,10 +1,10 @@
<template> <template>
<el-dialog <Dialog v-model:open="isVisible">
v-model="isVisible" <DialogContent class="sm:max-w-150">
:title="t('dialog.allowed_video_player_domains.header')" <DialogHeader>
width="600px" <DialogTitle>{{ t('dialog.allowed_video_player_domains.header') }}</DialogTitle>
destroy-on-close </DialogHeader>
append-to-body>
<div> <div>
<InputGroupAction <InputGroupAction
v-for="(domain, index) in urlList" v-for="(domain, index) in urlList"
@@ -20,15 +20,18 @@
{{ t('dialog.allowed_video_player_domains.add_domain') }} {{ t('dialog.allowed_video_player_domains.add_domain') }}
</Button> </Button>
</div> </div>
<template #footer>
<DialogFooter>
<Button :disabled="!worldAllowedDomainsDialog.worldId" @click="saveWorldAllowedDomains"> <Button :disabled="!worldAllowedDomainsDialog.worldId" @click="saveWorldAllowedDomains">
{{ t('dialog.allowed_video_player_domains.save') }} {{ t('dialog.allowed_video_player_domains.save') }}
</Button> </Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
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 { InputGroupAction } from '@/components/ui/input-group'; import { InputGroupAction } from '@/components/ui/input-group';

View File

@@ -1,11 +1,9 @@
<template> <template>
<el-dialog <Dialog v-model:open="isDialogVisible">
:z-index="worldDialogIndex" <DialogContent
class="x-dialog x-world-dialog" class="x-dialog x-world-dialog translate-y-0 sm:max-w-235"
v-model="isDialogVisible" :show-close-button="false"
top="10vh" style="top: 10vh">
:show-close="false"
width="940px">
<div v-loading="worldDialog.loading"> <div v-loading="worldDialog.loading">
<div style="display: flex"> <div style="display: flex">
<img <img
@@ -337,7 +335,9 @@
</div> </div>
<div v-for="room in worldDialog.rooms" :key="room.id"> <div v-for="room in worldDialog.rooms" :key="room.id">
<template <template
v-if="isAgeGatedInstancesVisible || !(room.ageGate || room.location?.includes('~ageGate'))"> v-if="
isAgeGatedInstancesVisible || !(room.ageGate || room.location?.includes('~ageGate'))
">
<div style="margin: 5px 0"> <div style="margin: 5px 0">
<div class="flex-align-center"> <div class="flex-align-center">
<LocationWorld <LocationWorld
@@ -373,7 +373,9 @@
><History class="h-4 w-4" /> ><History class="h-4 w-4" />
</Button> </Button>
</TooltipWrapper> </TooltipWrapper>
<LastJoin :location="room.$location.tag" :currentlocation="lastLocation.location" /> <LastJoin
:location="room.$location.tag"
:currentlocation="lastLocation.location" />
<InstanceInfo <InstanceInfo
:location="room.tag" :location="room.tag"
:instance="room.ref" :instance="room.ref"
@@ -487,7 +489,9 @@
class="x-friend-item" class="x-friend-item"
style="width: 350px" style="width: 350px"
@click=" @click="
openExternalLink(`https://www.youtube.com/watch?v=${worldDialog.ref.previewYoutubeId}`) openExternalLink(
`https://www.youtube.com/watch?v=${worldDialog.ref.previewYoutubeId}`
)
"> ">
<div class="detail"> <div class="detail">
<span class="name"> <span class="name">
@@ -505,7 +509,8 @@
</span> </span>
<span <span
v-if=" v-if="
worldDialog.ref.tags?.filter((tag) => tag.startsWith('author_tag')).length > 0 worldDialog.ref.tags?.filter((tag) => tag.startsWith('author_tag')).length >
0
" "
class="extra"> class="extra">
{{ worldTags }} {{ worldTags }}
@@ -696,6 +701,7 @@
</template> </template>
</TabsUnderline> </TabsUnderline>
</div> </div>
</DialogContent>
<template v-if="isDialogVisible"> <template v-if="isDialogVisible">
<WorldAllowedDomainsDialog :world-allowed-domains-dialog="worldAllowedDomainsDialog" /> <WorldAllowedDomainsDialog :world-allowed-domains-dialog="worldAllowedDomainsDialog" />
@@ -712,7 +718,7 @@
v-model:change-world-image-dialog-visible="changeWorldImageDialogVisible" v-model:change-world-image-dialog-visible="changeWorldImageDialogVisible"
v-model:previousImageUrl="previousImageUrl" /> v-model:previousImageUrl="previousImageUrl" />
</template> </template>
</el-dialog> </Dialog>
</template> </template>
<script setup> <script setup>
@@ -745,6 +751,7 @@
Wand2 Wand2
} 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 { Dialog, DialogContent } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
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';
@@ -787,9 +794,9 @@
DropdownMenuTrigger DropdownMenuTrigger
} from '../../ui/dropdown-menu'; } from '../../ui/dropdown-menu';
import { favoriteRequest, miscRequest, userRequest, worldRequest } from '../../../api'; import { favoriteRequest, miscRequest, userRequest, worldRequest } from '../../../api';
import { formatJsonVars, getNextDialogIndex } from '../../../shared/utils/base/ui';
import { Badge } from '../../ui/badge'; import { Badge } from '../../ui/badge';
import { database } from '../../../service/database.js'; import { database } from '../../../service/database.js';
import { formatJsonVars } from '../../../shared/utils/base/ui';
const modalStore = useModalStore(); const modalStore = useModalStore();
@@ -913,16 +920,12 @@
return platforms.join(', '); return platforms.join(', ');
}); });
const worldDialogIndex = ref(2000);
const worldDialogLastActiveTab = ref('Instances'); const worldDialogLastActiveTab = ref('Instances');
watch( watch(
() => worldDialog.value.loading, () => worldDialog.value.loading,
() => { () => {
if (worldDialog.value.visible) { if (worldDialog.value.visible) {
nextTick(() => {
worldDialogIndex.value = getNextDialogIndex();
});
handleDialogOpen(); handleDialogOpen();
!worldDialog.value.loading && loadLastActiveTab(); !worldDialog.value.loading && loadLastActiveTab();
} }

View File

@@ -44,10 +44,12 @@
<span>{{ t('view.charts.mutual_friend.progress.no_relationships_discovered') }}</span> <span>{{ t('view.charts.mutual_friend.progress.no_relationships_discovered') }}</span>
</div> </div>
<el-dialog <Dialog v-model:open="isForceDialogVisible">
v-model="isForceDialogVisible" <DialogContent>
:title="t('view.charts.mutual_friend.force_dialog.title')" <DialogHeader>
width="440px"> <DialogTitle>{{ t('view.charts.mutual_friend.force_dialog.title') }}</DialogTitle>
</DialogHeader>
<p class="mutual-graph__force-description"> <p class="mutual-graph__force-description">
{{ t('view.charts.mutual_friend.force_dialog.description') }} {{ t('view.charts.mutual_friend.force_dialog.description') }}
</p> </p>
@@ -123,7 +125,7 @@
</Field> </Field>
</FieldGroup> </FieldGroup>
<template #footer> <DialogFooter>
<div class="mutual-graph__dialog-footer"> <div class="mutual-graph__dialog-footer">
<Button variant="secondary" class="mr-2" @click="resetForceSettings">{{ <Button variant="secondary" class="mr-2" @click="resetForceSettings">{{
t('view.charts.mutual_friend.force_dialog.reset') t('view.charts.mutual_friend.force_dialog.reset')
@@ -132,13 +134,15 @@
{{ t('view.charts.mutual_friend.force_dialog.apply') }} {{ t('view.charts.mutual_friend.force_dialog.apply') }}
</Button> </Button>
</div> </div>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</div> </div>
</template> </template>
<script setup> <script setup>
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'; import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel } from '@/components/ui/field'; import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel } from '@/components/ui/field';
import { NumberField, NumberFieldContent, NumberFieldInput } from '@/components/ui/number-field'; import { NumberField, NumberFieldContent, NumberFieldInput } from '@/components/ui/number-field';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';

View File

@@ -1,5 +1,10 @@
<template> <template>
<el-dialog v-model="isDialogVisible" :title="t('dialog.avatar_export.header')" width="650px"> <Dialog v-model:open="isDialogVisible">
<DialogContent>
<DialogHeader>
<DialogTitle>{{ t('dialog.avatar_export.header') }}</DialogTitle>
</DialogHeader>
<div style="margin-bottom: 10px" class="flex flex-col gap-2"> <div style="margin-bottom: 10px" class="flex flex-col gap-2">
<label v-for="option in exportSelectOptions" :key="option.value" class="inline-flex items-center gap-2"> <label v-for="option in exportSelectOptions" :key="option.value" class="inline-flex items-center gap-2">
<Checkbox <Checkbox
@@ -54,11 +59,13 @@
style="margin-top: 15px" style="margin-top: 15px"
input-class="resize-none" input-class="resize-none"
@click="handleCopyAvatarExportData" /> @click="handleCopyAvatarExportData" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { Checkbox } from '@/components/ui/checkbox'; import { Checkbox } from '@/components/ui/checkbox';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';

View File

@@ -1,9 +1,9 @@
<template> <template>
<el-dialog <Dialog v-model:open="isVisible">
:z-index="avatarImportDialogIndex" <DialogContent>
v-model="isVisible" <DialogHeader>
:title="t('dialog.avatar_import.header')" <DialogTitle>{{ t('dialog.avatar_import.header') }}</DialogTitle>
width="650px"> </DialogHeader>
<div style="display: flex; align-items: center; justify-content: space-between"> <div style="display: flex; align-items: center; justify-content: space-between">
<div style="font-size: 12px">{{ t('dialog.avatar_import.description') }}</div> <div style="font-size: 12px">{{ t('dialog.avatar_import.description') }}</div>
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
@@ -110,11 +110,13 @@
:table-style="tableStyle" :table-style="tableStyle"
:show-pagination="false" :show-pagination="false"
style="margin-top: 10px" /> style="margin-top: 10px" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
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';
@@ -127,7 +129,6 @@
import { useAvatarStore, useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores'; import { useAvatarStore, useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores';
import { avatarRequest, favoriteRequest } from '../../../api'; import { avatarRequest, favoriteRequest } from '../../../api';
import { createColumns } from './avatarImportColumns.jsx'; import { createColumns } from './avatarImportColumns.jsx';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { removeFromArray } from '../../../shared/utils'; import { removeFromArray } from '../../../shared/utils';
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable'; import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
@@ -189,8 +190,6 @@
enableSorting: false enableSorting: false
}); });
const avatarImportDialogIndex = ref(2000);
const isVisible = computed({ const isVisible = computed({
get() { get() {
return avatarImportDialogVisible.value; return avatarImportDialogVisible.value;
@@ -204,7 +203,6 @@
() => avatarImportDialogVisible.value, () => avatarImportDialogVisible.value,
(value) => { (value) => {
if (value) { if (value) {
avatarImportDialogIndex.value = getNextDialogIndex();
clearAvatarImportTable(); clearAvatarImportTable();
resetAvatarImport(); resetAvatarImport();
if (avatarImportDialogInput.value) { if (avatarImportDialogInput.value) {

View File

@@ -1,18 +1,22 @@
<template> <template>
<el-dialog <Dialog v-model:open="isDialogVisible">
v-model="isDialogVisible" <DialogContent>
class="x-dialog" <DialogHeader>
:title="t('dialog.friend_export.header')" <DialogTitle>{{ t('dialog.friend_export.header') }}</DialogTitle>
width="650px" </DialogHeader>
destroy-on-close> <Select
<Select :model-value="friendExportFavoriteGroupSelection" @update:modelValue="handleFriendExportGroupSelect"> :model-value="friendExportFavoriteGroupSelection"
@update:modelValue="handleFriendExportGroupSelect">
<SelectTrigger size="sm"> <SelectTrigger size="sm">
<SelectValue placeholder="All Favorites" /> <SelectValue placeholder="All Favorites" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectGroup> <SelectGroup>
<SelectItem :value="FRIEND_EXPORT_ALL_VALUE">All Favorites</SelectItem> <SelectItem :value="FRIEND_EXPORT_ALL_VALUE">All Favorites</SelectItem>
<SelectItem v-for="groupAPI in favoriteFriendGroups" :key="groupAPI.name" :value="groupAPI.name"> <SelectItem
v-for="groupAPI in favoriteFriendGroups"
:key="groupAPI.name"
:value="groupAPI.name">
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }}) {{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
</SelectItem> </SelectItem>
</SelectGroup> </SelectGroup>
@@ -28,14 +32,16 @@
style="margin-top: 15px" style="margin-top: 15px"
input-class="resize-none" input-class="resize-none"
@click="handleCopyFriendExportData" /> @click="handleCopyFriendExportData" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';

View File

@@ -1,9 +1,9 @@
<template> <template>
<el-dialog <Dialog v-model:open="isVisible">
:z-index="friendImportDialogIndex" <DialogContent>
v-model="isVisible" <DialogHeader>
:title="t('dialog.friend_import.header')" <DialogTitle>{{ t('dialog.friend_import.header') }}</DialogTitle>
width="650px"> </DialogHeader>
<div style="display: flex; align-items: center; justify-content: space-between"> <div style="display: flex; align-items: center; justify-content: space-between">
<div style="font-size: 12px">{{ t('dialog.friend_import.description') }}</div> <div style="font-size: 12px">{{ t('dialog.friend_import.description') }}</div>
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
@@ -91,11 +91,13 @@
:table-style="tableStyle" :table-style="tableStyle"
:show-pagination="false" :show-pagination="false"
style="margin-top: 10px" /> style="margin-top: 10px" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
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';
@@ -109,7 +111,6 @@
import { useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores'; import { useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores';
import { favoriteRequest, userRequest } from '../../../api'; import { favoriteRequest, userRequest } from '../../../api';
import { createColumns } from './friendImportColumns.jsx'; import { createColumns } from './friendImportColumns.jsx';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable'; import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
const { t } = useI18n(); const { t } = useI18n();
@@ -169,8 +170,6 @@
enableSorting: false enableSorting: false
}); });
const friendImportDialogIndex = ref(2000);
const isVisible = computed({ const isVisible = computed({
get() { get() {
return friendImportDialogVisible.value; return friendImportDialogVisible.value;
@@ -184,7 +183,6 @@
() => friendImportDialogVisible.value, () => friendImportDialogVisible.value,
(value) => { (value) => {
if (value) { if (value) {
friendImportDialogIndex.value = getNextDialogIndex();
clearFriendImportTable(); clearFriendImportTable();
resetFriendImport(); resetFriendImport();
friendImportFavoriteGroupSelection.value = friendImportFavoriteGroupSelection.value =

View File

@@ -1,5 +1,10 @@
<template> <template>
<el-dialog v-model="isDialogVisible" :title="t('dialog.world_export.header')" width="650px"> <Dialog v-model:open="isDialogVisible">
<DialogContent>
<DialogHeader>
<DialogTitle>{{ t('dialog.world_export.header') }}</DialogTitle>
</DialogHeader>
<div style="margin-bottom: 10px" class="flex flex-col gap-2"> <div style="margin-bottom: 10px" class="flex flex-col gap-2">
<label v-for="option in exportSelectOptions" :key="option.value" class="inline-flex items-center gap-2"> <label v-for="option in exportSelectOptions" :key="option.value" class="inline-flex items-center gap-2">
<Checkbox <Checkbox
@@ -10,14 +15,19 @@
</div> </div>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<Select :model-value="worldExportFavoriteGroupSelection" @update:modelValue="handleWorldExportGroupSelect"> <Select
:model-value="worldExportFavoriteGroupSelection"
@update:modelValue="handleWorldExportGroupSelect">
<SelectTrigger size="sm"> <SelectTrigger size="sm">
<SelectValue placeholder="All Favorites" /> <SelectValue placeholder="All Favorites" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectGroup> <SelectGroup>
<SelectItem :value="WORLD_EXPORT_ALL_VALUE">None</SelectItem> <SelectItem :value="WORLD_EXPORT_ALL_VALUE">None</SelectItem>
<SelectItem v-for="groupAPI in favoriteWorldGroups" :key="groupAPI.name" :value="groupAPI.name"> <SelectItem
v-for="groupAPI in favoriteWorldGroups"
:key="groupAPI.name"
:value="groupAPI.name">
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }}) {{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
</SelectItem> </SelectItem>
</SelectGroup> </SelectGroup>
@@ -51,11 +61,13 @@
style="margin-top: 15px" style="margin-top: 15px"
input-class="resize-none" input-class="resize-none"
@click="handleCopyWorldExportData" /> @click="handleCopyWorldExportData" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { Checkbox } from '@/components/ui/checkbox'; import { Checkbox } from '@/components/ui/checkbox';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog v-model:open="isVisible">
:z-index="worldImportDialogIndex" <DialogContent>
v-model="isVisible" <DialogHeader>
:title="t('dialog.world_import.header')" <DialogTitle>{{ t('dialog.world_import.header') }}</DialogTitle>
width="650px" </DialogHeader>
class="x-dialog">
<div style="display: flex; align-items: center; justify-content: space-between"> <div style="display: flex; align-items: center; justify-content: space-between">
<div style="font-size: 12px">{{ t('dialog.world_import.description') }}</div> <div style="font-size: 12px">{{ t('dialog.world_import.description') }}</div>
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
@@ -115,11 +114,13 @@
:table-style="tableStyle" :table-style="tableStyle"
:show-pagination="false" :show-pagination="false"
style="margin-top: 10px" /> style="margin-top: 10px" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
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';
@@ -132,7 +133,6 @@
import { useFavoriteStore, useGalleryStore, useUserStore, useWorldStore } from '../../../stores'; import { useFavoriteStore, useGalleryStore, useUserStore, useWorldStore } from '../../../stores';
import { favoriteRequest, worldRequest } from '../../../api'; import { favoriteRequest, worldRequest } from '../../../api';
import { createColumns } from './worldImportColumns.jsx'; import { createColumns } from './worldImportColumns.jsx';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { removeFromArray } from '../../../shared/utils'; import { removeFromArray } from '../../../shared/utils';
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable'; import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
@@ -147,8 +147,6 @@
const { t } = useI18n(); const { t } = useI18n();
const worldImportDialogIndex = ref(2000);
const worldImportDialog = ref({ const worldImportDialog = ref({
loading: false, loading: false,
progress: 0, progress: 0,
@@ -211,7 +209,6 @@
() => worldImportDialogVisible.value, () => worldImportDialogVisible.value,
(visible) => { (visible) => {
if (visible) { if (visible) {
worldImportDialogIndex.value = getNextDialogIndex();
clearWorldImportTable(); clearWorldImportTable();
resetWorldImport(); resetWorldImport();
if (worldImportDialogInput.value) { if (worldImportDialogInput.value) {

View File

@@ -78,14 +78,15 @@
</div> </div>
</template> </template>
</DataTableLayout> </DataTableLayout>
<el-dialog <Dialog v-model:open="friendsListLoadDialogVisible">
v-model="friendsListLoadDialogVisible" <DialogContent
:title="t('view.friend_list.load_dialog_title')" :show-close-button="false"
width="420px" @interact-outside.prevent
:close-on-click-modal="false" @escape-key-down.prevent
:close-on-press-escape="false" class="sm:max-w-[420px]">
:show-close="false" <DialogHeader>
align-center> <DialogTitle>{{ t('view.friend_list.load_dialog_title') }}</DialogTitle>
</DialogHeader>
<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>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<Progress :model-value="friendsListLoadingPercent" class="h-4 w-full" /> <Progress :model-value="friendsListLoadingPercent" class="h-4 w-full" />
@@ -94,18 +95,20 @@
<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>
<template #footer> <DialogFooter>
<Button variant="secondary" @click="cancelFriendsListLoad"> <Button variant="secondary" @click="cancelFriendsListLoad">
{{ t('view.friend_list.load_cancel') }} {{ t('view.friend_list.load_cancel') }}
</Button> </Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, nextTick, ref, watch } from 'vue'; import { computed, nextTick, 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';

View File

@@ -1,11 +1,11 @@
<template> <template>
<el-dialog <Dialog
class="x-dialog" :open="editAndSendInviteResponseDialog.visible"
:model-value="editAndSendInviteResponseDialog.visible" @update:open="(open) => (open ? null : cancelEditAndSendInviteResponse())">
@close="cancelEditAndSendInviteResponse" <DialogContent>
:title="t('dialog.edit_send_invite_response_message.header')" <DialogHeader>
width="400px" <DialogTitle>{{ t('dialog.edit_send_invite_response_message.header') }}</DialogTitle>
append-to-body> </DialogHeader>
<div style="font-size: 12px"> <div style="font-size: 12px">
<span>{{ t('dialog.edit_send_invite_response_message.description') }}</span> <span>{{ t('dialog.edit_send_invite_response_message.description') }}</span>
</div> </div>
@@ -16,18 +16,22 @@
class="mt-2.5" class="mt-2.5"
placeholder="" placeholder=""
show-count /> show-count />
<template #footer> <DialogFooter>
<Button variant="secondary" class="mr-2" @click="cancelEditAndSendInviteResponse">{{ <Button variant="secondary" class="mr-2" @click="cancelEditAndSendInviteResponse">{{
t('dialog.edit_send_invite_response_message.cancel') t('dialog.edit_send_invite_response_message.cancel')
}}</Button> }}</Button>
<Button @click="saveEditAndSendInviteResponse" :disabled="!editAndSendInviteResponseDialog.newMessage">{{ <Button
t('dialog.edit_send_invite_response_message.send') @click="saveEditAndSendInviteResponse"
}}</Button> :disabled="!editAndSendInviteResponseDialog.newMessage"
</template> >{{ t('dialog.edit_send_invite_response_message.send') }}</Button
</el-dialog> >
</DialogFooter>
</DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';

View File

@@ -1,11 +1,11 @@
<template> <template>
<el-dialog <Dialog
class="x-dialog" :open="sendInviteRequestResponseDialogVisible"
:model-value="sendInviteRequestResponseDialogVisible" @update:open="(open) => (open ? null : cancelSendInviteRequestResponse())">
:title="t('dialog.invite_request_response_message.header')" <DialogContent>
width="800px" <DialogHeader>
append-to-body <DialogTitle>{{ t('dialog.invite_request_response_message.header') }}</DialogTitle>
@close="cancelSendInviteRequestResponse"> </DialogHeader>
<template v-if="isLocalUserVrcPlusSupporter"> <template v-if="isLocalUserVrcPlusSupporter">
<input class="inviteImageUploadButton" type="file" accept="image/*" @change="inviteImageUpload" /> <input class="inviteImageUploadButton" type="file" accept="image/*" @change="inviteImageUpload" />
</template> </template>
@@ -17,14 +17,14 @@
:show-pagination="false" :show-pagination="false"
:on-row-click="handleInviteRequestResponseRowClick" /> :on-row-click="handleInviteRequestResponseRowClick" />
<template #footer> <DialogFooter>
<Button variant="secondary" class="mr-2" @click="cancelSendInviteRequestResponse"> <Button variant="secondary" class="mr-2" @click="cancelSendInviteRequestResponse">
{{ t('dialog.invite_request_response_message.cancel') }} {{ t('dialog.invite_request_response_message.cancel') }}
</Button> </Button>
<Button @click="refreshInviteMessageTableData('requestResponse')"> <Button @click="refreshInviteMessageTableData('requestResponse')">
{{ t('dialog.invite_request_response_message.refresh') }} {{ t('dialog.invite_request_response_message.refresh') }}
</Button> </Button>
</template> </DialogFooter>
<EditAndSendInviteResponseDialog <EditAndSendInviteResponseDialog
:edit-and-send-invite-response-dialog="editAndSendInviteResponseDialog" :edit-and-send-invite-response-dialog="editAndSendInviteResponseDialog"
:send-invite-response-dialog="sendInviteResponseDialog" :send-invite-response-dialog="sendInviteResponseDialog"
@@ -35,10 +35,12 @@
:send-invite-response-confirm-dialog="sendInviteResponseConfirmDialog" :send-invite-response-confirm-dialog="sendInviteResponseConfirmDialog"
@closeInviteDialog="closeInviteDialog" @closeInviteDialog="closeInviteDialog"
@closeResponseConfirmDialog="closeResponseConfirmDialog" /> @closeResponseConfirmDialog="closeResponseConfirmDialog" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref } from 'vue'; import { computed, ref } 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';

View File

@@ -1,25 +1,27 @@
<template> <template>
<el-dialog <Dialog
class="x-dialog" :open="sendInviteResponseConfirmDialog.visible"
:model-value="sendInviteResponseConfirmDialog.visible" @update:open="(open) => (open ? null : cancelInviteResponseConfirm())">
:title="t('dialog.invite_response_message.header')" <DialogContent>
width="400px" <DialogHeader>
append-to-body <DialogTitle>{{ t('dialog.invite_response_message.header') }}</DialogTitle>
@close="cancelInviteResponseConfirm"> </DialogHeader>
<div style="font-size: 12px"> <div style="font-size: 12px">
<span>{{ t('dialog.invite_response_message.confirmation') }}</span> <span>{{ t('dialog.invite_response_message.confirmation') }}</span>
</div> </div>
<template #footer> <DialogFooter>
<Button variant="secondary" class="mr-2" @click="cancelInviteResponseConfirm">{{ <Button variant="secondary" class="mr-2" @click="cancelInviteResponseConfirm">{{
t('dialog.invite_response_message.cancel') t('dialog.invite_response_message.cancel')
}}</Button> }}</Button>
<Button @click="sendInviteResponseConfirm">{{ t('dialog.invite_response_message.confirm') }}</Button> <Button @click="sendInviteResponseConfirm">{{ t('dialog.invite_response_message.confirm') }}</Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
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';

View File

@@ -1,11 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="sendInviteResponseDialogVisible" @update:open="(open) => (open ? null : cancelSendInviteResponse())">
class="x-dialog" <DialogContent>
:model-value="sendInviteResponseDialogVisible" <DialogHeader>
:title="t('dialog.invite_response_message.header')" <DialogTitle>{{ t('dialog.invite_response_message.header') }}</DialogTitle>
width="800px" </DialogHeader>
append-to-body
@close="cancelSendInviteResponse">
<template v-if="isLocalUserVrcPlusSupporter"> <template v-if="isLocalUserVrcPlusSupporter">
<input class="inviteImageUploadButton" type="file" accept="image/*" @change="inviteImageUpload" /> <input class="inviteImageUploadButton" type="file" accept="image/*" @change="inviteImageUpload" />
</template> </template>
@@ -17,14 +15,14 @@
:show-pagination="false" :show-pagination="false"
:on-row-click="handleInviteResponseRowClick" /> :on-row-click="handleInviteResponseRowClick" />
<template #footer> <DialogFooter>
<Button variant="secondary" class="mr-2" @click="cancelSendInviteResponse">{{ <Button variant="secondary" class="mr-2" @click="cancelSendInviteResponse">{{
t('dialog.invite_response_message.cancel') t('dialog.invite_response_message.cancel')
}}</Button> }}</Button>
<Button @click="refreshInviteMessageTableData('response')">{{ <Button @click="refreshInviteMessageTableData('response')">{{
t('dialog.invite_response_message.refresh') t('dialog.invite_response_message.refresh')
}}</Button> }}</Button>
</template> </DialogFooter>
<EditAndSendInviteResponseDialog <EditAndSendInviteResponseDialog
:edit-and-send-invite-response-dialog="editAndSendInviteResponseDialog" :edit-and-send-invite-response-dialog="editAndSendInviteResponseDialog"
:send-invite-response-dialog="sendInviteResponseDialog" :send-invite-response-dialog="sendInviteResponseDialog"
@@ -35,10 +33,12 @@
:send-invite-response-confirm-dialog="sendInviteResponseConfirmDialog" :send-invite-response-confirm-dialog="sendInviteResponseConfirmDialog"
@closeResponseConfirmDialog="closeResponseConfirmDialog" @closeResponseConfirmDialog="closeResponseConfirmDialog"
@closeInviteDialog="closeInviteDialog" /> @closeInviteDialog="closeInviteDialog" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref } from 'vue'; import { computed, ref } 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';

View File

@@ -1,9 +1,9 @@
<template> <template>
<el-dialog <Dialog v-model:open="chatboxBlacklistDialog.visible">
class="x-dialog" <DialogContent>
v-model="chatboxBlacklistDialog.visible" <DialogHeader>
:title="t('dialog.chatbox_blacklist.header')" <DialogTitle>{{ t('dialog.chatbox_blacklist.header') }}</DialogTitle>
width="600px"> </DialogHeader>
<div v-if="chatboxBlacklistDialog.visible" v-loading="chatboxBlacklistDialog.loading"> <div v-if="chatboxBlacklistDialog.visible" v-loading="chatboxBlacklistDialog.loading">
<h2>{{ t('dialog.chatbox_blacklist.keyword_blacklist') }}</h2> <h2>{{ t('dialog.chatbox_blacklist.keyword_blacklist') }}</h2>
<InputGroupAction <InputGroupAction
@@ -51,10 +51,12 @@
</button> </button>
</Badge> </Badge>
</div> </div>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupAction } from '@/components/ui/input-group'; import { InputGroupAction } from '@/components/ui/input-group';
import { X } from 'lucide-vue-next'; import { X } from 'lucide-vue-next';

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="isAvatarProviderDialogVisible" @update:open="(open) => (open ? null : closeDialog())">
class="x-dialog" <DialogContent>
:model-value="isAvatarProviderDialogVisible" <DialogHeader>
:title="t('dialog.avatar_database_provider.header')" <DialogTitle>{{ t('dialog.avatar_database_provider.header') }}</DialogTitle>
width="600px" </DialogHeader>
@close="closeDialog">
<div> <div>
<InputGroupAction <InputGroupAction
v-for="(provider, index) in avatarRemoteDatabaseProviderList" v-for="(provider, index) in avatarRemoteDatabaseProviderList"
@@ -24,10 +23,12 @@
{{ t('dialog.avatar_database_provider.add_provider') }} {{ t('dialog.avatar_database_provider.add_provider') }}
</Button> </Button>
</div> </div>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupAction } from '@/components/ui/input-group'; import { InputGroupAction } from '@/components/ui/input-group';
import { Trash2 } from 'lucide-vue-next'; import { Trash2 } from 'lucide-vue-next';

View File

@@ -1,11 +1,9 @@
<template> <template>
<el-dialog <Dialog v-model:open="changeLogDialog.visible">
class="x-dialog" <DialogContent class="sm:max-w-4xl">
:model-value="changeLogDialog.visible" <DialogHeader>
:title="t('dialog.change_log.header')" <DialogTitle>{{ t('dialog.change_log.header') }}</DialogTitle>
width="800px" </DialogHeader>
append-to-body
@close="closeDialog">
<div v-loading="!changeLogDialog.changeLog" class="changelog-dialog"> <div v-loading="!changeLogDialog.changeLog" class="changelog-dialog">
<h2 v-text="changeLogDialog.buildName"></h2> <h2 v-text="changeLogDialog.buildName"></h2>
<span v-show="changeLogDialog.buildName"> <span v-show="changeLogDialog.buildName">
@@ -20,7 +18,7 @@
@click="handleLinkClick" @click="handleLinkClick"
style="height: 62vh; overflow-y: auto; margin-top: 10px" /> style="height: 62vh; overflow-y: auto; margin-top: 10px" />
</div> </div>
<template #footer> <DialogFooter>
<Button <Button
variant="ghost" variant="ghost"
class="mr-2" class="mr-2"
@@ -33,11 +31,13 @@
<Button @click="closeDialog"> <Button @click="closeDialog">
{{ t('dialog.change_log.close') }} {{ t('dialog.change_log.close') }}
</Button> </Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { defineAsyncComponent } from 'vue'; import { defineAsyncComponent } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="!!feedFiltersDialogMode" @update:open="(open) => !open && handleDialogClose()">
:model-value="!!feedFiltersDialogMode" <DialogContent>
:title="dialogTitle" <DialogHeader>
width="600px" <DialogTitle>{{ dialogTitle }}</DialogTitle>
destroy-on-close </DialogHeader>
@close="handleDialogClose">
<div class="toggle-list" style="height: 75vh; overflow-y: auto"> <div class="toggle-list" style="height: 75vh; overflow-y: auto">
<div v-for="setting in currentOptions" :key="setting.key" class="toggle-item"> <div v-for="setting in currentOptions" :key="setting.key" class="toggle-item">
<span class="toggle-name" <span class="toggle-name"
@@ -56,7 +55,10 @@
saveSharedFeedFilters(); saveSharedFeedFilters();
} }
"> ">
<ToggleGroupItem v-for="option in setting.options" :key="option.label" :value="option.label"> <ToggleGroupItem
v-for="option in setting.options"
:key="option.label"
:value="option.label">
{{ t(option.textKey) }} {{ t(option.textKey) }}
</ToggleGroupItem> </ToggleGroupItem>
</ToggleGroup> </ToggleGroup>
@@ -64,19 +66,21 @@
</template> </template>
</div> </div>
<template #footer> <DialogFooter>
<Button variant="secondary" @click="currentResetFunction">{{ <Button variant="secondary" @click="currentResetFunction">{{
t('dialog.shared_feed_filters.reset') t('dialog.shared_feed_filters.reset')
}}</Button> }}</Button>
<Button style="margin-left: 10px" @click="handleDialogClose">{{ <Button style="margin-left: 10px" @click="handleDialogClose">{{
t('dialog.shared_feed_filters.close') t('dialog.shared_feed_filters.close')
}}</Button> }}</Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Info, AlertTriangle } from 'lucide-vue-next'; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { AlertTriangle, Info } from 'lucide-vue-next';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { computed } from 'vue'; import { computed } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="isLaunchOptionsDialogVisible" @update:open="(open) => (open ? null : closeDialog())">
class="x-dialog" <DialogContent>
:model-value="isLaunchOptionsDialogVisible" <DialogHeader>
:title="t('dialog.launch_options.header')" <DialogTitle>{{ t('dialog.launch_options.header') }}</DialogTitle>
width="600px" </DialogHeader>
@close="closeDialog">
<div style="font-size: 12px"> <div style="font-size: 12px">
{{ t('dialog.launch_options.description') }} <br /> {{ t('dialog.launch_options.description') }} <br />
{{ t('dialog.launch_options.example') }} {{ t('dialog.launch_options.example') }}
@@ -34,7 +33,7 @@
input-class="resize-none min-h-0" /> input-class="resize-none min-h-0" />
</template> </template>
<template #footer> <DialogFooter>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div> <div>
<Button <Button
@@ -53,11 +52,13 @@
{{ t('dialog.launch_options.save') }} {{ t('dialog.launch_options.save') }}
</Button> </Button>
</div> </div>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="isNotificationPositionDialogVisible" @update:open="(open) => (open ? null : closeDialog())">
class="x-dialog" <DialogContent>
:model-value="isNotificationPositionDialogVisible" <DialogHeader>
:title="t('dialog.notification_position.header')" <DialogTitle>{{ t('dialog.notification_position.header') }}</DialogTitle>
width="400px" </DialogHeader>
@close="closeDialog">
<div style="font-size: 12px"> <div style="font-size: 12px">
{{ t('dialog.notification_position.description') }} {{ t('dialog.notification_position.description') }}
</div> </div>
@@ -76,17 +75,19 @@
</RadioGroup> </RadioGroup>
</div> </div>
<template #footer> <DialogFooter>
<div style="display: flex"> <div style="display: flex">
<Button @click="closeDialog"> <Button @click="closeDialog">
{{ t('dialog.notification_position.ok') }} {{ t('dialog.notification_position.ok') }}
</Button> </Button>
</div> </div>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';

View File

@@ -1,11 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="ossDialog" @update:open="(open) => !open && closeDialog()">
class="x-dialog" <DialogContent>
:model-value="ossDialog" <DialogHeader>
:title="t('dialog.open_source.header')" <DialogTitle>{{ t('dialog.open_source.header') }}</DialogTitle>
width="650px" </DialogHeader>
@close="closeDialog"
destroy-on-close>
<div v-once style="height: 350px; overflow: hidden scroll; word-break: break-all"> <div v-once style="height: 350px; overflow: hidden scroll; word-break: break-all">
<div> <div>
<span>{{ t('dialog.open_source.description') }}</span> <span>{{ t('dialog.open_source.description') }}</span>
@@ -16,10 +14,12 @@
<pre style="font-size: 12px; white-space: pre-line">{{ lib.licenseText }}</pre> <pre style="font-size: 12px; white-space: pre-line">{{ lib.licenseText }}</pre>
</div> </div>
</div> </div>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { openSourceSoftwareLicenses } from '../../../shared/constants/ossLicenses'; import { openSourceSoftwareLicenses } from '../../../shared/constants/ossLicenses';

View File

@@ -1,11 +1,9 @@
<template> <template>
<el-dialog <Dialog v-model:open="enablePrimaryPasswordDialog.visible">
class="x-dialog" <DialogContent @interact-outside.prevent>
v-model="enablePrimaryPasswordDialog.visible" <DialogHeader>
:before-close="enablePrimaryPasswordDialog.beforeClose" <DialogTitle>{{ t('dialog.primary_password.header') }}</DialogTitle>
:close-on-click-modal="false" </DialogHeader>
:title="t('dialog.primary_password.header')"
width="400px">
<InputGroupField <InputGroupField
v-model="enablePrimaryPasswordDialog.password" v-model="enablePrimaryPasswordDialog.password"
:placeholder="t('dialog.primary_password.password_placeholder')" :placeholder="t('dialog.primary_password.password_placeholder')"
@@ -22,7 +20,7 @@
size="sm" size="sm"
maxlength="32" maxlength="32"
show-password /> show-password />
<template #footer> <DialogFooter>
<Button <Button
:disabled=" :disabled="
enablePrimaryPasswordDialog.password.length === 0 || enablePrimaryPasswordDialog.password.length === 0 ||
@@ -31,11 +29,13 @@
@click="handleSetPrimaryPassword()"> @click="handleSetPrimaryPassword()">
{{ t('dialog.primary_password.ok') }} {{ t('dialog.primary_password.ok') }}
</Button> </Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
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 { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';

View File

@@ -1,11 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="isRegistryBackupDialogVisible" @update:open="(open) => !open && closeAndClearDialog()">
class="x-dialog" <DialogContent>
:model-value="isRegistryBackupDialogVisible" <DialogHeader>
:title="t('dialog.registry_backup.header')" <DialogTitle>{{ t('dialog.registry_backup.header') }}</DialogTitle>
width="600px" </DialogHeader>
@close="closeDialog"
@closed="clearVrcRegistryDialog">
<div style="margin-top: 10px"> <div style="margin-top: 10px">
<div style="display: flex; align-items: center; justify-content: space-between; font-size: 12px"> <div style="display: flex; align-items: center; justify-content: space-between; font-size: 12px">
<span class="name" style="margin-right: 24px">{{ t('dialog.registry_backup.auto_backup') }}</span> <span class="name" style="margin-right: 24px">{{ t('dialog.registry_backup.auto_backup') }}</span>
@@ -19,7 +17,9 @@
font-size: 12px; font-size: 12px;
margin-top: 5px; margin-top: 5px;
"> ">
<span class="name" style="margin-right: 24px">{{ t('dialog.registry_backup.ask_to_restore') }}</span> <span class="name" style="margin-right: 24px">{{
t('dialog.registry_backup.ask_to_restore')
}}</span>
<Switch :model-value="vrcRegistryAskRestore" @update:modelValue="setVrcRegistryAskRestore" /> <Switch :model-value="vrcRegistryAskRestore" @update:modelValue="setVrcRegistryAskRestore" />
</div> </div>
<DataTableLayout <DataTableLayout
@@ -43,10 +43,12 @@
</div> </div>
</div> </div>
</div> </div>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
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';
@@ -201,7 +203,8 @@
document.body.appendChild(fileInput); document.body.appendChild(fileInput);
fileInput.onchange = function (event) { fileInput.onchange = function (event) {
const file = event.target.files[0]; const target = /** @type {HTMLInputElement | null} */ (event.target);
const file = target?.files?.[0];
if (file) { if (file) {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = function () { reader.onload = function () {
@@ -263,6 +266,13 @@
registryBackupTable.value.data = []; registryBackupTable.value.data = [];
} }
function closeAndClearDialog() {
closeDialog();
// TODO: Element Plus had a distinct @closed event after animation.
// If you ever need exact timing, wrap DialogContent with a Transition and call clear on after-leave.
clearVrcRegistryDialog();
}
function closeDialog() { function closeDialog() {
isRegistryBackupDialogVisible.value = false; isRegistryBackupDialogVisible.value = false;
} }

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="isTranslationApiDialogVisible" @update:open="(open) => (open ? null : closeDialog())">
class="x-dialog" <DialogContent>
:model-value="isTranslationApiDialogVisible" <DialogHeader>
:title="t('dialog.translation_api.header')" <DialogTitle>{{ t('dialog.translation_api.header') }}</DialogTitle>
width="450px" </DialogHeader>
@close="closeDialog">
<div class="options-container-item"> <div class="options-container-item">
<span class="name">{{ t('view.settings.appearance.appearance.bio_language') }}</span> <span class="name">{{ t('view.settings.appearance.appearance.bio_language') }}</span>
<Select :model-value="bioLanguage" @update:modelValue="setBioLanguage"> <Select :model-value="bioLanguage" @update:modelValue="setBioLanguage">
@@ -25,7 +24,9 @@
<Field> <Field>
<FieldLabel>{{ t('dialog.translation_api.mode') }}</FieldLabel> <FieldLabel>{{ t('dialog.translation_api.mode') }}</FieldLabel>
<FieldContent> <FieldContent>
<Select :model-value="form.translationApiType" @update:modelValue="handleTranslationApiTypeChange"> <Select
:model-value="form.translationApiType"
@update:modelValue="handleTranslationApiTypeChange">
<SelectTrigger size="sm" style="width: 100%"> <SelectTrigger size="sm" style="width: 100%">
<SelectValue :placeholder="t('dialog.translation_api.mode')" /> <SelectValue :placeholder="t('dialog.translation_api.mode')" />
</SelectTrigger> </SelectTrigger>
@@ -100,7 +101,7 @@
</FieldGroup> </FieldGroup>
</template> </template>
<template #footer> <DialogFooter>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<Button <Button
variant="outline" variant="outline"
@@ -125,12 +126,14 @@
</Button> </Button>
</div> </div>
</div> </div>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field'; import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field';
import { InputGroupField, InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupField, InputGroupTextareaField } from '@/components/ui/input-group';
import { reactive, watch } from 'vue'; import { reactive, watch } from 'vue';

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="isVRChatConfigDialogVisible" @update:open="(open) => (open ? null : closeDialog())">
class="x-dialog" <DialogContent>
:model-value="isVRChatConfigDialogVisible" <DialogHeader>
:title="t('dialog.config_json.header')" <DialogTitle>{{ t('dialog.config_json.header') }}</DialogTitle>
width="420px" </DialogHeader>
@close="closeDialog">
<div v-loading="loading"> <div v-loading="loading">
<div style="font-size: 12px; word-break: keep-all"> <div style="font-size: 12px; word-break: keep-all">
{{ t('dialog.config_json.description1') }} <br /> {{ t('dialog.config_json.description1') }} <br />
@@ -31,9 +30,13 @@
<div style="margin-top: 10px"> <div style="margin-top: 10px">
<span style="margin-right: 5px">{{ t('dialog.config_json.delete_all_cache') }}</span> <span style="margin-right: 5px">{{ t('dialog.config_json.delete_all_cache') }}</span>
<Button size="sm" variant="outline" style="margin-left: 5px" @click="showDeleteAllVRChatCacheConfirm">{{ <Button
t('dialog.config_json.delete_cache') size="sm"
}}</Button> variant="outline"
style="margin-left: 5px"
@click="showDeleteAllVRChatCacheConfirm"
>{{ t('dialog.config_json.delete_cache') }}</Button
>
</div> </div>
<div style="margin-top: 10px"> <div style="margin-top: 10px">
@@ -147,7 +150,7 @@
<span>{{ t('dialog.config_json.disable_discord_presence') }}</span> <span>{{ t('dialog.config_json.disable_discord_presence') }}</span>
</label> </label>
</div> </div>
<template #footer> <DialogFooter>
<div style="display: flex; align-items: center; justify-content: space-between"> <div style="display: flex; align-items: center; justify-content: space-between">
<div> <div>
<Button <Button
@@ -165,12 +168,14 @@
}}</Button> }}</Button>
</div> </div>
</div> </div>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
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 { Checkbox } from '@/components/ui/checkbox'; import { Checkbox } from '@/components/ui/checkbox';

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="isYouTubeApiDialogVisible" @update:open="(open) => (open ? null : closeDialog())">
class="x-dialog" <DialogContent>
:model-value="isYouTubeApiDialogVisible" <DialogHeader>
:title="t('dialog.youtube_api.header')" <DialogTitle>{{ t('dialog.youtube_api.header') }}</DialogTitle>
width="450px" </DialogHeader>
@close="closeDialog">
<div style="font-size: 12px">{{ t('dialog.youtube_api.description') }} <br /></div> <div style="font-size: 12px">{{ t('dialog.youtube_api.description') }} <br /></div>
<InputGroupTextareaField <InputGroupTextareaField
@@ -15,20 +14,24 @@
class="mt-2.5" class="mt-2.5"
show-count /> show-count />
<template #footer> <DialogFooter>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<Button variant="outline" @click="openExternalLink('https://smashballoon.com/doc/youtube-api-key/')"> <Button
variant="outline"
@click="openExternalLink('https://smashballoon.com/doc/youtube-api-key/')">
{{ t('dialog.youtube_api.guide') }} {{ t('dialog.youtube_api.guide') }}
</Button> </Button>
<Button style="margin-left: auto" @click="testYouTubeApiKey"> <Button style="margin-left: auto" @click="testYouTubeApiKey">
{{ t('dialog.youtube_api.save') }} {{ t('dialog.youtube_api.save') }}
</Button> </Button>
</div> </div>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="isEditInviteMessageDialogVisible" @update:open="(open) => !open && closeDialog()">
class="x-dialog" <DialogContent class="sm:max-w-sm">
:model-value="isEditInviteMessageDialogVisible" <DialogHeader>
:title="t('dialog.edit_invite_message.header')" <DialogTitle>{{ t('dialog.edit_invite_message.header') }}</DialogTitle>
width="400px" </DialogHeader>
@close="closeDialog">
<div style="font-size: 12px"> <div style="font-size: 12px">
<span>{{ t('dialog.edit_invite_message.description') }}</span> <span>{{ t('dialog.edit_invite_message.description') }}</span>
<InputGroupTextareaField <InputGroupTextareaField
@@ -15,16 +14,18 @@
placeholder="" placeholder=""
show-count /> show-count />
</div> </div>
<template #footer> <DialogFooter>
<Button variant="secondary" class="mr-2" @click="closeDialog">{{ <Button variant="secondary" class="mr-2" @click="closeDialog">{{
t('dialog.edit_invite_message.cancel') t('dialog.edit_invite_message.cancel')
}}</Button> }}</Button>
<Button @click="saveEditInviteMessage">{{ t('dialog.edit_invite_message.save') }}</Button> <Button @click="saveEditInviteMessage">{{ t('dialog.edit_invite_message.save') }}</Button>
</template> </DialogFooter>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="isEditInviteMessagesDialogVisible" @update:open="(open) => !open && closeDialog()">
class="x-dialog" <DialogContent class="sm:max-w-5xl">
:model-value="isEditInviteMessagesDialogVisible" <DialogHeader>
:title="t('dialog.edit_invite_messages.header')" <DialogTitle>{{ t('dialog.edit_invite_messages.header') }}</DialogTitle>
width="1000px" </DialogHeader>
@close="closeDialog">
<TabsUnderline v-model="activeTab" :items="editInviteTabs" :unmount-on-hide="false" class="mt-2.5"> <TabsUnderline v-model="activeTab" :items="editInviteTabs" :unmount-on-hide="false" class="mt-2.5">
<template #message> <template #message>
<DataTableLayout <DataTableLayout
@@ -39,7 +38,8 @@
:on-row-click="handleEditInviteMessageRowClick" /> :on-row-click="handleEditInviteMessageRowClick" />
</template> </template>
</TabsUnderline> </TabsUnderline>
</el-dialog> </DialogContent>
</Dialog>
<template v-if="isEditInviteMessagesDialogVisible"> <template v-if="isEditInviteMessagesDialogVisible">
<EditInviteMessageDialog <EditInviteMessageDialog
v-model:isEditInviteMessageDialogVisible="isEditInviteMessageDialogVisible" v-model:isEditInviteMessageDialogVisible="isEditInviteMessageDialogVisible"
@@ -50,6 +50,7 @@
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { DataTableLayout } from '@/components/ui/data-table'; import { DataTableLayout } from '@/components/ui/data-table';
import { TabsUnderline } from '@/components/ui/tabs'; import { TabsUnderline } from '@/components/ui/tabs';

View File

@@ -1,5 +1,9 @@
<template> <template>
<el-dialog v-model="isVisible" :title="t('dialog.export_own_avatars.header')" width="650px"> <Dialog v-model:open="isVisible">
<DialogContent>
<DialogHeader>
<DialogTitle>{{ t('dialog.export_own_avatars.header') }}</DialogTitle>
</DialogHeader>
<InputGroupTextareaField <InputGroupTextareaField
v-model="exportAvatarsListCsv" v-model="exportAvatarsListCsv"
v-loading="loading" v-loading="loading"
@@ -8,13 +12,15 @@
style="margin-top: 15px" style="margin-top: 15px"
input-class="resize-none" input-class="resize-none"
@click="$event.target.tagName === 'TEXTAREA' && $event.target.select()" /> @click="$event.target.tagName === 'TEXTAREA' && $event.target.select()" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useAvatarStore, useUserStore } from '../../../stores'; import { useAvatarStore, useUserStore } from '../../../stores';

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="discordNamesDialogVisible" @update:open="(open) => !open && closeDialog()">
class="x-dialog" <DialogContent>
:model-value="discordNamesDialogVisible" <DialogHeader>
:title="t('dialog.discord_names.header')" <DialogTitle>{{ t('dialog.discord_names.header') }}</DialogTitle>
width="650px" </DialogHeader>
@close="closeDialog">
<div style="font-size: 12px"> <div style="font-size: 12px">
{{ t('dialog.discord_names.description') }} {{ t('dialog.discord_names.description') }}
</div> </div>
@@ -14,13 +13,15 @@
readonly readonly
style="margin-top: 15px" style="margin-top: 15px"
input-class="resize-none" /> input-class="resize-none" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { InputGroupTextareaField } from '@/components/ui/input-group'; import { InputGroupTextareaField } from '@/components/ui/input-group';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useUserStore } from '../../../stores'; import { useUserStore } from '../../../stores';

View File

@@ -1,5 +1,9 @@
<template> <template>
<el-dialog :title="t('dialog.export_friends_list.header')" v-model="isVisible" width="650px"> <Dialog v-model:open="isVisible">
<DialogContent>
<DialogHeader>
<DialogTitle>{{ t('dialog.export_friends_list.header') }}</DialogTitle>
</DialogHeader>
<TabsUnderline default-value="csv" :items="exportFriendsTabs" :unmount-on-hide="false" class="mt-2.5"> <TabsUnderline default-value="csv" :items="exportFriendsTabs" :unmount-on-hide="false" class="mt-2.5">
<template #csv> <template #csv>
<InputGroupTextareaField <InputGroupTextareaField
@@ -20,10 +24,12 @@
@click="$event.target.tagName === 'TEXTAREA' && $event.target.select()" /> @click="$event.target.tagName === 'TEXTAREA' && $event.target.select()" />
</template> </template>
</TabsUnderline> </TabsUnderline>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
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';

View File

@@ -1,14 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="visible" @update:open="(open) => (open ? null : closeDialog())">
class="x-dialog" <DialogContent class="x-dialog w-[90vw] max-w-[90vw] h-[80vh] overflow-hidden">
:model-value="visible" <DialogHeader>
:title="t('dialog.group_calendar.header')"
width="90vw"
height="80vh"
@close="closeDialog">
<template #header>
<div class="dialog-title-container"> <div class="dialog-title-container">
<span>{{ t('dialog.group_calendar.header') }}</span> <DialogTitle>{{ t('dialog.group_calendar.header') }}</DialogTitle>
<Button size="sm" variant="outline" @click="toggleViewMode" class="view-toggle-btn"> <Button size="sm" variant="outline" @click="toggleViewMode" class="view-toggle-btn">
{{ {{
viewMode === 'timeline' viewMode === 'timeline'
@@ -21,7 +16,7 @@
<span class="featured-switch-text">{{ t('dialog.group_calendar.featured_events') }}</span> <span class="featured-switch-text">{{ t('dialog.group_calendar.featured_events') }}</span>
<Switch v-model="showFeaturedEvents" @update:modelValue="toggleFeaturedEvents" /> <Switch v-model="showFeaturedEvents" @update:modelValue="toggleFeaturedEvents" />
</div> </div>
</template> </DialogHeader>
<div class="top-content"> <div class="top-content">
<transition name="el-fade-in-linear" mode="out-in"> <transition name="el-fade-in-linear" mode="out-in">
<div v-if="viewMode === 'timeline'" key="timeline" class="timeline-view"> <div v-if="viewMode === 'timeline'" key="timeline" class="timeline-view">
@@ -30,7 +25,9 @@
<el-timeline-item <el-timeline-item
v-for="(timeGroup, key) of groupedTimelineEvents" v-for="(timeGroup, key) of groupedTimelineEvents"
:key="key" :key="key"
:timestamp="dayjs(timeGroup.startsAt).format('MM-DD ddd') + ' ' + timeGroup.startTime" :timestamp="
dayjs(timeGroup.startsAt).format('MM-DD ddd') + ' ' + timeGroup.startTime
"
placement="top"> placement="top">
<div class="time-group-container"> <div class="time-group-container">
<GroupCalendarEventCard <GroupCalendarEventCard
@@ -54,12 +51,18 @@
<div class="date"> <div class="date">
<div <div
class="calendar-date-content" class="calendar-date-content"
:class="{ 'has-events': filteredCalendar[formatDateKey(data.date)]?.length }"> :class="{
'has-events': filteredCalendar[formatDateKey(data.date)]?.length
}">
{{ dayjs(data.date).format('D') }} {{ dayjs(data.date).format('D') }}
<div <div
v-if="filteredCalendar[formatDateKey(data.date)]?.length" v-if="filteredCalendar[formatDateKey(data.date)]?.length"
class="calendar-event-badge" class="calendar-event-badge"
:class="followingCalendarDate[formatDateKey(data.date)] ? 'has-following' : 'no-following'"> :class="
followingCalendarDate[formatDateKey(data.date)]
? 'has-following'
: 'no-following'
">
{{ filteredCalendar[formatDateKey(data.date)]?.length }} {{ filteredCalendar[formatDateKey(data.date)]?.length }}
</div> </div>
</div> </div>
@@ -110,10 +113,12 @@
</div> </div>
</transition> </transition>
</div> </div>
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, onMounted, ref, watch } from 'vue'; import { computed, onMounted, ref, watch } from 'vue';
import { ArrowRight } from 'lucide-vue-next'; import { ArrowRight } from 'lucide-vue-next';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';

View File

@@ -1,10 +1,9 @@
<template> <template>
<el-dialog <Dialog :open="isNoteExportDialogVisible" @update:open="(open) => !open && closeDialog()">
class="x-dialog" <DialogContent class="sm:max-w-5xl">
:model-value="isNoteExportDialogVisible" <DialogHeader>
:title="t('dialog.note_export.header')" <DialogTitle>{{ t('dialog.note_export.header') }}</DialogTitle>
width="1000px" </DialogHeader>
@close="closeDialog">
<div style="font-size: 12px"> <div style="font-size: 12px">
{{ t('dialog.note_export.description1') }} <br /> {{ t('dialog.note_export.description1') }} <br />
{{ t('dialog.note_export.description2') }} <br /> {{ t('dialog.note_export.description2') }} <br />
@@ -59,10 +58,12 @@
:table-style="tableStyle" :table-style="tableStyle"
:show-pagination="false" :show-pagination="false"
style="margin-top: 10px" /> style="margin-top: 10px" />
</el-dialog> </DialogContent>
</Dialog>
</template> </template>
<script setup> <script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
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';