mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-05 22:36:05 +02:00
feat: add quick search
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
import {
|
||||
searchAvatars,
|
||||
searchFavoriteAvatars,
|
||||
searchFavoriteWorlds,
|
||||
searchFriends,
|
||||
searchGroups,
|
||||
searchWorlds
|
||||
} from '../shared/utils/globalSearchUtils';
|
||||
import { useAvatarStore } from './avatar';
|
||||
import { useFavoriteStore } from './favorite';
|
||||
import { useFriendStore } from './friend';
|
||||
import { useGroupStore } from './group';
|
||||
import { useUserStore } from './user';
|
||||
import { useWorldStore } from './world';
|
||||
|
||||
export const useGlobalSearchStore = defineStore('GlobalSearch', () => {
|
||||
const friendStore = useFriendStore();
|
||||
const favoriteStore = useFavoriteStore();
|
||||
const avatarStore = useAvatarStore();
|
||||
const worldStore = useWorldStore();
|
||||
const groupStore = useGroupStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const isOpen = ref(false);
|
||||
const query = ref('');
|
||||
|
||||
const stringComparer = computed(
|
||||
() =>
|
||||
new Intl.Collator(undefined, {
|
||||
usage: 'search',
|
||||
sensitivity: 'base'
|
||||
})
|
||||
);
|
||||
|
||||
// Reset query when dialog closes
|
||||
watch(isOpen, (open) => {
|
||||
if (!open) {
|
||||
query.value = '';
|
||||
}
|
||||
});
|
||||
|
||||
const currentUserId = computed(() => userStore.currentUser?.id);
|
||||
|
||||
const friendResults = computed(() => {
|
||||
if (!query.value || query.value.length < 2) return [];
|
||||
return searchFriends(
|
||||
query.value,
|
||||
friendStore.friends,
|
||||
stringComparer.value
|
||||
);
|
||||
});
|
||||
|
||||
// Own avatars (filter cachedAvatars by authorId)
|
||||
const ownAvatarResults = computed(() => {
|
||||
if (!query.value || query.value.length < 2) return [];
|
||||
return searchAvatars(
|
||||
query.value,
|
||||
avatarStore.cachedAvatars,
|
||||
stringComparer.value,
|
||||
currentUserId.value
|
||||
);
|
||||
});
|
||||
|
||||
// Favorite avatars (from favoriteStore, deduplicated against own)
|
||||
const favoriteAvatarResults = computed(() => {
|
||||
if (!query.value || query.value.length < 2) return [];
|
||||
const favResults = searchFavoriteAvatars(
|
||||
query.value,
|
||||
favoriteStore.favoriteAvatars,
|
||||
stringComparer.value
|
||||
);
|
||||
// Deduplicate: remove items already in ownAvatarResults
|
||||
const ownIds = new Set(ownAvatarResults.value.map((r) => r.id));
|
||||
return favResults.filter((r) => !ownIds.has(r.id));
|
||||
});
|
||||
|
||||
// Own worlds (filter cachedWorlds by authorId)
|
||||
const ownWorldResults = computed(() => {
|
||||
if (!query.value || query.value.length < 2) return [];
|
||||
return searchWorlds(
|
||||
query.value,
|
||||
worldStore.cachedWorlds,
|
||||
stringComparer.value,
|
||||
currentUserId.value
|
||||
);
|
||||
});
|
||||
|
||||
// Favorite worlds (from favoriteStore, deduplicated against own)
|
||||
const favoriteWorldResults = computed(() => {
|
||||
if (!query.value || query.value.length < 2) return [];
|
||||
const favResults = searchFavoriteWorlds(
|
||||
query.value,
|
||||
favoriteStore.favoriteWorlds,
|
||||
stringComparer.value
|
||||
);
|
||||
// Deduplicate: remove items already in ownWorldResults
|
||||
const ownIds = new Set(ownWorldResults.value.map((r) => r.id));
|
||||
return favResults.filter((r) => !ownIds.has(r.id));
|
||||
});
|
||||
|
||||
// Own groups (filter by ownerId === currentUser)
|
||||
const ownGroupResults = computed(() => {
|
||||
if (!query.value || query.value.length < 2) return [];
|
||||
return searchGroups(
|
||||
query.value,
|
||||
groupStore.currentUserGroups,
|
||||
stringComparer.value,
|
||||
currentUserId.value
|
||||
);
|
||||
});
|
||||
|
||||
// Joined groups (all matching groups, deduplicated against own)
|
||||
const joinedGroupResults = computed(() => {
|
||||
if (!query.value || query.value.length < 2) return [];
|
||||
const allResults = searchGroups(
|
||||
query.value,
|
||||
groupStore.currentUserGroups,
|
||||
stringComparer.value
|
||||
);
|
||||
const ownIds = new Set(ownGroupResults.value.map((r) => r.id));
|
||||
return allResults.filter((r) => !ownIds.has(r.id));
|
||||
});
|
||||
|
||||
const hasResults = computed(
|
||||
() =>
|
||||
friendResults.value.length > 0 ||
|
||||
ownAvatarResults.value.length > 0 ||
|
||||
favoriteAvatarResults.value.length > 0 ||
|
||||
ownWorldResults.value.length > 0 ||
|
||||
favoriteWorldResults.value.length > 0 ||
|
||||
ownGroupResults.value.length > 0 ||
|
||||
joinedGroupResults.value.length > 0
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function open() {
|
||||
isOpen.value = true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function close() {
|
||||
isOpen.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{id: string, type: string}} item
|
||||
*/
|
||||
function selectResult(item) {
|
||||
if (!item) return;
|
||||
|
||||
close();
|
||||
|
||||
switch (item.type) {
|
||||
case 'friend':
|
||||
userStore.showUserDialog(item.id);
|
||||
break;
|
||||
case 'avatar':
|
||||
avatarStore.showAvatarDialog(item.id);
|
||||
break;
|
||||
case 'world':
|
||||
worldStore.showWorldDialog(item.id);
|
||||
break;
|
||||
case 'group':
|
||||
groupStore.showGroupDialog(item.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isOpen,
|
||||
query,
|
||||
friendResults,
|
||||
ownAvatarResults,
|
||||
favoriteAvatarResults,
|
||||
ownWorldResults,
|
||||
favoriteWorldResults,
|
||||
ownGroupResults,
|
||||
joinedGroupResults,
|
||||
hasResults,
|
||||
|
||||
open,
|
||||
close,
|
||||
selectResult
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user