replace el-tabs

This commit is contained in:
pa
2026-01-14 22:25:52 +09:00
committed by Natsumi
parent 442b1060f7
commit b7f3d91a03
17 changed files with 1382 additions and 1061 deletions

View File

@@ -325,8 +325,12 @@
</div>
</div>
</div>
<el-tabs v-model="avatarDialogLastActiveTab" @tab-click="avatarDialogTabClick">
<el-tab-pane name="Info" :label="t('dialog.avatar.info.header')">
<TabsUnderline
v-model="avatarDialogLastActiveTab"
:items="avatarDialogTabs"
:unmount-on-hide="false"
@update:modelValue="avatarDialogTabClick">
<template #Info>
<div class="x-friend-list" style="max-height: unset">
<div
v-if="avatarDialog.galleryImages.length || avatarDialog.ref.authorId === currentUser.id"
@@ -479,8 +483,8 @@
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane name="JSON" :label="t('dialog.avatar.json.header')" style="max-height: 50vh" lazy>
</template>
<template #JSON>
<Button
class="rounded-full h-6 w-6 mr-2"
size="icon-sm"
@@ -503,8 +507,8 @@
:deep="2"
:theme="isDarkMode ? 'dark' : 'light'"
show-icon />
</el-tab-pane>
</el-tabs>
</template>
</TabsUnderline>
</div>
<template v-if="avatarDialog.visible">
<SetAvatarTagsDialog v-model:setAvatarTagsDialog="setAvatarTagsDialog" />
@@ -535,6 +539,7 @@
import { Button } from '@/components/ui/button';
import { ElMessageBox } from 'element-plus';
import { InputGroupTextareaField } from '@/components/ui/input-group';
import { TabsUnderline } from '@/components/ui/tabs';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
@@ -595,6 +600,10 @@
const modalStore = useModalStore();
const { t } = useI18n();
const avatarDialogTabs = computed(() => [
{ value: 'Info', label: t('dialog.avatar.info.header') },
{ value: 'JSON', label: t('dialog.avatar.json.header') }
]);
const avatarDialogIndex = ref(2000);
const avatarDialogLastActiveTab = ref('Info');
@@ -680,12 +689,11 @@
handleAvatarDialogTab(avatarDialogLastActiveTab.value);
}
function avatarDialogTabClick(obj) {
if (obj.props.name === avatarDialogLastActiveTab.value) {
function avatarDialogTabClick(tabName) {
if (tabName === avatarDialogLastActiveTab.value) {
return;
}
handleAvatarDialogTab(obj.props.name);
avatarDialogLastActiveTab.value = obj.props.name;
handleAvatarDialogTab(tabName);
}
function getImageUrlFromImageId(imageId) {

View File

@@ -335,8 +335,12 @@
</div>
</div>
</div>
<el-tabs v-model="groupDialogLastActiveTab" @tab-click="groupDialogTabClick">
<el-tab-pane name="Info" :label="t('dialog.group.info.header')">
<TabsUnderline
v-model="groupDialogLastActiveTab"
:items="groupDialogTabs"
:unmount-on-hide="false"
@update:modelValue="groupDialogTabClick">
<template #Info>
<div class="group-banner-image-info">
<img
:src="groupDialog.ref.bannerUrl"
@@ -706,8 +710,8 @@
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane name="Posts" :label="t('dialog.group.posts.header')" lazy>
</template>
<template #Posts>
<template v-if="groupDialog.visible">
<span style="margin-right: 10px; vertical-align: top"
>{{ t('dialog.group.posts.posts_count') }} {{ groupDialog.posts.length }}</span
@@ -822,8 +826,8 @@
</div>
</div>
</template>
</el-tab-pane>
<el-tab-pane name="Members" :label="t('dialog.group.members.header')" lazy>
</template>
<template #Members>
<template v-if="groupDialog.visible">
<span
v-if="hasGroupPermission(groupDialog.ref, 'group-members-viewall')"
@@ -1039,8 +1043,8 @@
</div>
</ul>
</template>
</el-tab-pane>
<el-tab-pane name="Photos" :label="t('dialog.group.gallery.header')" lazy>
</template>
<template #Photos>
<Button
class="rounded-full"
variant="outline"
@@ -1050,48 +1054,51 @@
<Spinner v-if="isGroupGalleryLoading" />
<Refresh v-else />
</Button>
<el-tabs
<TabsUnderline
v-model="groupDialogGalleryCurrentName"
:items="groupGalleryTabs"
:unmount-on-hide="false"
v-loading="isGroupGalleryLoading"
style="margin-top: 10px">
<template v-for="(gallery, index) in groupDialog.ref.galleries" :key="index">
<el-tab-pane>
<template #label>
<span style="font-weight: bold; font-size: 16px" v-text="gallery.name" />
<i
class="x-status-icon"
style="margin-left: 5px"
:class="groupGalleryStatus(gallery)" />
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{
groupDialog.galleries[gallery.id] ? groupDialog.galleries[gallery.id].length : 0
}}</span>
</template>
<span style="color: #c7c7c7; padding: 10px" v-text="gallery.description" />
<div
style="
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 15px;
margin-top: 10px;
max-height: 600px;
overflow-y: auto;
">
<Card
v-for="image in groupDialog.galleries[gallery.id]"
:key="image.id"
class="p-0 overflow-hidden transition-shadow hover:shadow-md">
<img
:src="image.imageUrl"
:class="['x-link', 'x-popover-image']"
@click="showFullscreenImageDialog(image.imageUrl)"
loading="lazy" />
</Card>
</div>
</el-tab-pane>
class="mt-2.5">
<template
v-for="(gallery, index) in groupDialog.ref.galleries"
:key="`label-${index}`"
v-slot:[`label-${index}`]>
<span style="font-weight: bold; font-size: 16px" v-text="gallery.name" />
<i class="x-status-icon" style="margin-left: 5px" :class="groupGalleryStatus(gallery)" />
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{
groupDialog.galleries[gallery.id] ? groupDialog.galleries[gallery.id].length : 0
}}</span>
</template>
</el-tabs>
</el-tab-pane>
<el-tab-pane name="JSON" :label="t('dialog.group.json.header')" lazy>
<template
v-for="(gallery, index) in groupDialog.ref.galleries"
:key="`content-${index}`"
v-slot:[String(index)]>
<span style="color: #c7c7c7; padding: 10px" v-text="gallery.description" />
<div
style="
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 15px;
margin-top: 10px;
max-height: 600px;
overflow-y: auto;
">
<Card
v-for="image in groupDialog.galleries[gallery.id]"
:key="image.id"
class="p-0 overflow-hidden transition-shadow hover:shadow-md">
<img
:src="image.imageUrl"
:class="['x-link', 'x-popover-image']"
@click="showFullscreenImageDialog(image.imageUrl)"
loading="lazy" />
</Card>
</div>
</template>
</TabsUnderline>
</template>
<template #JSON>
<Button
class="rounded-full h-6 w-6 mr-2"
size="icon-sm"
@@ -1111,8 +1118,8 @@
:deep="2"
:theme="isDarkMode ? 'dark' : 'light'"
show-icon />
</el-tab-pane>
</el-tabs>
</template>
</TabsUnderline>
</div>
<GroupPostEditDialog :dialog-data="groupPostEditDialog" :selected-gallery-file="selectedGalleryFile" />
<PreviousInstancesGroupDialog
@@ -1153,6 +1160,7 @@
import { InputGroupField } from '@/components/ui/input-group';
import { RefreshCcw } from 'lucide-vue-next';
import { Spinner } from '@/components/ui/spinner';
import { TabsUnderline } from '@/components/ui/tabs';
import { VirtualCombobox } from '@/components/ui/virtual-combobox';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner';
@@ -1202,6 +1210,19 @@
import * as workerTimers from 'worker-timers';
const { t } = useI18n();
const groupDialogTabs = computed(() => [
{ value: 'Info', label: t('dialog.group.info.header') },
{ value: 'Posts', label: t('dialog.group.posts.header') },
{ value: 'Members', label: t('dialog.group.members.header') },
{ value: 'Photos', label: t('dialog.group.gallery.header') },
{ value: 'JSON', label: t('dialog.group.json.header') }
]);
const groupGalleryTabs = computed(() =>
(groupDialog.value?.ref?.galleries || []).map((gallery, index) => ({
value: String(index),
label: gallery?.name ?? ''
}))
);
const modalStore = useModalStore();
@@ -1654,12 +1675,12 @@
handleGroupDialogTab(groupDialogLastActiveTab.value);
}
function groupDialogTabClick(obj) {
if (obj.props.name === groupDialogTabCurrentName.value) {
function groupDialogTabClick(tabName) {
if (tabName === groupDialogTabCurrentName.value) {
return;
}
handleGroupDialogTab(obj.props.name);
groupDialogTabCurrentName.value = obj.props.name;
handleGroupDialogTab(tabName);
groupDialogTabCurrentName.value = tabName;
}
function showGroupPostEditDialog(groupId, post) {

View File

@@ -7,8 +7,12 @@
width="90vw">
<div>
<h3>{{ groupMemberModeration.groupRef.name }}</h3>
<el-tabs style="height: 100%">
<el-tab-pane :label="t('dialog.group_member_moderation.members')">
<TabsUnderline
default-value="members"
:items="groupModerationTabs"
:unmount-on-hide="false"
style="height: 100%">
<template #members>
<div style="margin-top: 10px">
<Button
class="rounded-full"
@@ -124,11 +128,9 @@
:page-sizes="pageSizes"
:total-items="groupMemberModerationTotalItems" />
</div>
</el-tab-pane>
</template>
<el-tab-pane
:label="t('dialog.group_member_moderation.bans')"
:disabled="!hasGroupPermission(groupMemberModeration.groupRef, 'group-bans-manage')">
<template #bans>
<div style="margin-top: 10px">
<Button
class="rounded-full"
@@ -159,11 +161,9 @@
:page-sizes="pageSizes"
:total-items="groupBansModerationTotalItems" />
</div>
</el-tab-pane>
</template>
<el-tab-pane
:label="t('dialog.group_member_moderation.invites')"
:disabled="!hasGroupPermission(groupMemberModeration.groupRef, 'group-invites-manage')">
<template #invites>
<div style="margin-top: 10px">
<Button
class="rounded-full"
@@ -175,16 +175,32 @@
<Refresh v-else />
</Button>
<br />
<el-tabs>
<el-tab-pane>
<template #label>
<span style="font-weight: bold; font-size: 16px">{{
t('dialog.group_member_moderation.sent_invites')
}}</span>
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{
groupInvitesModerationTable.data.length
}}</span>
</template>
<TabsUnderline default-value="sent" :items="groupInvitesTabs" :unmount-on-hide="false">
<template #label-sent>
<span style="font-weight: bold; font-size: 16px">{{
t('dialog.group_member_moderation.sent_invites')
}}</span>
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{
groupInvitesModerationTable.data.length
}}</span>
</template>
<template #label-join>
<span style="font-weight: bold; font-size: 16px">{{
t('dialog.group_member_moderation.join_requests')
}}</span>
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{
groupJoinRequestsModerationTable.data.length
}}</span>
</template>
<template #label-blocked>
<span style="font-weight: bold; font-size: 16px">{{
t('dialog.group_member_moderation.blocked_requests')
}}</span>
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{
groupBlockedModerationTable.data.length
}}</span>
</template>
<template #sent>
<Button size="sm" variant="outline" @click="selectAllGroupInvites">{{
t('dialog.group_member_moderation.select_all')
}}</Button>
@@ -206,17 +222,9 @@
@click="groupMembersDeleteSentInvite"
>{{ t('dialog.group_member_moderation.delete_sent_invite') }}</Button
>
</el-tab-pane>
</template>
<el-tab-pane>
<template #label>
<span style="font-weight: bold; font-size: 16px">{{
t('dialog.group_member_moderation.join_requests')
}}</span>
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{
groupJoinRequestsModerationTable.data.length
}}</span>
</template>
<template #join>
<Button size="sm" variant="outline" @click="selectAllGroupJoinRequests">{{
t('dialog.group_member_moderation.select_all')
}}</Button>
@@ -262,17 +270,9 @@
@click="groupMembersBlockJoinRequest"
>{{ t('dialog.group_member_moderation.block_join_requests') }}</Button
>
</el-tab-pane>
</template>
<el-tab-pane>
<template #label>
<span style="font-weight: bold; font-size: 16px">{{
t('dialog.group_member_moderation.blocked_requests')
}}</span>
<span style="color: #909399; font-size: 12px; margin-left: 5px">{{
groupBlockedModerationTable.data.length
}}</span>
</template>
<template #blocked>
<Button size="sm" variant="outline" @click="selectAllGroupBlocked">{{
t('dialog.group_member_moderation.select_all')
}}</Button>
@@ -294,14 +294,12 @@
@click="groupMembersDeleteBlockedRequest"
>{{ t('dialog.group_member_moderation.delete_blocked_requests') }}</Button
>
</el-tab-pane>
</el-tabs>
</template>
</TabsUnderline>
</div>
</el-tab-pane>
</template>
<el-tab-pane
:label="t('dialog.group_member_moderation.logs')"
:disabled="!hasGroupPermission(groupMemberModeration.groupRef, 'group-audit-view')">
<template #logs>
<div style="margin-top: 10px">
<Button
class="rounded-full"
@@ -352,8 +350,8 @@
:page-sizes="pageSizes"
:total-items="groupLogsModerationTotalItems" />
</div>
</el-tab-pane>
</el-tabs>
</template>
</TabsUnderline>
<br />
<br />
@@ -533,6 +531,7 @@
import { InputGroupField, InputGroupTextareaField } from '@/components/ui/input-group';
import { Button } from '@/components/ui/button';
import { Spinner } from '@/components/ui/spinner';
import { TabsUnderline } from '@/components/ui/tabs';
import { Trash2 } from 'lucide-vue-next';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner';
@@ -566,6 +565,29 @@
const { applyGroupMember, handleGroupMember, handleGroupMemberProps } = useGroupStore();
const { showFullscreenImageDialog } = useGalleryStore();
const { t } = useI18n();
const groupModerationTabs = computed(() => [
{ value: 'members', label: t('dialog.group_member_moderation.members') },
{
value: 'bans',
label: t('dialog.group_member_moderation.bans'),
disabled: !hasGroupPermission(groupMemberModeration.value?.groupRef, 'group-bans-manage')
},
{
value: 'invites',
label: t('dialog.group_member_moderation.invites'),
disabled: !hasGroupPermission(groupMemberModeration.value?.groupRef, 'group-invites-manage')
},
{
value: 'logs',
label: t('dialog.group_member_moderation.logs'),
disabled: !hasGroupPermission(groupMemberModeration.value?.groupRef, 'group-audit-view')
}
]);
const groupInvitesTabs = computed(() => [
{ value: 'sent', label: t('dialog.group_member_moderation.sent_invites') },
{ value: 'join', label: t('dialog.group_member_moderation.join_requests') },
{ value: 'blocked', label: t('dialog.group_member_moderation.blocked_requests') }
]);
const selectedUsers = reactive({});
const selectedUsersArray = ref([]);
const isGroupMembersLoading = ref(false);

View File

@@ -5,8 +5,12 @@
:title="t('dialog.new_instance.header')"
width="650px"
append-to-body>
<el-tabs v-model="newInstanceDialog.selectedTab" @tab-click="newInstanceTabClick">
<el-tab-pane name="Normal" :label="t('dialog.new_instance.normal')">
<TabsUnderline
v-model="newInstanceDialog.selectedTab"
:items="newInstanceTabs"
:unmount-on-hide="false"
@update:modelValue="newInstanceTabClick">
<template #Normal>
<FieldGroup class="gap-4">
<Field>
<FieldLabel>{{ t('dialog.new_instance.access_type') }}</FieldLabel>
@@ -221,8 +225,8 @@
</Field>
</template>
</FieldGroup>
</el-tab-pane>
<el-tab-pane name="Legacy" :label="t('dialog.new_instance.legacy')">
</template>
<template #Legacy>
<FieldGroup class="gap-4">
<Field>
<FieldLabel>{{ t('dialog.new_instance.access_type') }}</FieldLabel>
@@ -429,8 +433,8 @@
</FieldContent>
</Field>
</FieldGroup>
</el-tab-pane>
</el-tabs>
</template>
</TabsUnderline>
<template v-if="newInstanceDialog.selectedTab === 'Normal'" #footer>
<template v-if="newInstanceDialog.instanceCreated">
<Button variant="outline" class="mr-2" @click="copyInstanceUrl(newInstanceDialog.location)">{{
@@ -514,6 +518,7 @@
import { Check as CheckIcon } from 'lucide-vue-next';
import { Checkbox } from '@/components/ui/checkbox';
import { InputGroupField } from '@/components/ui/input-group';
import { TabsUnderline } from '@/components/ui/tabs';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
@@ -551,6 +556,10 @@
required: true
}
});
const newInstanceTabs = computed(() => [
{ value: 'Normal', label: t('dialog.new_instance.normal') },
{ value: 'Legacy', label: t('dialog.new_instance.legacy') }
]);
const { t } = useI18n();
@@ -858,8 +867,8 @@
configRepository.setBool('instanceDialogAgeGate', ageGate);
configRepository.setString('instanceDialogDisplayName', displayName);
}
function newInstanceTabClick(obj) {
if (obj.props.name === 'Normal') {
function newInstanceTabClick(tabName) {
if (tabName === 'Normal') {
buildInstance();
} else {
buildLegacyInstance();

View File

@@ -14,8 +14,12 @@
:toggle-badge-showcased="toggleBadgeShowcased"
:user-dialog-command="userDialogCommand" />
<el-tabs v-model="userDialogLastActiveTab" @tab-click="userDialogTabClick">
<el-tab-pane name="Info" :label="t('dialog.user.info.header')">
<TabsUnderline
v-model="userDialogLastActiveTab"
:items="userDialogTabs"
:unmount-on-hide="false"
@update:modelValue="userDialogTabClick">
<template #Info>
<template v-if="isFriendOnline(userDialog.friend) || currentUser.id === userDialog.id">
<div
v-if="userDialog.ref.location"
@@ -546,13 +550,9 @@
</div>
</div>
</div>
</el-tab-pane>
</template>
<el-tab-pane
name="Mutual Friends"
v-if="userDialog.id !== currentUser.id && !currentUser.hasSharedConnectionsOptOut"
:label="t('dialog.user.mutual_friends.header')"
lazy>
<template v-if="userDialog.id !== currentUser.id && !currentUser.hasSharedConnectionsOptOut" #mutual>
<div style="display: flex; align-items: center; justify-content: space-between">
<div style="display: flex; align-items: center">
<Button
@@ -621,9 +621,9 @@
</div>
</li>
</ul>
</el-tab-pane>
</template>
<el-tab-pane name="Groups" :label="t('dialog.user.groups.header')" lazy>
<template #Groups>
<div style="display: flex; align-items: center; justify-content: space-between">
<div style="display: flex; align-items: center">
<Button
@@ -1012,9 +1012,9 @@
</template>
</template>
</div>
</el-tab-pane>
</template>
<el-tab-pane name="Worlds" :label="t('dialog.user.worlds.header')" lazy>
<template #Worlds>
<div style="display: flex; align-items: center; justify-content: space-between">
<div style="display: flex; align-items: center">
<Button
@@ -1085,9 +1085,9 @@
</div>
</div>
</div>
</el-tab-pane>
</template>
<el-tab-pane name="Favorite Worlds" :label="t('dialog.user.favorite_worlds.header')" lazy>
<template #favorite-worlds>
<!-- <Button
variant="outline"
v-if="userFavoriteWorlds && userFavoriteWorlds.length > 0"
@@ -1099,33 +1099,35 @@
style="position: absolute; right: 15px; bottom: 15px; z-index: 99"
@click="getUserFavoriteWorlds(userDialog.id)">
</Button> -->
<el-tabs
ref="favoriteWorldsRef"
v-loading="userDialog.isFavoriteWorldsLoading"
class="zero-margin-tabs"
type="card"
stretch
style="margin-top: 10px; height: 50vh">
<template v-if="userFavoriteWorlds && userFavoriteWorlds.length > 0">
<el-tab-pane v-for="(list, index) in userFavoriteWorlds" :key="index" lazy>
<template #label>
<span>
<i
class="x-status-icon"
style="margin-right: 6px"
:class="userFavoriteWorldsStatus(list[1])">
</i>
<span style="font-weight: bold; font-size: 14px" v-text="list[0]"></span>
<span
style="
color: var(--el-text-color-secondary);
font-size: 10px;
margin-left: 5px;
"
>{{ list[2].length }}/{{ favoriteLimits.maxFavoritesPerGroup.world }}</span
>
</span>
</template>
<template v-if="userFavoriteWorlds && userFavoriteWorlds.length > 0">
<TabsUnderline
v-model="favoriteWorldsTab"
:items="favoriteWorldTabs"
:unmount-on-hide="false"
v-loading="userDialog.isFavoriteWorldsLoading"
class="zero-margin-tabs"
style="margin-top: 10px; height: 50vh">
<template
v-for="(list, index) in userFavoriteWorlds"
:key="`favorite-worlds-label-${index}`"
v-slot:[`label-${index}`]>
<span>
<i
class="x-status-icon"
style="margin-right: 6px"
:class="userFavoriteWorldsStatus(list[1])">
</i>
<span style="font-weight: bold; font-size: 14px" v-text="list[0]"></span>
<span
style="color: var(--el-text-color-secondary); font-size: 10px; margin-left: 5px"
>{{ list[2].length }}/{{ favoriteLimits.maxFavoritesPerGroup.world }}</span
>
</span>
</template>
<template
v-for="(list, index) in userFavoriteWorlds"
:key="`favorite-worlds-content-${index}`"
v-slot:[String(index)]>
<div
class="x-friend-list"
style="margin-top: 10px; margin-bottom: 15px; min-height: 60px; max-height: none">
@@ -1143,17 +1145,17 @@
</div>
</div>
</div>
</el-tab-pane>
</template>
<template v-else-if="!userDialog.isFavoriteWorldsLoading">
<div style="display: flex; justify-content: center; align-items: center; height: 100%">
<span style="font-size: 16px">No favorite worlds found.</span>
</div>
</template>
</el-tabs>
</el-tab-pane>
</template>
</TabsUnderline>
</template>
<template v-else-if="!userDialog.isFavoriteWorldsLoading">
<div style="display: flex; justify-content: center; align-items: center; height: 100%">
<span style="font-size: 16px">No favorite worlds found.</span>
</div>
</template>
</template>
<el-tab-pane name="Avatars" :label="t('dialog.user.avatars.header')" lazy>
<template #Avatars>
<div style="display: flex; align-items: center; justify-content: space-between">
<div style="display: flex; align-items: center">
<Button
@@ -1250,9 +1252,9 @@
</div>
</div>
</div>
</el-tab-pane>
</template>
<el-tab-pane name="JSON" :label="t('dialog.user.json.header')" lazy style="height: 50vh">
<template #JSON>
<Button
class="rounded-full h-6 w-6 mr-2"
size="icon-sm"
@@ -1272,8 +1274,8 @@
:deep="2"
:theme="isDarkMode ? 'dark' : 'light'"
show-icon />
</el-tab-pane>
</el-tabs>
</template>
</TabsUnderline>
</div>
<SendInviteDialog
v-model:sendInviteDialogVisible="sendInviteDialogVisible"
@@ -1319,6 +1321,7 @@
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Spinner } from '@/components/ui/spinner';
import { TabsUnderline } from '@/components/ui/tabs';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
@@ -1392,6 +1395,26 @@
const EditNoteAndMemoDialog = defineAsyncComponent(() => import('./EditNoteAndMemoDialog.vue'));
const { t } = useI18n();
const userDialogTabs = computed(() => {
const tabs = [
{ value: 'Info', label: t('dialog.user.info.header') },
{ value: 'Groups', label: t('dialog.user.groups.header') },
{ value: 'Worlds', label: t('dialog.user.worlds.header') },
{ value: 'favorite-worlds', label: t('dialog.user.favorite_worlds.header') },
{ value: 'Avatars', label: t('dialog.user.avatars.header') },
{ value: 'JSON', label: t('dialog.user.json.header') }
];
if (userDialog.value.id !== currentUser.value.id && !currentUser.value.hasSharedConnectionsOptOut) {
tabs.splice(1, 0, { value: 'mutual', label: t('dialog.user.mutual_friends.header') });
}
return tabs;
});
const favoriteWorldTabs = computed(() =>
(userFavoriteWorlds.value || []).map((list, index) => ({
value: String(index),
label: list?.[0] ?? ''
}))
);
const modalStore = useModalStore();
@@ -1476,7 +1499,7 @@
remainingGroups: []
});
const favoriteWorldsRef = ref(null);
const favoriteWorldsTab = ref('0');
const sendInviteDialogVisible = ref(false);
const sendInviteDialog = ref({
@@ -1588,7 +1611,7 @@
if (vrchatCredit.value === null) {
getVRChatCredits();
}
} else if (tabName === 'Mutual Friends') {
} else if (tabName === 'mutual') {
if (userId === currentUser.value.id) {
userDialogLastActiveTab.value = 'Info';
return;
@@ -1618,7 +1641,7 @@
userDialogLastWorld.value = userId;
refreshUserDialogWorlds();
}
} else if (tabName === 'Favorite Worlds') {
} else if (tabName === 'favorite-worlds') {
if (userDialogLastFavoriteWorld.value !== userId) {
userDialogLastFavoriteWorld.value = userId;
getUserFavoriteWorlds(userId);
@@ -1632,12 +1655,11 @@
handleUserDialogTab(userDialogLastActiveTab.value);
}
function userDialogTabClick(obj) {
if (obj.props.name === userDialogLastActiveTab.value) {
function userDialogTabClick(tabName) {
if (tabName === userDialogLastActiveTab.value) {
return;
}
handleUserDialogTab(obj.props.name);
userDialogLastActiveTab.value = obj.props.name;
handleUserDialogTab(tabName);
}
function showPronounsDialog() {
@@ -2318,9 +2340,7 @@
async function getUserFavoriteWorlds(userId) {
userDialog.value.isFavoriteWorldsLoading = true;
if (favoriteWorldsRef.value) {
favoriteWorldsRef.value.currentName = '0'; // select first tab
}
favoriteWorldsTab.value = '0';
userFavoriteWorlds.value = [];
const worldLists = [];
let params = {

View File

@@ -314,8 +314,12 @@
</div>
</div>
</div>
<el-tabs v-model="worldDialogLastActiveTab" @tab-click="worldDialogTabClick">
<el-tab-pane name="Instances" :label="t('dialog.world.instances.header')">
<TabsUnderline
v-model="worldDialogLastActiveTab"
:items="worldDialogTabs"
:unmount-on-hide="false"
@update:modelValue="worldDialogTabClick">
<template #Instances>
<div class="">
<el-icon><User /></el-icon>
{{ t('dialog.world.instances.public_count', { count: worldDialog.ref.publicOccupants }) }}
@@ -429,8 +433,8 @@
</div>
</template>
</div>
</el-tab-pane>
<el-tab-pane name="Info" :label="t('dialog.world.info.header')" lazy>
</template>
<template #Info>
<div class="x-friend-list" style="max-height: none">
<div class="x-friend-item" style="width: 100%; cursor: default">
<div class="detail">
@@ -695,8 +699,8 @@
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane name="JSON" :label="t('dialog.world.json.header')" style="max-height: 50vh" lazy>
</template>
<template #JSON>
<Button
class="rounded-full h-6 w-6 mr-2"
size="icon-sm"
@@ -719,8 +723,8 @@
:deep="2"
:theme="isDarkMode ? 'dark' : 'light'"
show-icon />
</el-tab-pane>
</el-tabs>
</template>
</TabsUnderline>
</div>
<template v-if="isDialogVisible">
@@ -768,6 +772,7 @@
import { Button } from '@/components/ui/button';
import { ElMessageBox } from 'element-plus';
import { InputGroupTextareaField } from '@/components/ui/input-group';
import { TabsUnderline } from '@/components/ui/tabs';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
@@ -834,6 +839,11 @@
const { isGameRunning } = storeToRefs(useGameStore());
const { showFullscreenImageDialog } = useGalleryStore();
const { t } = useI18n();
const worldDialogTabs = computed(() => [
{ value: 'Instances', label: t('dialog.world.instances.header') },
{ value: 'Info', label: t('dialog.world.info.header') },
{ value: 'JSON', label: t('dialog.world.json.header') }
]);
const treeData = ref({});
const worldAllowedDomainsDialog = ref({
@@ -954,12 +964,11 @@
handleWorldDialogTab(worldDialogLastActiveTab.value);
}
function worldDialogTabClick(obj) {
if (obj.props.name === worldDialogLastActiveTab.value) {
function worldDialogTabClick(tabName) {
if (tabName === worldDialogLastActiveTab.value) {
return;
}
handleWorldDialogTab(obj.props.name);
worldDialogLastActiveTab.value = obj.props.name;
handleWorldDialogTab(tabName);
}
function handleDialogOpen() {