mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-18 22:33:50 +02:00
replace some el-button
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<template #content>
|
||||
<span>{{ t('dialog.user.info.last_join') }} <Timer :epoch="lastJoin" /></span>
|
||||
</template>
|
||||
<i class="ri-history-line"></i>
|
||||
<i class="ri-map-pin-time-line text-muted-foreground"></i>
|
||||
</TooltipWrapper>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
@@ -12,13 +12,12 @@
|
||||
style="padding: 7px"></el-progress>
|
||||
</div>
|
||||
<div v-else-if="pendingVRCXUpdate || pendingVRCXInstall" class="pending-update">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
<Button
|
||||
variant="outline"
|
||||
style="font-size: 19px; height: 36px; width: 44px; margin: 10px"
|
||||
@click="showVRCXUpdateDialog">
|
||||
<i class="ri-download-line"></i>
|
||||
</el-button>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<el-menu ref="navMenuRef" class="nav-menu" :collapse="isCollapsed" :collapse-transition="false">
|
||||
@@ -249,6 +248,7 @@
|
||||
<script setup>
|
||||
import { computed, defineAsyncComponent, onMounted, ref, watch } from 'vue';
|
||||
import { ElMessageBox, dayjs } from 'element-plus';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
@@ -179,57 +179,57 @@
|
||||
v-text="avatarDialog.ref.description"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex: none; margin-left: 10px">
|
||||
<div class="flex items-center">
|
||||
<TooltipWrapper
|
||||
v-if="avatarDialog.inCache"
|
||||
side="top"
|
||||
:content="t('dialog.avatar.actions.delete_cache_tooltip')">
|
||||
<el-button
|
||||
:icon="Delete"
|
||||
size="large"
|
||||
circle
|
||||
<Button
|
||||
class="rounded-full mr-2"
|
||||
size="icon-lg"
|
||||
variant="outline"
|
||||
:disabled="isGameRunning && avatarDialog.cacheLocked"
|
||||
@click="deleteVRChatCache(avatarDialog.ref)"></el-button>
|
||||
@click="deleteVRChatCache(avatarDialog.ref)"
|
||||
><Trash2
|
||||
/></Button>
|
||||
</TooltipWrapper>
|
||||
|
||||
<TooltipWrapper
|
||||
v-if="avatarDialog.isFavorite"
|
||||
side="top"
|
||||
:content="t('dialog.avatar.actions.favorite_tooltip')">
|
||||
<el-button
|
||||
type="warning"
|
||||
:icon="StarFilled"
|
||||
size="large"
|
||||
circle
|
||||
style="margin-left: 5px"
|
||||
@click="avatarDialogCommand('Add Favorite')"></el-button>
|
||||
<Button class="rounded-full" size="icon-lg" @click="avatarDialogCommand('Add Favorite')"
|
||||
><Star
|
||||
/></Button>
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper v-else side="top" :content="t('dialog.avatar.actions.favorite_tooltip')">
|
||||
<el-button
|
||||
type="default"
|
||||
:icon="Star"
|
||||
size="large"
|
||||
circle
|
||||
style="margin-left: 5px"
|
||||
@click="avatarDialogCommand('Add Favorite')"></el-button>
|
||||
<Button
|
||||
class="rounded-full"
|
||||
size="icon-lg"
|
||||
variant="outline"
|
||||
@click="avatarDialogCommand('Add Favorite')"
|
||||
><Star
|
||||
/></Button>
|
||||
</TooltipWrapper>
|
||||
|
||||
<TooltipWrapper side="top" :content="t('dialog.avatar.actions.select')">
|
||||
<el-button
|
||||
type="default"
|
||||
:icon="Check"
|
||||
size="large"
|
||||
circle
|
||||
<Button
|
||||
class="rounded-full ml-2"
|
||||
size="icon-lg"
|
||||
variant="outline"
|
||||
:disabled="currentUser.currentAvatar === avatarDialog.id"
|
||||
style="margin-left: 5px"
|
||||
@click="selectAvatarWithoutConfirmation(avatarDialog.id)"></el-button>
|
||||
@click="selectAvatarWithoutConfirmation(avatarDialog.id)">
|
||||
<CircleCheck
|
||||
/></Button>
|
||||
</TooltipWrapper>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<el-button
|
||||
:type="avatarDialog.isBlocked ? 'danger' : 'default'"
|
||||
:icon="MoreFilled"
|
||||
size="large"
|
||||
style="margin-left: 5px"
|
||||
circle></el-button>
|
||||
<Button
|
||||
class="rounded-full ml-2"
|
||||
:variant="avatarDialog.isBlocked ? 'destructive' : 'outline'"
|
||||
size="icon-lg">
|
||||
<Ellipsis />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem @click="avatarDialogCommand('Refresh')">
|
||||
@@ -442,12 +442,13 @@
|
||||
}}<TooltipWrapper side="top" :content="t('dialog.avatar.info.id_tooltip')">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<el-button
|
||||
type="default"
|
||||
:icon="CopyDocument"
|
||||
size="small"
|
||||
circle
|
||||
@click.stop></el-button>
|
||||
<Button
|
||||
class="rounded-full text-xs"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
@click.stop
|
||||
><i class="ri-file-copy-line"></i
|
||||
></Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem @click="copyAvatarId(avatarDialog.id)">
|
||||
@@ -511,19 +512,20 @@
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="JSON" :label="t('dialog.avatar.json.header')" style="max-height: 50vh" lazy>
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="Refresh"
|
||||
circle
|
||||
@click="refreshAvatarDialogTreeData"></el-button>
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="Download"
|
||||
circle
|
||||
style="margin-left: 5px"
|
||||
@click="downloadAndSaveJson(avatarDialog.id, avatarDialog.ref)"></el-button>
|
||||
<Button
|
||||
class="rounded-full h-6 w-6 mr-2"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
@click="refreshAvatarDialogTreeData()">
|
||||
<RefreshCcw />
|
||||
</Button>
|
||||
<Button
|
||||
class="rounded-full h-6 w-6"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
@click="downloadAndSaveJson(avatarDialog.id, avatarDialog.ref)">
|
||||
<Download />
|
||||
</Button>
|
||||
<vue-json-pretty :data="treeData" :deep="2" :theme="isDarkMode ? 'dark' : 'light'" show-icon />
|
||||
<br />
|
||||
<vue-json-pretty
|
||||
@@ -547,26 +549,20 @@
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
Back,
|
||||
Check,
|
||||
CircleCheck,
|
||||
CircleClose,
|
||||
CopyDocument,
|
||||
Delete,
|
||||
Download,
|
||||
Edit,
|
||||
MoreFilled,
|
||||
Picture,
|
||||
Refresh,
|
||||
Right,
|
||||
Share,
|
||||
Star,
|
||||
StarFilled,
|
||||
Upload,
|
||||
User,
|
||||
Warning
|
||||
} from '@element-plus/icons-vue';
|
||||
import { CircleCheck, Ellipsis, RefreshCcw, Star, Trash2 } from 'lucide-vue-next';
|
||||
import { computed, defineAsyncComponent, nextTick, ref, watch } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toast } from 'vue-sonner';
|
||||
|
||||
@@ -35,14 +35,14 @@
|
||||
<br />
|
||||
<template
|
||||
v-if="setAvatarTagsDialog.ownAvatars.length === props.setAvatarTagsDialog.selectedAvatarIds.length">
|
||||
<el-button size="small" @click="setAvatarTagsSelectToggle">{{
|
||||
<Button size="sm" variant="outline" @click="setAvatarTagsSelectToggle">{{
|
||||
t('dialog.set_avatar_tags.select_none')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button size="small" @click="setAvatarTagsSelectToggle">{{
|
||||
<Button size="sm" variant="outline" @click="setAvatarTagsSelectToggle">{{
|
||||
t('dialog.set_avatar_tags.select_all')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</template>
|
||||
<span style="margin-left: 5px"
|
||||
>{{ props.setAvatarTagsDialog.selectedAvatarIds.length }} /
|
||||
@@ -76,24 +76,25 @@
|
||||
<span v-else class="extra" v-text="avatar.releaseStatus"></span>
|
||||
<span class="extra" v-text="avatarTagStrings.get(avatar.id)"></span>
|
||||
</div>
|
||||
<el-button text size="small" style="margin-left: 5px" @click.stop>
|
||||
<Button size="sm" variant="ghost" style="margin-left: 5px" @click.stop>
|
||||
<el-checkbox
|
||||
:model-value="props.setAvatarTagsDialog.selectedAvatarIds.includes(avatar.id)"
|
||||
@click="toggleAvatarSelection(avatar.id)"></el-checkbox>
|
||||
</el-button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="closeSetAvatarTagsDialog">{{ t('dialog.set_avatar_tags.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="saveSetAvatarTagsDialog">{{
|
||||
t('dialog.set_avatar_tags.save')
|
||||
}}</el-button>
|
||||
<Button variant="secondary" @click="closeSetAvatarTagsDialog">{{
|
||||
t('dialog.set_avatar_tags.cancel')
|
||||
}}</Button>
|
||||
<Button @click="saveSetAvatarTagsDialog">{{ t('dialog.set_avatar_tags.save') }}</Button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Loading } from '@element-plus/icons-vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
@@ -357,12 +357,13 @@
|
||||
<Location :location="room.tag" style="display: inline-block" />
|
||||
<InviteYourself :location="room.tag" style="margin-left: 5px" />
|
||||
<TooltipWrapper side="top" content="Refresh player count">
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Refresh"
|
||||
style="margin-left: 5px"
|
||||
circle
|
||||
@click="refreshInstancePlayerCount(room.tag)" />
|
||||
<Button
|
||||
class="rounded-full w-6 h-6 text-xs text-muted-foreground hover:text-foreground"
|
||||
size="icon"
|
||||
variant="outline"
|
||||
@click="refreshInstancePlayerCount(room.tag)"
|
||||
><i class="ri-refresh-line"></i
|
||||
></Button>
|
||||
</TooltipWrapper>
|
||||
<LastJoin :location="room.tag" :currentlocation="lastLocation.location" />
|
||||
<InstanceInfo
|
||||
@@ -485,22 +486,20 @@
|
||||
</TooltipWrapper>
|
||||
<template v-if="hasGroupPermission(groupDialog.ref, 'group-announcement-manage')">
|
||||
<TooltipWrapper side="top" :content="t('dialog.group.posts.edit_tooltip')">
|
||||
<el-button
|
||||
text
|
||||
:icon="Edit"
|
||||
size="small"
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
style="margin-left: 5px; padding: 0"
|
||||
@click="
|
||||
showGroupPostEditDialog(groupDialog.id, groupDialog.announcement)
|
||||
" />
|
||||
"></Button>
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper side="top" :content="t('dialog.group.posts.delete_tooltip')">
|
||||
<el-button
|
||||
text
|
||||
:icon="Delete"
|
||||
size="small"
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
style="margin-left: 5px; padding: 0"
|
||||
@click="confirmDeleteGroupPost(groupDialog.announcement)" />
|
||||
@click="confirmDeleteGroupPost(groupDialog.announcement)"></Button>
|
||||
</TooltipWrapper>
|
||||
</template>
|
||||
</div>
|
||||
@@ -621,13 +620,12 @@
|
||||
<span class="extra"
|
||||
>{{ groupDialog.ref.$url }}
|
||||
<TooltipWrapper side="top" :content="t('dialog.group.info.url_tooltip')">
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="CopyDocument"
|
||||
circle
|
||||
<Button
|
||||
class="rounded-full"
|
||||
size="icon"
|
||||
variant="outline"
|
||||
style="margin-left: 5px"
|
||||
@click="copyToClipboard(groupDialog.ref.$url)" /> </TooltipWrapper
|
||||
@click="copyToClipboard(groupDialog.ref.$url)"></Button> </TooltipWrapper
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -637,13 +635,12 @@
|
||||
<span class="extra"
|
||||
>{{ groupDialog.id }}
|
||||
<TooltipWrapper side="top" :content="t('dialog.group.info.id_tooltip')">
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="CopyDocument"
|
||||
circle
|
||||
<Button
|
||||
class="rounded-full"
|
||||
size="icon"
|
||||
variant="outline"
|
||||
style="margin-left: 5px"
|
||||
@click="copyToClipboard(groupDialog.id)" /> </TooltipWrapper
|
||||
@click="copyToClipboard(groupDialog.id)"></Button> </TooltipWrapper
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -797,22 +794,24 @@
|
||||
<template
|
||||
v-if="hasGroupPermission(groupDialog.ref, 'group-announcement-manage')">
|
||||
<TooltipWrapper side="top" :content="t('dialog.group.posts.edit_tooltip')">
|
||||
<el-button
|
||||
text
|
||||
:icon="Edit"
|
||||
size="small"
|
||||
style="margin-left: 5px"
|
||||
@click="showGroupPostEditDialog(groupDialog.id, post)" />
|
||||
<Button
|
||||
size="icon-sm"
|
||||
class="h-6 w-6 text-xs text-muted-foreground hover:text-foreground"
|
||||
variant="ghost"
|
||||
@click="showGroupPostEditDialog(groupDialog.id, post)"
|
||||
><i class="ri-pencil-line"></i
|
||||
></Button>
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper
|
||||
side="top"
|
||||
:content="t('dialog.group.posts.delete_tooltip')">
|
||||
<el-button
|
||||
text
|
||||
:icon="Delete"
|
||||
size="small"
|
||||
style="margin-left: 5px"
|
||||
@click="confirmDeleteGroupPost(post)" />
|
||||
<Button
|
||||
size="icon-sm"
|
||||
class="h-6 w-6 text-xs text-muted-foreground hover:text-foreground"
|
||||
variant="ghost"
|
||||
@click="confirmDeleteGroupPost(post)"
|
||||
><i class="ri-delete-bin-line"></i
|
||||
></Button>
|
||||
</TooltipWrapper>
|
||||
</template>
|
||||
</div>
|
||||
@@ -832,20 +831,23 @@
|
||||
t('dialog.group.members.friends_only')
|
||||
}}</span>
|
||||
<div style="margin-top: 10px">
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="Refresh"
|
||||
<Button
|
||||
class="rounded-full h-6 w-6"
|
||||
variant="outline"
|
||||
size="icon-sm"
|
||||
:loading="isGroupMembersLoading"
|
||||
circle
|
||||
@click="loadAllGroupMembers" />
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="Download"
|
||||
circle
|
||||
@click="loadAllGroupMembers">
|
||||
<Spinner v-if="isGroupMembersLoading" /><RefreshCcw v-else
|
||||
/></Button>
|
||||
<Button
|
||||
class="rounded-full h-6 w-6 ml-2"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
style="margin-left: 5px"
|
||||
@click="downloadAndSaveJson(`${groupDialog.id}_members`, groupDialog.members)" />
|
||||
@click="downloadAndSaveJson(`${groupDialog.id}_members`, groupDialog.members)">
|
||||
<Download class="h-4 w-4" />
|
||||
</Button>
|
||||
<span
|
||||
v-if="groupDialog.memberSearch.length"
|
||||
style="font-size: 14px; margin-left: 5px; margin-right: 5px"
|
||||
@@ -856,62 +858,41 @@
|
||||
>
|
||||
<div
|
||||
v-if="hasGroupPermission(groupDialog.ref, 'group-members-manage')"
|
||||
style="float: right">
|
||||
style="float: right"
|
||||
class="flex items-center">
|
||||
<span style="margin-right: 5px">{{ t('dialog.group.members.sort_by') }}</span>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
as-child
|
||||
:disabled="isGroupMembersLoading || groupDialog.memberSearch.length > 0">
|
||||
<el-button
|
||||
size="small"
|
||||
:disabled="isGroupMembersLoading || groupDialog.memberSearch.length > 0"
|
||||
@click.stop>
|
||||
<span>
|
||||
{{ t(groupDialog.memberSortOrder.name) }}
|
||||
<el-icon style="margin-left: 5px"><ArrowDown /></el-icon>
|
||||
</span>
|
||||
</el-button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem
|
||||
<Select
|
||||
v-model="groupDialogMemberSortValue"
|
||||
:disabled="isGroupMembersLoading || groupDialog.memberSearch.length > 0">
|
||||
<SelectTrigger class="h-8 w-45 mr-1">
|
||||
<SelectValue :placeholder="t('dialog.group.members.sort_by')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem
|
||||
v-for="item in groupDialogSortingOptions"
|
||||
:key="item.name"
|
||||
@click="setGroupMemberSortOrder(item)">
|
||||
:key="item.value"
|
||||
:value="item.value">
|
||||
{{ t(item.name) }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<span style="margin-right: 5px">{{ t('dialog.group.members.filter') }}</span>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
as-child
|
||||
:disabled="isGroupMembersLoading || groupDialog.memberSearch.length > 0">
|
||||
<el-button
|
||||
size="small"
|
||||
:disabled="isGroupMembersLoading || groupDialog.memberSearch.length > 0"
|
||||
@click.stop>
|
||||
<span>
|
||||
{{ t(groupDialog.memberFilter.name) }}
|
||||
<el-icon style="margin-left: 5px"><ArrowDown /></el-icon>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span class="ml-2 mr-1">{{ t('dialog.group.members.filter') }}</span>
|
||||
<div style="display: inline-block; width: 220px">
|
||||
<VirtualCombobox
|
||||
v-model="groupDialogMemberFilterKey"
|
||||
:groups="groupDialogMemberFilterGroups"
|
||||
:disabled="isGroupMembersLoading || groupDialog.memberSearch.length > 0"
|
||||
:placeholder="t('dialog.group.members.filter')"
|
||||
:search-placeholder="t('dialog.group.members.search')"
|
||||
:clearable="false"
|
||||
:close-on-select="true">
|
||||
<template #trigger="{ text }">
|
||||
<span class="truncate">
|
||||
{{ text || t('dialog.group.members.filter') }}
|
||||
</span>
|
||||
</el-button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem
|
||||
v-for="item in groupDialogFilterOptions"
|
||||
:key="item.name"
|
||||
@click="setGroupMemberFilter(item)">
|
||||
{{ t(item.name) }}
|
||||
</DropdownMenuItem>
|
||||
<template v-for="role in groupDialog.ref.roles" :key="role.name">
|
||||
<DropdownMenuItem
|
||||
v-if="!role.defaultRole"
|
||||
@click="setGroupMemberFilter(role)">
|
||||
{{ role.name }}
|
||||
</DropdownMenuItem>
|
||||
</template>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</VirtualCombobox>
|
||||
</div>
|
||||
</div>
|
||||
<el-input
|
||||
v-model="groupDialog.memberSearch"
|
||||
@@ -1107,19 +1088,20 @@
|
||||
</el-tabs>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="JSON" :label="t('dialog.group.json.header')" lazy>
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="Refresh"
|
||||
circle
|
||||
@click="refreshGroupDialogTreeData()" />
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="Download"
|
||||
circle
|
||||
style="margin-left: 5px"
|
||||
@click="downloadAndSaveJson(groupDialog.id, groupDialog.ref)" />
|
||||
<Button
|
||||
class="rounded-full h-6 w-6 mr-2"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
@click="refreshGroupDialogTreeData()">
|
||||
<RefreshCcw />
|
||||
</Button>
|
||||
<Button
|
||||
class="rounded-full h-6 w-6"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
@click="downloadAndSaveJson(groupDialog.id, groupDialog.ref)">
|
||||
<Download />
|
||||
</Button>
|
||||
<vue-json-pretty
|
||||
:data="groupDialog.treeData"
|
||||
:deep="2"
|
||||
@@ -1137,7 +1119,6 @@
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ArrowDown,
|
||||
Bell,
|
||||
ChatLineSquare,
|
||||
Check,
|
||||
@@ -1145,7 +1126,6 @@
|
||||
CircleClose,
|
||||
Close,
|
||||
CollectionTag,
|
||||
CopyDocument,
|
||||
Delete,
|
||||
Download,
|
||||
Edit,
|
||||
@@ -1162,8 +1142,13 @@
|
||||
View,
|
||||
Warning
|
||||
} from '@element-plus/icons-vue';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { computed, nextTick, reactive, ref, watch } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import { RefreshCcw } from 'lucide-vue-next';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { VirtualCombobox } from '@/components/ui/virtual-combobox';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
@@ -1240,6 +1225,78 @@
|
||||
const groupDialogGalleryCurrentName = ref('0');
|
||||
const groupDialogTabCurrentName = ref('0');
|
||||
const isGroupGalleryLoading = ref(false);
|
||||
|
||||
const groupDialogMemberSortValue = computed({
|
||||
get() {
|
||||
return groupDialog.value?.memberSortOrder?.value ?? '';
|
||||
},
|
||||
set(value) {
|
||||
const option = Object.values(groupDialogSortingOptions).find((item) => item.value === value);
|
||||
if (option) {
|
||||
setGroupMemberSortOrder(option);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const groupDialogMemberFilterKey = computed({
|
||||
get() {
|
||||
const filter = groupDialog.value?.memberFilter;
|
||||
if (!filter) return null;
|
||||
|
||||
if (filter.id === null) return 'everyone';
|
||||
if (filter.id === '') return 'usersWithNoRole';
|
||||
return `role:${filter.id}`;
|
||||
},
|
||||
set(key) {
|
||||
if (!key) return;
|
||||
|
||||
if (key === 'everyone') {
|
||||
setGroupMemberFilter(groupDialogFilterOptions.everyone);
|
||||
return;
|
||||
}
|
||||
if (key === 'usersWithNoRole') {
|
||||
setGroupMemberFilter(groupDialogFilterOptions.usersWithNoRole);
|
||||
return;
|
||||
}
|
||||
|
||||
if (key.startsWith('role:')) {
|
||||
const roleId = key.slice('role:'.length);
|
||||
const role = groupDialog.value?.ref?.roles?.find((r) => r.id === roleId);
|
||||
if (role) {
|
||||
setGroupMemberFilter(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const groupDialogMemberFilterGroups = computed(() => {
|
||||
const filterItems = Object.values(groupDialogFilterOptions).map((item) => ({
|
||||
value: item.id === null ? 'everyone' : item.id === '' ? 'usersWithNoRole' : `role:${item.id}`,
|
||||
label: t(item.name),
|
||||
search: t(item.name)
|
||||
}));
|
||||
|
||||
const roleItems = (groupDialog.value?.ref?.roles ?? [])
|
||||
.filter((role) => !role.defaultRole)
|
||||
.map((role) => ({
|
||||
value: `role:${role.id}`,
|
||||
label: role.name,
|
||||
search: role.name
|
||||
}));
|
||||
|
||||
return [
|
||||
{
|
||||
key: 'filters',
|
||||
label: t('dialog.group.members.filter'),
|
||||
items: filterItems
|
||||
},
|
||||
{
|
||||
key: 'roles',
|
||||
label: 'Roles',
|
||||
items: roleItems
|
||||
}
|
||||
].filter((group) => group.items.length);
|
||||
});
|
||||
const selectedGalleryFile = ref({
|
||||
selectedFileId: '',
|
||||
selectedImageUrl: ''
|
||||
|
||||
@@ -75,29 +75,33 @@
|
||||
style="flex: none; width: 60px; height: 60px; border-radius: 4px; object-fit: cover"
|
||||
@click="showFullscreenImageDialog(gallerySelectDialog.selectedImageUrl)"
|
||||
loading="lazy" />
|
||||
<el-button size="small" style="vertical-align: top" @click="clearImageGallerySelect">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
style="vertical-align: top"
|
||||
@click="clearImageGallerySelect">
|
||||
{{ t('dialog.invite_message.clear_selected_image') }}
|
||||
</el-button>
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button size="small" style="margin-right: 5px" @click="showGallerySelectDialog">
|
||||
<Button size="sm" variant="outline" @click="showGallerySelectDialog">
|
||||
{{ t('dialog.invite_message.select_image') }}
|
||||
</el-button>
|
||||
</Button>
|
||||
</template>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="groupPostEditDialog.visible = false">
|
||||
<Button variant="secondary" @click="groupPostEditDialog.visible = false">
|
||||
{{ t('dialog.group_post_edit.cancel') }}
|
||||
</el-button>
|
||||
<el-button v-if="groupPostEditDialog.postId" @click="editGroupPost">
|
||||
</Button>
|
||||
<Button v-if="groupPostEditDialog.postId" @click="editGroupPost">
|
||||
{{ t('dialog.group_post_edit.edit_post') }}
|
||||
</el-button>
|
||||
<el-button v-else @click="createGroupPost">
|
||||
</Button>
|
||||
<Button v-else @click="createGroupPost">
|
||||
{{ t('dialog.group_post_edit.create_post') }}
|
||||
</el-button>
|
||||
</Button>
|
||||
</template>
|
||||
<GallerySelectDialog
|
||||
:gallery-select-dialog="gallerySelectDialog"
|
||||
@@ -108,6 +112,7 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button type="default" @click="cancelInviteConfirm">
|
||||
<Button variant="secondary" @click="cancelInviteConfirm">
|
||||
{{ t('dialog.invite_message.cancel') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="sendInviteConfirm">
|
||||
</Button>
|
||||
<Button @click="sendInviteConfirm">
|
||||
{{ t('dialog.invite_message.confirm') }}
|
||||
</el-button>
|
||||
</Button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -366,73 +366,74 @@
|
||||
</el-tabs>
|
||||
<template v-if="newInstanceDialog.selectedTab === 'Normal'" #footer>
|
||||
<template v-if="newInstanceDialog.instanceCreated">
|
||||
<el-button @click="copyInstanceUrl(newInstanceDialog.location)">{{
|
||||
<Button variant="outline" class="mr-2" @click="copyInstanceUrl(newInstanceDialog.location)">{{
|
||||
t('dialog.new_instance.copy_url')
|
||||
}}</el-button>
|
||||
<el-button @click="selfInvite(newInstanceDialog.location)">{{
|
||||
}}</Button>
|
||||
<Button variant="outline" class="mr-2" @click="selfInvite(newInstanceDialog.location)">{{
|
||||
t('dialog.new_instance.self_invite')
|
||||
}}</el-button>
|
||||
<el-button
|
||||
}}</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
class="mr-2"
|
||||
:disabled="
|
||||
(newInstanceDialog.accessType === 'friends' || newInstanceDialog.accessType === 'invite') &&
|
||||
newInstanceDialog.userId !== currentUser.id
|
||||
"
|
||||
@click="showInviteDialog(newInstanceDialog.location)"
|
||||
>{{ t('dialog.new_instance.invite') }}</el-button
|
||||
>{{ t('dialog.new_instance.invite') }}</Button
|
||||
>
|
||||
<template v-if="canOpenInstanceInGame">
|
||||
<el-button @click="showLaunchDialog(newInstanceDialog.location, newInstanceDialog.shortName)">{{
|
||||
t('dialog.new_instance.launch')
|
||||
}}</el-button>
|
||||
<el-button @click="handleAttachGame(newInstanceDialog.location, newInstanceDialog.shortName)">
|
||||
<Button
|
||||
variant="secondary"
|
||||
class="mr-2"
|
||||
@click="showLaunchDialog(newInstanceDialog.location, newInstanceDialog.shortName)"
|
||||
>{{ t('dialog.new_instance.launch') }}</Button
|
||||
>
|
||||
<Button @click="handleAttachGame(newInstanceDialog.location, newInstanceDialog.shortName)">
|
||||
{{ t('dialog.new_instance.open_ingame') }}
|
||||
</el-button>
|
||||
</Button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="showLaunchDialog(newInstanceDialog.location, newInstanceDialog.shortName)"
|
||||
>{{ t('dialog.new_instance.launch') }}</el-button
|
||||
>
|
||||
<Button @click="showLaunchDialog(newInstanceDialog.location, newInstanceDialog.shortName)">{{
|
||||
t('dialog.new_instance.launch')
|
||||
}}</Button>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button type="primary" @click="handleCreateNewInstance">{{
|
||||
t('dialog.new_instance.create_instance')
|
||||
}}</el-button>
|
||||
<Button @click="handleCreateNewInstance">{{ t('dialog.new_instance.create_instance') }}</Button>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else-if="newInstanceDialog.selectedTab === 'Legacy'" #footer>
|
||||
<el-button @click="copyInstanceUrl(newInstanceDialog.location)">{{
|
||||
<Button variant="outline" class="mr-2" @click="copyInstanceUrl(newInstanceDialog.location)">{{
|
||||
t('dialog.new_instance.copy_url')
|
||||
}}</el-button>
|
||||
<el-button @click="selfInvite(newInstanceDialog.location)">{{
|
||||
}}</Button>
|
||||
<Button variant="outline" class="mr-2" @click="selfInvite(newInstanceDialog.location)">{{
|
||||
t('dialog.new_instance.self_invite')
|
||||
}}</el-button>
|
||||
<el-button
|
||||
}}</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
:disabled="
|
||||
(newInstanceDialog.accessType === 'friends' || newInstanceDialog.accessType === 'invite') &&
|
||||
newInstanceDialog.userId !== currentUser.id
|
||||
"
|
||||
@click="showInviteDialog(newInstanceDialog.location)"
|
||||
>{{ t('dialog.new_instance.invite') }}</el-button
|
||||
>{{ t('dialog.new_instance.invite') }}</Button
|
||||
>
|
||||
<template v-if="canOpenInstanceInGame">
|
||||
<el-button @click="showLaunchDialog(newInstanceDialog.location, newInstanceDialog.shortName)">{{
|
||||
t('dialog.new_instance.launch')
|
||||
}}</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleAttachGame(newInstanceDialog.location, newInstanceDialog.shortName)">
|
||||
<Button
|
||||
variant="secondary"
|
||||
class="mr-2"
|
||||
@click="showLaunchDialog(newInstanceDialog.location, newInstanceDialog.shortName)"
|
||||
>{{ t('dialog.new_instance.launch') }}</Button
|
||||
>
|
||||
<Button @click="handleAttachGame(newInstanceDialog.location, newInstanceDialog.shortName)">
|
||||
{{ t('dialog.new_instance.open_ingame') }}
|
||||
</el-button>
|
||||
</Button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="showLaunchDialog(newInstanceDialog.location, newInstanceDialog.shortName)"
|
||||
>{{ t('dialog.new_instance.launch') }}</el-button
|
||||
>
|
||||
<Button @click="showLaunchDialog(newInstanceDialog.location, newInstanceDialog.shortName)">{{
|
||||
t('dialog.new_instance.launch')
|
||||
}}</Button>
|
||||
</template>
|
||||
</template>
|
||||
<InviteDialog :invite-dialog="inviteDialog" @closeInviteDialog="closeInviteDialog" />
|
||||
@@ -441,6 +442,7 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, nextTick, ref, watch } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Check as CheckIcon } from 'lucide-vue-next';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toast } from 'vue-sonner';
|
||||
@@ -467,7 +469,6 @@
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '../ui/select';
|
||||
import { groupRequest, instanceRequest, worldRequest } from '../../api';
|
||||
import { ToggleGroup, ToggleGroupItem } from '../ui/toggle-group';
|
||||
import { Button } from '../ui/button';
|
||||
import { VirtualCombobox } from '../ui/virtual-combobox';
|
||||
import { getNextDialogIndex } from '../../shared/utils/base/ui';
|
||||
|
||||
|
||||
@@ -28,26 +28,31 @@
|
||||
">
|
||||
<div style="flex: none">
|
||||
<template v-if="isRealInstance(userDialog.$location.tag)">
|
||||
<Launch :location="userDialog.$location.tag" />
|
||||
<InviteYourself
|
||||
:location="userDialog.$location.tag"
|
||||
:shortname="userDialog.$location.shortName"
|
||||
style="margin-left: 5px" />
|
||||
<TooltipWrapper side="top" :content="t('dialog.user.info.refresh_instance_info')"
|
||||
><el-button
|
||||
size="small"
|
||||
:icon="Refresh"
|
||||
style="margin-left: 5px"
|
||||
circle
|
||||
@click="refreshInstancePlayerCount(userDialog.$location.tag)"></el-button>
|
||||
</TooltipWrapper>
|
||||
<LastJoin
|
||||
:location="userDialog.$location.tag"
|
||||
:currentlocation="lastLocation.location" />
|
||||
<InstanceInfo
|
||||
:location="userDialog.$location.tag"
|
||||
:instance="userDialog.instance.ref"
|
||||
:friendcount="userDialog.instance.friendCount" />
|
||||
<div class="flex items-center mb-1">
|
||||
<Launch :location="userDialog.$location.tag" />
|
||||
<InviteYourself
|
||||
:location="userDialog.$location.tag"
|
||||
:shortname="userDialog.$location.shortName"
|
||||
style="margin-left: 5px" />
|
||||
<TooltipWrapper
|
||||
side="top"
|
||||
:content="t('dialog.user.info.refresh_instance_info')"
|
||||
><Button
|
||||
class="rounded-full w-6 h-6 text-xs text-muted-foreground hover:text-foreground"
|
||||
size="icon"
|
||||
variant="outline"
|
||||
@click="refreshInstancePlayerCount(userDialog.$location.tag)"
|
||||
><i class="ri-refresh-line"></i
|
||||
></Button>
|
||||
</TooltipWrapper>
|
||||
<LastJoin
|
||||
:location="userDialog.$location.tag"
|
||||
:currentlocation="lastLocation.location" />
|
||||
<InstanceInfo
|
||||
:location="userDialog.$location.tag"
|
||||
:instance="userDialog.instance.ref"
|
||||
:friendcount="userDialog.instance.friendCount" />
|
||||
</div>
|
||||
</template>
|
||||
<Location
|
||||
:location="userDialog.ref.location"
|
||||
@@ -234,23 +239,24 @@
|
||||
>{{ bioCache.translated || userDialog.ref.bio || '-' }}</pre
|
||||
>
|
||||
<div style="float: right">
|
||||
<el-button
|
||||
<Button
|
||||
v-if="translationApi && userDialog.ref.bio"
|
||||
text
|
||||
size="small"
|
||||
:loading="translateLoading"
|
||||
:disabled="translateLoading"
|
||||
style="margin-left: 5px; padding: 0"
|
||||
@click="translateBio"
|
||||
><i class="ri-translate-2"></i
|
||||
></el-button>
|
||||
<el-button
|
||||
class="w-3 h-6 text-xs mr-0.5"
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
@click="translateBio">
|
||||
<Spinner v-if="translateLoading" class="size-1" />
|
||||
<i v-else class="ri-translate-2"> </i
|
||||
></Button>
|
||||
<Button
|
||||
class="w-3 h-6 text-xs"
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
v-if="userDialog.id === currentUser.id"
|
||||
text
|
||||
:icon="Edit"
|
||||
size="small"
|
||||
style="margin-left: 5px; padding: 0"
|
||||
@click="showBioDialog"></el-button>
|
||||
@click="showBioDialog"
|
||||
><i class="ri-pencil-line"></i
|
||||
></Button>
|
||||
</div>
|
||||
<div style="margin-top: 5px" class="flex items-center">
|
||||
<TooltipWrapper v-for="(link, index) in userDialog.ref.bioLinks" :key="index">
|
||||
@@ -496,13 +502,14 @@
|
||||
<span class="name">{{ t('dialog.user.info.home_location') }}</span>
|
||||
<span class="extra">
|
||||
<span v-text="userDialog.$homeLocationName"></span>
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Delete"
|
||||
circle
|
||||
<Button
|
||||
class="rounded-full text-xs ml-1"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
style="margin-left: 5px"
|
||||
@click.stop="resetHome()">
|
||||
</el-button>
|
||||
@click.stop="resetHome()"
|
||||
><i class="ri-delete-bin-line"></i>
|
||||
</Button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -514,12 +521,13 @@
|
||||
<TooltipWrapper side="top" :content="t('dialog.user.info.id_tooltip')">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<el-button
|
||||
type="default"
|
||||
:icon="CopyDocument"
|
||||
size="small"
|
||||
circle
|
||||
@click.stop></el-button>
|
||||
<Button
|
||||
class="rounded-full text-xs"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
@click.stop
|
||||
><i class="ri-file-copy-line"></i
|
||||
></Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem @click="copyUserId(userDialog.id)">
|
||||
@@ -562,24 +570,22 @@
|
||||
</div>
|
||||
<div style="display: flex; align-items: center">
|
||||
<span style="margin-right: 5px">{{ t('dialog.user.groups.sort_by') }}</span>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child :disabled="userDialog.isMutualFriendsLoading">
|
||||
<el-button size="small" :disabled="userDialog.isMutualFriendsLoading" @click.stop>
|
||||
<span>
|
||||
{{ t(userDialog.mutualFriendSorting.name) }}
|
||||
<el-icon style="margin-left: 5px"><ArrowDown /></el-icon>
|
||||
</span>
|
||||
</el-button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem
|
||||
<Select
|
||||
:model-value="userDialogMutualFriendSortingKey"
|
||||
:disabled="userDialog.isMutualFriendsLoading"
|
||||
@update:modelValue="setUserDialogMutualFriendSortingByKey">
|
||||
<SelectTrigger size="sm" @click.stop>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem
|
||||
v-for="(item, key) in userDialogMutualFriendSortingOptions"
|
||||
:key="key"
|
||||
@click="setUserDialogMutualFriendSorting(item)">
|
||||
:key="String(key)"
|
||||
:value="String(key)">
|
||||
{{ t(item.name) }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -641,96 +647,80 @@
|
||||
<div style="display: flex; align-items: center">
|
||||
<template v-if="!userDialogGroupEditMode">
|
||||
<span style="margin-right: 5px">{{ t('dialog.user.groups.sort_by') }}</span>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child :disabled="userDialog.isGroupsLoading">
|
||||
<el-button size="small" :disabled="userDialog.isGroupsLoading" @click.stop>
|
||||
<span>
|
||||
{{ t(userDialog.groupSorting.name) }}
|
||||
<el-icon style="margin-left: 5px"><ArrowDown /></el-icon>
|
||||
</span>
|
||||
</el-button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem
|
||||
<Select
|
||||
:model-value="userDialogGroupSortingKey"
|
||||
:disabled="userDialog.isGroupsLoading"
|
||||
@update:modelValue="setUserDialogGroupSortingByKey">
|
||||
<SelectTrigger size="sm" @click.stop>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem
|
||||
v-for="(item, key) in userDialogGroupSortingOptions"
|
||||
:key="key"
|
||||
:key="String(key)"
|
||||
:value="String(key)"
|
||||
:disabled="
|
||||
item === userDialogGroupSortingOptions.inGame &&
|
||||
userDialog.id !== currentUser.id
|
||||
"
|
||||
@click="setUserDialogGroupSorting(item)">
|
||||
">
|
||||
{{ t(item.name) }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</template>
|
||||
<el-button
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
v-if="userDialogGroupEditMode"
|
||||
size="small"
|
||||
:icon="Edit"
|
||||
style="margin-right: 5px; height: 29px; padding: 7px 15px"
|
||||
@click="exitEditModeCurrentUserGroups">
|
||||
{{ t('dialog.user.groups.exit_edit_mode') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
v-else-if="currentUser.id === userDialog.id"
|
||||
size="small"
|
||||
:icon="Edit"
|
||||
style="margin-right: 5px; height: 29px; padding: 7px 15px"
|
||||
class="ml-2"
|
||||
@click="editModeCurrentUserGroups">
|
||||
{{ t('dialog.user.groups.edit_mode') }}
|
||||
</el-button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-loading="userDialog.isGroupsLoading" style="margin-top: 10px">
|
||||
<template v-if="userDialogGroupEditMode">
|
||||
<div class="x-friend-list" style="margin-top: 10px; margin-bottom: 15px; max-height: unset">
|
||||
<!-- Bulk actions dropdown (shown only in edit mode) -->
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Setting"
|
||||
style="
|
||||
margin-right: 5px;
|
||||
height: 29px;
|
||||
padding: 7px 15px;
|
||||
margin-bottom: 5px;
|
||||
">
|
||||
{{ t('dialog.group.actions.manage_selected') }}
|
||||
<el-icon style="margin-left: 5px"><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem @click="bulkSetVisibility('visible')">
|
||||
<Select :model-value="bulkGroupActionValue" @update:modelValue="handleBulkGroupAction">
|
||||
<SelectTrigger size="sm" style="margin-right: 5px; margin-bottom: 5px" @click.stop>
|
||||
<SelectValue :placeholder="t('dialog.group.actions.manage_selected')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="visibility:visible">
|
||||
{{ t('dialog.group.actions.visibility_everyone') }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="bulkSetVisibility('friends')">
|
||||
</SelectItem>
|
||||
<SelectItem value="visibility:friends">
|
||||
{{ t('dialog.group.actions.visibility_friends') }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="bulkSetVisibility('hidden')">
|
||||
</SelectItem>
|
||||
<SelectItem value="visibility:hidden">
|
||||
{{ t('dialog.group.actions.visibility_hidden') }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem variant="destructive" @click="bulkLeaveGroups">
|
||||
<Delete class="size-4" />
|
||||
</SelectItem>
|
||||
<SelectItem value="leave">
|
||||
{{ t('dialog.user.groups.leave_group_tooltip') }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<!-- Select All button -->
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="userDialogGroupAllSelected ? Close : Check"
|
||||
style="height: 29px; padding: 7px 15px; margin-bottom: 5px"
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
style="padding: 7px 15px; margin-bottom: 5px"
|
||||
@click="selectAllGroups">
|
||||
{{
|
||||
userDialogGroupAllSelected
|
||||
? t('dialog.group.actions.deselect_all')
|
||||
: t('dialog.group.actions.select_all')
|
||||
}}
|
||||
</el-button>
|
||||
</Button>
|
||||
|
||||
<div
|
||||
v-for="group in userDialogGroupEditGroups"
|
||||
@@ -755,7 +745,7 @@
|
||||
<div style="margin-right: 3px; margin-left: 5px" @click.stop>
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Download"
|
||||
:icon="DownloadIcon"
|
||||
style="
|
||||
display: block;
|
||||
padding: 7px;
|
||||
@@ -767,7 +757,7 @@
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Download"
|
||||
:icon="DownloadIcon"
|
||||
style="display: block; padding: 7px; font-size: 9px; margin-left: 0"
|
||||
@click="moveGroupBottom(group.id)">
|
||||
</el-button>
|
||||
@@ -810,43 +800,40 @@
|
||||
<span>({{ group.memberCount }})</span>
|
||||
</span>
|
||||
</div>
|
||||
<DropdownMenu v-if="group.myMember?.visibility">
|
||||
<DropdownMenuTrigger as-child :disabled="group.privacy !== 'default'">
|
||||
<el-button :disabled="group.privacy !== 'default'" @click.stop size="small">
|
||||
<span v-if="group.myMember.visibility === 'visible'">{{
|
||||
t('dialog.group.tags.visible')
|
||||
}}</span>
|
||||
<span v-else-if="group.myMember.visibility === 'friends'">{{
|
||||
t('dialog.group.tags.friends')
|
||||
}}</span>
|
||||
<span v-else-if="group.myMember.visibility === 'hidden'">{{
|
||||
t('dialog.group.tags.hidden')
|
||||
}}</span>
|
||||
<span v-else>{{ group.myMember.visibility }}</span>
|
||||
<el-icon style="margin-left: 5px"><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem @click="setGroupVisibility(group.id, 'visible')">
|
||||
<Check v-if="group.myMember.visibility === 'visible'" class="size-4" />
|
||||
<Select
|
||||
v-if="group.myMember?.visibility"
|
||||
:model-value="group.myMember.visibility"
|
||||
:disabled="group.privacy !== 'default'"
|
||||
@update:modelValue="(value) => setGroupVisibility(group.id, value)">
|
||||
<SelectTrigger size="sm" @click.stop>
|
||||
<SelectValue
|
||||
:placeholder="
|
||||
group.myMember.visibility === 'visible'
|
||||
? t('dialog.group.tags.visible')
|
||||
: group.myMember.visibility === 'friends'
|
||||
? t('dialog.group.tags.friends')
|
||||
: group.myMember.visibility === 'hidden'
|
||||
? t('dialog.group.tags.hidden')
|
||||
: group.myMember.visibility
|
||||
" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="visible">
|
||||
{{ t('dialog.group.actions.visibility_everyone') }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="setGroupVisibility(group.id, 'friends')">
|
||||
<Check v-if="group.myMember.visibility === 'friends'" class="size-4" />
|
||||
</SelectItem>
|
||||
<SelectItem value="friends">
|
||||
{{ t('dialog.group.actions.visibility_friends') }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="setGroupVisibility(group.id, 'hidden')">
|
||||
<Check v-if="group.myMember.visibility === 'hidden'" class="size-4" />
|
||||
</SelectItem>
|
||||
<SelectItem value="hidden">
|
||||
{{ t('dialog.group.actions.visibility_hidden') }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<!--//- JSON is missing isSubscribedToAnnouncements, can't be implemented-->
|
||||
<!-- <el-button
|
||||
<!-- <Button size="sm" variant="outline"
|
||||
@click.stop="
|
||||
setGroupSubscription(group.id, !group.myMember.isSubscribedToAnnouncements)
|
||||
"
|
||||
size="small">
|
||||
">
|
||||
<span v-if="group.myMember.isSubscribedToAnnouncements"
|
||||
><el-icon style="margin-left: 5px"><MuteNotification /></el-icon>
|
||||
{{ t('dialog.group.tags.subscribed') }}</span
|
||||
@@ -855,24 +842,26 @@
|
||||
><el-icon style="margin-left: 5px"><Bell /></el-icon>
|
||||
{{ t('dialog.group.tags.unsubscribed') }}</span
|
||||
>
|
||||
</el-button> -->
|
||||
</Button> -->
|
||||
<TooltipWrapper side="right" :content="t('dialog.user.groups.leave_group_tooltip')">
|
||||
<el-button
|
||||
<Button
|
||||
class="rounded-full h-6 w-6"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
v-if="shiftHeld"
|
||||
size="small"
|
||||
:icon="Close"
|
||||
circle
|
||||
style="color: var(--el-color-danger); margin-left: 5px"
|
||||
@click.stop="leaveGroup(group.id)">
|
||||
</el-button>
|
||||
<el-button
|
||||
<LogOut />
|
||||
</Button>
|
||||
<Button
|
||||
class="rounded-full h-6 w-6 text-red-600"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
v-else
|
||||
size="small"
|
||||
:icon="Delete"
|
||||
circle
|
||||
style="margin-left: 5px"
|
||||
@click.stop="leaveGroupPrompt(group.id)">
|
||||
</el-button>
|
||||
<LogOut />
|
||||
</Button>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1036,44 +1025,40 @@
|
||||
}}</span>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center">
|
||||
<span style="margin-right: 5px">{{ t('dialog.user.worlds.sort_by') }}</span>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child :disabled="userDialog.isWorldsLoading">
|
||||
<el-button size="small" :disabled="userDialog.isWorldsLoading" @click.stop>
|
||||
<span>
|
||||
{{ t(userDialog.worldSorting.name) }}
|
||||
<el-icon style="margin-left: 5px"><ArrowDown /></el-icon>
|
||||
</span>
|
||||
</el-button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem
|
||||
<span class="mr-1">{{ t('dialog.user.worlds.sort_by') }}</span>
|
||||
<Select
|
||||
:model-value="userDialogWorldSortingKey"
|
||||
:disabled="userDialog.isWorldsLoading"
|
||||
@update:modelValue="setUserDialogWorldSortingByKey">
|
||||
<SelectTrigger size="sm" @click.stop>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem
|
||||
v-for="(item, key) in userDialogWorldSortingOptions"
|
||||
:key="key"
|
||||
@click="setUserDialogWorldSorting(item)">
|
||||
:key="String(key)"
|
||||
:value="String(key)">
|
||||
{{ t(item.name) }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<span style="margin: 0 5px">{{ t('dialog.user.worlds.order_by') }}</span>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child :disabled="userDialog.isWorldsLoading">
|
||||
<el-button size="small" :disabled="userDialog.isWorldsLoading" @click.stop>
|
||||
<span>
|
||||
{{ t(userDialog.worldOrder.name) }}
|
||||
<el-icon style="margin-left: 5px"><ArrowDown /></el-icon>
|
||||
</span>
|
||||
</el-button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span class="ml-2 mr-1">{{ t('dialog.user.worlds.order_by') }}</span>
|
||||
<Select
|
||||
:model-value="userDialogWorldOrderKey"
|
||||
:disabled="userDialog.isWorldsLoading"
|
||||
@update:modelValue="setUserDialogWorldOrderByKey">
|
||||
<SelectTrigger size="sm" @click.stop>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem
|
||||
v-for="(item, key) in userDialogWorldOrderOptions"
|
||||
:key="key"
|
||||
@click="setUserDialogWorldOrder(item)">
|
||||
:key="String(key)"
|
||||
:value="String(key)">
|
||||
{{ t(item.name) }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -1097,7 +1082,8 @@
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane name="Favorite Worlds" :label="t('dialog.user.favorite_worlds.header')" lazy>
|
||||
<el-button
|
||||
<!-- <Button
|
||||
variant="outline"
|
||||
v-if="userFavoriteWorlds && userFavoriteWorlds.length > 0"
|
||||
type="default"
|
||||
:loading="userDialog.isFavoriteWorldsLoading"
|
||||
@@ -1106,7 +1092,7 @@
|
||||
circle
|
||||
style="position: absolute; right: 15px; bottom: 15px; z-index: 99"
|
||||
@click="getUserFavoriteWorlds(userDialog.id)">
|
||||
</el-button>
|
||||
</Button> -->
|
||||
<el-tabs
|
||||
ref="favoriteWorldsRef"
|
||||
v-loading="userDialog.isFavoriteWorldsLoading"
|
||||
@@ -1186,51 +1172,43 @@
|
||||
t('dialog.user.avatars.total_count', { count: userDialogAvatars.length })
|
||||
}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center">
|
||||
<template v-if="userDialog.ref.id === currentUser.id">
|
||||
<span style="margin-right: 5px">{{ t('dialog.user.avatars.sort_by') }}</span>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child :disabled="userDialog.isWorldsLoading">
|
||||
<el-button size="small" :disabled="userDialog.isWorldsLoading" @click.stop>
|
||||
<span>
|
||||
{{ t(`dialog.user.avatars.sort_by_${userDialog.avatarSorting}`) }}
|
||||
<el-icon style="margin-left: 5px"><ArrowDown /></el-icon>
|
||||
</span>
|
||||
</el-button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem @click="changeUserDialogAvatarSorting('name')">
|
||||
{{ t('dialog.user.avatars.sort_by_name') }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="changeUserDialogAvatarSorting('update')">
|
||||
{{ t('dialog.user.avatars.sort_by_update') }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<span style="margin-right: 5px; margin-left: 10px">{{
|
||||
t('dialog.user.avatars.group_by')
|
||||
}}</span>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child :disabled="userDialog.isWorldsLoading">
|
||||
<el-button size="small" :disabled="userDialog.isWorldsLoading" @click.stop>
|
||||
<span>
|
||||
{{ t(`dialog.user.avatars.${userDialog.avatarReleaseStatus}`) }}
|
||||
<el-icon style="margin-left: 5px"><ArrowDown /></el-icon>
|
||||
</span>
|
||||
</el-button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem @click="userDialog.avatarReleaseStatus = 'all'">
|
||||
{{ t('dialog.user.avatars.all') }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="userDialog.avatarReleaseStatus = 'public'">
|
||||
{{ t('dialog.user.avatars.public') }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="userDialog.avatarReleaseStatus = 'private'">
|
||||
{{ t('dialog.user.avatars.private') }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<span class="mr-1">{{ t('dialog.user.avatars.sort_by') }}</span>
|
||||
<Select
|
||||
:model-value="userDialog.avatarSorting"
|
||||
:disabled="userDialog.isWorldsLoading"
|
||||
@update:modelValue="changeUserDialogAvatarSorting">
|
||||
<SelectTrigger size="sm" @click.stop>
|
||||
<SelectValue
|
||||
:placeholder="
|
||||
t(`dialog.user.avatars.sort_by_${userDialog.avatarSorting}`)
|
||||
" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="name">{{
|
||||
t('dialog.user.avatars.sort_by_name')
|
||||
}}</SelectItem>
|
||||
<SelectItem value="update">{{
|
||||
t('dialog.user.avatars.sort_by_update')
|
||||
}}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span class="ml-2 mr-1">{{ t('dialog.user.avatars.group_by') }}</span>
|
||||
<Select
|
||||
:model-value="userDialog.avatarReleaseStatus"
|
||||
:disabled="userDialog.isWorldsLoading"
|
||||
@update:modelValue="(value) => (userDialog.avatarReleaseStatus = value)">
|
||||
<SelectTrigger size="sm" @click.stop>
|
||||
<SelectValue
|
||||
:placeholder="t(`dialog.user.avatars.${userDialog.avatarReleaseStatus}`)" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">{{ t('dialog.user.avatars.all') }}</SelectItem>
|
||||
<SelectItem value="public">{{ t('dialog.user.avatars.public') }}</SelectItem>
|
||||
<SelectItem value="private">{{ t('dialog.user.avatars.private') }}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1264,16 +1242,20 @@
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane name="JSON" :label="t('dialog.user.json.header')" lazy style="height: 50vh">
|
||||
<el-button type="default" size="small" :icon="Refresh" circle @click="refreshUserDialogTreeData()">
|
||||
</el-button>
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="Download"
|
||||
circle
|
||||
style="margin-left: 5px"
|
||||
<Button
|
||||
class="rounded-full h-6 w-6 mr-2"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
@click="refreshUserDialogTreeData()">
|
||||
<RefreshCcw />
|
||||
</Button>
|
||||
<Button
|
||||
class="rounded-full h-6 w-6"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
@click="downloadAndSaveJson(userDialog.id, userDialog.ref)">
|
||||
</el-button>
|
||||
<Download />
|
||||
</Button>
|
||||
<vue-json-pretty
|
||||
:data="userDialog.treeData"
|
||||
:deep="2"
|
||||
@@ -1304,25 +1286,28 @@
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ArrowDown,
|
||||
Bottom,
|
||||
Check,
|
||||
Close,
|
||||
CollectionTag,
|
||||
CopyDocument,
|
||||
Delete,
|
||||
Download,
|
||||
Edit,
|
||||
Download as DownloadIcon,
|
||||
Loading,
|
||||
MoreFilled,
|
||||
Refresh,
|
||||
Setting,
|
||||
Top,
|
||||
View,
|
||||
Warning
|
||||
} from '@element-plus/icons-vue';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { computed, defineAsyncComponent, nextTick, ref, watch } from 'vue';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { Download, LogOut, RefreshCcw } from 'lucide-vue-next';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
@@ -1376,13 +1361,6 @@
|
||||
userRequest,
|
||||
worldRequest
|
||||
} from '../../../api';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger
|
||||
} from '../../ui/dropdown-menu';
|
||||
import { processBulk, request } from '../../../service/request';
|
||||
import { userDialogGroupSortingOptions, userDialogMutualFriendSortingOptions } from '../../../shared/constants';
|
||||
import { userDialogWorldOrderOptions, userDialogWorldSortingOptions } from '../../../shared/constants/';
|
||||
@@ -2368,6 +2346,9 @@
|
||||
}
|
||||
|
||||
async function translateBio() {
|
||||
if (translateLoading.value) {
|
||||
return;
|
||||
}
|
||||
const bio = userDialog.value.ref.bio;
|
||||
if (!bio) {
|
||||
return;
|
||||
@@ -2455,6 +2436,25 @@
|
||||
copyToClipboard(displayName, 'User DisplayName copied to clipboard');
|
||||
}
|
||||
|
||||
const userDialogGroupSortingKey = computed(() => {
|
||||
const current = userDialog.value.groupSorting;
|
||||
const found = Object.entries(userDialogGroupSortingOptions).find(([, option]) => {
|
||||
if (option === current) {
|
||||
return true;
|
||||
}
|
||||
return option?.value === current?.value || option?.name === current?.name;
|
||||
});
|
||||
return found ? String(found[0]) : '';
|
||||
});
|
||||
|
||||
function setUserDialogGroupSortingByKey(key) {
|
||||
const option = userDialogGroupSortingOptions[key];
|
||||
if (!option) {
|
||||
return;
|
||||
}
|
||||
setUserDialogGroupSorting(option);
|
||||
}
|
||||
|
||||
async function setUserDialogGroupSorting(sortOrder) {
|
||||
const D = userDialog.value;
|
||||
if (D.groupSorting.value === sortOrder.value) {
|
||||
@@ -2464,6 +2464,25 @@
|
||||
await sortCurrentUserGroups();
|
||||
}
|
||||
|
||||
const userDialogMutualFriendSortingKey = computed(() => {
|
||||
const current = userDialog.value.mutualFriendSorting;
|
||||
const found = Object.entries(userDialogMutualFriendSortingOptions).find(([, option]) => {
|
||||
if (option === current) {
|
||||
return true;
|
||||
}
|
||||
return option?.value === current?.value || option?.name === current?.name;
|
||||
});
|
||||
return found ? String(found[0]) : '';
|
||||
});
|
||||
|
||||
function setUserDialogMutualFriendSortingByKey(key) {
|
||||
const option = userDialogMutualFriendSortingOptions[key];
|
||||
if (!option) {
|
||||
return;
|
||||
}
|
||||
setUserDialogMutualFriendSorting(option);
|
||||
}
|
||||
|
||||
async function setUserDialogMutualFriendSorting(sortOrder) {
|
||||
const D = userDialog.value;
|
||||
D.mutualFriendSorting = sortOrder;
|
||||
@@ -2524,6 +2543,23 @@
|
||||
});
|
||||
}
|
||||
|
||||
const bulkGroupActionValue = ref('');
|
||||
|
||||
function handleBulkGroupAction(value) {
|
||||
bulkGroupActionValue.value = value;
|
||||
|
||||
if (value === 'leave') {
|
||||
bulkLeaveGroups();
|
||||
} else if (typeof value === 'string' && value.startsWith('visibility:')) {
|
||||
const newVisibility = value.slice('visibility:'.length);
|
||||
bulkSetVisibility(newVisibility);
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
bulkGroupActionValue.value = '';
|
||||
});
|
||||
}
|
||||
|
||||
// Apply the given visibility to all selected groups
|
||||
async function bulkSetVisibility(newVisibility) {
|
||||
for (const groupId of userDialogGroupEditSelectedGroupIds.value) {
|
||||
@@ -2593,6 +2629,25 @@
|
||||
refreshUserDialogWorlds();
|
||||
}
|
||||
|
||||
const userDialogWorldSortingKey = computed(() => {
|
||||
const current = userDialog.value.worldSorting;
|
||||
const found = Object.entries(userDialogWorldSortingOptions).find(([, option]) => {
|
||||
if (option === current) {
|
||||
return true;
|
||||
}
|
||||
return option?.value === current?.value || option?.name === current?.name;
|
||||
});
|
||||
return found ? String(found[0]) : '';
|
||||
});
|
||||
|
||||
function setUserDialogWorldSortingByKey(key) {
|
||||
const option = userDialogWorldSortingOptions[key];
|
||||
if (!option) {
|
||||
return;
|
||||
}
|
||||
setUserDialogWorldSorting(option);
|
||||
}
|
||||
|
||||
async function setUserDialogWorldOrder(order) {
|
||||
const D = userDialog.value;
|
||||
if (D.worldOrder.value === order.value) {
|
||||
@@ -2602,6 +2657,25 @@
|
||||
refreshUserDialogWorlds();
|
||||
}
|
||||
|
||||
const userDialogWorldOrderKey = computed(() => {
|
||||
const current = userDialog.value.worldOrder;
|
||||
const found = Object.entries(userDialogWorldOrderOptions).find(([, option]) => {
|
||||
if (option === current) {
|
||||
return true;
|
||||
}
|
||||
return option?.value === current?.value || option?.name === current?.name;
|
||||
});
|
||||
return found ? String(found[0]) : '';
|
||||
});
|
||||
|
||||
function setUserDialogWorldOrderByKey(key) {
|
||||
const option = userDialogWorldOrderOptions[key];
|
||||
if (!option) {
|
||||
return;
|
||||
}
|
||||
setUserDialogWorldOrder(option);
|
||||
}
|
||||
|
||||
function changeUserDialogAvatarSorting(sortOption) {
|
||||
const D = userDialog.value;
|
||||
D.avatarSorting = sortOption;
|
||||
|
||||
@@ -165,30 +165,37 @@
|
||||
v-if="worldDialog.inCache"
|
||||
side="top"
|
||||
:content="t('dialog.world.actions.delete_cache_tooltip')">
|
||||
<el-button
|
||||
:icon="Delete"
|
||||
size="large"
|
||||
circle
|
||||
<Button
|
||||
class="rounded-full mr-2"
|
||||
size="icon-lg"
|
||||
variant="outline"
|
||||
:disabled="isGameRunning && worldDialog.cacheLocked"
|
||||
@click="deleteVRChatCache(worldDialog.ref)" />
|
||||
@click="deleteVRChatCache(worldDialog.ref)"
|
||||
><Trash2
|
||||
/></Button>
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper side="top" :content="t('dialog.world.actions.favorites_tooltip')">
|
||||
<el-button
|
||||
:type="worldDialog.isFavorite ? 'warning' : 'default'"
|
||||
:icon="worldDialog.isFavorite ? StarFilled : Star"
|
||||
size="large"
|
||||
circle
|
||||
style="margin-left: 5px"
|
||||
@click="worldDialogCommand('Add Favorite')" />
|
||||
<TooltipWrapper
|
||||
v-if="worldDialog.isFavorite"
|
||||
side="top"
|
||||
:content="t('dialog.world.actions.favorites_tooltip')">
|
||||
<Button class="rounded-full" size="icon-lg" @click="worldDialogCommand('Add Favorite')"
|
||||
><Star
|
||||
/></Button>
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper v-else side="top" :content="t('dialog.world.actions.favorites_tooltip')">
|
||||
<Button
|
||||
class="rounded-full"
|
||||
size="icon-lg"
|
||||
variant="outline"
|
||||
@click="worldDialogCommand('Add Favorite')"
|
||||
><Star
|
||||
/></Button>
|
||||
</TooltipWrapper>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<el-button
|
||||
type="default"
|
||||
:icon="MoreFilled"
|
||||
size="large"
|
||||
style="margin-left: 5px"
|
||||
circle />
|
||||
<Button variant="outline" size="icon-lg" class="rounded-full ml-2">
|
||||
<Ellipsis />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem @click="worldDialogCommand('Refresh')">
|
||||
@@ -343,24 +350,26 @@
|
||||
<TooltipWrapper
|
||||
side="top"
|
||||
:content="t('dialog.world.instances.refresh_instance_info')">
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Refresh"
|
||||
style="margin-left: 5px"
|
||||
circle
|
||||
@click="refreshInstancePlayerCount(room.tag)" />
|
||||
<Button
|
||||
class="rounded-full w-6 h-6 text-xs text-muted-foreground hover:text-foreground"
|
||||
size="icon"
|
||||
variant="outline"
|
||||
@click="refreshInstancePlayerCount(room.tag)"
|
||||
><i class="ri-refresh-line"></i
|
||||
></Button>
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper
|
||||
v-if="instanceJoinHistory.get(room.$location.tag)"
|
||||
side="top"
|
||||
:content="t('dialog.previous_instances.info')">
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="DataLine"
|
||||
<Button
|
||||
class="rounded-full w-6 h-6 text-xs text-muted-foreground hover:text-foreground"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
style="margin-left: 5px"
|
||||
plain
|
||||
circle
|
||||
@click="showPreviousInstancesInfoDialog(room.location)" />
|
||||
@click="showPreviousInstancesInfoDialog(room.location)"
|
||||
><i class="ri-history-line"></i
|
||||
></Button>
|
||||
</TooltipWrapper>
|
||||
<LastJoin :location="room.$location.tag" :currentlocation="lastLocation.location" />
|
||||
<InstanceInfo
|
||||
@@ -452,12 +461,13 @@
|
||||
<TooltipWrapper side="top" :content="t('dialog.world.info.id_tooltip')">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<el-button
|
||||
type="default"
|
||||
:icon="CopyDocument"
|
||||
size="small"
|
||||
circle
|
||||
@click.stop />
|
||||
<Button
|
||||
class="rounded-full text-xs"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
@click.stop
|
||||
><i class="ri-file-copy-line"></i
|
||||
></Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem @click="copyWorldId()">
|
||||
@@ -690,19 +700,20 @@
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="JSON" :label="t('dialog.world.json.header')" style="max-height: 50vh" lazy>
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="Refresh"
|
||||
circle
|
||||
@click="refreshWorldDialogTreeData"></el-button>
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="Download"
|
||||
circle
|
||||
style="margin-left: 5px"
|
||||
@click="downloadAndSaveJson(worldDialog.id, worldDialog.ref)"></el-button>
|
||||
<Button
|
||||
class="rounded-full h-6 w-6 mr-2"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
@click="refreshWorldDialogTreeData()">
|
||||
<RefreshCcw />
|
||||
</Button>
|
||||
<Button
|
||||
class="rounded-full h-6 w-6"
|
||||
size="icon-sm"
|
||||
variant="outline"
|
||||
@click="downloadAndSaveJson(worldDialog.id, worldDialog.ref)">
|
||||
<Download />
|
||||
</Button>
|
||||
<vue-json-pretty :data="treeData" :deep="2" :theme="isDarkMode ? 'dark' : 'light'" show-icon />
|
||||
<br />
|
||||
<vue-json-pretty
|
||||
@@ -737,7 +748,6 @@
|
||||
import {
|
||||
ArrowDown,
|
||||
Check,
|
||||
CopyDocument,
|
||||
DataLine,
|
||||
Delete,
|
||||
Download,
|
||||
@@ -747,12 +757,9 @@
|
||||
Loading,
|
||||
MagicStick,
|
||||
Message,
|
||||
MoreFilled,
|
||||
Picture,
|
||||
Refresh,
|
||||
Share,
|
||||
Star,
|
||||
StarFilled,
|
||||
Upload,
|
||||
User,
|
||||
UserFilled,
|
||||
@@ -760,6 +767,8 @@
|
||||
Warning
|
||||
} from '@element-plus/icons-vue';
|
||||
import { computed, defineAsyncComponent, nextTick, ref, watch } from 'vue';
|
||||
import { Ellipsis, RefreshCcw, Star, Trash2 } from 'lucide-vue-next';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toast } from 'vue-sonner';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { TooltipWrapper } from '../components/ui/tooltip';
|
||||
|
||||
import AvatarInfo from '../components/AvatarInfo.vue';
|
||||
import CountdownTimer from '../components/CountdownTimer.vue';
|
||||
import DataTable from '../components/DataTable.vue';
|
||||
@@ -9,7 +11,6 @@ import Launch from '../components/Launch.vue';
|
||||
import Location from '../components/Location.vue';
|
||||
import LocationWorld from '../components/LocationWorld.vue';
|
||||
import Timer from '../components/Timer.vue';
|
||||
import { TooltipWrapper } from '../components/ui/tooltip';
|
||||
|
||||
export function initComponents(app) {
|
||||
app.component('Location', Location);
|
||||
|
||||
@@ -3,7 +3,14 @@
|
||||
<div class="options-container mutual-graph__toolbar">
|
||||
<div class="mutual-graph__actions">
|
||||
<TooltipWrapper :content="t('view.charts.mutual_friend.force_dialog.open_label')" side="top">
|
||||
<el-button circle :icon="Setting" :disabled="!graphReady" @click="openForceDialog"></el-button>
|
||||
<Button
|
||||
class="rounded-full"
|
||||
size="icon"
|
||||
variant="outline"
|
||||
:disabled="!graphReady"
|
||||
@click="openForceDialog">
|
||||
<Settings />
|
||||
</Button>
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper :content="fetchButtonLabel" side="top">
|
||||
<el-button type="primary" :disabled="fetchButtonDisabled" :loading="isFetching" @click="startFetch">
|
||||
@@ -14,9 +21,9 @@
|
||||
v-if="isFetching"
|
||||
:content="t('view.charts.mutual_friend.actions.stop_fetching')"
|
||||
side="top">
|
||||
<el-button type="danger" plain :disabled="status.cancelRequested" @click="cancelFetch">
|
||||
<Button variant="destructive" :disabled="status.cancelRequested" @click="cancelFetch">
|
||||
{{ t('view.charts.mutual_friend.actions.stop') }}
|
||||
</el-button>
|
||||
</Button>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
</div>
|
||||
@@ -90,12 +97,12 @@
|
||||
|
||||
<template #footer>
|
||||
<div class="mutual-graph__dialog-footer">
|
||||
<el-button @click="resetForceSettings">{{
|
||||
<Button variant="secondary" class="mr-2" @click="resetForceSettings">{{
|
||||
t('view.charts.mutual_friend.force_dialog.reset')
|
||||
}}</el-button>
|
||||
<el-button type="primary" :disabled="!graphReady" @click="applyForceSettings">
|
||||
}}</Button>
|
||||
<Button :disabled="!graphReady" @click="applyForceSettings">
|
||||
{{ t('view.charts.mutual_friend.force_dialog.apply') }}
|
||||
</el-button>
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -104,8 +111,9 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import { Setting } from '@element-plus/icons-vue';
|
||||
import { Settings } from 'lucide-vue-next';
|
||||
import { onBeforeRouteLeave } from 'vue-router';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toast } from 'vue-sonner';
|
||||
|
||||
@@ -20,20 +20,18 @@
|
||||
style="margin-top: 10px">
|
||||
</el-input>
|
||||
<template #footer>
|
||||
<el-button @click="cancelEditAndSendInviteResponse">{{
|
||||
<Button variant="secondary" class="mr-2" @click="cancelEditAndSendInviteResponse">{{
|
||||
t('dialog.edit_send_invite_response_message.cancel')
|
||||
}}</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="saveEditAndSendInviteResponse"
|
||||
:disabled="!editAndSendInviteResponseDialog.newMessage"
|
||||
>{{ t('dialog.edit_send_invite_response_message.send') }}</el-button
|
||||
>
|
||||
}}</Button>
|
||||
<Button @click="saveEditAndSendInviteResponse" :disabled="!editAndSendInviteResponseDialog.newMessage">{{
|
||||
t('dialog.edit_send_invite_response_message.send')
|
||||
}}</Button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
@@ -106,18 +106,18 @@
|
||||
:long-label="true"
|
||||
@change="setAvatarRemoteDatabase(!avatarRemoteDatabase)" />
|
||||
<div class="options-container-item">
|
||||
<el-button size="small" :icon="User" @click="showAvatarProviderDialog">{{
|
||||
<Button size="sm" variant="outline" @click="showAvatarProviderDialog">{{
|
||||
t('view.settings.advanced.advanced.remote_database.avatar_database_provider')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="!isLinux">
|
||||
<div class="options-container">
|
||||
<span class="header">{{ t('view.settings.advanced.advanced.app_launcher.header') }}</span>
|
||||
<br />
|
||||
<el-button size="small" :icon="Folder" style="margin-top: 5px" @click="openShortcutFolder()">{{
|
||||
<Button size="sm" variant="outline" style="margin-top: 5px" @click="openShortcutFolder()">{{
|
||||
t('view.settings.advanced.advanced.app_launcher.folder')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
<simple-switch
|
||||
:label="t('view.settings.advanced.advanced.remote_database.enable')"
|
||||
:value="enableAppLauncher"
|
||||
@@ -145,9 +145,9 @@
|
||||
:long-label="true"
|
||||
@change="changeYouTubeApi('VRCX_youtubeAPI')" />
|
||||
<div class="options-container-item">
|
||||
<el-button size="small" :icon="CaretRight" @click="showYouTubeApiDialog">{{
|
||||
<Button size="sm" variant="outline" @click="showYouTubeApiDialog">{{
|
||||
t('view.settings.advanced.advanced.youtube_api.youtube_api_key')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options-container">
|
||||
@@ -159,9 +159,9 @@
|
||||
:long-label="true"
|
||||
@change="changeTranslationAPI('VRCX_translationAPI')" />
|
||||
<div class="options-container-item">
|
||||
<el-button size="small" @click="showTranslationApiDialog"
|
||||
<Button size="sm" variant="outline" @click="showTranslationApiDialog"
|
||||
><i class="ri-translate-2" style="margin-right: 5px"></i
|
||||
>{{ t('view.settings.advanced.advanced.translation_api.translation_api_key') }}</el-button
|
||||
>{{ t('view.settings.advanced.advanced.translation_api.translation_api_key') }}</Button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -192,17 +192,18 @@
|
||||
:long-label="true"
|
||||
@change="setShowConfirmationOnSwitchAvatar" />
|
||||
<div class="options-container-item">
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Paperclip"
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
class="mr-2"
|
||||
@click="openExternalLink('https://github.com/vrcx-team/VRCX/wiki/Launch-parameters-&-VRCX.json')"
|
||||
>{{ t('view.settings.advanced.advanced.launch_commands.docs') }}</el-button
|
||||
>{{ t('view.settings.advanced.advanced.launch_commands.docs') }}</Button
|
||||
>
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Paperclip"
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
@click="openExternalLink('https://github.com/Myrkie/open-in-vrcx')"
|
||||
>{{ t('view.settings.advanced.advanced.launch_commands.website_userscript') }}</el-button
|
||||
>{{ t('view.settings.advanced.advanced.launch_commands.website_userscript') }}</Button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -210,15 +211,15 @@
|
||||
<span class="header">{{ t('view.settings.advanced.advanced.cache_debug.header') }}</span>
|
||||
<br />
|
||||
<div class="options-container-item">
|
||||
<el-button size="small" :icon="DeleteFilled" @click="clearVRCXCache">{{
|
||||
<Button size="sm" variant="outline" class="mr-2" @click="clearVRCXCache">{{
|
||||
t('view.settings.advanced.advanced.cache_debug.clear_cache')
|
||||
}}</el-button>
|
||||
<el-button size="small" :icon="Timer" @click="promptAutoClearVRCXCacheFrequency">{{
|
||||
}}</Button>
|
||||
<Button size="sm" variant="outline" class="mr-2" @click="promptAutoClearVRCXCacheFrequency">{{
|
||||
t('view.settings.advanced.advanced.cache_debug.auto_clear_cache')
|
||||
}}</el-button>
|
||||
<el-button size="small" :icon="Refresh" @click="refreshCacheSize">{{
|
||||
}}</Button>
|
||||
<Button size="sm" variant="outline" @click="refreshCacheSize">{{
|
||||
t('view.settings.advanced.advanced.cache_debug.refresh_cache')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
|
||||
<simple-switch
|
||||
@@ -263,17 +264,17 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="options-container-item">
|
||||
<el-button size="small" :icon="Tickets" @click="showConsole">{{
|
||||
<Button size="sm" variant="outline" @click="showConsole">{{
|
||||
t('view.settings.advanced.advanced.cache_debug.show_console')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options-container">
|
||||
<span class="sub-header">{{ t('view.settings.advanced.advanced.sqlite_table_size.header') }}</span>
|
||||
<div class="options-container-item">
|
||||
<el-button size="small" :icon="Refresh" @click="getSqliteTableSizes">{{
|
||||
<Button size="sm" variant="outline" @click="getSqliteTableSizes">{{
|
||||
t('view.settings.advanced.advanced.sqlite_table_size.refresh')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
<div class="options-container-item">
|
||||
<span class="name">
|
||||
@@ -353,22 +354,14 @@
|
||||
<div class="header-bar">
|
||||
<span class="header">{{ t('view.profile.config_json') }}</span>
|
||||
<TooltipWrapper side="top" :content="t('view.profile.refresh_tooltip')">
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="Refresh"
|
||||
circle
|
||||
style="margin-left: 5px"
|
||||
@click="refreshConfigTreeData()"></el-button>
|
||||
<Button class="rounded-full mr-2" size="icon-sm" variant="outline" @click="refreshConfigTreeData()">
|
||||
<RefreshCcw />
|
||||
</Button>
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper side="top" :content="t('view.profile.clear_results_tooltip')">
|
||||
<el-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="Delete"
|
||||
circle
|
||||
style="margin-left: 5px"
|
||||
@click="configTreeData = {}"></el-button>
|
||||
<Button class="rounded-full" size="icon-sm" variant="outline" @click="configTreeData = {}">
|
||||
<Trash2
|
||||
/></Button>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
<vue-json-pretty
|
||||
@@ -391,20 +384,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
CaretRight,
|
||||
Delete,
|
||||
DeleteFilled,
|
||||
Folder,
|
||||
Goods,
|
||||
Operation,
|
||||
Paperclip,
|
||||
Refresh,
|
||||
Tickets,
|
||||
Timer,
|
||||
User
|
||||
} from '@element-plus/icons-vue';
|
||||
import { Folder, Goods, Operation } from '@element-plus/icons-vue';
|
||||
import { computed, reactive, ref } from 'vue';
|
||||
import { RefreshCcw, Trash2 } from 'lucide-vue-next';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ButtonGroup } from '@/components/ui/button-group';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
@@ -165,9 +165,9 @@
|
||||
:value="compactTableMode"
|
||||
@change="setCompactTableMode" />
|
||||
<div class="options-container-item">
|
||||
<el-button size="small" :icon="Notebook" style="margin-right: 10px" @click="promptMaxTableSizeDialog">{{
|
||||
<Button size="sm" variant="outline" @click="promptMaxTableSizeDialog">{{
|
||||
t('view.settings.appearance.appearance.table_max_size')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options-container">
|
||||
@@ -425,9 +425,9 @@
|
||||
} from '@/components/ui/tags-input';
|
||||
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
||||
import { ArrowRight, Notebook } from '@element-plus/icons-vue';
|
||||
import { CheckIcon, ChevronDown } from 'lucide-vue-next';
|
||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||
import { ArrowRight } from '@element-plus/icons-vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toast } from 'vue-sonner';
|
||||
|
||||
@@ -35,12 +35,12 @@
|
||||
<div class="options-container">
|
||||
<span class="header">{{ t('view.settings.general.vrcx_updater.header') }}</span>
|
||||
<div class="options-container-item">
|
||||
<el-button size="small" :icon="Document" @click="showChangeLogDialog">{{
|
||||
<Button size="sm" variant="outline" class="mr-2" @click="showChangeLogDialog">{{
|
||||
t('view.settings.general.vrcx_updater.change_log')
|
||||
}}</el-button>
|
||||
<el-button v-if="!noUpdater" size="small" :icon="Upload" @click="showVRCXUpdateDialog()">{{
|
||||
}}</Button>
|
||||
<Button size="sm" variant="outline" v-if="!noUpdater" @click="showVRCXUpdateDialog()">{{
|
||||
t('view.settings.general.vrcx_updater.change_build')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
<div v-if="!noUpdater" class="options-container-item">
|
||||
<span class="name">{{ t('view.settings.general.vrcx_updater.update_action') }}</span>
|
||||
@@ -104,9 +104,9 @@
|
||||
:tooltip="t('view.settings.general.application.disable_gpu_acceleration_tooltip')"
|
||||
@change="setDisableVrOverlayGpuAcceleration" />
|
||||
<div class="options-container-item">
|
||||
<el-button size="small" :icon="Connection" @click="promptProxySettings">{{
|
||||
<Button size="sm" variant="outline" @click="promptProxySettings">{{
|
||||
t('view.settings.general.application.proxy')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options-container">
|
||||
@@ -291,9 +291,9 @@
|
||||
<p>{{ t('view.settings.general.legal_notice.disclaimer2') }}</p>
|
||||
</div>
|
||||
<div class="options-container-item">
|
||||
<el-button size="small" @click="openOSSDialog">{{
|
||||
<Button size="sm" variant="outline" @click="openOSSDialog">{{
|
||||
t('view.settings.general.legal_notice.open_source_software_notice')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
<OpenSourceSoftwareNoticeDialog v-if="ossDialog" v-model:ossDialog="ossDialog" />
|
||||
@@ -301,8 +301,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Connection, Document, InfoFilled, Upload } from '@element-plus/icons-vue';
|
||||
import { computed, defineAsyncComponent, ref } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { InfoFilled } from '@element-plus/icons-vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
<div class="options-container" style="margin-top: 0">
|
||||
<span class="header">{{ t('view.settings.notifications.notifications.header') }}</span>
|
||||
<div class="options-container-item">
|
||||
<el-button size="small" :icon="ChatSquare" @click="showNotyFeedFiltersDialog">{{
|
||||
<Button size="sm" variant="outline" @click="showNotyFeedFiltersDialog">{{
|
||||
t('view.settings.notifications.notifications.notification_filter')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options-container">
|
||||
@@ -65,14 +65,14 @@
|
||||
saveOpenVROption();
|
||||
" />
|
||||
<div class="options-container-item">
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Rank"
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
:disabled="!overlayNotifications || !openVR"
|
||||
@click="showNotificationPositionDialog"
|
||||
>{{
|
||||
t('view.settings.notifications.notifications.steamvr_notifications.notification_position')
|
||||
}}</el-button
|
||||
}}</Button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
@@ -85,14 +85,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="options-container-item">
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Timer"
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
:disabled="(!overlayNotifications || !openVR) && !xsNotifications"
|
||||
@click="promptNotificationTimeout"
|
||||
>{{
|
||||
t('view.settings.notifications.notifications.steamvr_notifications.notification_timeout')
|
||||
}}</el-button
|
||||
}}</Button
|
||||
>
|
||||
</div>
|
||||
<simple-switch
|
||||
@@ -262,9 +262,9 @@
|
||||
:placeholder="t('view.settings.notifications.notifications.text_to_speech.tts_test_placeholder')"
|
||||
:rows="1"
|
||||
style="width: 175px; display: inline-block"></el-input>
|
||||
<el-button size="small" :icon="VideoPlay" style="margin-left: 10px" @click="testNotificationTTS">{{
|
||||
<Button size="sm" variant="outline" style="margin-left: 10px" @click="testNotificationTTS">{{
|
||||
t('view.settings.notifications.notifications.text_to_speech.play')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
<NotificationPositionDialog v-model:isNotificationPositionDialogVisible="isNotificationPositionDialogVisible" />
|
||||
@@ -274,8 +274,8 @@
|
||||
|
||||
<script setup>
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { ChatSquare, Rank, Timer, VideoPlay } from '@element-plus/icons-vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
:value="screenshotHelperCopyToClipboard"
|
||||
@change="setScreenshotHelperCopyToClipboard()"
|
||||
:long-label="true" />
|
||||
<el-button size="small" :icon="Delete" @click="askDeleteAllScreenshotMetadata()">{{
|
||||
<Button size="sm" variant="outline" @click="askDeleteAllScreenshotMetadata()">{{
|
||||
t('view.settings.advanced.advanced.delete_all_screenshot_metadata.button')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
|
||||
<div class="options-container">
|
||||
@@ -46,15 +46,15 @@
|
||||
t('view.settings.advanced.advanced.user_generated_content.description')
|
||||
}}</span>
|
||||
</div>
|
||||
<el-button size="small" :icon="Folder" @click="openUGCFolder()">{{
|
||||
<Button size="sm" variant="outline" @click="openUGCFolder()">{{
|
||||
t('view.settings.advanced.advanced.user_generated_content.folder')
|
||||
}}</el-button>
|
||||
<el-button size="small" :icon="FolderOpened" @click="openUGCFolderSelector()">{{
|
||||
}}</Button>
|
||||
<Button size="sm" variant="outline" @click="openUGCFolderSelector()">{{
|
||||
t('view.settings.advanced.advanced.user_generated_content.set_folder')
|
||||
}}</el-button>
|
||||
<el-button size="small" :icon="Delete" @click="resetUGCFolder()" v-if="ugcFolderPath">{{
|
||||
}}</Button>
|
||||
<Button size="sm" variant="outline" @click="resetUGCFolder()" v-if="ugcFolderPath">{{
|
||||
t('view.settings.advanced.advanced.user_generated_content.reset_override')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
@@ -101,7 +101,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Delete, Folder, FolderOpened, InfoFilled } from '@element-plus/icons-vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { InfoFilled } from '@element-plus/icons-vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
<div class="options-container" style="margin-top: 0">
|
||||
<span class="header">{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.header') }}</span>
|
||||
<div class="options-container-item">
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Files"
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
:disabled="!openVR || !overlayWrist"
|
||||
@click="emit('open-feed-filters')"
|
||||
>{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.wrist_feed_filters') }}</el-button
|
||||
>{{ t('view.settings.wrist_overlay.steamvr_wrist_overlay.wrist_feed_filters') }}</Button
|
||||
>
|
||||
</div>
|
||||
<div class="options-container-item">
|
||||
@@ -156,7 +156,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Files } from '@element-plus/icons-vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
|
||||
@@ -65,16 +65,19 @@
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="currentResetFunction">{{ t('dialog.shared_feed_filters.reset') }}</el-button>
|
||||
<el-button type="primary" style="margin-left: 10px" @click="handleDialogClose">{{
|
||||
<Button variant="secondary" @click="currentResetFunction">{{
|
||||
t('dialog.shared_feed_filters.reset')
|
||||
}}</Button>
|
||||
<Button style="margin-left: 10px" @click="handleDialogClose">{{
|
||||
t('dialog.shared_feed_filters.close')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { InfoFilled, Warning } from '@element-plus/icons-vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
@@ -29,20 +29,16 @@
|
||||
|
||||
<div style="margin-top: 10px">
|
||||
<span style="margin-right: 5px">{{ t('dialog.config_json.delete_all_cache') }}</span>
|
||||
<el-button
|
||||
size="small"
|
||||
style="margin-left: 5px"
|
||||
:icon="Delete"
|
||||
@click="showDeleteAllVRChatCacheConfirm"
|
||||
>{{ t('dialog.config_json.delete_cache') }}</el-button
|
||||
>
|
||||
<Button size="sm" variant="outline" style="margin-left: 5px" @click="showDeleteAllVRChatCacheConfirm">{{
|
||||
t('dialog.config_json.delete_cache')
|
||||
}}</Button>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 10px">
|
||||
<span style="margin-right: 5px">{{ t('dialog.config_json.delete_old_cache') }}</span>
|
||||
<el-button size="small" style="margin-left: 5px" :icon="FolderDelete" @click="sweepVRChatCache">{{
|
||||
<Button size="sm" variant="outline" style="margin-left: 5px" @click="sweepVRChatCache">{{
|
||||
t('dialog.config_json.sweep_cache')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
|
||||
<div v-for="(item, value) in VRChatConfigList" :key="value" style="display: block; margin-top: 10px">
|
||||
@@ -58,11 +54,11 @@
|
||||
@input="refreshDialogValues"
|
||||
style="flex: 1; margin-top: 5px">
|
||||
<template #append>
|
||||
<el-button
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
v-if="item.folderBrowser"
|
||||
size="small"
|
||||
:icon="FolderOpened"
|
||||
@click="openConfigFolderBrowser(value)"></el-button>
|
||||
@click="openConfigFolderBrowser(value)"></Button>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
@@ -153,15 +149,19 @@
|
||||
<template #footer>
|
||||
<div style="display: flex; align-items: center; justify-content: space-between">
|
||||
<div>
|
||||
<el-button @click="openExternalLink('https://docs.vrchat.com/docs/configuration-file')">{{
|
||||
t('dialog.config_json.vrchat_docs')
|
||||
}}</el-button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
@click="openExternalLink('https://docs.vrchat.com/docs/configuration-file')"
|
||||
>{{ t('dialog.config_json.vrchat_docs') }}</Button
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<el-button @click="closeDialog">{{ t('dialog.config_json.cancel') }}</el-button>
|
||||
<el-button type="primary" :disabled="loading" @click="saveVRChatConfigFile">{{
|
||||
<Button variant="secondary" class="mr-2" @click="closeDialog">{{
|
||||
t('dialog.config_json.cancel')
|
||||
}}</Button>
|
||||
<Button :disabled="loading" @click="saveVRChatConfigFile">{{
|
||||
t('dialog.config_json.save')
|
||||
}}</el-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -170,9 +170,10 @@
|
||||
|
||||
<script setup>
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Delete, FolderDelete, FolderOpened, Refresh } from '@element-plus/icons-vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import { Refresh } from '@element-plus/icons-vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<template #header>
|
||||
<div class="dialog-title-container">
|
||||
<span>{{ t('dialog.group_calendar.header') }}</span>
|
||||
<el-button @click="toggleViewMode" type="primary" size="small" class="view-toggle-btn">
|
||||
<Button size="sm" variant="outline" @click="toggleViewMode" class="view-toggle-btn">
|
||||
{{
|
||||
viewMode === 'timeline'
|
||||
? t('dialog.group_calendar.list_view')
|
||||
: t('dialog.group_calendar.calendar_view')
|
||||
}}
|
||||
</el-button>
|
||||
</Button>
|
||||
</div>
|
||||
<div class="featured-switch">
|
||||
<span class="featured-switch-text">{{ t('dialog.group_calendar.featured_events') }}</span>
|
||||
@@ -126,6 +126,7 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { ArrowRight } from '@element-plus/icons-vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
</span>
|
||||
|
||||
<template v-if="errors">
|
||||
<el-button size="small" @click="errors = ''">
|
||||
<Button size="sm" variant="outline" @click="errors = ''">
|
||||
{{ t('dialog.note_export.clear_errors') }}
|
||||
</el-button>
|
||||
</Button>
|
||||
<h2 style="font-weight: bold; margin: 0">
|
||||
{{ t('dialog.note_export.errors') }}
|
||||
</h2>
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
<el-table-column :label="t('table.import.skip_export')" width="90" align="right">
|
||||
<template #default="{ row }">
|
||||
<el-button text :icon="Close" size="small" @click="removeFromNoteExportTable(row)"></el-button>
|
||||
<Button size="sm" variant="ghost" @click="removeFromNoteExportTable(row)"></Button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</DataTable>
|
||||
@@ -87,8 +87,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Close, Loading } from '@element-plus/icons-vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Loading } from '@element-plus/icons-vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
|
||||
@@ -16,37 +16,40 @@
|
||||
}}</span>
|
||||
<br />
|
||||
<br />
|
||||
<el-button size="small" :icon="FolderOpened" @click="getAndDisplayScreenshotFromFile">{{
|
||||
<Button size="sm" variant="outline" class="mr-2" @click="getAndDisplayScreenshotFromFile">{{
|
||||
t('dialog.screenshot_metadata.browse')
|
||||
}}</el-button>
|
||||
<el-button size="small" :icon="Picture" @click="getAndDisplayLastScreenshot">{{
|
||||
}}</Button>
|
||||
<Button size="sm" variant="outline" class="mr-2" @click="getAndDisplayLastScreenshot">{{
|
||||
t('dialog.screenshot_metadata.last_screenshot')
|
||||
}}</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="CopyDocument"
|
||||
}}</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
class="mr-2"
|
||||
@click="copyImageToClipboard(screenshotMetadataDialog.metadata.filePath)"
|
||||
>{{ t('dialog.screenshot_metadata.copy_image') }}</el-button
|
||||
>{{ t('dialog.screenshot_metadata.copy_image') }}</Button
|
||||
>
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Folder"
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
class="mr-2"
|
||||
@click="openImageFolder(screenshotMetadataDialog.metadata.filePath)"
|
||||
>{{ t('dialog.screenshot_metadata.open_folder') }}</el-button
|
||||
>{{ t('dialog.screenshot_metadata.open_folder') }}</Button
|
||||
>
|
||||
<el-button
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
class="mr-2"
|
||||
v-if="isLocalUserVrcPlusSupporter && screenshotMetadataDialog.metadata.filePath"
|
||||
size="small"
|
||||
:icon="Upload"
|
||||
@click="uploadScreenshotToGallery"
|
||||
>{{ t('dialog.screenshot_metadata.upload') }}</el-button
|
||||
>{{ t('dialog.screenshot_metadata.upload') }}</Button
|
||||
>
|
||||
<el-button
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
v-if="screenshotMetadataDialog.metadata.filePath"
|
||||
size="small"
|
||||
:icon="Delete"
|
||||
@click="deleteMetadata(screenshotMetadataDialog.metadata.filePath)"
|
||||
>{{ t('dialog.screenshot_metadata.delete_metadata') }}</el-button
|
||||
>{{ t('dialog.screenshot_metadata.delete_metadata') }}</Button
|
||||
>
|
||||
<br />
|
||||
<br />
|
||||
@@ -157,9 +160,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { CopyDocument, Delete, Folder, FolderOpened, Picture, Upload } from '@element-plus/icons-vue';
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
Reference in New Issue
Block a user