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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -1,102 +1,115 @@
<template>
<el-dialog
ref="setAvatarTagsDialog"
class="x-dialog"
:model-value="setAvatarTagsDialog.visible"
@close="closeSetAvatarTagsDialog"
:title="t('dialog.set_avatar_tags.header')"
width="780px"
append-to-body>
<template v-if="setAvatarTagsDialog.visible">
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setAvatarTagsDialog.contentHorror" @update:modelValue="updateSelectedAvatarTags" />
<span>{{ t('dialog.set_avatar_tags.content_horror') }}</span>
</label>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setAvatarTagsDialog.contentGore" @update:modelValue="updateSelectedAvatarTags" />
<span>{{ t('dialog.set_avatar_tags.content_gore') }}</span>
</label>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setAvatarTagsDialog.contentViolence" @update:modelValue="updateSelectedAvatarTags" />
<span>{{ t('dialog.set_avatar_tags.content_violence') }}</span>
</label>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setAvatarTagsDialog.contentAdult" @update:modelValue="updateSelectedAvatarTags" />
<span>{{ t('dialog.set_avatar_tags.content_adult') }}</span>
</label>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setAvatarTagsDialog.contentSex" @update:modelValue="updateSelectedAvatarTags" />
<span>{{ t('dialog.set_avatar_tags.content_sex') }}</span>
</label>
<br />
<InputGroupTextareaField
v-model="setAvatarTagsDialog.selectedTagsCsv"
:rows="2"
:placeholder="t('dialog.set_avatar_tags.custom_tags_placeholder')"
style="margin-top: 10px"
input-class="resize-none"
@input="updateInputAvatarTags" />
<br />
<br />
<template
v-if="setAvatarTagsDialog.ownAvatars.length === props.setAvatarTagsDialog.selectedAvatarIds.length">
<Button size="sm" variant="outline" @click="setAvatarTagsSelectToggle">{{
t('dialog.set_avatar_tags.select_none')
}}</Button>
</template>
<template v-else>
<Button size="sm" variant="outline" @click="setAvatarTagsSelectToggle">{{
t('dialog.set_avatar_tags.select_all')
}}</Button>
</template>
<span style="margin-left: 5px"
>{{ props.setAvatarTagsDialog.selectedAvatarIds.length }} /
{{ setAvatarTagsDialog.ownAvatars.length }}</span
>
<Loader2 v-if="setAvatarTagsDialog.loading" class="is-loading" style="margin-left: 5px" />
<br />
<div class="x-friend-list" style="margin-top: 10px; min-height: 60px; max-height: 280px">
<div
v-for="avatar in setAvatarTagsDialog.ownAvatars"
:key="avatar.id"
:class="['item-width', 'x-friend-item', 'x-friend-item-border']"
@click="showAvatarDialog(avatar.id)">
<div class="avatar">
<img v-if="avatar.thumbnailImageUrl" :src="avatar.thumbnailImageUrl" loading="lazy" />
<Dialog
:open="setAvatarTagsDialog.visible"
@update:open="
(open) => {
if (!open) closeSetAvatarTagsDialog();
}
">
<DialogContent class="x-dialog sm:max-w-195">
<DialogHeader>
<DialogTitle>{{ t('dialog.set_avatar_tags.header') }}</DialogTitle>
</DialogHeader>
<template v-if="setAvatarTagsDialog.visible">
<label class="inline-flex items-center gap-2">
<Checkbox
v-model="setAvatarTagsDialog.contentHorror"
@update:modelValue="updateSelectedAvatarTags" />
<span>{{ t('dialog.set_avatar_tags.content_horror') }}</span>
</label>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setAvatarTagsDialog.contentGore" @update:modelValue="updateSelectedAvatarTags" />
<span>{{ t('dialog.set_avatar_tags.content_gore') }}</span>
</label>
<label class="inline-flex items-center gap-2">
<Checkbox
v-model="setAvatarTagsDialog.contentViolence"
@update:modelValue="updateSelectedAvatarTags" />
<span>{{ t('dialog.set_avatar_tags.content_violence') }}</span>
</label>
<label class="inline-flex items-center gap-2">
<Checkbox
v-model="setAvatarTagsDialog.contentAdult"
@update:modelValue="updateSelectedAvatarTags" />
<span>{{ t('dialog.set_avatar_tags.content_adult') }}</span>
</label>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setAvatarTagsDialog.contentSex" @update:modelValue="updateSelectedAvatarTags" />
<span>{{ t('dialog.set_avatar_tags.content_sex') }}</span>
</label>
<br />
<InputGroupTextareaField
v-model="setAvatarTagsDialog.selectedTagsCsv"
:rows="2"
:placeholder="t('dialog.set_avatar_tags.custom_tags_placeholder')"
style="margin-top: 10px"
input-class="resize-none"
@input="updateInputAvatarTags" />
<br />
<br />
<template
v-if="setAvatarTagsDialog.ownAvatars.length === props.setAvatarTagsDialog.selectedAvatarIds.length">
<Button size="sm" variant="outline" @click="setAvatarTagsSelectToggle">{{
t('dialog.set_avatar_tags.select_none')
}}</Button>
</template>
<template v-else>
<Button size="sm" variant="outline" @click="setAvatarTagsSelectToggle">{{
t('dialog.set_avatar_tags.select_all')
}}</Button>
</template>
<span style="margin-left: 5px"
>{{ props.setAvatarTagsDialog.selectedAvatarIds.length }} /
{{ setAvatarTagsDialog.ownAvatars.length }}</span
>
<Loader2 v-if="setAvatarTagsDialog.loading" class="is-loading" style="margin-left: 5px" />
<br />
<div class="x-friend-list" style="margin-top: 10px; min-height: 60px; max-height: 280px">
<div
v-for="avatar in setAvatarTagsDialog.ownAvatars"
:key="avatar.id"
:class="['item-width', 'x-friend-item', 'x-friend-item-border']"
@click="showAvatarDialog(avatar.id)">
<div class="avatar">
<img v-if="avatar.thumbnailImageUrl" :src="avatar.thumbnailImageUrl" loading="lazy" />
</div>
<div class="detail">
<span class="name" v-text="avatar.name"></span>
<span
v-if="avatar.releaseStatus === 'public'"
class="extra"
style="color: var(--el-color-success)"
v-text="avatar.releaseStatus"></span>
<span
v-else-if="avatar.releaseStatus === 'private'"
class="extra"
style="color: var(--el-color-danger)"
v-text="avatar.releaseStatus"></span>
<span v-else class="extra" v-text="avatar.releaseStatus"></span>
<span class="extra" v-text="avatarTagStrings.get(avatar.id)"></span>
</div>
<Button size="sm" variant="ghost" style="margin-left: 5px" @click.stop>
<Checkbox
:model-value="props.setAvatarTagsDialog.selectedAvatarIds.includes(avatar.id)"
@update:modelValue="(val) => toggleAvatarSelection(avatar.id, val)" />
</Button>
</div>
<div class="detail">
<span class="name" v-text="avatar.name"></span>
<span
v-if="avatar.releaseStatus === 'public'"
class="extra"
style="color: var(--el-color-success)"
v-text="avatar.releaseStatus"></span>
<span
v-else-if="avatar.releaseStatus === 'private'"
class="extra"
style="color: var(--el-color-danger)"
v-text="avatar.releaseStatus"></span>
<span v-else class="extra" v-text="avatar.releaseStatus"></span>
<span class="extra" v-text="avatarTagStrings.get(avatar.id)"></span>
</div>
<Button size="sm" variant="ghost" style="margin-left: 5px" @click.stop>
<Checkbox
:model-value="props.setAvatarTagsDialog.selectedAvatarIds.includes(avatar.id)"
@update:modelValue="(val) => toggleAvatarSelection(avatar.id, val)" />
</Button>
</div>
</div>
</template>
<template #footer>
<Button variant="secondary" class="mr-2" @click="closeSetAvatarTagsDialog">{{
t('dialog.set_avatar_tags.cancel')
}}</Button>
<Button @click="saveSetAvatarTagsDialog">{{ t('dialog.set_avatar_tags.save') }}</Button>
</template>
</el-dialog>
</template>
<DialogFooter>
<Button variant="secondary" class="mr-2" @click="closeSetAvatarTagsDialog">{{
t('dialog.set_avatar_tags.cancel')
}}</Button>
<Button @click="saveSetAvatarTagsDialog">{{ t('dialog.set_avatar_tags.save') }}</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</template>
<script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { InputGroupTextareaField } from '@/components/ui/input-group';

View File

@@ -1,6 +1,10 @@
<template>
<el-dialog :z-index="favoriteDialogIndex" v-model="isVisible" :title="t('dialog.favorite.header')" width="300px">
<div v-loading="loading">
<Dialog v-model:open="isVisible">
<DialogContent>
<DialogHeader>
<DialogTitle>{{ t('dialog.favorite.header') }}</DialogTitle>
</DialogHeader>
<div v-loading="loading">
<span style="display: block; text-align: center">{{ t('dialog.favorite.vrchat_favorites') }}</span>
<template v-if="favoriteDialog.currentGroup && favoriteDialog.currentGroup.key">
<Button
@@ -23,8 +27,8 @@
{{ group.displayName }} ({{ group.count }} / {{ group.capacity }})
</Button>
</template>
</div>
<div v-if="favoriteDialog.type === 'world'" style="margin-top: 20px">
</div>
<div v-if="favoriteDialog.type === 'world'" style="margin-top: 20px">
<span style="display: block; text-align: center">{{ t('dialog.favorite.local_favorites') }}</span>
<template v-for="group in localWorldFavoriteGroups" :key="group">
<Button
@@ -44,8 +48,8 @@
{{ group }} ({{ localWorldFavGroupLength(group) }})
</Button>
</template>
</div>
<div v-if="favoriteDialog.type === 'avatar'" style="margin-top: 20px">
</div>
<div v-if="favoriteDialog.type === 'avatar'" style="margin-top: 20px">
<span style="text-align: center">{{ t('dialog.favorite.local_avatar_favorites') }}</span>
<template v-for="group in localAvatarFavoriteGroups" :key="group">
<Button
@@ -66,14 +70,16 @@
{{ group }} ({{ localAvatarFavGroupLength(group) }})
</Button>
</template>
</div>
</el-dialog>
</div>
</DialogContent>
</Dialog>
</template>
<script setup>
import { computed, nextTick, ref, watch } from 'vue';
import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button';
import { Check } from 'lucide-vue-next';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
@@ -81,7 +87,6 @@
import { useFavoriteStore, useUserStore } from '../../stores';
import { favoriteRequest } from '../../api';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
const { t } = useI18n();
@@ -107,7 +112,6 @@
} = favoriteStore;
const { isLocalUserVrcPlusSupporter } = storeToRefs(useUserStore());
const favoriteDialogIndex = ref(2000);
const groups = ref([]);
const loading = ref(false);
@@ -123,9 +127,6 @@
(value) => {
if (value) {
initFavoriteDialog();
nextTick(() => {
favoriteDialogIndex.value = getNextDialogIndex();
});
}
}
);

View File

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

View File

@@ -1,61 +1,66 @@
<template>
<el-dialog
class="x-dialog"
v-model="gallerySelectDialog.visible"
:title="t('dialog.gallery_select.header')"
width="100%"
append-to-body>
<div>
<span>{{ t('dialog.gallery_select.gallery') }}</span>
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{ galleryTable.length }}/64</span>
<br />
<input
id="GalleryUploadButton"
type="file"
accept="image/*"
style="display: none"
@change="onFileChangeGallery" />
<ButtonGroup>
<Button variant="outline" size="sm" @click="selectImageGallerySelect('', '')">
<X />
{{ t('dialog.gallery_select.none') }}
</Button>
<Button variant="outline" size="sm" @click="refreshGalleryTable">
<RefreshCw />
{{ t('dialog.gallery_select.refresh') }}
</Button>
<Button
variant="outline"
size="sm"
:disabled="!isLocalUserVrcPlusSupporter"
@click="displayGalleryUpload">
<Upload />
{{ t('dialog.gallery_select.upload') }}
</Button>
</ButtonGroup>
<br />
<div
v-for="image in galleryTable"
:key="image.id"
class="x-friend-item"
style="display: inline-block; margin-top: 10px; width: unset; cursor: default">
<template v-if="image.versions && image.versions.length > 0">
<div
v-if="image.versions[image.versions.length - 1].file.url"
class="vrcplus-icon"
@click="selectImageGallerySelect(image.versions[image.versions.length - 1].file.url, image.id)">
<img
:src="image.versions[image.versions.length - 1].file.url"
class="avatar"
loading="lazy" /></div
></template>
<Dialog v-model:open="gallerySelectDialog.visible">
<DialogContent class="x-dialog w-full sm:max-w-none">
<DialogHeader>
<DialogTitle>{{ t('dialog.gallery_select.header') }}</DialogTitle>
</DialogHeader>
<div>
<span>{{ t('dialog.gallery_select.gallery') }}</span>
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{ galleryTable.length }}/64</span>
<br />
<input
id="GalleryUploadButton"
type="file"
accept="image/*"
style="display: none"
@change="onFileChangeGallery" />
<ButtonGroup>
<Button variant="outline" size="sm" @click="selectImageGallerySelect('', '')">
<X />
{{ t('dialog.gallery_select.none') }}
</Button>
<Button variant="outline" size="sm" @click="refreshGalleryTable">
<RefreshCw />
{{ t('dialog.gallery_select.refresh') }}
</Button>
<Button
variant="outline"
size="sm"
:disabled="!isLocalUserVrcPlusSupporter"
@click="displayGalleryUpload">
<Upload />
{{ t('dialog.gallery_select.upload') }}
</Button>
</ButtonGroup>
<br />
<div
v-for="image in galleryTable"
:key="image.id"
class="x-friend-item"
style="display: inline-block; margin-top: 10px; width: unset; cursor: default">
<template v-if="image.versions && image.versions.length > 0">
<div
v-if="image.versions[image.versions.length - 1].file.url"
class="vrcplus-icon"
@click="
selectImageGallerySelect(image.versions[image.versions.length - 1].file.url, image.id)
">
<img
:src="image.versions[image.versions.length - 1].file.url"
class="avatar"
loading="lazy" />
</div>
</template>
</div>
</div>
</div>
</el-dialog>
</DialogContent>
</Dialog>
</template>
<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 { ButtonGroup } from '@/components/ui/button-group';
import { storeToRefs } from 'pinia';

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,41 @@
<template>
<el-dialog
class="x-dialog"
:model-value="isGroupLogsExportDialogVisible"
:title="t('dialog.group_member_moderation.export_logs')"
width="650px"
append-to-body
@close="setIsGroupLogsExportDialogVisible">
<div style="margin-bottom: 10px" class="flex flex-col gap-2">
<label
v-for="option in checkGroupsLogsExportLogsOptions"
:key="option.label"
class="inline-flex items-center gap-2">
<Checkbox
:model-value="checkedGroupLogsExportLogsOptions.includes(option.label)"
@update:modelValue="(val) => toggleGroupLogsExportOption(option.label, val)" />
<span>{{ t(option.text) }}</span>
</label>
</div>
<br />
<InputGroupTextareaField
v-model="groupLogsExportContent"
:rows="15"
readonly
style="margin-top: 15px"
input-class="resize-none"
@click="handleCopyGroupLogsExportContent" />
</el-dialog>
<Dialog
:open="isGroupLogsExportDialogVisible"
@update:open="
(open) => {
if (!open) 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">
<label
v-for="option in checkGroupsLogsExportLogsOptions"
:key="option.label"
class="inline-flex items-center gap-2">
<Checkbox
:model-value="checkedGroupLogsExportLogsOptions.includes(option.label)"
@update:modelValue="(val) => toggleGroupLogsExportOption(option.label, val)" />
<span>{{ t(option.text) }}</span>
</label>
</div>
<br />
<InputGroupTextareaField
v-model="groupLogsExportContent"
:rows="15"
readonly
style="margin-top: 15px"
input-class="resize-none"
@click="handleCopyGroupLogsExportContent" />
</DialogContent>
</Dialog>
</template>
<script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { ref, watch } from 'vue';
import { Checkbox } from '@/components/ui/checkbox';
import { InputGroupTextareaField } from '@/components/ui/input-group';

View File

@@ -1,131 +1,144 @@
<template>
<el-dialog
v-model="groupPostEditDialog.visible"
:title="t('dialog.group_post_edit.header')"
width="650px"
append-to-body>
<div v-if="groupPostEditDialog.visible">
<FieldGroup class="gap-4">
<Field>
<FieldLabel>{{ t('dialog.group_post_edit.title') }}</FieldLabel>
<FieldContent>
<InputGroupField v-model="groupPostEditDialog.title" size="sm" />
</FieldContent>
</Field>
<Field>
<FieldLabel>{{ t('dialog.group_post_edit.message') }}</FieldLabel>
<FieldContent>
<InputGroupTextareaField
v-model="groupPostEditDialog.text"
:rows="4"
style="margin-top: 10px"
input-class="resize-none" />
</FieldContent>
</Field>
<Field v-if="!groupPostEditDialog.postId">
<FieldLabel class="sr-only">{{ t('dialog.group_post_edit.send_notification') }}</FieldLabel>
<FieldContent>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="groupPostEditDialog.sendNotification" />
<span>{{ t('dialog.group_post_edit.send_notification') }}</span>
</label>
</FieldContent>
</Field>
<Field>
<FieldLabel>{{ t('dialog.group_post_edit.post_visibility') }}</FieldLabel>
<FieldContent>
<RadioGroup v-model="groupPostEditDialog.visibility" class="flex items-center gap-4">
<div class="flex items-center space-x-2">
<RadioGroupItem id="groupPostVisibility-public" value="public" />
<label for="groupPostVisibility-public">
{{ t('dialog.group_post_edit.visibility_public') }}
</label>
</div>
<div class="flex items-center space-x-2">
<RadioGroupItem id="groupPostVisibility-group" value="group" />
<label for="groupPostVisibility-group">
{{ t('dialog.group_post_edit.visibility_group') }}
</label>
</div>
</RadioGroup>
</FieldContent>
</Field>
<Field v-if="groupPostEditDialog.visibility === 'group'">
<FieldLabel>{{ t('dialog.new_instance.roles') }}</FieldLabel>
<FieldContent>
<Select
multiple
:model-value="Array.isArray(groupPostEditDialog.roleIds) ? groupPostEditDialog.roleIds : []"
@update:modelValue="handleRoleIdsChange">
<SelectTrigger size="sm" class="w-full">
<SelectValue>
<span class="truncate">
{{ selectedRoleSummary || t('dialog.new_instance.role_placeholder') }}
</span>
</SelectValue>
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="role in groupPostEditDialog.groupRef?.roles ?? []"
:key="role.id"
:value="role.id">
{{ role.name }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</FieldContent>
</Field>
<Field>
<FieldLabel>{{ t('dialog.group_post_edit.image') }}</FieldLabel>
<FieldContent>
<template v-if="gallerySelectDialog.selectedFileId">
<div style="display: inline-block; flex: none; margin-right: 5px">
<img
:src="gallerySelectDialog.selectedImageUrl"
style="flex: none; width: 60px; height: 60px; border-radius: 4px; object-fit: cover"
@click="showFullscreenImageDialog(gallerySelectDialog.selectedImageUrl)"
loading="lazy" />
<Button
size="sm"
variant="outline"
style="vertical-align: top"
@click="clearImageGallerySelect">
{{ t('dialog.invite_message.clear_selected_image') }}
<Dialog v-model:open="groupPostEditDialog.visible">
<DialogContent class="sm:max-w-162.5">
<DialogHeader>
<DialogTitle>{{ t('dialog.group_post_edit.header') }}</DialogTitle>
</DialogHeader>
<div v-if="groupPostEditDialog.visible">
<FieldGroup class="gap-4">
<Field>
<FieldLabel>{{ t('dialog.group_post_edit.title') }}</FieldLabel>
<FieldContent>
<InputGroupField v-model="groupPostEditDialog.title" size="sm" />
</FieldContent>
</Field>
<Field>
<FieldLabel>{{ t('dialog.group_post_edit.message') }}</FieldLabel>
<FieldContent>
<InputGroupTextareaField
v-model="groupPostEditDialog.text"
:rows="4"
style="margin-top: 10px"
input-class="resize-none" />
</FieldContent>
</Field>
<Field v-if="!groupPostEditDialog.postId">
<FieldLabel class="sr-only">{{ t('dialog.group_post_edit.send_notification') }}</FieldLabel>
<FieldContent>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="groupPostEditDialog.sendNotification" />
<span>{{ t('dialog.group_post_edit.send_notification') }}</span>
</label>
</FieldContent>
</Field>
<Field>
<FieldLabel>{{ t('dialog.group_post_edit.post_visibility') }}</FieldLabel>
<FieldContent>
<RadioGroup v-model="groupPostEditDialog.visibility" class="flex items-center gap-4">
<div class="flex items-center space-x-2">
<RadioGroupItem id="groupPostVisibility-public" value="public" />
<label for="groupPostVisibility-public">
{{ t('dialog.group_post_edit.visibility_public') }}
</label>
</div>
<div class="flex items-center space-x-2">
<RadioGroupItem id="groupPostVisibility-group" value="group" />
<label for="groupPostVisibility-group">
{{ t('dialog.group_post_edit.visibility_group') }}
</label>
</div>
</RadioGroup>
</FieldContent>
</Field>
<Field v-if="groupPostEditDialog.visibility === 'group'">
<FieldLabel>{{ t('dialog.new_instance.roles') }}</FieldLabel>
<FieldContent>
<Select
multiple
:model-value="
Array.isArray(groupPostEditDialog.roleIds) ? groupPostEditDialog.roleIds : []
"
@update:modelValue="handleRoleIdsChange">
<SelectTrigger size="sm" class="w-full">
<SelectValue>
<span class="truncate">
{{ selectedRoleSummary || t('dialog.new_instance.role_placeholder') }}
</span>
</SelectValue>
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="role in groupPostEditDialog.groupRef?.roles ?? []"
:key="role.id"
:value="role.id">
{{ role.name }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</FieldContent>
</Field>
<Field>
<FieldLabel>{{ t('dialog.group_post_edit.image') }}</FieldLabel>
<FieldContent>
<template v-if="gallerySelectDialog.selectedFileId">
<div style="display: inline-block; flex: none; margin-right: 5px">
<img
:src="gallerySelectDialog.selectedImageUrl"
style="
flex: none;
width: 60px;
height: 60px;
border-radius: 4px;
object-fit: cover;
"
@click="showFullscreenImageDialog(gallerySelectDialog.selectedImageUrl)"
loading="lazy" />
<Button
size="sm"
variant="outline"
style="vertical-align: top"
@click="clearImageGallerySelect">
{{ t('dialog.invite_message.clear_selected_image') }}
</Button>
</div>
</template>
<template v-else>
<Button size="sm" variant="outline" @click="showGallerySelectDialog">
{{ t('dialog.invite_message.select_image') }}
</Button>
</div>
</template>
<template v-else>
<Button size="sm" variant="outline" @click="showGallerySelectDialog">
{{ t('dialog.invite_message.select_image') }}
</Button>
</template>
</FieldContent>
</Field>
</FieldGroup>
</div>
<template #footer>
<div class="flex gap-2">
<Button variant="secondary" @click="groupPostEditDialog.visible = false">
{{ t('dialog.group_post_edit.cancel') }}
</Button>
<Button v-if="groupPostEditDialog.postId" @click="editGroupPost">
{{ t('dialog.group_post_edit.edit_post') }}
</Button>
<Button v-else @click="createGroupPost">
{{ t('dialog.group_post_edit.create_post') }}
</Button>
</template>
</FieldContent>
</Field>
</FieldGroup>
</div>
</template>
<GallerySelectDialog
:gallery-select-dialog="gallerySelectDialog"
:gallery-table="galleryTable"
@refresh-gallery-table="refreshGalleryTable" />
</el-dialog>
<DialogFooter>
<div class="flex gap-2">
<Button variant="secondary" @click="groupPostEditDialog.visible = false">
{{ t('dialog.group_post_edit.cancel') }}
</Button>
<Button v-if="groupPostEditDialog.postId" @click="editGroupPost">
{{ t('dialog.group_post_edit.edit_post') }}
</Button>
<Button v-else @click="createGroupPost">
{{ t('dialog.group_post_edit.create_post') }}
</Button>
</div>
</DialogFooter>
<GallerySelectDialog
:gallery-select-dialog="gallerySelectDialog"
:gallery-table="galleryTable"
@refresh-gallery-table="refreshGalleryTable" />
</DialogContent>
</Dialog>
</template>
<script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field';
import { InputGroupField, InputGroupTextareaField } from '@/components/ui/input-group';
import { computed, ref } from 'vue';

View File

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

View File

@@ -1,89 +1,97 @@
<template>
<el-dialog
class="x-dialog"
:model-value="inviteDialog.visible"
@close="closeInviteDialog"
:title="t('dialog.invite.header')"
width="500px"
append-to-body>
<div v-if="inviteDialog.visible" v-loading="inviteDialog.loading">
<Location :location="inviteDialog.worldId" :link="false" />
<br />
<Button size="sm" class="mr-2" variant="outline" style="margin-top: 10px" @click="addSelfToInvite">{{
t('dialog.invite.add_self')
}}</Button>
<Button
size="sm"
class="mr-2"
variant="outline"
:disabled="inviteDialog.friendsInInstance.length === 0"
style="margin-top: 10px"
@click="addFriendsInInstanceToInvite"
>{{ t('dialog.invite.add_friends_in_instance') }}</Button
>
<Button
size="sm"
variant="outline"
:disabled="vipFriends.length === 0"
style="margin-top: 10px"
@click="addFavoriteFriendsToInvite"
>{{ t('dialog.invite.add_favorite_friends') }}</Button
>
<Dialog
:open="inviteDialog.visible"
@update:open="
(open) => {
if (!open) closeInviteDialog();
}
">
<DialogContent class="x-dialog sm:max-w-125">
<DialogHeader>
<DialogTitle>{{ t('dialog.invite.header') }}</DialogTitle>
</DialogHeader>
<div style="width: 100%; margin-top: 15px">
<VirtualCombobox
:model-value="Array.isArray(inviteDialog.userIds) ? inviteDialog.userIds : []"
@update:modelValue="setInviteUserIds"
:groups="userPickerGroups"
multiple
:disabled="inviteDialog.loading"
:placeholder="t('dialog.invite.select_placeholder')"
:search-placeholder="t('dialog.invite.select_placeholder')"
:clearable="true">
<template #item="{ item, selected }">
<div class="x-friend-item flex w-full items-center">
<template v-if="item.user">
<div :class="['avatar', userStatusClass(item.user)]">
<img :src="userImage(item.user)" loading="lazy" />
</div>
<div class="detail">
<span class="name" :style="{ color: item.user.$userColour }">{{
item.user.displayName
}}</span>
</div>
</template>
<template v-else>
<span>{{ item.label }}</span>
</template>
<div v-if="inviteDialog.visible" v-loading="inviteDialog.loading">
<Location :location="inviteDialog.worldId" :link="false" />
<br />
<Button size="sm" class="mr-2" variant="outline" style="margin-top: 10px" @click="addSelfToInvite">{{
t('dialog.invite.add_self')
}}</Button>
<Button
size="sm"
class="mr-2"
variant="outline"
:disabled="inviteDialog.friendsInInstance.length === 0"
style="margin-top: 10px"
@click="addFriendsInInstanceToInvite"
>{{ t('dialog.invite.add_friends_in_instance') }}</Button
>
<Button
size="sm"
variant="outline"
:disabled="vipFriends.length === 0"
style="margin-top: 10px"
@click="addFavoriteFriendsToInvite"
>{{ t('dialog.invite.add_favorite_friends') }}</Button
>
<CheckIcon :class="['ml-auto size-4', selected ? 'opacity-100' : 'opacity-0']" />
</div>
</template>
</VirtualCombobox>
<div style="width: 100%; margin-top: 15px">
<VirtualCombobox
:model-value="Array.isArray(inviteDialog.userIds) ? inviteDialog.userIds : []"
@update:modelValue="setInviteUserIds"
:groups="userPickerGroups"
multiple
:disabled="inviteDialog.loading"
:placeholder="t('dialog.invite.select_placeholder')"
:search-placeholder="t('dialog.invite.select_placeholder')"
:clearable="true">
<template #item="{ item, selected }">
<div class="x-friend-item flex w-full items-center">
<template v-if="item.user">
<div :class="['avatar', userStatusClass(item.user)]">
<img :src="userImage(item.user)" loading="lazy" />
</div>
<div class="detail">
<span class="name" :style="{ color: item.user.$userColour }">{{
item.user.displayName
}}</span>
</div>
</template>
<template v-else>
<span>{{ item.label }}</span>
</template>
<CheckIcon :class="['ml-auto size-4', selected ? 'opacity-100' : 'opacity-0']" />
</div>
</template>
</VirtualCombobox>
</div>
</div>
</div>
<template #footer>
<Button
variant="secondary"
class="mr-2"
:disabled="inviteDialog.loading || !inviteDialog.userIds.length"
@click="showSendInviteDialog"
>{{ t('dialog.invite.invite_with_message') }}</Button
>
<Button :disabled="inviteDialog.loading || !inviteDialog.userIds.length" @click="sendInvite">{{
t('dialog.invite.invite')
}}</Button>
</template>
<DialogFooter>
<Button
variant="secondary"
class="mr-2"
:disabled="inviteDialog.loading || !inviteDialog.userIds.length"
@click="showSendInviteDialog"
>{{ t('dialog.invite.invite_with_message') }}</Button
>
<Button :disabled="inviteDialog.loading || !inviteDialog.userIds.length" @click="sendInvite">{{
t('dialog.invite.invite')
}}</Button>
</DialogFooter>
</DialogContent>
<SendInviteDialog
v-model:sendInviteDialogVisible="sendInviteDialogVisible"
v-model:sendInviteDialog="sendInviteDialog"
:invite-dialog="inviteDialog"
@closeInviteDialog="closeInviteDialog" />
</el-dialog>
</Dialog>
</template>
<script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref } from 'vue';
import { Button } from '@/components/ui/button';
import { Check as CheckIcon } from 'lucide-vue-next';

View File

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

View File

@@ -1,55 +1,62 @@
<template>
<el-dialog
class="x-dialog"
:model-value="sendInviteDialogVisible"
:title="t('dialog.invite_message.header')"
width="800px"
append-to-body
@close="cancelSendInvite">
<template v-if="isLocalUserVrcPlusSupporter">
<!-- <template v-if="gallerySelectDialog.selectedFileId">-->
<!-- <div style="display: inline-block; flex: none; margin-right: 5px">-->
<!-- <el-popover placement="right" :width="500px" trigger="click">-->
<!-- <template #reference>-->
<!-- <img-->
<!-- class="x-link"-->
<!-- :src="gallerySelectDialog.selectedImageUrl"-->
<!-- style="flex: none; width: 60px; height: 60px; border-radius: 4px; object-fit: cover" />-->
<!-- </template>-->
<!-- <img-->
<!-- class="x-link"-->
<!-- :src="gallerySelectDialog.selectedImageUrl"-->
<!-- style="height: 500px"-->
<!-- @click="showFullscreenImageDialog(gallerySelectDialog.selectedImageUrl)" />-->
<!-- </el-popover>-->
<!-- </div>-->
<!-- <el-button size="small" @click="clearImageGallerySelect" style="vertical-align: top">-->
<!-- {{ t('dialog.invite_message.clear_selected_image') }}-->
<!-- </el-button>-->
<!-- </template>-->
<!-- <template v-else>-->
<!-- <el-button size="small" @click="showGallerySelectDialog" style="margin-right: 5px">-->
<!-- {{ t('dialog.invite_message.select_image') }}-->
<!-- </el-button>-->
<!-- </template>-->
<input class="inviteImageUploadButton" type="file" accept="image/*" @change="inviteImageUpload" />
</template>
<Dialog
:open="sendInviteDialogVisible"
@update:open="
(open) => {
if (!open) cancelSendInvite();
}
">
<DialogContent class="x-dialog sm:max-w-200">
<DialogHeader>
<DialogTitle>{{ t('dialog.invite_message.header') }}</DialogTitle>
</DialogHeader>
<DataTableLayout
style="margin-top: 10px"
:table="inviteMessageTanstackTable"
:loading="false"
:show-pagination="false"
:on-row-click="handleInviteMessageRowClick" />
<template v-if="isLocalUserVrcPlusSupporter">
<!-- <template v-if="gallerySelectDialog.selectedFileId">-->
<!-- <div style="display: inline-block; flex: none; margin-right: 5px">-->
<!-- <el-popover placement="right" :width="500px" trigger="click">-->
<!-- <template #reference>-->
<!-- <img-->
<!-- class="x-link"-->
<!-- :src="gallerySelectDialog.selectedImageUrl"-->
<!-- style="flex: none; width: 60px; height: 60px; border-radius: 4px; object-fit: cover" />-->
<!-- </template>-->
<!-- <img-->
<!-- class="x-link"-->
<!-- :src="gallerySelectDialog.selectedImageUrl"-->
<!-- style="height: 500px"-->
<!-- @click="showFullscreenImageDialog(gallerySelectDialog.selectedImageUrl)" />-->
<!-- </el-popover>-->
<!-- </div>-->
<!-- <el-button size="small" @click="clearImageGallerySelect" style="vertical-align: top">-->
<!-- {{ t('dialog.invite_message.clear_selected_image') }}-->
<!-- </el-button>-->
<!-- </template>-->
<!-- <template v-else>-->
<!-- <el-button size="small" @click="showGallerySelectDialog" style="margin-right: 5px">-->
<!-- {{ t('dialog.invite_message.select_image') }}-->
<!-- </el-button>-->
<!-- </template>-->
<input class="inviteImageUploadButton" type="file" accept="image/*" @change="inviteImageUpload" />
</template>
<DataTableLayout
style="margin-top: 10px"
:table="inviteMessageTanstackTable"
:loading="false"
:show-pagination="false"
:on-row-click="handleInviteMessageRowClick" />
<DialogFooter>
<Button variant="secondary" @click="cancelSendInvite">
{{ t('dialog.invite_message.cancel') }}
</Button>
<Button variant="outline" @click="refreshInviteMessageTableData('message')">
{{ t('dialog.invite_message.refresh') }}
</Button>
</DialogFooter>
</DialogContent>
<template #footer>
<Button variant="secondary" @click="cancelSendInvite">
{{ t('dialog.invite_message.cancel') }}
</Button>
<Button variant="outline" @click="refreshInviteMessageTableData('message')">
{{ t('dialog.invite_message.refresh') }}
</Button>
</template>
<SendInviteConfirmDialog
v-model:isSendInviteConfirmDialogVisible="isSendInviteConfirmDialogVisible"
:sendInviteDialog="sendInviteDialog"
@@ -62,10 +69,11 @@
@update:sendInviteDialog="emit('update:sendInviteDialog', $event)"
:invite-dialog="inviteDialog"
@closeInviteDialog="closeInviteDialog" />
</el-dialog>
</Dialog>
</template>
<script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref } from 'vue';
import { Button } from '@/components/ui/button';
import { DataTableLayout } from '@/components/ui/data-table';

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,34 +1,36 @@
<template>
<el-dialog
:z-index="previousInstancesGroupDialogIndex"
v-model="isVisible"
:title="t('dialog.previous_instances.header')"
width="1000px"
append-to-body>
<DataTableLayout
class="min-w-0 w-full"
:table="table"
:loading="loading"
:table-style="tableStyle"
:page-sizes="pageSizes"
:total-items="totalItems"
:on-page-size-change="handlePageSizeChange">
<template #toolbar>
<div style="display: flex; align-items: center; justify-content: space-between">
<span style="font-size: 14px" v-text="previousInstancesGroupDialog.groupRef.name"></span>
<InputGroupField
class="w-1/3"
v-model="search"
:placeholder="t('dialog.previous_instances.search_placeholder')"
clearable />
</div>
</template>
</DataTableLayout>
</el-dialog>
<Dialog v-model:open="isVisible">
<DialogContent class="sm:max-w-250">
<DialogHeader>
<DialogTitle>{{ t('dialog.previous_instances.header') }}</DialogTitle>
</DialogHeader>
<DataTableLayout
class="min-w-0 w-full"
:table="table"
:loading="loading"
:table-style="tableStyle"
:page-sizes="pageSizes"
:total-items="totalItems"
:on-page-size-change="handlePageSizeChange">
<template #toolbar>
<div style="display: flex; align-items: center; justify-content: space-between">
<span style="font-size: 14px" v-text="previousInstancesGroupDialog.groupRef.name"></span>
<InputGroupField
class="w-1/3"
v-model="search"
:placeholder="t('dialog.previous_instances.search_placeholder')"
clearable />
</div>
</template>
</DataTableLayout>
</DialogContent>
</Dialog>
</template>
<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 { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
@@ -44,7 +46,6 @@
import { DataTableLayout } from '../../ui/data-table';
import { createColumns } from './previousInstancesGroupColumns.jsx';
import { database } from '../../../service/database';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
const { showPreviousInstancesInfoDialog } = useInstanceStore();
@@ -52,7 +53,6 @@
const { stringComparer } = storeToRefs(useSearchStore());
const { t } = useI18n();
const previousInstancesGroupDialogIndex = ref(2000);
const loading = ref(false);
const modalStore = useModalStore();
@@ -140,9 +140,6 @@
() => props.previousInstancesGroupDialog.openFlg,
() => {
if (props.previousInstancesGroupDialog.visible) {
nextTick(() => {
previousInstancesGroupDialogIndex.value = getNextDialogIndex();
});
refreshPreviousInstancesGroupTable();
}
}

View File

@@ -1,35 +1,41 @@
<template>
<el-dialog
:z-index="previousInstancesInfoDialogIndex"
:model-value="previousInstancesInfoDialogVisible"
:title="t('dialog.previous_instances.info')"
width="800px"
:fullscreen="fullscreen"
destroy-on-close
@close="closeDialog">
<DataTableLayout
class="min-w-0 w-full"
:table="table"
:loading="loading"
:table-style="tableStyle"
:page-sizes="pageSizes"
:total-items="totalItems"
:on-page-size-change="handlePageSizeChange">
<template #toolbar>
<div style="display: flex; align-items: center; justify-content: space-between">
<Location :location="location.tag" style="font-size: 14px" />
<InputGroupField
v-model="search"
:placeholder="t('dialog.previous_instances.search_placeholder')"
style="width: 150px"
clearable />
</div>
</template>
</DataTableLayout>
</el-dialog>
<Dialog
:open="previousInstancesInfoDialogVisible"
@update:open="
(open) => {
if (!open) closeDialog();
}
">
<DialogContent class="sm:max-w-200">
<DialogHeader>
<DialogTitle>{{ t('dialog.previous_instances.info') }}</DialogTitle>
</DialogHeader>
<DataTableLayout
class="min-w-0 w-full"
:table="table"
:loading="loading"
:table-style="tableStyle"
:page-sizes="pageSizes"
:total-items="totalItems"
:on-page-size-change="handlePageSizeChange">
<template #toolbar>
<div style="display: flex; align-items: center; justify-content: space-between">
<Location :location="location.tag" style="font-size: 14px" />
<InputGroupField
v-model="search"
:placeholder="t('dialog.previous_instances.search_placeholder')"
style="width: 150px"
clearable />
</div>
</template>
</DataTableLayout>
</DialogContent>
</Dialog>
</template>
<script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, nextTick, ref, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
@@ -40,7 +46,6 @@
import { InputGroupField } from '../../../components/ui/input-group';
import { createColumns } from './previousInstancesInfoColumns.jsx';
import { database } from '../../../service/database';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
const { lookupUser } = useUserStore();
@@ -49,8 +54,6 @@
const { gameLogIsFriend, gameLogIsFavorite } = useGameLogStore();
const { t } = useI18n();
const previousInstancesInfoDialogIndex = ref(2000);
const loading = ref(false);
const rawRows = ref([]);
const search = ref('');
@@ -147,7 +150,6 @@
);
function init() {
previousInstancesInfoDialogIndex.value = getNextDialogIndex();
loading.value = true;
location.value = parseLocation(previousInstancesInfoDialogInstanceId.value);
}

View File

@@ -1,35 +1,37 @@
<template>
<el-dialog
:z-index="previousInstancesWorldDialogIndex"
v-model="isVisible"
:title="t('dialog.previous_instances.header')"
width="1000px"
append-to-body>
<DataTableLayout
class="min-w-0 w-full"
:table="table"
:loading="loading"
:table-style="tableStyle"
:page-sizes="pageSizes"
:total-items="totalItems"
:on-page-size-change="handlePageSizeChange">
<template #toolbar>
<div style="display: flex; align-items: center; justify-content: space-between">
<span style="font-size: 14px" v-text="previousInstancesWorldDialog.worldRef.name"></span>
<InputGroupField
v-model="search"
:placeholder="t('dialog.previous_instances.search_placeholder')"
clearable
class="w-1/3"
style="display: block" />
</div>
</template>
</DataTableLayout>
</el-dialog>
<Dialog v-model:open="isVisible">
<DialogContent class="sm:max-w-250">
<DialogHeader>
<DialogTitle>{{ t('dialog.previous_instances.header') }}</DialogTitle>
</DialogHeader>
<DataTableLayout
class="min-w-0 w-full"
:table="table"
:loading="loading"
:table-style="tableStyle"
:page-sizes="pageSizes"
:total-items="totalItems"
:on-page-size-change="handlePageSizeChange">
<template #toolbar>
<div style="display: flex; align-items: center; justify-content: space-between">
<span style="font-size: 14px" v-text="previousInstancesWorldDialog.worldRef.name"></span>
<InputGroupField
v-model="search"
:placeholder="t('dialog.previous_instances.search_placeholder')"
clearable
class="w-1/3"
style="display: block" />
</div>
</template>
</DataTableLayout>
</DialogContent>
</Dialog>
</template>
<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 { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
@@ -52,7 +54,6 @@
import { DataTableLayout } from '../../ui/data-table';
import { createColumns } from './previousInstancesWorldColumns.jsx';
import { database } from '../../../service/database';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
const { t } = useI18n();
@@ -79,7 +80,6 @@
const pageSize = ref(10);
const tableStyle = { maxHeight: '400px' };
const loading = ref(false);
const previousInstancesWorldDialogIndex = ref(2000);
const isVisible = computed({
get: () => props.previousInstancesWorldDialog.visible,
@@ -188,9 +188,6 @@
() => props.previousInstancesWorldDialog.openFlg,
() => {
if (props.previousInstancesWorldDialog.visible) {
nextTick(() => {
previousInstancesWorldDialogIndex.value = getNextDialogIndex();
});
refreshPreviousInstancesWorldTable();
}
}

View File

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

View File

@@ -1,56 +1,58 @@
<template>
<el-dialog
class="x-dialog"
v-model="bioDialog.visible"
:title="t('dialog.bio.header')"
width="600px"
append-to-body>
<div v-loading="bioDialog.loading">
<InputGroupTextareaField
v-model="bioDialog.bio"
:maxlength="512"
:rows="5"
:placeholder="t('dialog.bio.bio_placeholder')"
class="mb-2.5"
show-count />
<Dialog v-model:open="bioDialog.visible">
<DialogContent class="x-dialog sm:max-w-150">
<DialogHeader>
<DialogTitle>{{ t('dialog.bio.header') }}</DialogTitle>
</DialogHeader>
<InputGroupAction
v-for="(link, index) in bioDialog.bioLinks"
:key="index"
v-model="bioDialog.bioLinks[index]"
:maxlength="64"
show-count
size="sm"
style="margin-top: 5px">
<template #leading>
<img :src="getFaviconUrl(link)" style="width: 16px; height: 16px; vertical-align: middle" />
</template>
<template #actions>
<Button variant="ghost" size="icon-sm" @click="bioDialog.bioLinks.splice(index, 1)"
><Trash2 class="size-4"
/></Button>
</template>
</InputGroupAction>
<div v-loading="bioDialog.loading">
<InputGroupTextareaField
v-model="bioDialog.bio"
:maxlength="512"
:rows="5"
:placeholder="t('dialog.bio.bio_placeholder')"
class="mb-2.5"
show-count />
<Button
variant="outline"
:disabled="bioDialog.bioLinks.length >= 3"
size="sm"
class="mt-2"
@click="bioDialog.bioLinks.push('')">
{{ t('dialog.bio.add_link') }}
</Button>
</div>
<InputGroupAction
v-for="(link, index) in bioDialog.bioLinks"
:key="index"
v-model="bioDialog.bioLinks[index]"
:maxlength="64"
show-count
size="sm"
style="margin-top: 5px">
<template #leading>
<img :src="getFaviconUrl(link)" style="width: 16px; height: 16px; vertical-align: middle" />
</template>
<template #actions>
<Button variant="ghost" size="icon-sm" @click="bioDialog.bioLinks.splice(index, 1)"
><Trash2 class="size-4"
/></Button>
</template>
</InputGroupAction>
<template #footer>
<Button :disabled="bioDialog.loading" @click="saveBio">
{{ t('dialog.bio.update') }}
</Button>
</template>
</el-dialog>
<Button
variant="outline"
:disabled="bioDialog.bioLinks.length >= 3"
size="sm"
class="mt-2"
@click="bioDialog.bioLinks.push('')">
{{ t('dialog.bio.add_link') }}
</Button>
</div>
<DialogFooter>
<Button :disabled="bioDialog.loading" @click="saveBio">
{{ t('dialog.bio.update') }}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</template>
<script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { InputGroupAction, InputGroupTextareaField } from '@/components/ui/input-group';
import { Button } from '@/components/ui/button';
import { Trash2 } from 'lucide-vue-next';

View File

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

View File

@@ -1,63 +1,67 @@
<template>
<el-dialog
class="x-dialog"
v-model="languageDialog.visible"
:title="t('dialog.language.header')"
width="400px"
append-to-body>
<div v-loading="languageDialog.loading">
<div v-for="item in currentUser.$languages" :key="item.key" style="margin: 6px 0">
<Badge variant="outline" style="margin-right: 5px">
<span
class="flags"
:class="languageClass(item.key)"
style="display: inline-block; margin-right: 5px"></span>
{{ item.value }} ({{ item.key.toUpperCase() }})
<button
type="button"
style="
margin-left: 6px;
border: none;
background: transparent;
padding: 0;
display: inline-flex;
align-items: center;
color: inherit;
cursor: pointer;
"
@click="removeUserLanguage(item.key)">
<X class="h-3 w-3" />
</button>
</Badge>
<Dialog v-model:open="languageDialog.visible">
<DialogContent class="x-dialog sm:max-w-100">
<DialogHeader>
<DialogTitle>{{ t('dialog.language.header') }}</DialogTitle>
</DialogHeader>
<div v-loading="languageDialog.loading">
<div v-for="item in currentUser.$languages" :key="item.key" style="margin: 6px 0">
<Badge variant="outline" style="margin-right: 5px">
<span
class="flags"
:class="languageClass(item.key)"
style="display: inline-block; margin-right: 5px"></span>
{{ item.value }} ({{ item.key.toUpperCase() }})
<button
type="button"
style="
margin-left: 6px;
border: none;
background: transparent;
padding: 0;
display: inline-flex;
align-items: center;
color: inherit;
cursor: pointer;
"
@click="removeUserLanguage(item.key)">
<X class="h-3 w-3" />
</button>
</Badge>
</div>
<Select
:model-value="selectedLanguageToAdd"
:disabled="
languageDialog.loading || (currentUser.$languages && currentUser.$languages.length === 3)
"
@update:modelValue="handleAddUserLanguage">
<SelectTrigger size="sm" style="margin-top: 14px">
<SelectValue :placeholder="t('dialog.language.select_language')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="item in languageDialog.languages"
:key="item.key"
:value="item.key"
:text-value="item.value">
<span
class="flags"
:class="languageClass(item.key)"
style="display: inline-block; margin-right: 5px"></span>
{{ item.value }} ({{ item.key.toUpperCase() }})
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
<Select
:model-value="selectedLanguageToAdd"
:disabled="languageDialog.loading || (currentUser.$languages && currentUser.$languages.length === 3)"
@update:modelValue="handleAddUserLanguage">
<SelectTrigger size="sm" style="margin-top: 14px">
<SelectValue :placeholder="t('dialog.language.select_language')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="item in languageDialog.languages"
:key="item.key"
:value="item.key"
:text-value="item.value">
<span
class="flags"
:class="languageClass(item.key)"
style="display: inline-block; margin-right: 5px"></span>
{{ item.value }} ({{ item.key.toUpperCase() }})
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
</el-dialog>
</DialogContent>
</Dialog>
</template>
<script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { X } from 'lucide-vue-next';
import { ref } from 'vue';
import { storeToRefs } from 'pinia';

View File

@@ -1,35 +1,37 @@
<template>
<el-dialog
:z-index="previousInstancesUserDialogIndex"
v-model="isVisible"
:title="t('dialog.previous_instances.header')"
width="1000px"
append-to-body>
<DataTableLayout
class="min-w-0 w-full"
:table="table"
:loading="loading"
:table-style="tableStyle"
:page-sizes="pageSizes"
:total-items="totalItems"
:on-page-size-change="handlePageSizeChange">
<template #toolbar>
<div style="display: flex; align-items: center; justify-content: space-between">
<span style="font-size: 14px" v-text="previousInstancesUserDialog.userRef.displayName"></span>
<InputGroupField
v-model="search"
:placeholder="t('dialog.previous_instances.search_placeholder')"
clearable
class="w-1/3"
style="display: block" />
</div>
</template>
</DataTableLayout>
</el-dialog>
<Dialog v-model:open="isVisible">
<DialogContent class="sm:max-w-250">
<DialogHeader>
<DialogTitle>{{ t('dialog.previous_instances.header') }}</DialogTitle>
</DialogHeader>
<DataTableLayout
class="min-w-0 w-full"
:table="table"
:loading="loading"
:table-style="tableStyle"
:page-sizes="pageSizes"
:total-items="totalItems"
:on-page-size-change="handlePageSizeChange">
<template #toolbar>
<div style="display: flex; align-items: center; justify-content: space-between">
<span style="font-size: 14px" v-text="previousInstancesUserDialog.userRef.displayName"></span>
<InputGroupField
v-model="search"
:placeholder="t('dialog.previous_instances.search_placeholder')"
clearable
class="w-1/3"
style="display: block" />
</div>
</template>
</DataTableLayout>
</DialogContent>
</Dialog>
</template>
<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 { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
@@ -52,7 +54,6 @@
import { DataTableLayout } from '../../ui/data-table';
import { createColumns } from './previousInstancesUserColumns.jsx';
import { database } from '../../../service/database';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
const props = defineProps({
@@ -90,8 +91,6 @@
const vrcxStore = useVrcxStore();
const { t } = useI18n();
const previousInstancesUserDialogIndex = ref(2000);
const isVisible = computed({
get: () => props.previousInstancesUserDialog.visible,
set: (value) => {
@@ -178,9 +177,6 @@
() => props.previousInstancesUserDialog.openFlg,
() => {
if (props.previousInstancesUserDialog.visible) {
nextTick(() => {
previousInstancesUserDialogIndex.value = getNextDialogIndex();
});
refreshPreviousInstancesUserTable();
}
}

View File

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

View File

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

View File

@@ -1,96 +1,98 @@
<template>
<el-dialog
class="x-dialog"
v-model="socialStatusDialog.visible"
:title="t('dialog.social_status.header')"
append-to-body
width="400px">
<div v-loading="socialStatusDialog.loading">
<Select :model-value="socialStatusDialog.status" @update:modelValue="handleSocialStatusChange">
<SelectTrigger size="sm" style="margin-top: 10px; width: 100%">
<span class="flex items-center gap-2">
<i v-if="socialStatusDialog.status === 'join me'" class="x-user-status joinme"></i>
<i v-else-if="socialStatusDialog.status === 'active'" class="x-user-status online"></i>
<i v-else-if="socialStatusDialog.status === 'ask me'" class="x-user-status askme"></i>
<i v-else-if="socialStatusDialog.status === 'busy'" class="x-user-status busy"></i>
<i v-else-if="socialStatusDialog.status === 'offline'" class="x-user-status offline"></i>
<SelectValue :placeholder="t('dialog.social_status.status_placeholder')" />
</span>
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="join me" :text-value="t('dialog.user.status.join_me')">
<i class="x-user-status joinme"></i> {{ t('dialog.user.status.join_me') }}
</SelectItem>
<SelectItem value="active" :text-value="t('dialog.user.status.online')">
<i class="x-user-status online"></i> {{ t('dialog.user.status.online') }}
</SelectItem>
<SelectItem value="ask me" :text-value="t('dialog.user.status.ask_me')">
<i class="x-user-status askme"></i> {{ t('dialog.user.status.ask_me') }}
</SelectItem>
<SelectItem value="busy" :text-value="t('dialog.user.status.busy')">
<i class="x-user-status busy"></i> {{ t('dialog.user.status.busy') }}
</SelectItem>
<SelectItem
v-if="currentUser.$isModerator"
value="offline"
:text-value="t('dialog.user.status.offline')">
<i class="x-user-status offline"></i> {{ t('dialog.user.status.offline') }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<Dialog v-model:open="socialStatusDialog.visible">
<DialogContent class="x-dialog sm:max-w-100">
<DialogHeader>
<DialogTitle>{{ t('dialog.social_status.header') }}</DialogTitle>
</DialogHeader>
<InputGroupField
v-model="socialStatusDialog.statusDescription"
:placeholder="t('dialog.social_status.status_placeholder')"
:maxlength="32"
clearable
show-count
class="mt-2.5" />
<Collapsible v-model:open="isOpen" class="mt-3 flex w-full flex-col gap-2">
<div class="flex items-center justify-between gap-4 px-4">
<h4 class="text-sm font-semibold">{{ t('dialog.social_status.history') }}</h4>
<CollapsibleTrigger as-child>
<Button variant="ghost" size="icon" class="size-8">
<ChevronsUpDown />
<span class="sr-only">Toggle</span>
</Button>
</CollapsibleTrigger>
</div>
<div
v-if="!isOpen && latestHistoryItem"
class="cursor-pointer rounded-md border w-full px-4 py-2 font-mono text-sm"
@click="setSocialStatusFromHistory(latestHistoryItem)">
{{ latestHistoryItem.status }}
</div>
<CollapsibleContent class="flex flex-col gap-2">
<div
v-for="item in historyItems"
:key="item.no ?? item.status"
class="cursor-pointer rounded-md border w-full px-4 py-2 font-mono text-sm"
@click="setSocialStatusFromHistory(item)">
{{ item.status }}
<div v-loading="socialStatusDialog.loading">
<Select :model-value="socialStatusDialog.status" @update:modelValue="handleSocialStatusChange">
<SelectTrigger size="sm" style="margin-top: 10px; width: 100%">
<span class="flex items-center gap-2">
<i v-if="socialStatusDialog.status === 'join me'" class="x-user-status joinme"></i>
<i v-else-if="socialStatusDialog.status === 'active'" class="x-user-status online"></i>
<i v-else-if="socialStatusDialog.status === 'ask me'" class="x-user-status askme"></i>
<i v-else-if="socialStatusDialog.status === 'busy'" class="x-user-status busy"></i>
<i v-else-if="socialStatusDialog.status === 'offline'" class="x-user-status offline"></i>
<SelectValue :placeholder="t('dialog.social_status.status_placeholder')" />
</span>
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="join me" :text-value="t('dialog.user.status.join_me')">
<i class="x-user-status joinme"></i> {{ t('dialog.user.status.join_me') }}
</SelectItem>
<SelectItem value="active" :text-value="t('dialog.user.status.online')">
<i class="x-user-status online"></i> {{ t('dialog.user.status.online') }}
</SelectItem>
<SelectItem value="ask me" :text-value="t('dialog.user.status.ask_me')">
<i class="x-user-status askme"></i> {{ t('dialog.user.status.ask_me') }}
</SelectItem>
<SelectItem value="busy" :text-value="t('dialog.user.status.busy')">
<i class="x-user-status busy"></i> {{ t('dialog.user.status.busy') }}
</SelectItem>
<SelectItem
v-if="currentUser.$isModerator"
value="offline"
:text-value="t('dialog.user.status.offline')">
<i class="x-user-status offline"></i> {{ t('dialog.user.status.offline') }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<InputGroupField
v-model="socialStatusDialog.statusDescription"
:placeholder="t('dialog.social_status.status_placeholder')"
:maxlength="32"
clearable
show-count
class="mt-2.5" />
<Collapsible v-model:open="isOpen" class="mt-3 flex w-full flex-col gap-2">
<div class="flex items-center justify-between gap-4 px-4">
<h4 class="text-sm font-semibold">{{ t('dialog.social_status.history') }}</h4>
<CollapsibleTrigger as-child>
<Button variant="ghost" size="icon" class="size-8">
<ChevronsUpDown />
<span class="sr-only">Toggle</span>
</Button>
</CollapsibleTrigger>
</div>
</CollapsibleContent>
</Collapsible>
</div>
<div
v-if="!isOpen && latestHistoryItem"
class="cursor-pointer rounded-md border w-full px-4 py-2 font-mono text-sm"
@click="setSocialStatusFromHistory(latestHistoryItem)">
{{ latestHistoryItem.status }}
</div>
<CollapsibleContent class="flex flex-col gap-2">
<div
v-for="item in historyItems"
:key="item.no ?? item.status"
class="cursor-pointer rounded-md border w-full px-4 py-2 font-mono text-sm"
@click="setSocialStatusFromHistory(item)">
{{ item.status }}
</div>
</CollapsibleContent></Collapsible
>
</div>
<template #footer>
<Button :disabled="socialStatusDialog.loading" @click="saveSocialStatus">
{{ t('dialog.social_status.update') }}
</Button>
</template>
</el-dialog>
<DialogFooter>
<Button :disabled="socialStatusDialog.loading" @click="saveSocialStatus">
{{ t('dialog.social_status.update') }}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</template>
<script setup lang="ts">
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 { computed, ref } from 'vue';
import { Button } from '@/components/ui/button';
import { InputGroupField } from '@/components/ui/input-group';
import { ChevronsUpDown } from 'lucide-vue-next';
import { InputGroupField } from '@/components/ui/input-group';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,33 +1,40 @@
<template>
<el-dialog
class="x-dialog"
:model-value="changeWorldImageDialogVisible"
:title="t('dialog.change_content_image.world')"
width="850px"
append-to-body
@close="closeDialog">
<div>
<input
id="WorldImageUploadButton"
type="file"
accept="image/*"
style="display: none"
@change="onFileChangeWorldImage" />
<span>{{ t('dialog.change_content_image.description') }}</span>
<br />
<Button variant="outline" size="sm" :disabled="changeWorldImageDialogLoading" @click="uploadWorldImage">
<Upload />
{{ t('dialog.change_content_image.upload') }}
</Button>
<br />
<div class="x-change-image-item">
<img :src="previousImageUrl" class="img-size" loading="lazy" />
<Dialog
:open="changeWorldImageDialogVisible"
@update:open="
(open) => {
if (!open) closeDialog();
}
">
<DialogContent class="x-dialog sm:max-w-212.5">
<DialogHeader>
<DialogTitle>{{ t('dialog.change_content_image.world') }}</DialogTitle>
</DialogHeader>
<div>
<input
id="WorldImageUploadButton"
type="file"
accept="image/*"
style="display: none"
@change="onFileChangeWorldImage" />
<span>{{ t('dialog.change_content_image.description') }}</span>
<br />
<Button variant="outline" size="sm" :disabled="changeWorldImageDialogLoading" @click="uploadWorldImage">
<Upload />
{{ t('dialog.change_content_image.upload') }}
</Button>
<br />
<div class="x-change-image-item">
<img :src="previousImageUrl" class="img-size" loading="lazy" />
</div>
</div>
</div>
</el-dialog>
</DialogContent>
</Dialog>
</template>
<script setup>
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Upload } from 'lucide-vue-next';
import { ref } from 'vue';

View File

@@ -1,107 +1,110 @@
<template>
<el-dialog
v-model="isVisible"
:title="t('dialog.set_world_tags.header')"
width="400px"
destroy-on-close
append-to-body>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.avatarScalingDisabled" />
<span>{{ t('dialog.set_world_tags.avatar_scaling_disabled') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.focusViewDisabled" />
<span>{{ t('dialog.set_world_tags.focus_view_disabled') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.debugAllowed" />
<span>{{ t('dialog.set_world_tags.enable_debugging') }}</span>
</label>
<div style="font-size: 12px; margin-top: 10px">{{ t('dialog.set_world_tags.author_tags') }}<br /></div>
<InputGroupTextareaField
v-model="setWorldTagsDialog.authorTags"
:rows="2"
placeholder=""
style="margin-top: 10px"
input-class="resize-none" />
<div style="font-size: 12px; margin-top: 10px">{{ t('dialog.set_world_tags.content_tags') }}<br /></div>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.contentHorror" />
<span>{{ t('dialog.set_world_tags.content_horror') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.contentGore" />
<span>{{ t('dialog.set_world_tags.content_gore') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.contentViolence" />
<span>{{ t('dialog.set_world_tags.content_violence') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.contentAdult" />
<span>{{ t('dialog.set_world_tags.content_adult') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.contentSex" />
<span>{{ t('dialog.set_world_tags.content_sex') }}</span>
</label>
<div style="font-size: 12px; margin-top: 10px">
{{ t('dialog.set_world_tags.default_content_settings') }}<br />
</div>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.emoji" />
<span>{{ t('dialog.new_instance.content_emoji') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.stickers" />
<span>{{ t('dialog.new_instance.content_stickers') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.pedestals" />
<span>{{ t('dialog.new_instance.content_pedestals') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.prints" />
<span>{{ t('dialog.new_instance.content_prints') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.drones" />
<span>{{ t('dialog.new_instance.content_drones') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.props" />
<span>{{ t('dialog.new_instance.content_items') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.thirdPerson" />
<span>{{ t('dialog.new_instance.content_third_person') }}</span>
</label>
<template #footer>
<div class="flex gap-2">
<Button variant="secondary" @click="isVisible = false">
{{ t('dialog.set_world_tags.cancel') }}
</Button>
<Button @click="saveSetWorldTagsDialog">
{{ t('dialog.set_world_tags.save') }}
</Button>
<Dialog v-model:open="isVisible">
<DialogContent class="sm:max-w-100">
<DialogHeader>
<DialogTitle>{{ t('dialog.set_world_tags.header') }}</DialogTitle>
</DialogHeader>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.avatarScalingDisabled" />
<span>{{ t('dialog.set_world_tags.avatar_scaling_disabled') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.focusViewDisabled" />
<span>{{ t('dialog.set_world_tags.focus_view_disabled') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.debugAllowed" />
<span>{{ t('dialog.set_world_tags.enable_debugging') }}</span>
</label>
<div style="font-size: 12px; margin-top: 10px">{{ t('dialog.set_world_tags.author_tags') }}<br /></div>
<InputGroupTextareaField
v-model="setWorldTagsDialog.authorTags"
:rows="2"
placeholder=""
style="margin-top: 10px"
input-class="resize-none" />
<div style="font-size: 12px; margin-top: 10px">{{ t('dialog.set_world_tags.content_tags') }}<br /></div>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.contentHorror" />
<span>{{ t('dialog.set_world_tags.content_horror') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.contentGore" />
<span>{{ t('dialog.set_world_tags.content_gore') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.contentViolence" />
<span>{{ t('dialog.set_world_tags.content_violence') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.contentAdult" />
<span>{{ t('dialog.set_world_tags.content_adult') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.contentSex" />
<span>{{ t('dialog.set_world_tags.content_sex') }}</span>
</label>
<div style="font-size: 12px; margin-top: 10px">
{{ t('dialog.set_world_tags.default_content_settings') }}<br />
</div>
</template>
</el-dialog>
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.emoji" />
<span>{{ t('dialog.new_instance.content_emoji') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.stickers" />
<span>{{ t('dialog.new_instance.content_stickers') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.pedestals" />
<span>{{ t('dialog.new_instance.content_pedestals') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.prints" />
<span>{{ t('dialog.new_instance.content_prints') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.drones" />
<span>{{ t('dialog.new_instance.content_drones') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.props" />
<span>{{ t('dialog.new_instance.content_items') }}</span>
</label>
<br />
<label class="inline-flex items-center gap-2">
<Checkbox v-model="setWorldTagsDialog.thirdPerson" />
<span>{{ t('dialog.new_instance.content_third_person') }}</span>
</label>
<DialogFooter>
<div class="flex gap-2">
<Button variant="secondary" @click="isVisible = false">
{{ t('dialog.set_world_tags.cancel') }}
</Button>
<Button @click="saveSetWorldTagsDialog">
{{ t('dialog.set_world_tags.save') }}
</Button>
</div>
</DialogFooter>
</DialogContent>
</Dialog>
</template>
<script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';

View File

@@ -1,34 +1,37 @@
<template>
<el-dialog
v-model="isVisible"
:title="t('dialog.allowed_video_player_domains.header')"
width="600px"
destroy-on-close
append-to-body>
<div>
<InputGroupAction
v-for="(domain, index) in urlList"
:key="index"
v-model="urlList[index]"
size="sm"
style="margin-top: 5px">
<template #actions>
<Button variant="ghost" @click="urlList.splice(index, 1)"><Trash2 /></Button>
</template>
</InputGroupAction>
<Button size="sm" variant="outline" style="margin-top: 5px" @click="urlList.push('')">
{{ t('dialog.allowed_video_player_domains.add_domain') }}
</Button>
</div>
<template #footer>
<Button :disabled="!worldAllowedDomainsDialog.worldId" @click="saveWorldAllowedDomains">
{{ t('dialog.allowed_video_player_domains.save') }}
</Button>
</template>
</el-dialog>
<Dialog v-model:open="isVisible">
<DialogContent class="sm:max-w-150">
<DialogHeader>
<DialogTitle>{{ t('dialog.allowed_video_player_domains.header') }}</DialogTitle>
</DialogHeader>
<div>
<InputGroupAction
v-for="(domain, index) in urlList"
:key="index"
v-model="urlList[index]"
size="sm"
style="margin-top: 5px">
<template #actions>
<Button variant="ghost" @click="urlList.splice(index, 1)"><Trash2 /></Button>
</template>
</InputGroupAction>
<Button size="sm" variant="outline" style="margin-top: 5px" @click="urlList.push('')">
{{ t('dialog.allowed_video_player_domains.add_domain') }}
</Button>
</div>
<DialogFooter>
<Button :disabled="!worldAllowedDomainsDialog.worldId" @click="saveWorldAllowedDomains">
{{ t('dialog.allowed_video_player_domains.save') }}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</template>
<script setup>
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button';
import { InputGroupAction } from '@/components/ui/input-group';

File diff suppressed because it is too large Load Diff