Merge server project header into project header (#5500)

This commit is contained in:
Prospector
2026-03-09 12:19:55 -07:00
committed by GitHub
parent 97051cc64d
commit c9c8079853
6 changed files with 68 additions and 119 deletions

View File

@@ -52,14 +52,14 @@
> >
<ProjectBackgroundGradient :project="data" /> <ProjectBackgroundGradient :project="data" />
</Teleport> </Teleport>
<ServerProjectHeader <ProjectHeader
v-if="isServerProject" v-else
:project="data" :project="data"
:project-v3="projectV3" :project-v3="projectV3"
:ping="serverPing" :ping="serverPing"
@contextmenu.prevent.stop="handleRightClick" @contextmenu.prevent.stop="handleRightClick"
> >
<template #actions> <template v-if="isServerProject" #actions>
<ButtonStyled v-if="serverPlaying" size="large" color="red"> <ButtonStyled v-if="serverPlaying" size="large" color="red">
<button @click="handleStopServer"> <button @click="handleStopServer">
<StopCircleIcon /> <StopCircleIcon />
@@ -111,9 +111,7 @@
</OverflowMenu> </OverflowMenu>
</ButtonStyled> </ButtonStyled>
</template> </template>
</ServerProjectHeader> <template v-else #actions>
<ProjectHeader v-else :project="data" @contextmenu.prevent.stop="handleRightClick">
<template #actions>
<ButtonStyled size="large" color="brand"> <ButtonStyled size="large" color="brand">
<button <button
v-tooltip="installed ? `This project is already installed` : null" v-tooltip="installed ? `This project is already installed` : null"
@@ -238,7 +236,6 @@ import {
ProjectSidebarLinks, ProjectSidebarLinks,
ProjectSidebarServerInfo, ProjectSidebarServerInfo,
ProjectSidebarTags, ProjectSidebarTags,
ServerProjectHeader,
} from '@modrinth/ui' } from '@modrinth/ui'
import { openUrl } from '@tauri-apps/plugin-opener' import { openUrl } from '@tauri-apps/plugin-opener'
import dayjs from 'dayjs' import dayjs from 'dayjs'

View File

@@ -433,14 +433,11 @@
}" }"
> >
<div class="normal-page__header relative my-4"> <div class="normal-page__header relative my-4">
<component <ProjectHeader
:is="isServerProject ? ServerProjectHeader : ProjectHeader"
v-if="projectV3Loaded" v-if="projectV3Loaded"
v-bind=" :project="project"
isServerProject :project-v3="projectV3"
? { project, projectV3, member: !!currentMember } :member="!!currentMember"
: { project, member: !!currentMember }
"
> >
<template #actions> <template #actions>
<ButtonStyled <ButtonStyled
@@ -800,7 +797,7 @@
</OverflowMenu> </OverflowMenu>
</ButtonStyled> </ButtonStyled>
</template> </template>
</component> </ProjectHeader>
<ProjectMemberHeader <ProjectMemberHeader
v-if="currentMember" v-if="currentMember"
:project="project" :project="project"
@@ -1071,7 +1068,6 @@ import {
ProjectSidebarTags, ProjectSidebarTags,
provideProjectPageContext, provideProjectPageContext,
ScrollablePanel, ScrollablePanel,
ServerProjectHeader,
ServersPromo, ServersPromo,
StyledInput, StyledInput,
TagItem, TagItem,

View File

@@ -3,6 +3,8 @@
import type { FunctionalComponent, SVGAttributes } from 'vue' import type { FunctionalComponent, SVGAttributes } from 'vue'
export type IconComponent = FunctionalComponent<SVGAttributes>
import _AffiliateIcon from './icons/affiliate.svg?component' import _AffiliateIcon from './icons/affiliate.svg?component'
import _AlignLeftIcon from './icons/align-left.svg?component' import _AlignLeftIcon from './icons/align-left.svg?component'
import _ArchiveIcon from './icons/archive.svg?component' import _ArchiveIcon from './icons/archive.svg?component'
@@ -378,8 +380,6 @@ import _XCircleIcon from './icons/x-circle.svg?component'
import _ZoomInIcon from './icons/zoom-in.svg?component' import _ZoomInIcon from './icons/zoom-in.svg?component'
import _ZoomOutIcon from './icons/zoom-out.svg?component' import _ZoomOutIcon from './icons/zoom-out.svg?component'
export type IconComponent = FunctionalComponent<SVGAttributes>
export const AffiliateIcon = _AffiliateIcon export const AffiliateIcon = _AffiliateIcon
export const AlignLeftIcon = _AlignLeftIcon export const AlignLeftIcon = _AlignLeftIcon
export const ArchiveIcon = _ArchiveIcon export const ArchiveIcon = _ArchiveIcon

View File

@@ -14,42 +14,51 @@
</template> </template>
<template #stats> <template #stats>
<div class="flex items-center gap-3 flex-wrap gap-y-0"> <div class="flex items-center gap-3 flex-wrap gap-y-0">
<div <template v-if="isServerProject">
v-tooltip=" <ServerDetails
capitalizeString( v-if="projectV3?.status !== 'draft'"
formatMessage(commonMessages.projectDownloads, { :online-players="playersOnline"
count: formatNumber(project.downloads, false), :status-online="statusOnline"
}), :recent-plays="javaServer?.verified_plays_2w ?? 0"
) />
" </template>
class="flex items-center gap-2 font-semibold cursor-help" <template v-else>
> <div
<DownloadIcon class="h-6 w-6 text-secondary" /> v-tooltip="
{{ formatNumber(project.downloads) }} capitalizeString(
</div> formatMessage(commonMessages.projectDownloads, {
<div count: formatNumber(project.downloads, false),
v-tooltip=" }),
capitalizeString( )
formatMessage(commonMessages.projectFollowers, { "
count: formatNumber(project.followers, false), class="flex items-center gap-2 font-semibold cursor-help"
}), >
) <DownloadIcon class="h-6 w-6 text-secondary" />
" {{ formatNumber(project.downloads) }}
class="flex items-center gap-2 cursor-help" </div>
:class="{ 'md:border-r': project.categories.length > 0 }" <div
> v-tooltip="
<HeartIcon class="h-6 w-6 text-secondary" /> capitalizeString(
<span class="font-semibold"> formatMessage(commonMessages.projectFollowers, {
{{ formatNumber(project.followers) }} count: formatNumber(project.followers, false),
</span> }),
</div> )
"
class="flex items-center gap-2 cursor-help"
:class="{ 'md:border-r': project.categories.length > 0 }"
>
<HeartIcon class="h-6 w-6 text-secondary" />
<span class="font-semibold">
{{ formatNumber(project.followers) }}
</span>
</div>
</template>
<div v-if="project.categories.length > 0" class="hidden items-center gap-2 md:flex"> <div v-if="project.categories.length > 0" class="hidden items-center gap-2 md:flex">
<TagsIcon class="h-6 w-6 text-secondary" />
<div class="flex flex-wrap gap-2"> <div class="flex flex-wrap gap-2">
<TagItem <TagItem
v-for="(category, index) in project.categories" v-for="(category, index) in project.categories"
:key="index" :key="index"
:action="() => router.push(`/${project.project_type}s?f=categories:${category}`)" :action="() => router.push(`${searchUrl}?f=categories:${category}`)"
> >
<FormattedTag :tag="category" /> <FormattedTag :tag="category" />
</TagItem> </TagItem>
@@ -63,8 +72,10 @@
</ContentPageHeader> </ContentPageHeader>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { DownloadIcon, HeartIcon, TagsIcon } from '@modrinth/assets' import type { Labrinth } from '@modrinth/api-client'
import { DownloadIcon, HeartIcon } from '@modrinth/assets'
import { capitalizeString, formatNumber, type Project } from '@modrinth/utils' import { capitalizeString, formatNumber, type Project } from '@modrinth/utils'
import { computed } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useVIntl } from '../../composables' import { useVIntl } from '../../composables'
@@ -74,17 +85,30 @@ import ContentPageHeader from '../base/ContentPageHeader.vue'
import FormattedTag from '../base/FormattedTag.vue' import FormattedTag from '../base/FormattedTag.vue'
import TagItem from '../base/TagItem.vue' import TagItem from '../base/TagItem.vue'
import ProjectStatusBadge from './ProjectStatusBadge.vue' import ProjectStatusBadge from './ProjectStatusBadge.vue'
import ServerDetails from './server/ServerDetails.vue'
const router = useRouter() const router = useRouter()
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
project: Project project: Project
member?: boolean member?: boolean
projectV3?: Labrinth.Projects.v3.Project | null
ping?: number
}>(), }>(),
{ {
member: false, member: false,
}, },
) )
const searchUrl = computed(
() => `/discover/${isServerProject.value ? 'servers' : `${props.project.project_type}s`}`,
)
const isServerProject = computed(() => !!props.projectV3?.minecraft_server)
const javaServer = computed(() => props.projectV3?.minecraft_java_server)
const javaServerPingData = computed(() => props.projectV3?.minecraft_java_server?.ping?.data)
const playersOnline = computed(() => javaServerPingData.value?.players_online ?? 0)
const statusOnline = computed(() => !!javaServerPingData.value)
</script> </script>

View File

@@ -1,67 +0,0 @@
<template>
<ContentPageHeader disable-line-clamp>
<template #icon>
<Avatar :src="project.icon_url" :alt="project.title" size="108px" />
</template>
<template #title>
{{ project.title }}
</template>
<template #title-suffix>
<ProjectStatusBadge v-if="member || project.status !== 'approved'" :status="project.status" />
</template>
<template #summary>
{{ project.description }}
</template>
<template #stats>
<div class="flex items-center gap-3 gap-y-1 flex-wrap">
<ServerDetails
v-if="projectV3?.status !== 'draft'"
:online-players="playersOnline"
:status-online="statusOnline"
:recent-plays="javaServer?.verified_plays_2w ?? 0"
/>
<div v-if="project.categories.length > 0" class="hidden items-center gap-2 md:flex">
<div class="flex gap-2">
<TagItem
v-for="(category, index) in project.categories"
:key="index"
:action="() => router.push(`/discover/servers?sc=${category}`)"
>
<FormattedTag :tag="category" />
</TagItem>
</div>
</div>
</div>
</template>
<template #actions>
<slot name="actions" />
</template>
</ContentPageHeader>
</template>
<script setup lang="ts">
import type { Labrinth } from '@modrinth/api-client'
import type { Project } from '@modrinth/utils'
import { computed } from 'vue'
import { useRouter } from 'vue-router'
import Avatar from '../base/Avatar.vue'
import ContentPageHeader from '../base/ContentPageHeader.vue'
import FormattedTag from '../base/FormattedTag.vue'
import TagItem from '../base/TagItem.vue'
import ProjectStatusBadge from './ProjectStatusBadge.vue'
import ServerDetails from './server/ServerDetails.vue'
const router = useRouter()
const { project, projectV3, member } = defineProps<{
project: Project
projectV3: Labrinth.Projects.v3.Project | null
member?: boolean
ping?: number
}>()
const javaServer = computed(() => projectV3?.minecraft_java_server)
const javaServerPingData = computed(() => projectV3?.minecraft_java_server?.ping?.data)
const playersOnline = computed(() => javaServerPingData.value?.players_online ?? 0)
const statusOnline = computed(() => !!javaServerPingData.value)
</script>

View File

@@ -16,5 +16,4 @@ export { default as ProjectSidebarLinks } from './ProjectSidebarLinks.vue'
export { default as ProjectSidebarServerInfo } from './ProjectSidebarServerInfo.vue' export { default as ProjectSidebarServerInfo } from './ProjectSidebarServerInfo.vue'
export { default as ProjectSidebarTags } from './ProjectSidebarTags.vue' export { default as ProjectSidebarTags } from './ProjectSidebarTags.vue'
export { default as ProjectStatusBadge } from './ProjectStatusBadge.vue' export { default as ProjectStatusBadge } from './ProjectStatusBadge.vue'
export { default as ServerProjectHeader } from './ServerProjectHeader.vue'
export { default as TagsOverflow } from './TagsOverflow.vue' export { default as TagsOverflow } from './TagsOverflow.vue'