mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 21:26:40 +00:00
fix: make search use v3 everywhere
This commit is contained in:
@@ -27,14 +27,14 @@ interface BrowseServerInstance {
|
||||
interface ContextMenuHandle {
|
||||
showMenu: (
|
||||
event: MouseEvent,
|
||||
result: Labrinth.Search.v2.ResultSearchProject | Labrinth.Search.v3.ResultSearchProject,
|
||||
result: Labrinth.Search.v3.ResultSearchProject,
|
||||
options: { name: string }[],
|
||||
) => void
|
||||
}
|
||||
|
||||
interface ContextMenuOptionClick {
|
||||
option: 'open_link' | 'copy_link'
|
||||
item: Labrinth.Search.v2.ResultSearchProject | Labrinth.Search.v3.ResultSearchProject
|
||||
item: Labrinth.Search.v3.ResultSearchProject
|
||||
}
|
||||
|
||||
export interface UseAppServerBrowseOptions {
|
||||
@@ -263,10 +263,7 @@ export function useAppServerBrowse(options: UseAppServerBrowseOptions) {
|
||||
return actions
|
||||
}
|
||||
|
||||
function handleRightClick(
|
||||
event: MouseEvent,
|
||||
result: Labrinth.Search.v2.ResultSearchProject | Labrinth.Search.v3.ResultSearchProject,
|
||||
) {
|
||||
function handleRightClick(event: MouseEvent, result: Labrinth.Search.v3.ResultSearchProject) {
|
||||
contextMenuRef.value?.showMenu(event, result, [{ name: 'open_link' }, { name: 'copy_link' }])
|
||||
}
|
||||
|
||||
@@ -315,9 +312,7 @@ export function useAppServerBrowse(options: UseAppServerBrowseOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
function getProjectUrl(
|
||||
item: Labrinth.Search.v2.ResultSearchProject | Labrinth.Search.v3.ResultSearchProject,
|
||||
) {
|
||||
const projectType = 'project_types' in item ? item.project_types?.[0] : item.project_type
|
||||
function getProjectUrl(item: Labrinth.Search.v3.ResultSearchProject) {
|
||||
const projectType = item.project_types?.[0]
|
||||
return `https://modrinth.com/${projectType ?? 'project'}/${item.slug ?? item.project_id}`
|
||||
}
|
||||
|
||||
@@ -670,7 +670,7 @@ async function getInstallProjectVersions(projectId: string) {
|
||||
}
|
||||
|
||||
async function chooseInstanceInstallVersion(
|
||||
project: Labrinth.Search.v2.ResultSearchProject & Labrinth.Search.v3.ResultSearchProject,
|
||||
project: Labrinth.Search.v3.ResultSearchProject,
|
||||
projectTypeValue: string,
|
||||
) {
|
||||
const targetInstance = instance.value
|
||||
@@ -697,16 +697,14 @@ async function chooseInstanceInstallVersion(
|
||||
}
|
||||
|
||||
function getCardActions(
|
||||
result: Labrinth.Search.v2.ResultSearchProject | Labrinth.Search.v3.ResultSearchProject,
|
||||
result: Labrinth.Search.v3.ResultSearchProject,
|
||||
currentProjectType: string,
|
||||
): CardAction[] {
|
||||
if (currentProjectType === 'server') {
|
||||
return getServerCardActions(result as Labrinth.Search.v3.ResultSearchProject)
|
||||
return getServerCardActions(result)
|
||||
}
|
||||
|
||||
// Non-server project actions
|
||||
const projectResult = result as (Labrinth.Search.v2.ResultSearchProject &
|
||||
Labrinth.Search.v3.ResultSearchProject) & {
|
||||
const projectResult = result as Labrinth.Search.v3.ResultSearchProject & {
|
||||
installed?: boolean
|
||||
installing?: boolean
|
||||
}
|
||||
@@ -917,11 +915,9 @@ async function search(requestParams: string) {
|
||||
}
|
||||
|
||||
const hits = rawResults.result.hits.map((hit) => {
|
||||
const mapped = {
|
||||
const mapped: Labrinth.Search.v3.ResultSearchProject & { installed?: boolean } = {
|
||||
...hit,
|
||||
title: hit.name,
|
||||
description: hit.summary,
|
||||
} as unknown as Labrinth.Search.v2.ResultSearchProject & { installed?: boolean }
|
||||
}
|
||||
|
||||
if (instance.value || isServerContext.value) {
|
||||
const installedIds = instance.value
|
||||
@@ -1068,7 +1064,7 @@ provideBrowseManager({
|
||||
projectType,
|
||||
...searchState,
|
||||
advancedFiltersCollapsed,
|
||||
getProjectLink: (result: Labrinth.Search.v2.ResultSearchProject) => ({
|
||||
getProjectLink: (result: Labrinth.Search.v3.ResultSearchProject) => ({
|
||||
path: `/project/${result.project_id ?? result.slug}`,
|
||||
query: getProjectBrowseQuery(),
|
||||
}),
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
getStoredServerAddonInstallQueue,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
type ModpackSearchResult,
|
||||
type PendingServerContentInstall,
|
||||
type PendingServerContentInstallType,
|
||||
readPendingServerContentInstalls,
|
||||
@@ -24,7 +25,6 @@ import { useRoute, useRouter } from 'vue-router'
|
||||
type ServerFlowFrom = 'onboarding' | 'reset-server'
|
||||
|
||||
type InstallableSearchResult = Labrinth.Search.v3.ResultSearchProject & {
|
||||
title?: string
|
||||
installing?: boolean
|
||||
installed?: boolean
|
||||
}
|
||||
@@ -69,10 +69,7 @@ export interface ServerInstallContentContext {
|
||||
installQueuedServerInstallsAndBack: () => Promise<boolean>
|
||||
initServerContext: () => Promise<void>
|
||||
watchServerContextChanges: () => void
|
||||
searchServerModpacks: (
|
||||
query: string,
|
||||
limit?: number,
|
||||
) => Promise<Labrinth.Projects.v2.SearchResult>
|
||||
searchServerModpacks: (query: string, limit?: number) => Promise<ModpackSearchResult>
|
||||
getServerProjectVersions: (projectId: string) => Promise<{ id: string }[]>
|
||||
enforceSetupModpackRoute: (currentProjectType: string | undefined) => void
|
||||
getQueuedServerInstallPlans: () => Map<string, BrowseInstallPlan<InstallableSearchResult>>
|
||||
@@ -172,7 +169,7 @@ function getQueuedInstallPlaceholder(
|
||||
projectId: plan.projectId,
|
||||
versionId: plan.versionId,
|
||||
contentType: plan.contentType as PendingServerContentInstallType,
|
||||
title: project.title ?? project.name ?? 'Project',
|
||||
title: project.name ?? 'Project',
|
||||
versionName: plan.versionName ?? null,
|
||||
versionNumber: plan.versionNumber ?? null,
|
||||
fileName: plan.fileName ?? null,
|
||||
@@ -236,7 +233,7 @@ export function createServerInstallContent(opts: {
|
||||
const selectedServerInstallProjects = computed<BrowseSelectedProject[]>(() =>
|
||||
Array.from(queuedServerInstalls.value.values()).map((plan) => ({
|
||||
id: plan.projectId,
|
||||
name: plan.project.title ?? plan.project.name ?? 'Project',
|
||||
name: plan.project.name ?? 'Project',
|
||||
iconUrl: plan.project.icon_url ?? null,
|
||||
})),
|
||||
)
|
||||
@@ -359,12 +356,24 @@ export function createServerInstallContent(opts: {
|
||||
}
|
||||
|
||||
async function searchServerModpacks(query: string, limit: number = 10) {
|
||||
return client.labrinth.projects_v2.search({
|
||||
const results = await client.labrinth.projects_v3.search({
|
||||
query: query || undefined,
|
||||
new_filters:
|
||||
'project_types = "modpack" AND (client_side = "optional" OR client_side = "required") AND server_side = "required"',
|
||||
'project_types = "modpack" AND environment IN ["client_and_server", "server_only_client_optional"]',
|
||||
limit,
|
||||
})
|
||||
|
||||
return {
|
||||
hits: results.hits.map((hit) => ({
|
||||
project_id: hit.project_id,
|
||||
title: hit.name,
|
||||
icon_url: hit.icon_url ?? '',
|
||||
latest_version: hit.version_id,
|
||||
})),
|
||||
total_hits: results.total_hits,
|
||||
offset: (results.page - 1) * results.hits_per_page,
|
||||
limit: results.hits_per_page,
|
||||
}
|
||||
}
|
||||
|
||||
async function getServerProjectVersions(projectId: string) {
|
||||
|
||||
@@ -51,7 +51,7 @@ export interface ServerInstallModalHandle {
|
||||
ctx?: CreationFlowContextValue | null
|
||||
}
|
||||
|
||||
export interface ServerInstallSearchResult extends Labrinth.Search.v2.ResultSearchProject {
|
||||
export interface ServerInstallSearchResult extends Labrinth.Search.v3.ResultSearchProject {
|
||||
installed?: boolean
|
||||
}
|
||||
|
||||
@@ -128,6 +128,11 @@ export function useServerInstallContent({
|
||||
const { handleError } = injectNotificationManager()
|
||||
let browseSearchState: ServerInstallBrowseSearchState | null = null
|
||||
|
||||
function getInstallProjectName(project: ServerInstallSearchResult) {
|
||||
const legacyTitle = (project as ServerInstallSearchResult & { title?: string }).title
|
||||
return project.name || legacyTitle || formatMessage(commonMessages.projectLabel)
|
||||
}
|
||||
|
||||
const currentServerId = computed(() => queryAsString(route.query.sid) || null)
|
||||
const fromContext = computed(() => queryAsString(route.query.from) || null)
|
||||
const currentWorldId = computed(() => queryAsString(route.query.wid) || null)
|
||||
@@ -177,7 +182,7 @@ export function useServerInstallContent({
|
||||
const selectedServerInstallProjects = computed(() =>
|
||||
Array.from(queuedServerInstalls.value.values()).map((plan) => ({
|
||||
id: plan.projectId,
|
||||
name: plan.project.title ?? formatMessage(commonMessages.projectLabel),
|
||||
name: getInstallProjectName(plan.project),
|
||||
iconUrl: plan.project.icon_url ?? null,
|
||||
})),
|
||||
)
|
||||
@@ -261,7 +266,7 @@ export function useServerInstallContent({
|
||||
projectId: plan.projectId,
|
||||
versionId: plan.versionId,
|
||||
contentType: plan.contentType as PendingServerContentInstallType,
|
||||
title: plan.project.title ?? formatMessage(commonMessages.projectLabel),
|
||||
title: getInstallProjectName(plan.project),
|
||||
versionName: plan.versionName ?? null,
|
||||
versionNumber: plan.versionNumber ?? null,
|
||||
fileName: plan.fileName ?? null,
|
||||
@@ -635,7 +640,7 @@ export function useServerInstallContent({
|
||||
ctx.modpackSelection.value = {
|
||||
projectId: plan.projectId,
|
||||
versionId: plan.versionId,
|
||||
name: plan.project.title,
|
||||
name: getInstallProjectName(plan.project),
|
||||
iconUrl: plan.project.icon_url ?? undefined,
|
||||
}
|
||||
ctx.modal.value?.setStage('final-config')
|
||||
|
||||
@@ -66,7 +66,7 @@ const auth = await useAuth()
|
||||
let prefetchTimeout: ReturnType<typeof useTimeoutFn> | null = null
|
||||
const HOVER_DURATION_TO_PREFETCH_MS = 500
|
||||
|
||||
const handleProjectMouseEnter = (result: Labrinth.Search.v2.ResultSearchProject) => {
|
||||
const handleProjectMouseEnter = (result: Labrinth.Search.v3.ResultSearchProject) => {
|
||||
const slug = result.slug || result.project_id
|
||||
prefetchTimeout = useTimeoutFn(
|
||||
() => {
|
||||
@@ -199,24 +199,6 @@ function getServerModpackContent(project: Labrinth.Search.v3.ResultSearchProject
|
||||
return undefined
|
||||
}
|
||||
|
||||
type DiscoverProjectSearchHit = Labrinth.Search.v2.ResultSearchProject & {
|
||||
version_id?: string | null
|
||||
}
|
||||
|
||||
function mapV3ProjectHit(hit: Labrinth.Search.v3.ResultSearchProject): DiscoverProjectSearchHit {
|
||||
return {
|
||||
...hit,
|
||||
project_type: hit.project_types[0] ?? projectTypeId.value,
|
||||
title: hit.name,
|
||||
description: hit.summary,
|
||||
versions: hit.version_id ? [hit.version_id] : [],
|
||||
latest_version: hit.version_id,
|
||||
icon_url: hit.icon_url ?? '',
|
||||
client_side: 'unknown',
|
||||
server_side: 'unknown',
|
||||
}
|
||||
}
|
||||
|
||||
const hostingContextQuery = computed(() => {
|
||||
const query: LocationQueryRaw = {}
|
||||
|
||||
@@ -234,6 +216,18 @@ function withHostingContext(path: string) {
|
||||
return hostingContextQuery.value ? { path, query: hostingContextQuery.value } : path
|
||||
}
|
||||
|
||||
function parseSearchParams(requestParams: string): Labrinth.Search.SearchParams {
|
||||
const params = new URLSearchParams(requestParams.replace(/^\?/, ''))
|
||||
|
||||
return {
|
||||
query: params.get('query') ?? undefined,
|
||||
offset: params.get('offset') ?? undefined,
|
||||
index: params.get('index') ?? undefined,
|
||||
limit: params.get('limit') ?? undefined,
|
||||
new_filters: params.get('new_filters') ?? undefined,
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchSearch(requestParams: string) {
|
||||
debug('search() called', {
|
||||
requestParams: requestParams.substring(0, 100),
|
||||
@@ -241,11 +235,7 @@ async function fetchSearch(requestParams: string) {
|
||||
projectTypeId: projectTypeId.value,
|
||||
})
|
||||
|
||||
const raw = await client.request<Labrinth.Search.v3.SearchResults>('/search', {
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'GET',
|
||||
params: Object.fromEntries(new URLSearchParams(requestParams.replace(/^\?/, ''))),
|
||||
const raw = await client.labrinth.projects_v3.search(parseSearchParams(requestParams), {
|
||||
headers: withLabrinthCanaryHeader(),
|
||||
})
|
||||
|
||||
@@ -261,7 +251,7 @@ async function fetchSearch(requestParams: string) {
|
||||
}
|
||||
|
||||
return {
|
||||
projectHits: raw.hits.map(mapV3ProjectHit),
|
||||
projectHits: raw.hits,
|
||||
serverHits: [],
|
||||
total_hits: raw.total_hits,
|
||||
per_page: raw.hits_per_page,
|
||||
@@ -277,7 +267,7 @@ async function search(requestParams: string) {
|
||||
}
|
||||
|
||||
function getCardActions(
|
||||
result: Labrinth.Search.v2.ResultSearchProject | Labrinth.Search.v3.ResultSearchProject,
|
||||
result: Labrinth.Search.v3.ResultSearchProject,
|
||||
currentProjectType: string,
|
||||
): CardAction[] {
|
||||
if (currentProjectType === 'server') return []
|
||||
@@ -492,7 +482,7 @@ provideBrowseManager({
|
||||
tags,
|
||||
projectType: projectTypeId,
|
||||
...searchState,
|
||||
getProjectLink: (result: Labrinth.Search.v2.ResultSearchProject) =>
|
||||
getProjectLink: (result: Labrinth.Search.v3.ResultSearchProject) =>
|
||||
withHostingContext(
|
||||
`/${projectType.value?.id ?? 'project'}/${result.slug ? result.slug : result.project_id}`,
|
||||
),
|
||||
|
||||
@@ -183,14 +183,7 @@
|
||||
:downloads="project.downloads"
|
||||
:followers="project.followers"
|
||||
:tags="project.categories"
|
||||
:environment="
|
||||
project.client_side && project.server_side
|
||||
? {
|
||||
clientSide: project.client_side,
|
||||
serverSide: project.server_side,
|
||||
}
|
||||
: undefined
|
||||
"
|
||||
:environment="project.environment?.[0]"
|
||||
:status="
|
||||
auth.user && (auth.user.id! === user.id || tags.staffRoles.includes(auth.user.role))
|
||||
? (project.status as ProjectStatus)
|
||||
@@ -266,10 +259,7 @@ import {
|
||||
import { isPermission } from '~/utils/permissions.ts'
|
||||
import { projectUserSorting } from '~/utils/projects.ts'
|
||||
|
||||
type ProjectV3 = Labrinth.Projects.v3.Project & {
|
||||
client_side: 'required' | 'optional' | 'unsupported'
|
||||
server_side: 'required' | 'optional' | 'unsupported'
|
||||
}
|
||||
type ProjectV3 = Labrinth.Projects.v3.Project
|
||||
|
||||
const vintl = useVIntl()
|
||||
const { formatMessage } = vintl
|
||||
@@ -353,31 +343,7 @@ const {
|
||||
categories = categories.concat(project.mrpack_loaders as string[])
|
||||
}
|
||||
|
||||
const singleplayer = project.singleplayer && (project.singleplayer as string[])[0]
|
||||
const clientAndServer =
|
||||
project.client_and_server && (project.client_and_server as string[])[0]
|
||||
const clientOnly = project.client_only && (project.client_only as string[])[0]
|
||||
const serverOnly = project.server_only && (project.server_only as string[])[0]
|
||||
|
||||
let client_side: ProjectV3['client_side'] | undefined
|
||||
let server_side: ProjectV3['server_side'] | undefined
|
||||
|
||||
// quick and dirty hack to show envs as legacy
|
||||
if (singleplayer && clientAndServer && !clientOnly && !serverOnly) {
|
||||
client_side = 'required'
|
||||
server_side = 'required'
|
||||
} else if (singleplayer && clientAndServer && clientOnly && !serverOnly) {
|
||||
client_side = 'required'
|
||||
server_side = 'unsupported'
|
||||
} else if (singleplayer && clientAndServer && !clientOnly && serverOnly) {
|
||||
client_side = 'unsupported'
|
||||
server_side = 'required'
|
||||
} else if (singleplayer && clientAndServer && clientOnly && serverOnly) {
|
||||
client_side = 'optional'
|
||||
server_side = 'optional'
|
||||
}
|
||||
|
||||
return { ...project, categories, client_side, server_side }
|
||||
return { ...project, categories }
|
||||
})
|
||||
},
|
||||
placeholderData: [],
|
||||
|
||||
@@ -73,6 +73,30 @@ export class LabrinthProjectsV3Module extends AbstractModule {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Search projects (v3)
|
||||
*
|
||||
* @param params - Search parameters
|
||||
* @returns Promise resolving to v3 search results
|
||||
*/
|
||||
public async search(
|
||||
params: Labrinth.Search.SearchParams,
|
||||
options?: {
|
||||
headers?: Record<string, string>
|
||||
},
|
||||
): Promise<Labrinth.Search.v3.SearchResults> {
|
||||
return this.client.request<Labrinth.Search.v3.SearchResults>(`/search`, {
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'GET',
|
||||
headers: options?.headers,
|
||||
params: {
|
||||
...params,
|
||||
facets: params.facets ? JSON.stringify(params.facets) : undefined,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a project (v3)
|
||||
*
|
||||
|
||||
@@ -1750,6 +1750,17 @@ export namespace Labrinth {
|
||||
}
|
||||
|
||||
export namespace Search {
|
||||
export type SearchParams = {
|
||||
query?: string
|
||||
offset?: string | number
|
||||
index?: string
|
||||
limit?: string | number
|
||||
new_filters?: string
|
||||
facets?: string[][]
|
||||
filters?: string
|
||||
version?: string
|
||||
}
|
||||
|
||||
export namespace v2 {
|
||||
export interface ResultSearchProject {
|
||||
project_id: string
|
||||
@@ -1812,7 +1823,9 @@ export namespace Labrinth {
|
||||
featured_gallery: string | null
|
||||
color: number | null
|
||||
loaders: string[]
|
||||
project_loader_fields?: Record<string, unknown[]>
|
||||
project_loader_fields?: Record<string, unknown[]> & {
|
||||
environment?: Projects.v3.Environment[]
|
||||
}
|
||||
minecraft_server?: Projects.v3.MinecraftServer | null
|
||||
minecraft_java_server?: Projects.v3.MinecraftJavaServer | null
|
||||
minecraft_bedrock_server?: Projects.v3.MinecraftBedrockServer | null
|
||||
|
||||
@@ -250,9 +250,9 @@ pub struct SearchResultsV3 {
|
||||
pub struct SearchResultV3 {
|
||||
pub hits: Vec<serde_json::Value>,
|
||||
#[serde(default)]
|
||||
pub offset: u32,
|
||||
#[serde(default)]
|
||||
pub limit: u32,
|
||||
pub page: u32,
|
||||
#[serde(default, alias = "limit")]
|
||||
pub hits_per_page: u32,
|
||||
#[serde(default)]
|
||||
pub total_hits: u32,
|
||||
}
|
||||
|
||||
@@ -68,11 +68,7 @@
|
||||
class="smart-clickable:allow-pointer-events"
|
||||
/>
|
||||
</template>
|
||||
<ProjectCardEnvironment
|
||||
v-if="environment"
|
||||
:client-side="environment.clientSide"
|
||||
:server-side="environment.serverSide"
|
||||
/>
|
||||
<ProjectCardEnvironment v-if="environment" :environment="environment" />
|
||||
<ProjectCardTags
|
||||
v-if="tags"
|
||||
:tags="tags"
|
||||
@@ -168,11 +164,7 @@
|
||||
class="smart-clickable:allow-pointer-events"
|
||||
/>
|
||||
</template>
|
||||
<ProjectCardEnvironment
|
||||
v-if="environment"
|
||||
:client-side="environment.clientSide"
|
||||
:server-side="environment.serverSide"
|
||||
/>
|
||||
<ProjectCardEnvironment v-if="environment" :environment="environment" />
|
||||
<ProjectCardTags
|
||||
v-if="tags"
|
||||
:tags="tags"
|
||||
@@ -213,7 +205,7 @@ import ServerRegion from '../server/ServerRegion.vue'
|
||||
import ProjectCardAuthor from './ProjectCardAuthor.vue'
|
||||
import ProjectCardDate from './ProjectCardDate.vue'
|
||||
import ProjectCardEnvironment, {
|
||||
type ProjectCardEnvironmentProps,
|
||||
type ProjectCardEnvironmentValue,
|
||||
} from './ProjectCardEnvironment.vue'
|
||||
import ProjectCardStats from './ProjectCardStats.vue'
|
||||
import ProjectCardTags from './ProjectCardTags.vue'
|
||||
@@ -257,7 +249,7 @@ const props = defineProps<{
|
||||
isServerProject?: boolean
|
||||
banner?: string
|
||||
color?: string | number
|
||||
environment?: ProjectCardEnvironmentProps
|
||||
environment?: ProjectCardEnvironmentValue
|
||||
status?: ProjectStatus
|
||||
maxTags?: number
|
||||
}>()
|
||||
|
||||
@@ -1,18 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { ClientIcon, GlobeIcon, ServerIcon } from '@modrinth/assets'
|
||||
import { ClientIcon, GlobeIcon, ServerIcon, UserIcon } from '@modrinth/assets'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { defineMessages, useVIntl } from '../../../composables'
|
||||
import { TagItem } from '../../base'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
export type ProjectCardEnvironmentProps = {
|
||||
export type LegacyProjectEnvironment = {
|
||||
clientSide: Labrinth.Projects.v2.Environment
|
||||
serverSide: Labrinth.Projects.v2.Environment
|
||||
}
|
||||
|
||||
defineProps<ProjectCardEnvironmentProps>()
|
||||
export type ProjectCardEnvironmentValue =
|
||||
| Labrinth.Projects.v3.Environment
|
||||
| LegacyProjectEnvironment
|
||||
|
||||
export type ProjectCardEnvironmentProps = {
|
||||
environment?: ProjectCardEnvironmentValue
|
||||
clientSide?: Labrinth.Projects.v2.Environment
|
||||
serverSide?: Labrinth.Projects.v2.Environment
|
||||
}
|
||||
|
||||
const props = defineProps<ProjectCardEnvironmentProps>()
|
||||
|
||||
const messages = defineMessages({
|
||||
clientOrServer: {
|
||||
@@ -31,36 +42,99 @@ const messages = defineMessages({
|
||||
id: 'project-card.environment.server',
|
||||
defaultMessage: 'Server',
|
||||
},
|
||||
singleplayer: {
|
||||
id: 'project-card.environment.singleplayer',
|
||||
defaultMessage: 'Singleplayer',
|
||||
},
|
||||
dedicatedServer: {
|
||||
id: 'project-card.environment.dedicated-server',
|
||||
defaultMessage: 'Dedicated server',
|
||||
},
|
||||
})
|
||||
|
||||
const displayEnvironment = computed(() => {
|
||||
const environment =
|
||||
props.environment ??
|
||||
(props.clientSide && props.serverSide
|
||||
? { clientSide: props.clientSide, serverSide: props.serverSide }
|
||||
: undefined)
|
||||
|
||||
if (typeof environment === 'string') {
|
||||
switch (environment) {
|
||||
case 'client_or_server':
|
||||
case 'client_or_server_prefers_both':
|
||||
return 'client-or-server'
|
||||
case 'client_and_server':
|
||||
return 'client-and-server'
|
||||
case 'client_only':
|
||||
case 'client_only_server_optional':
|
||||
return 'client'
|
||||
case 'server_only':
|
||||
case 'server_only_client_optional':
|
||||
return 'server'
|
||||
case 'singleplayer_only':
|
||||
return 'singleplayer'
|
||||
case 'dedicated_server_only':
|
||||
return 'dedicated-server'
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
if (!environment) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const { clientSide, serverSide } = environment
|
||||
|
||||
if (clientSide === 'optional' && serverSide === 'optional') {
|
||||
return 'client-or-server'
|
||||
}
|
||||
if (clientSide === 'required' && serverSide === 'required') {
|
||||
return 'client-and-server'
|
||||
}
|
||||
if (
|
||||
(clientSide === 'optional' || clientSide === 'required') &&
|
||||
(serverSide === 'optional' || serverSide === 'unsupported')
|
||||
) {
|
||||
return 'client'
|
||||
}
|
||||
if (
|
||||
(serverSide === 'optional' || serverSide === 'required') &&
|
||||
(clientSide === 'optional' || clientSide === 'unsupported')
|
||||
) {
|
||||
return 'server'
|
||||
}
|
||||
|
||||
return undefined
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TagItem class="empty:hidden">
|
||||
<template v-if="clientSide === 'optional' && serverSide === 'optional'">
|
||||
<template v-if="displayEnvironment === 'client-or-server'">
|
||||
<GlobeIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.clientOrServer) }}
|
||||
</template>
|
||||
<template v-else-if="clientSide === 'required' && serverSide === 'required'">
|
||||
<template v-else-if="displayEnvironment === 'client-and-server'">
|
||||
<GlobeIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.clientAndServer) }}
|
||||
</template>
|
||||
<template
|
||||
v-else-if="
|
||||
(clientSide === 'optional' || clientSide === 'required') &&
|
||||
(serverSide === 'optional' || serverSide === 'unsupported')
|
||||
"
|
||||
>
|
||||
<template v-else-if="displayEnvironment === 'client'">
|
||||
<ClientIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.client) }}
|
||||
</template>
|
||||
<template
|
||||
v-else-if="
|
||||
(serverSide === 'optional' || serverSide === 'required') &&
|
||||
(clientSide === 'optional' || clientSide === 'unsupported')
|
||||
"
|
||||
>
|
||||
<template v-else-if="displayEnvironment === 'server'">
|
||||
<ServerIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.server) }}
|
||||
</template>
|
||||
<template v-else-if="displayEnvironment === 'singleplayer'">
|
||||
<UserIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.singleplayer) }}
|
||||
</template>
|
||||
<template v-else-if="displayEnvironment === 'dedicated-server'">
|
||||
<ServerIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.dedicatedServer) }}
|
||||
</template>
|
||||
</TagItem>
|
||||
</template>
|
||||
|
||||
@@ -6,6 +6,7 @@ export type {
|
||||
Gamemode,
|
||||
GeneratorSettingsMode,
|
||||
LoaderVersionType,
|
||||
ModpackSearchResult,
|
||||
SetupType,
|
||||
} from '../../flows/creation-flow-modal/creation-flow-context'
|
||||
export { default as CreationFlowModal } from '../../flows/creation-flow-modal/index.vue'
|
||||
|
||||
@@ -66,6 +66,33 @@ const messages = defineMessages({
|
||||
defaultMessage: 'No results found for your query!',
|
||||
},
|
||||
})
|
||||
|
||||
function getLoaderFieldValues(
|
||||
result: Labrinth.Search.v3.ResultSearchProject,
|
||||
field: string,
|
||||
): string[] {
|
||||
return (result.project_loader_fields?.[field] ?? []).filter(
|
||||
(value): value is string => typeof value === 'string',
|
||||
)
|
||||
}
|
||||
|
||||
function getProjectCardTags(result: Labrinth.Search.v3.ResultSearchProject, displayOnly: boolean) {
|
||||
const tags = new Set(displayOnly ? result.display_categories : result.categories)
|
||||
|
||||
for (const loader of result.loaders) {
|
||||
if (loader !== 'mrpack') {
|
||||
tags.add(loader)
|
||||
}
|
||||
}
|
||||
|
||||
if (result.loaders.includes('mrpack')) {
|
||||
for (const loader of getLoaderFieldValues(result, 'mrpack_loaders')) {
|
||||
tags.add(loader)
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(tags)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -247,8 +274,8 @@ const messages = defineMessages({
|
||||
v-for="result in ctx.projectHits.value"
|
||||
:key="result.project_id"
|
||||
:link="ctx.getProjectLink(result)"
|
||||
:title="result.title"
|
||||
:icon-url="result.icon_url"
|
||||
:title="result.name"
|
||||
:icon-url="result.icon_url ?? undefined"
|
||||
:author="{
|
||||
name: result.organization == null ? result.author : result.organization,
|
||||
link:
|
||||
@@ -266,9 +293,9 @@ const messages = defineMessages({
|
||||
ctx.effectiveCurrentSortType.value.name === 'newest' ? 'published' : 'updated'
|
||||
"
|
||||
:downloads="result.downloads"
|
||||
:summary="result.description"
|
||||
:tags="result.display_categories"
|
||||
:all-tags="result.categories"
|
||||
:summary="result.summary"
|
||||
:tags="getProjectCardTags(result, true)"
|
||||
:all-tags="getProjectCardTags(result, false)"
|
||||
:deprioritized-tags="ctx.deprioritizedTags.value"
|
||||
:exclude-loaders="ctx.excludeLoaders.value"
|
||||
:followers="result.follows"
|
||||
@@ -276,10 +303,7 @@ const messages = defineMessages({
|
||||
:color="result.color ?? undefined"
|
||||
:environment="
|
||||
['mod', 'modpack'].includes(ctx.projectType.value)
|
||||
? {
|
||||
clientSide: result.client_side as Labrinth.Projects.v2.Environment,
|
||||
serverSide: result.server_side as Labrinth.Projects.v2.Environment,
|
||||
}
|
||||
? result.project_loader_fields?.environment?.[0]
|
||||
: undefined
|
||||
"
|
||||
:layout="ctx.effectiveLayout.value"
|
||||
|
||||
@@ -46,7 +46,7 @@ export interface BrowseManagerContext {
|
||||
clearSearch: () => void
|
||||
onFilterChange: () => void
|
||||
|
||||
getProjectLink: (result: Labrinth.Search.v2.ResultSearchProject) => string | RouteLocationRaw
|
||||
getProjectLink: (result: Labrinth.Search.v3.ResultSearchProject) => string | RouteLocationRaw
|
||||
getServerProjectLink: (
|
||||
result: Labrinth.Search.v3.ResultSearchProject,
|
||||
) => string | RouteLocationRaw
|
||||
@@ -57,7 +57,7 @@ export interface BrowseManagerContext {
|
||||
variant: 'app' | 'web'
|
||||
|
||||
getCardActions?: (
|
||||
result: Labrinth.Search.v2.ResultSearchProject | Labrinth.Search.v3.ResultSearchProject,
|
||||
result: Labrinth.Search.v3.ResultSearchProject,
|
||||
projectType: string,
|
||||
) => CardAction[]
|
||||
|
||||
@@ -85,13 +85,10 @@ export interface BrowseManagerContext {
|
||||
result: Labrinth.Search.v3.ResultSearchProject,
|
||||
) => ServerModpackContent | undefined
|
||||
|
||||
onProjectHover?: (result: Labrinth.Search.v2.ResultSearchProject) => void
|
||||
onProjectHover?: (result: Labrinth.Search.v3.ResultSearchProject) => void
|
||||
onServerProjectHover?: (result: Labrinth.Search.v3.ResultSearchProject) => void
|
||||
onProjectHoverEnd?: () => void
|
||||
onContextMenu?: (
|
||||
event: MouseEvent,
|
||||
result: Labrinth.Search.v2.ResultSearchProject | Labrinth.Search.v3.ResultSearchProject,
|
||||
) => void
|
||||
onContextMenu?: (event: MouseEvent, result: Labrinth.Search.v3.ResultSearchProject) => void
|
||||
offline?: Ref<boolean>
|
||||
|
||||
filtersMenuOpen?: Ref<boolean>
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { Component } from 'vue'
|
||||
import type { RouteLocationRaw } from 'vue-router'
|
||||
|
||||
export interface BrowseSearchResponse {
|
||||
projectHits: (Labrinth.Search.v2.ResultSearchProject & {
|
||||
projectHits: (Labrinth.Search.v3.ResultSearchProject & {
|
||||
installed?: boolean
|
||||
installing?: boolean
|
||||
})[]
|
||||
|
||||
@@ -2825,9 +2825,15 @@
|
||||
"project-card.environment.client-or-server": {
|
||||
"defaultMessage": "Client or server"
|
||||
},
|
||||
"project-card.environment.dedicated-server": {
|
||||
"defaultMessage": "Dedicated server"
|
||||
},
|
||||
"project-card.environment.server": {
|
||||
"defaultMessage": "Server"
|
||||
},
|
||||
"project-card.environment.singleplayer": {
|
||||
"defaultMessage": "Singleplayer"
|
||||
},
|
||||
"project-type.all": {
|
||||
"defaultMessage": "All"
|
||||
},
|
||||
|
||||
@@ -63,7 +63,7 @@ export const AllTypes: Story = {
|
||||
:followers="25000"
|
||||
date-updated="2023-06-01T00:00:00Z"
|
||||
:tags="['utility']"
|
||||
:environment="{ clientSide: 'unsupported', serverSide: 'required' }"
|
||||
environment="server_only"
|
||||
/>
|
||||
<ProjectCard
|
||||
link="/modpack/example-modpack"
|
||||
|
||||
Reference in New Issue
Block a user