diff --git a/src/localization/en.json b/src/localization/en.json index 08bfd0a1..d3c52111 100644 --- a/src/localization/en.json +++ b/src/localization/en.json @@ -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", diff --git a/src/views/Favorites/FavoritesWorld.vue b/src/views/Favorites/FavoritesWorld.vue index 0fe6bf3c..075643d0 100644 --- a/src/views/Favorites/FavoritesWorld.vue +++ b/src/views/Favorites/FavoritesWorld.vue @@ -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); }); diff --git a/src/views/Favorites/components/FavoritesToolbar.vue b/src/views/Favorites/components/FavoritesToolbar.vue index 29cccdca..c7252960 100644 --- a/src/views/Favorites/components/FavoritesToolbar.vue +++ b/src/views/Favorites/components/FavoritesToolbar.vue @@ -37,7 +37,24 @@ class="flex-1" :placeholder="searchPlaceholder" @update:modelValue="$emit('update:searchQuery', $event)" - @input="$emit('search')" /> + @input="$emit('search')"> + + @@ -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',