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