Envs v3 frontend (#4267)

* New envs frontend

* lint fix

* Add blog post, user-facing changes, dashboard warning, project page member warning, and migration reviewing. maybe some other misc stuff

* lint

* lint

* ignore .data in .prettierignore

* i18n as fuck

* fix proj page

* Improve news markdown rendering

* improve phrasing of initial paragraph

* Fix environments not reloading after save

* index.ts instead of underscored name

* shrink-0 back on these icons
This commit is contained in:
Prospector
2025-08-28 15:11:35 -07:00
committed by GitHub
parent 0ac42344e7
commit 46c325f78a
49 changed files with 2509 additions and 397 deletions

View File

@@ -26,8 +26,17 @@
</TagItem>
</div>
</section>
<section v-if="showEnvironments" class="flex flex-col gap-2">
<h3 class="text-primary text-base m-0">{{ formatMessage(messages.environments) }}</h3>
<div class="flex flex-wrap gap-1">
<TagItem v-for="tag in primaryEnvironmentTags" :key="`environment-tag-${tag.message.id}`">
<component :is="tag.icon" />
{{ formatMessage(tag.message) }}
</TagItem>
</div>
</section>
<section
v-if="
v-else-if="
(project.project_type === 'mod' || project.project_type === 'modpack') &&
!(project.client_side === 'unsupported' && project.server_side === 'unsupported') &&
!(project.client_side === 'unknown' && project.server_side === 'unknown')
@@ -76,9 +85,10 @@
</template>
<script setup lang="ts">
import { ClientIcon, MonitorSmartphoneIcon, ServerIcon, UserIcon } from '@modrinth/assets'
import type { GameVersionTag, PlatformTag } from '@modrinth/utils'
import type { EnvironmentV3, GameVersionTag, PlatformTag, ProjectV3Partial } from '@modrinth/utils'
import { formatCategory, getVersionsToDisplay } from '@modrinth/utils'
import { defineMessages, useVIntl } from '@vintl/vintl'
import { defineMessage, defineMessages, type MessageDescriptor, useVIntl } from '@vintl/vintl'
import { type Component, computed } from 'vue'
import { useRouter } from 'vue-router'
import TagItem from '../base/TagItem.vue'
@@ -88,7 +98,9 @@ const router = useRouter()
type EnvironmentValue = 'optional' | 'required' | 'unsupported' | 'unknown'
defineProps<{
const TYPES_WITH_ENVS = ['mod', 'modpack'] as const
const props = defineProps<{
project: {
actualProjectType: string
project_type: string
@@ -102,23 +114,112 @@ defineProps<{
gameVersions: GameVersionTag[]
loaders: PlatformTag[]
}
v3Metadata?: ProjectV3Partial
}>()
const showEnvironments = computed(
() =>
TYPES_WITH_ENVS.some((x) => props.v3Metadata?.project_types.includes(x)) &&
primaryEnvironment.value,
)
const primaryEnvironment = computed<EnvironmentV3 | undefined>(() =>
props.v3Metadata?.environment?.find((x) => x !== 'unknown'),
)
type EnvironmentTag = {
icon: Component
message: MessageDescriptor
environments: EnvironmentV3[]
}
const environmentTags: EnvironmentTag[] = [
{
icon: ClientIcon,
message: defineMessage({
id: `project.about.compatibility.environments.client-side`,
defaultMessage: 'Client-side',
}),
environments: [
'client_only',
'client_only_server_optional',
'client_or_server',
'client_or_server_prefers_both',
],
},
{
icon: ServerIcon,
message: defineMessage({
id: `project.about.compatibility.environments.server-side`,
defaultMessage: 'Server-side',
}),
environments: [
'server_only',
'server_only_client_optional',
'client_or_server',
'client_or_server_prefers_both',
],
},
{
icon: ServerIcon,
message: defineMessage({
id: `project.about.compatibility.environments.dedicated-servers-only`,
defaultMessage: 'Dedicated servers only',
}),
environments: ['dedicated_server_only'],
},
{
icon: UserIcon,
message: defineMessage({
id: `project.about.compatibility.environments.singleplayer-only`,
defaultMessage: 'Singleplayer only',
}),
environments: ['singleplayer_only'],
},
{
icon: UserIcon,
message: defineMessage({
id: `project.about.compatibility.environments.singleplayer`,
defaultMessage: 'Singleplayer',
}),
environments: ['server_only'],
},
{
icon: MonitorSmartphoneIcon,
message: defineMessage({
id: `project.about.compatibility.environments.client-and-server`,
defaultMessage: 'Client and server',
}),
environments: [
'client_and_server',
'client_only_server_optional',
'server_only_client_optional',
'client_or_server_prefers_both',
],
},
]
const primaryEnvironmentTags = computed(() => {
return primaryEnvironment.value
? environmentTags.filter((x) => x.environments.includes(primaryEnvironment.value ?? 'unknown'))
: []
})
const messages = defineMessages({
title: {
id: 'project.about.compatibility.title',
id: `project.about.compatibility.title`,
defaultMessage: 'Compatibility',
},
minecraftJava: {
id: 'project.about.compatibility.game.minecraftJava',
id: `project.about.compatibility.game.minecraftJava`,
defaultMessage: 'Minecraft: Java Edition',
},
platforms: {
id: 'project.about.compatibility.platforms',
id: `project.about.compatibility.platforms`,
defaultMessage: 'Platforms',
},
environments: {
id: 'project.about.compatibility.environments',
id: `project.about.compatibility.environments`,
defaultMessage: 'Supported environments',
},
})