mirror of
https://github.com/vrcx-team/VRCX.git
synced 2026-04-06 00:32:02 +02:00
feat: Add favorites world search by tag (#1275)
This commit is contained in:
@@ -315,6 +315,9 @@
|
||||
"favorite": {
|
||||
"worlds": {
|
||||
"search": "Search",
|
||||
"search_by_tag": "Search by Tag",
|
||||
"search_mode_name": "Name",
|
||||
"search_mode_tag": "Tag",
|
||||
"vrchat_favorites": "VRChat Favorites",
|
||||
"local_favorites": "Local Favorites",
|
||||
"new_group": "New Group",
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
:sort-value="worldSortValue"
|
||||
:extra-sort-options="worldExtraSortOptions"
|
||||
v-model:search-query="worldFavoriteSearch"
|
||||
:search-placeholder="t('view.favorite.worlds.search')"
|
||||
:search-placeholder="worldSearchPlaceholder"
|
||||
v-model:search-mode="worldSearchMode"
|
||||
:search-mode-visible="true"
|
||||
v-model:toolbar-menu-open="worldToolbarMenuOpen"
|
||||
v-model:card-scale-value="worldCardScaleValue"
|
||||
:card-scale-percent="worldCardScalePercent"
|
||||
@@ -502,6 +504,13 @@
|
||||
const worldEditMode = ref(false);
|
||||
const worldToolbarMenuOpen = ref(false);
|
||||
const worldSortMode = ref('none');
|
||||
const worldSearchMode = ref('name');
|
||||
|
||||
const worldSearchPlaceholder = computed(() =>
|
||||
worldSearchMode.value === 'tag'
|
||||
? t('view.favorite.worlds.search_by_tag')
|
||||
: t('view.favorite.worlds.search')
|
||||
);
|
||||
|
||||
const worldExtraSortOptions = computed(() => [
|
||||
{ value: 'players', label: t('view.settings.appearance.appearance.sort_favorite_by_players') }
|
||||
@@ -745,6 +754,12 @@
|
||||
}
|
||||
});
|
||||
|
||||
watch(worldSearchMode, () => {
|
||||
if (isSearchActive.value) {
|
||||
doSearchWorldFavorites();
|
||||
}
|
||||
});
|
||||
|
||||
watch([currentLocalFavorites, worldCardScale, worldCardSpacing, activeLocalGroupName], () => {
|
||||
nextTick(() => {
|
||||
localVirtualizer.value?.measure?.();
|
||||
@@ -1000,16 +1015,25 @@
|
||||
*
|
||||
* @param worldFavoriteSearch
|
||||
*/
|
||||
function doSearchWorldFavorites(worldFavoriteSearch) {
|
||||
const search = worldFavoriteSearch.trim().toLowerCase();
|
||||
function doSearchWorldFavorites(searchInput) {
|
||||
const search = (searchInput ?? worldFavoriteSearch.value).trim().toLowerCase();
|
||||
if (search.length < 3) {
|
||||
worldFavoriteSearchResults.value = [];
|
||||
return;
|
||||
}
|
||||
const isTagMode = worldSearchMode.value === 'tag';
|
||||
const filtered = searchableWorldEntries.value.filter((ref) => {
|
||||
if (!ref || typeof ref.id === 'undefined' || typeof ref.name === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
if (isTagMode) {
|
||||
if (Array.isArray(ref.tags)) {
|
||||
return ref.tags.some(
|
||||
(tag) => tag.startsWith('author_tag_') && tag.substring(11).toLowerCase().includes(search)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const authorName = ref.authorName || '';
|
||||
return ref.name.toLowerCase().includes(search) || authorName.toLowerCase().includes(search);
|
||||
});
|
||||
|
||||
@@ -37,7 +37,24 @@
|
||||
class="flex-1"
|
||||
:placeholder="searchPlaceholder"
|
||||
@update:modelValue="$emit('update:searchQuery', $event)"
|
||||
@input="$emit('search')" />
|
||||
@input="$emit('search')">
|
||||
<template v-if="searchModeVisible" #trailing>
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
:model-value="searchMode"
|
||||
variant="outline"
|
||||
size="xs"
|
||||
class="mr-0.5"
|
||||
@update:modelValue="$emit('update:searchMode', $event)">
|
||||
<ToggleGroupItem value="name" class="h-5! px-1.5! text-[11px]">
|
||||
{{ t('view.favorite.worlds.search_mode_name') }}
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="tag" class="h-5! px-1.5! text-[11px]">
|
||||
{{ t('view.favorite.worlds.search_mode_tag') }}
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</template>
|
||||
</InputGroupSearch>
|
||||
<DropdownMenu :open="toolbarMenuOpen" @update:open="$emit('update:toolbarMenuOpen', $event)">
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button class="rounded-full" size="icon-sm" variant="ghost"><Ellipsis /></Button>
|
||||
@@ -91,6 +108,7 @@
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
||||
import { ArrowUpDown, Ellipsis } from 'lucide-vue-next';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { InputGroupSearch } from '@/components/ui/input-group';
|
||||
@@ -102,6 +120,8 @@
|
||||
extraSortOptions: { type: Array, default: () => [] },
|
||||
searchQuery: { type: String, default: '' },
|
||||
searchPlaceholder: { type: String, default: '' },
|
||||
searchMode: { type: String, default: 'name' },
|
||||
searchModeVisible: { type: Boolean, default: false },
|
||||
toolbarMenuOpen: { type: Boolean, default: false },
|
||||
cardScaleValue: { type: Array, default: () => [50] },
|
||||
cardScalePercent: { type: Number, default: 100 },
|
||||
@@ -114,6 +134,7 @@
|
||||
defineEmits([
|
||||
'update:sortValue',
|
||||
'update:searchQuery',
|
||||
'update:searchMode',
|
||||
'update:toolbarMenuOpen',
|
||||
'update:cardScaleValue',
|
||||
'update:cardSpacingValue',
|
||||
|
||||
Reference in New Issue
Block a user