Merge server project header into project header (#5500)
This commit is contained in:
@@ -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'
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
|
||||||
@@ -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'
|
||||||
|
|||||||
Reference in New Issue
Block a user