Files
VRCX/src/views/Favorites/Favorites.vue
T
2025-10-26 18:48:39 +11:00

229 lines
8.0 KiB
Vue

<template>
<div class="x-container">
<div class="header">
<div v-if="editFavoritesMode" style="display: inline-block; margin-right: 10px">
<el-button size="small" @click="clearBulkFavoriteSelection">{{ t('view.favorite.clear') }}</el-button>
<el-button size="small" @click="handleBulkCopyFavoriteSelection">{{
t('view.favorite.copy')
}}</el-button>
<el-button size="small" @click="showBulkUnfavoriteSelectionConfirm">{{
t('view.favorite.bulk_unfavorite')
}}</el-button>
</div>
<div style="display: flex; align-items: center; margin-right: 10px">
<span class="name">{{ t('view.favorite.edit_mode') }}</span>
<el-switch v-model="editFavoritesMode" style="margin-left: 5px"></el-switch>
</div>
<el-tooltip placement="bottom" :content="t('view.favorite.refresh_favorites_tooltip')" :teleported="false">
<el-button
type="default"
:loading="isFavoriteLoading"
size="small"
:icon="Refresh"
circle
@click="
refreshFavorites();
getLocalWorldFavorites();
"></el-button>
</el-tooltip>
</div>
<el-tabs v-model="currentFavoriteTab" v-loading="isFavoriteLoading" type="card" style="height: 100%">
<el-tab-pane name="friend" :label="t('view.favorite.friends.header')">
<FavoritesFriendTab
:edit-favorites-mode="editFavoritesMode"
@change-favorite-group-name="changeFavoriteGroupName" />
</el-tab-pane>
<el-tab-pane name="world" :label="t('view.favorite.worlds.header')" lazy>
<FavoritesWorldTab
:edit-favorites-mode="editFavoritesMode"
@change-favorite-group-name="changeFavoriteGroupName" />
</el-tab-pane>
<el-tab-pane name="avatar" :label="t('view.favorite.avatars.header')" lazy>
<FavoritesAvatarTab
:edit-favorites-mode="editFavoritesMode"
@change-favorite-group-name="changeFavoriteGroupName" />
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup>
import { ElMessage, ElMessageBox } from 'element-plus';
import { Refresh } from '@element-plus/icons-vue';
import { ref } from 'vue';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import { favoriteRequest } from '../../api';
import { useFavoriteStore } from '../../stores';
import FavoritesAvatarTab from './components/FavoritesAvatarTab.vue';
import FavoritesFriendTab from './components/FavoritesFriendTab.vue';
import FavoritesWorldTab from './components/FavoritesWorldTab.vue';
const { t } = useI18n();
const {
favoriteFriends,
favoriteWorlds,
favoriteAvatars,
isFavoriteLoading,
avatarImportDialogInput,
worldImportDialogInput,
friendImportDialogInput,
currentFavoriteTab
} = storeToRefs(useFavoriteStore());
const {
refreshFavorites,
refreshFavoriteGroups,
clearBulkFavoriteSelection,
getLocalWorldFavorites,
handleFavoriteGroup,
showFriendImportDialog,
showWorldImportDialog,
showAvatarImportDialog
} = useFavoriteStore();
const editFavoritesMode = ref(false);
function showBulkUnfavoriteSelectionConfirm() {
const elementsTicked = [];
// check favorites type
for (const ctx of favoriteFriends.value) {
if (ctx.$selected) {
elementsTicked.push(ctx.id);
}
}
for (const ctx of favoriteWorlds.value) {
if (ctx.$selected) {
elementsTicked.push(ctx.id);
}
}
for (const ctx of favoriteAvatars.value) {
if (ctx.$selected) {
elementsTicked.push(ctx.id);
}
}
if (elementsTicked.length === 0) {
return;
}
ElMessageBox.confirm(
`Are you sure you want to unfavorite ${elementsTicked.length} favorites?
This action cannot be undone.`,
`Delete ${elementsTicked.length} favorites?`,
{
confirmButtonText: 'Confirm',
cancelButtonText: 'Cancel',
type: 'info'
}
)
.then((action) => {
if (action === 'confirm') {
bulkUnfavoriteSelection(elementsTicked);
}
})
.catch(() => {});
}
function bulkUnfavoriteSelection(elementsTicked) {
for (const id of elementsTicked) {
favoriteRequest.deleteFavorite({
objectId: id
});
}
editFavoritesMode.value = false;
}
function changeFavoriteGroupName(ctx) {
ElMessageBox.prompt(
t('prompt.change_favorite_group_name.description'),
t('prompt.change_favorite_group_name.header'),
{
distinguishCancelAndClose: true,
cancelButtonText: t('prompt.change_favorite_group_name.cancel'),
confirmButtonText: t('prompt.change_favorite_group_name.change'),
inputPlaceholder: t('prompt.change_favorite_group_name.input_placeholder'),
inputValue: ctx.displayName,
inputPattern: /\S+/,
inputErrorMessage: t('prompt.change_favorite_group_name.input_error')
}
)
.then(({ value }) => {
favoriteRequest
.saveFavoriteGroup({
type: ctx.type,
group: ctx.name,
displayName: value
})
.then((args) => {
handleFavoriteGroup({
json: args.json,
params: {
favoriteGroupId: args.json.id
}
});
ElMessage({
message: t('prompt.change_favorite_group_name.message.success'),
type: 'success'
});
// load new group name
refreshFavoriteGroups();
});
})
.catch(() => {});
}
function handleBulkCopyFavoriteSelection() {
let idList = '';
switch (currentFavoriteTab.value) {
case 'friend':
for (const ctx of favoriteFriends.value) {
if (ctx.$selected) {
idList += `${ctx.id}\n`;
}
}
friendImportDialogInput.value = idList;
showFriendImportDialog();
break;
case 'world':
for (const ctx of favoriteWorlds.value) {
if (ctx.$selected) {
idList += `${ctx.id}\n`;
}
}
worldImportDialogInput.value = idList;
showWorldImportDialog();
break;
case 'avatar':
for (const ctx of favoriteAvatars.value) {
if (ctx.$selected) {
idList += `${ctx.id}\n`;
}
}
avatarImportDialogInput.value = idList;
showAvatarImportDialog();
break;
default:
break;
}
console.log('Favorite selection\n', idList);
}
</script>
<style scoped>
.header {
font-size: 13px;
position: absolute;
display: flex;
align-items: center;
right: 0;
z-index: 1;
margin-right: 15px;
}
</style>