diff --git a/apps/frontend/src/pages/discover/[type]/index.vue b/apps/frontend/src/pages/discover/[type]/index.vue index 438b539a3..25fee7a0a 100644 --- a/apps/frontend/src/pages/discover/[type]/index.vue +++ b/apps/frontend/src/pages/discover/[type]/index.vue @@ -36,6 +36,7 @@ import { StyledInput, useDebugLogger, useSearch, + useServerSearch, useVIntl, } from '@modrinth/ui' import { capitalizeString, cycleValue } from '@modrinth/utils' @@ -87,17 +88,17 @@ const handleProjectMouseEnter = (result: Labrinth.Search.v2.ResultSearchProject) prefetchTimeout.start() } -const _handleServerProjectMouseEnter = (result: Labrinth.Search.v3.ResultSearchProject) => { +const handleServerProjectMouseEnter = (result: Labrinth.Search.v3.ResultSearchProject) => { const slug = result.slug || result.project_id prefetchTimeout = useTimeoutFn( async () => { - queryClient.prefetchQuery(projectQueryOptions.v2(slug, modrinthClient)) - queryClient.prefetchQuery(projectQueryOptions.v3(slug, modrinthClient)) + queryClient.prefetchQuery(projectQueryOptions.v2(slug, client)) + queryClient.prefetchQuery(projectQueryOptions.v3(slug, client)) const content = result.minecraft_java_server?.content if (content?.kind === 'modpack' && content.version_id) { - queryClient.prefetchQuery(versionQueryOptions.v3(content.version_id, modrinthClient)) + queryClient.prefetchQuery(versionQueryOptions.v3(content.version_id, client)) } }, HOVER_DURATION_TO_PREFETCH_MS, @@ -114,6 +115,8 @@ const currentType = computed(() => queryAsStringOrEmpty(route.params.type).replaceAll(/^\/|s\/?$/g, ''), ) +const isServerType = computed(() => currentType.value === 'server') + const projectType = computed(() => tags.value.projectTypes.find((x) => x.id === currentType.value)) const projectTypes = computed(() => (projectType.value ? [projectType.value.id] : [])) @@ -330,6 +333,36 @@ const { } = useSearch(projectTypes, tags, serverFilters) debug('useSearch initialized, requestParams:', requestParams.value) +const { + serverCurrentSortType, + serverCurrentFilters, + serverToggledGroups, + serverSortTypes, + serverFilterTypes, + serverRequestParams, + createServerPageParams, +} = useServerSearch({ tags, query, maxResults, currentPage }) + +const effectiveRequestParams = computed(() => + isServerType.value ? serverRequestParams.value : requestParams.value, +) +const effectiveSortTypes = computed(() => + isServerType.value ? (serverSortTypes as readonly SortType[]) : sortTypes, +) +const effectiveCurrentSortType = computed({ + get: () => (isServerType.value ? serverCurrentSortType.value : currentSortType.value), + set: (v: SortType) => { + if (isServerType.value) serverCurrentSortType.value = v + else currentSortType.value = v + }, +}) +const effectiveCurrentFilters = computed({ + get: () => (isServerType.value ? serverCurrentFilters.value : currentFilters.value), + set: (v) => { + if (isServerType.value) serverCurrentFilters.value = v + else currentFilters.value = v + }, +}) const selectedFilterTags = computed(() => currentFilters.value .filter( @@ -458,6 +491,22 @@ async function serverInstall(project: InstallableSearchResult) { project.installing = false } +function getServerModpackContent(project: Labrinth.Search.v3.ResultSearchProject) { + const content = project.minecraft_java_server?.content + if (content?.kind === 'modpack') { + const { project_name, project_icon, project_id } = content + if (!project_name) return undefined + return { + name: project_name, + icon: project_icon, + onclick: + project_id !== project.project_id ? () => navigateTo(`/project/${project_id}`) : undefined, + showCustomModpackTooltip: project_id === project.project_id, + } + } + return undefined +} + const noLoad = ref(false) const { data: rawResults, @@ -466,19 +515,31 @@ const { } = useLazyFetch( () => { const config = useRuntimeConfig() - const base = import.meta.server ? config.apiBaseUrl : config.public.apiBaseUrl + let base = import.meta.server ? config.apiBaseUrl : config.public.apiBaseUrl - const url = `${base}search${requestParams.value}` - debug('useLazyFetch URL:', url) - return url + if (currentType.value === 'server') { + base = base.replace(/\/v\d\//, '/v3/').replace(/\/v\d$/, '/v3') + } + + return `${base}search${effectiveRequestParams.value}` }, { headers: computed(() => withLabrinthCanaryHeader()), + watch: false, - transform: (hits) => { - debug('useLazyFetch transform, hits:', (hits as any)?.total_hits) + transform: ( + hits: Labrinth.Search.v2.SearchResults | Labrinth.Search.v3.SearchResults, + ): Labrinth.Search.v2.SearchResults => { noLoad.value = false - return hits as Labrinth.Search.v2.SearchResults + if ('hits_per_page' in hits) { + return { + hits: hits.hits as unknown as Labrinth.Search.v2.ResultSearchProject[], + total_hits: hits.total_hits, + limit: hits.hits_per_page, + offset: (hits.page - 1) * hits.hits_per_page, + } + } + return hits }, }, ) @@ -487,9 +548,18 @@ watch(searchLoading, (val) => debug('searchLoading:', val)) watch(rawResults, (val) => debug('rawResults changed, total_hits:', val?.total_hits)) const results = computed(() => rawResults.value) -const pageCount = computed(() => - results.value ? Math.ceil(results.value.total_hits / results.value.limit) : 1, +const serverResults = computed(() => + isServerType.value ? (results.value as Labrinth.Search.v3.SearchResults | null) : null, ) +const projectResults = computed(() => + isServerType.value ? null : (results.value as Labrinth.Search.v2.SearchResults | null), +) +const pageCount = computed(() => { + if (!results.value) return 1 + // @ts-expect-error + const perPage = 'limit' in results.value ? results.value.limit : results.value.hits_per_page + return Math.ceil(results.value.total_hits / perPage) +}) function scrollToTop(behavior: ScrollBehavior = 'smooth') { window.scrollTo({ top: 0, behavior }) @@ -535,14 +605,14 @@ function updateSearchResults(pageNumber: number = 1, resetScroll = true) { const params = { ...persistentParams, - ...createPageParams(), + ...(isServerType.value ? createServerPageParams() : createPageParams()), } router.replace({ path: route.path, query: params }) } } -watch([currentFilters], () => { +watch([effectiveCurrentFilters], () => { updateSearchResults(1, false) }) @@ -734,41 +804,73 @@ useSeoMeta({ @update:model-value="updateSearchResults()" /> - - - - - - - + +
@@ -788,10 +890,10 @@ useSeoMeta({
@@ -837,6 +939,14 @@ useSeoMeta({ />
+ -