mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-18 22:33:50 +02:00
add search for userdialog tabs (#476)
This commit is contained in:
@@ -27,8 +27,8 @@
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<Input v-model="avatarSearchQuery" class="h-8 w-40 mr-2" placeholder="Search avatars" @click.stop />
|
||||
<template v-if="userDialog.ref.id === currentUser.id">
|
||||
<Input v-model="avatarSearchQuery" class="h-8 w-40 mr-2" placeholder="Search avatars" @click.stop />
|
||||
<span class="mr-1">{{ t('dialog.user.avatars.sort_by') }}</span>
|
||||
<Select
|
||||
:model-value="userDialog.avatarSorting"
|
||||
@@ -136,9 +136,6 @@
|
||||
const avatarSearchQuery = ref('');
|
||||
const filteredUserDialogAvatars = computed(() => {
|
||||
const avatars = userDialogAvatars.value;
|
||||
if (userDialog.value.ref?.id !== currentUser.value.id) {
|
||||
return avatars;
|
||||
}
|
||||
const query = avatarSearchQuery.value.trim().toLowerCase();
|
||||
if (!query) {
|
||||
return avatars;
|
||||
|
||||
@@ -14,7 +14,33 @@
|
||||
<DeprecationAlert
|
||||
v-if="userDialog.ref.id === currentUser.id"
|
||||
:feature-name="t('nav_tooltip.favorite_worlds')" />
|
||||
<Input v-model="searchQuery" class="h-8 w-40 mt-2" placeholder="Search worlds" @click.stop />
|
||||
<template v-if="searchActive">
|
||||
<div
|
||||
class="flex flex-wrap items-start"
|
||||
style="margin-top: 8px; min-height: 60px; max-height: 50vh; overflow: auto">
|
||||
<div
|
||||
v-for="world in allFilteredFavoriteWorlds"
|
||||
:key="world.favoriteId"
|
||||
class="box-border flex items-center p-1.5 text-[13px] cursor-pointer w-[167px] hover:rounded-[25px_5px_5px_25px]"
|
||||
@click="showWorldDialog(world.id)">
|
||||
<div class="relative inline-block flex-none size-9 mr-2.5">
|
||||
<Avatar class="size-9">
|
||||
<AvatarImage :src="world.thumbnailImageUrl" class="object-cover" />
|
||||
<AvatarFallback>
|
||||
<Image class="size-4 text-muted-foreground" />
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
<div class="flex-1 overflow-hidden">
|
||||
<span class="block truncate font-medium leading-[18px]" v-text="world.name"></span>
|
||||
<span v-if="world.occupants" class="block truncate text-xs">({{ world.occupants }})</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<TabsUnderline
|
||||
v-else
|
||||
v-model="favoriteWorldsTab"
|
||||
:items="favoriteWorldTabs"
|
||||
:unmount-on-hide="false"
|
||||
@@ -69,8 +95,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { Image } from 'lucide-vue-next';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { DataTableEmpty } from '@/components/ui/data-table';
|
||||
import { TabsUnderline } from '@/components/ui/tabs';
|
||||
@@ -99,6 +126,17 @@
|
||||
}))
|
||||
);
|
||||
|
||||
const searchQuery = ref('');
|
||||
const searchActive = computed(() => searchQuery.value.trim().length > 0);
|
||||
const allFilteredFavoriteWorlds = computed(() => {
|
||||
const query = searchQuery.value.trim().toLowerCase();
|
||||
if (!query) return [];
|
||||
const lists = userDialog.value.userFavoriteWorlds || [];
|
||||
const all = lists.flatMap((list) => list[2] || []);
|
||||
return all.filter((w) => (w.name || '').toLowerCase().includes(query));
|
||||
});
|
||||
watch(() => userDialog.value.id, () => { searchQuery.value = ''; });
|
||||
|
||||
/**
|
||||
*
|
||||
* @param visibility
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
</div>
|
||||
<div style="display: flex; align-items: center">
|
||||
<template v-if="!userDialogGroupEditMode">
|
||||
<Input v-model="groupSearchQuery" class="h-8 w-40 mr-2" placeholder="Search groups" @click.stop />
|
||||
<span style="margin-right: 6px">{{ t('dialog.user.groups.sort_by') }}</span>
|
||||
<Select
|
||||
:model-value="userDialogGroupSortingKey"
|
||||
@@ -236,6 +237,36 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="groupSearchActive">
|
||||
<div class="flex flex-wrap items-start" style="margin-top: 8px; min-height: 60px">
|
||||
<div
|
||||
v-for="group in allFilteredGroups"
|
||||
:key="group.id"
|
||||
class="box-border flex items-center p-1.5 text-[13px] cursor-pointer w-[167px] hover:rounded-[25px_5px_5px_25px]"
|
||||
@click="showGroupDialog(group.id)">
|
||||
<div class="relative inline-block flex-none size-9 mr-2.5">
|
||||
<Avatar class="size-9">
|
||||
<AvatarImage :src="group.iconUrl" class="object-cover" />
|
||||
<AvatarFallback>
|
||||
<Users class="size-4 text-muted-foreground" />
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
<div class="flex-1 overflow-hidden">
|
||||
<span class="block truncate font-medium leading-[18px]" v-text="group.name"></span>
|
||||
<div class="block truncate text-xs inline-flex! items-center">
|
||||
<TooltipWrapper
|
||||
v-if="group.isRepresenting"
|
||||
side="top"
|
||||
:content="t('dialog.group.members.representing')">
|
||||
<Tag style="margin-right: 6px" />
|
||||
</TooltipWrapper>
|
||||
<span>({{ group.memberCount }})</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="userDialog.userGroups.ownGroups.length > 0">
|
||||
<span class="text-base font-bold">{{ t('dialog.user.groups.own_groups') }}</span>
|
||||
@@ -384,9 +415,10 @@
|
||||
import { ArrowDown, ArrowUp, DownloadIcon, Eye, LogOut, RefreshCw, Tag, Users } from 'lucide-vue-next';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { nextTick, ref } from 'vue';
|
||||
import { computed, nextTick, ref, watch } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toast } from 'vue-sonner';
|
||||
@@ -426,6 +458,15 @@
|
||||
setUserDialogGroupSorting
|
||||
);
|
||||
|
||||
const groupSearchQuery = ref('');
|
||||
const groupSearchActive = computed(() => groupSearchQuery.value.trim().length > 0);
|
||||
const allFilteredGroups = computed(() => {
|
||||
const query = groupSearchQuery.value.trim().toLowerCase();
|
||||
if (!query) return [];
|
||||
return userDialog.value.userGroups.groups.filter((g) => (g.name || '').toLowerCase().includes(query));
|
||||
});
|
||||
watch(() => userDialog.value.id, () => { groupSearchQuery.value = ''; });
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sortOrder
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
}}</span>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center">
|
||||
<Input v-model="searchQuery" class="h-8 w-40 mr-2" placeholder="Search friends" @click.stop />
|
||||
<span style="margin-right: 6px">{{ t('dialog.user.groups.sort_by') }}</span>
|
||||
<Select
|
||||
:model-value="userDialogMutualFriendSortingKey"
|
||||
@@ -36,7 +37,7 @@
|
||||
</div>
|
||||
<ul class="flex flex-wrap items-start" style="margin-top: 8px; overflow: auto; max-height: 250px; min-width: 130px">
|
||||
<li
|
||||
v-for="user in userDialog.mutualFriends"
|
||||
v-for="user in filteredMutualFriends"
|
||||
:key="user.id"
|
||||
class="box-border flex items-center p-1.5 text-[13px] cursor-pointer w-[167px] hover:rounded-[25px_5px_5px_25px]"
|
||||
@click="showUserDialog(user.id)">
|
||||
@@ -64,6 +65,8 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { RefreshCw, User } from 'lucide-vue-next';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
@@ -89,6 +92,15 @@
|
||||
setUserDialogMutualFriendSorting
|
||||
);
|
||||
|
||||
const searchQuery = ref('');
|
||||
const filteredMutualFriends = computed(() => {
|
||||
const friends = userDialog.value.mutualFriends;
|
||||
const query = searchQuery.value.trim().toLowerCase();
|
||||
if (!query) return friends;
|
||||
return friends.filter((u) => (u.displayName || '').toLowerCase().includes(query));
|
||||
});
|
||||
watch(() => userDialog.value.id, () => { searchQuery.value = ''; });
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sortOrder
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
}}</span>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center">
|
||||
<Input v-model="searchQuery" class="h-8 w-40 mr-2" placeholder="Search worlds" @click.stop />
|
||||
<span class="mr-1">{{ t('dialog.user.worlds.sort_by') }}</span>
|
||||
<Select
|
||||
:model-value="userDialogWorldSortingKey"
|
||||
@@ -54,7 +55,7 @@
|
||||
<div class="flex flex-wrap items-start" style="margin-top: 8px; min-height: 60px">
|
||||
<template v-if="userDialog.worlds.length">
|
||||
<div
|
||||
v-for="world in userDialog.worlds"
|
||||
v-for="world in filteredWorlds"
|
||||
:key="world.id"
|
||||
class="box-border flex items-center p-1.5 text-[13px] cursor-pointer w-[167px] hover:rounded-[25px_5px_5px_25px]"
|
||||
@click="showWorldDialog(world.id)">
|
||||
@@ -87,7 +88,8 @@
|
||||
import { Image, RefreshCw } from 'lucide-vue-next';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { ref } from 'vue';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
@@ -105,6 +107,15 @@
|
||||
|
||||
const userDialogWorldsRequestId = ref(0);
|
||||
|
||||
const searchQuery = ref('');
|
||||
const filteredWorlds = computed(() => {
|
||||
const worlds = userDialog.value.worlds;
|
||||
const query = searchQuery.value.trim().toLowerCase();
|
||||
if (!query) return worlds;
|
||||
return worlds.filter((w) => (w.name || '').toLowerCase().includes(query));
|
||||
});
|
||||
watch(() => userDialog.value.id, () => { searchQuery.value = ''; });
|
||||
|
||||
/**
|
||||
*
|
||||
* @param userId
|
||||
|
||||
Reference in New Issue
Block a user