You've already forked AstralRinth
forked from didirus/AstralRinth
83d53dafe7
* fix: tags in project settings to have icons and ordered correctly * fix copy in project list layout settings * fix tag item in header navigation * adjust ping ranges * add handle click tag * fix: dont show offline in project page for draft status * move tags above creators in app * preload server project page on load and optimize queries * add server project card to organization page * fix minecraft_java_server label * pnpm prepr * have user option in project create modal be circle * feat: implement better mobile project page view * disable summary line clamp for servers * fix: unlink instance doesnt update instance * increase icon upload size * small fix on button size * improve how server ping info loads * remove unnecessary pings for instance page * fix order of computing dependency diff * remove linked_project_id from world, use name+address to match for managed world instead * pnpm prepr * hide duplicate worlds with same domain name in worlds list * add install content warning for server instance * increase summary max width * add handling for server projects for bulk editing links * implement include user unlisted projects in published modpack select * pnpm prepr * filter to only user unlisted status * add bad link warnings * fix modpack tags appearing in server * cargo fmt
235 lines
7.4 KiB
Vue
235 lines
7.4 KiB
Vue
<template>
|
|
<div v-if="hasContent" class="flex flex-col gap-3">
|
|
<h2 class="text-lg m-0">{{ formatMessage(messages.title) }}</h2>
|
|
|
|
<div
|
|
v-if="ipAddress"
|
|
v-tooltip="`Copy Java IP: ${ipAddress}`"
|
|
class="bg-button-bg flex gap-2 justify-between rounded-2xl items-center px-3 pr-1.5 h-12 cursor-pointer hover:bg-button-bg-hover hover:brightness-125 transition-all active:scale-95"
|
|
@click="handleCopyIP"
|
|
>
|
|
<div class="font-semibold truncate">
|
|
{{ ipAddress }}
|
|
</div>
|
|
<div class="w-9 h-9 grid place-content-center">
|
|
<CopyIcon class="shrink-0" />
|
|
</div>
|
|
</div>
|
|
|
|
<section v-if="requiredContent" class="flex flex-col gap-2">
|
|
<h3 class="text-primary text-base m-0">Required content</h3>
|
|
<ServerModpackContentCard
|
|
:name="requiredContent.name"
|
|
:version-number="requiredContent.versionNumber ?? ''"
|
|
:icon="requiredContent.icon"
|
|
:onclick-name="requiredContent.onclickName"
|
|
:onclick-version="requiredContent.onclickVersion"
|
|
:onclick-download="requiredContent.onclickDownload"
|
|
:show-custom-modpack-tooltip="requiredContent.showCustomModpackTooltip"
|
|
/>
|
|
</section>
|
|
<section v-if="recommendedVersions.length" class="flex flex-col gap-2">
|
|
<h3 class="text-primary text-base m-0">Minecraft: Java Edition</h3>
|
|
<div class="flex flex-wrap gap-1.5">
|
|
<TagItem
|
|
v-for="version in formatVersionsForDisplay(recommendedVersions, tags.gameVersions)"
|
|
:key="`recommended-tag-${version}`"
|
|
>
|
|
{{ version }}
|
|
<template v-if="supportedVersions.length > 0"> (Recommended) </template>
|
|
</TagItem>
|
|
<TagItem
|
|
v-for="version in formatVersionsForDisplay(supportedVersionsList, tags.gameVersions)"
|
|
:key="`supported-tag-${version}`"
|
|
>
|
|
{{ version }}
|
|
</TagItem>
|
|
<TagItem
|
|
v-for="loader in loaders ?? []"
|
|
:key="`loader-${loader}`"
|
|
class="border !border-solid border-surface-5"
|
|
:style="`--_color: var(--color-platform-${loader})`"
|
|
>
|
|
<component :is="getLoaderIcon(loader)" v-if="getLoaderIcon(loader)" />
|
|
<FormattedTag :tag="loader" enforce-type="loader" />
|
|
</TagItem>
|
|
</div>
|
|
</section>
|
|
<section v-if="props.ping !== undefined || region" class="flex flex-col gap-2">
|
|
<h3 class="text-primary text-base m-0">Region</h3>
|
|
<div class="flex flex-wrap gap-1.5 items-center">
|
|
<ServerPing
|
|
v-if="projectV3?.status !== 'draft'"
|
|
:ping="props.ping"
|
|
:status-online="props.statusOnline"
|
|
/>
|
|
<ServerRegion v-if="region" :region="region" />
|
|
</div>
|
|
</section>
|
|
<section v-if="languages.length > 0" class="flex flex-col gap-2">
|
|
<h3 class="text-primary text-base m-0">Languages</h3>
|
|
<div class="flex flex-wrap gap-1.5">
|
|
<TagItem v-for="language in languages" :key="`${language}`">
|
|
{{ languageDisplay.find((l) => l.value === language)?.label ?? language }}
|
|
</TagItem>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</template>
|
|
<script setup lang="ts">
|
|
import type { Labrinth } from '@modrinth/api-client'
|
|
import { CopyIcon, getLoaderIcon } from '@modrinth/assets'
|
|
import { formatVersionsForDisplay, type GameVersionTag, type PlatformTag } from '@modrinth/utils'
|
|
import { computed } from 'vue'
|
|
|
|
import { defineMessages, useVIntl } from '../../composables'
|
|
import { injectNotificationManager } from '../../providers'
|
|
import FormattedTag from '../base/FormattedTag.vue'
|
|
import TagItem from '../base/TagItem.vue'
|
|
import ServerModpackContentCard from './server/ServerModpackContentCard.vue'
|
|
import ServerPing from './server/ServerPing.vue'
|
|
import ServerRegion from './server/ServerRegion.vue'
|
|
|
|
interface RequiredContent {
|
|
name: string
|
|
versionNumber?: string
|
|
icon?: string
|
|
onclickName?: () => void
|
|
onclickVersion?: () => void
|
|
onclickDownload?: () => void
|
|
showCustomModpackTooltip?: boolean
|
|
}
|
|
|
|
interface Props {
|
|
projectV3: Labrinth.Projects.v3.Project | null
|
|
tags: {
|
|
gameVersions: GameVersionTag[]
|
|
loaders: PlatformTag[]
|
|
}
|
|
requiredContent?: RequiredContent | null
|
|
recommendedVersion?: string | null
|
|
supportedVersions?: string[]
|
|
loaders?: string[]
|
|
ping?: number
|
|
statusOnline?: boolean
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
requiredContent: null,
|
|
recommendedVersion: null,
|
|
supportedVersions: () => [],
|
|
loaders: () => [],
|
|
ping: undefined,
|
|
})
|
|
|
|
const ipAddress = computed(() => props.projectV3?.minecraft_java_server?.address ?? '')
|
|
const languages = computed(() => props.projectV3?.minecraft_server?.languages ?? [])
|
|
const region = computed(() => props.projectV3?.minecraft_server?.region)
|
|
|
|
const recommendedVersions = computed(() => {
|
|
if (props.recommendedVersion) return [props.recommendedVersion]
|
|
|
|
const content = props.projectV3?.minecraft_java_server?.content
|
|
if (content?.kind === 'vanilla' && content.recommended_game_version) {
|
|
return [content.recommended_game_version]
|
|
}
|
|
|
|
return []
|
|
})
|
|
|
|
const hasContent = computed(
|
|
() =>
|
|
!!ipAddress.value ||
|
|
!!props.requiredContent ||
|
|
recommendedVersions.value.length > 0 ||
|
|
supportedVersionsList.value.length > 0 ||
|
|
languages.value.length > 0 ||
|
|
props.ping !== undefined,
|
|
)
|
|
|
|
const supportedVersionsList = computed(() => {
|
|
if (props.supportedVersions.length > 0) return props.supportedVersions
|
|
|
|
const content = props.projectV3?.minecraft_java_server?.content
|
|
if (content?.kind === 'vanilla' && content.supported_game_versions?.length) {
|
|
return content.supported_game_versions.filter((v): v is string => !!v)
|
|
}
|
|
|
|
return []
|
|
})
|
|
|
|
const { addNotification } = injectNotificationManager()
|
|
const { formatMessage } = useVIntl()
|
|
|
|
function handleCopyIP() {
|
|
navigator.clipboard.writeText(ipAddress.value).then(() => {
|
|
addNotification({
|
|
type: 'success',
|
|
title: formatMessage(messages.copied),
|
|
text: formatMessage(messages.copiedText),
|
|
})
|
|
})
|
|
}
|
|
|
|
const languageDisplay = [
|
|
{ value: 'en', label: 'English' },
|
|
{ value: 'es', label: 'Spanish' },
|
|
{ value: 'pt', label: 'Portuguese' },
|
|
{ value: 'fr', label: 'French' },
|
|
{ value: 'de', label: 'German' },
|
|
{ value: 'it', label: 'Italian' },
|
|
{ value: 'nl', label: 'Dutch' },
|
|
{ value: 'ru', label: 'Russian' },
|
|
{ value: 'uk', label: 'Ukrainian' },
|
|
{ value: 'pl', label: 'Polish' },
|
|
{ value: 'cs', label: 'Czech' },
|
|
{ value: 'sk', label: 'Slovak' },
|
|
{ value: 'hu', label: 'Hungarian' },
|
|
{ value: 'ro', label: 'Romanian' },
|
|
{ value: 'bg', label: 'Bulgarian' },
|
|
{ value: 'hr', label: 'Croatian' },
|
|
{ value: 'sr', label: 'Serbian' },
|
|
{ value: 'el', label: 'Greek' },
|
|
{ value: 'tr', label: 'Turkish' },
|
|
{ value: 'ar', label: 'Arabic' },
|
|
{ value: 'he', label: 'Hebrew' },
|
|
{ value: 'hi', label: 'Hindi' },
|
|
{ value: 'bn', label: 'Bengali' },
|
|
{ value: 'ur', label: 'Urdu' },
|
|
{ value: 'zh', label: 'Chinese' },
|
|
{ value: 'ja', label: 'Japanese' },
|
|
{ value: 'ko', label: 'Korean' },
|
|
{ value: 'th', label: 'Thai' },
|
|
{ value: 'vi', label: 'Vietnamese' },
|
|
{ value: 'id', label: 'Indonesian' },
|
|
{ value: 'ms', label: 'Malay' },
|
|
{ value: 'tl', label: 'Filipino' },
|
|
{ value: 'sv', label: 'Swedish' },
|
|
{ value: 'no', label: 'Norwegian' },
|
|
{ value: 'da', label: 'Danish' },
|
|
{ value: 'fi', label: 'Finnish' },
|
|
{ value: 'lt', label: 'Lithuanian' },
|
|
{ value: 'lv', label: 'Latvian' },
|
|
{ value: 'et', label: 'Estonian' },
|
|
]
|
|
|
|
const messages = defineMessages({
|
|
copied: {
|
|
id: `project.about.server.copied`,
|
|
defaultMessage: 'Copied!',
|
|
},
|
|
copiedText: {
|
|
id: `project.about.server.copiedText`,
|
|
defaultMessage: 'IP address copied to clipboard',
|
|
},
|
|
title: {
|
|
id: `project.about.server.title`,
|
|
defaultMessage: 'Server details',
|
|
},
|
|
latency: {
|
|
id: `project.about.server.latency`,
|
|
defaultMessage: 'Latency',
|
|
},
|
|
})
|
|
</script>
|