proj card fixes
This commit is contained in:
@@ -285,9 +285,9 @@
|
|||||||
]"
|
]"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<ProjectCardList
|
||||||
v-if="projects && projects?.length > 0"
|
v-if="projects && projects?.length > 0"
|
||||||
:class="'project-list display-mode--' + (cosmetics.searchDisplayMode.collection || 'list')"
|
:layout="cosmetics.searchDisplayMode.collection"
|
||||||
>
|
>
|
||||||
<ProjectCard
|
<ProjectCard
|
||||||
v-for="project in (route.params.projectType !== undefined
|
v-for="project in (route.params.projectType !== undefined
|
||||||
@@ -343,7 +343,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</ProjectCard>
|
</ProjectCard>
|
||||||
</div>
|
</ProjectCardList>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div class="mx-auto flex flex-col justify-center gap-8 p-6 text-center">
|
<div class="mx-auto flex flex-col justify-center gap-8 p-6 text-center">
|
||||||
<EmptyIllustration class="h-[120px] w-auto" />
|
<EmptyIllustration class="h-[120px] w-auto" />
|
||||||
@@ -402,6 +402,7 @@ import {
|
|||||||
NormalPage,
|
NormalPage,
|
||||||
OverflowMenu,
|
OverflowMenu,
|
||||||
ProjectCard,
|
ProjectCard,
|
||||||
|
ProjectCardList,
|
||||||
RadioButtons,
|
RadioButtons,
|
||||||
SidebarCard,
|
SidebarCard,
|
||||||
useRelativeTime,
|
useRelativeTime,
|
||||||
|
|||||||
@@ -186,50 +186,47 @@
|
|||||||
<div v-if="navLinks.length > 2" class="mb-4 max-w-full overflow-x-auto">
|
<div v-if="navLinks.length > 2" class="mb-4 max-w-full overflow-x-auto">
|
||||||
<NavTabs :links="navLinks" />
|
<NavTabs :links="navLinks" />
|
||||||
</div>
|
</div>
|
||||||
<template v-if="projects && projects.length > 0">
|
<ProjectCardList v-if="projects && projects.length > 0">
|
||||||
<div class="project-list display-mode--list">
|
<ProjectCard
|
||||||
<ProjectCard
|
v-for="project in (route.params.projectType !== undefined
|
||||||
v-for="project in (route.params.projectType !== undefined
|
? (projects ?? []).filter((x) =>
|
||||||
? (projects ?? []).filter((x) =>
|
x.project_types.includes(
|
||||||
x.project_types.includes(
|
typeof route.params.projectType === 'string'
|
||||||
typeof route.params.projectType === 'string'
|
? route.params.projectType.slice(0, route.params.projectType.length - 1)
|
||||||
? route.params.projectType.slice(0, route.params.projectType.length - 1)
|
: route.params.projectType[0]?.slice(
|
||||||
: route.params.projectType[0]?.slice(
|
0,
|
||||||
0,
|
route.params.projectType[0].length - 1,
|
||||||
route.params.projectType[0].length - 1,
|
) || '',
|
||||||
) || '',
|
),
|
||||||
),
|
)
|
||||||
)
|
: (projects ?? [])
|
||||||
: (projects ?? [])
|
)
|
||||||
)
|
.slice()
|
||||||
.slice()
|
.sort((a, b) => b.downloads - a.downloads)"
|
||||||
.sort((a, b) => b.downloads - a.downloads)"
|
:key="project.id"
|
||||||
:key="project.id"
|
:link="`/${project.project_types[0] ?? 'project'}/${project.slug || project.id}`"
|
||||||
:link="`/${project.project_types[0] ?? 'project'}/${project.slug || project.id}`"
|
:title="project.name"
|
||||||
:title="project.name"
|
:icon-url="project.icon_url"
|
||||||
:icon-url="project.icon_url"
|
:banner="project.gallery.find((element) => element.featured)?.url"
|
||||||
:banner="project.gallery.find((element) => element.featured)?.url"
|
:summary="project.summary"
|
||||||
:summary="project.summary"
|
:date-updated="project.updated"
|
||||||
:date-updated="project.updated"
|
:downloads="project.downloads"
|
||||||
:downloads="project.downloads"
|
:followers="project.followers"
|
||||||
:followers="project.followers"
|
:tags="project.categories"
|
||||||
:tags="project.categories"
|
:environment="{
|
||||||
:environment="{
|
clientSide: project.client_side,
|
||||||
clientSide: project.client_side,
|
serverSide: project.server_side,
|
||||||
serverSide: project.server_side,
|
}"
|
||||||
}"
|
:status="
|
||||||
:status="
|
auth.user &&
|
||||||
auth.user &&
|
(auth.user.id! === (user as any).id || tags.staffRoles.includes(auth.user.role))
|
||||||
(auth.user.id! === (user as any).id || tags.staffRoles.includes(auth.user.role))
|
? (project.status as ProjectStatus)
|
||||||
? (project.status as ProjectStatus)
|
: undefined
|
||||||
: undefined
|
"
|
||||||
"
|
:color="project.color"
|
||||||
:color="project.color"
|
layout="list"
|
||||||
layout="list"
|
/>
|
||||||
/>
|
</ProjectCardList>
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div v-else-if="true" class="error">
|
<div v-else-if="true" class="error">
|
||||||
<UpToDate class="icon" />
|
<UpToDate class="icon" />
|
||||||
<br />
|
<br />
|
||||||
@@ -267,6 +264,7 @@ import {
|
|||||||
ContentPageHeader,
|
ContentPageHeader,
|
||||||
OverflowMenu,
|
OverflowMenu,
|
||||||
ProjectCard,
|
ProjectCard,
|
||||||
|
ProjectCardList,
|
||||||
useVIntl,
|
useVIntl,
|
||||||
} from '@modrinth/ui'
|
} from '@modrinth/ui'
|
||||||
import type { Organization, ProjectStatus, ProjectType, ProjectV3 } from '@modrinth/utils'
|
import type { Organization, ProjectStatus, ProjectType, ProjectV3 } from '@modrinth/utils'
|
||||||
|
|||||||
@@ -286,9 +286,9 @@
|
|||||||
<NavTabs :links="navLinks" />
|
<NavTabs :links="navLinks" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="projects.length > 0">
|
<div v-if="projects.length > 0">
|
||||||
<div
|
<ProjectCardList
|
||||||
v-if="route.params.projectType !== 'collections'"
|
v-if="route.params.projectType !== 'collections'"
|
||||||
:class="'project-list display-mode--' + cosmetics.searchDisplayMode.user"
|
:layout="cosmetics.searchDisplayMode.user"
|
||||||
>
|
>
|
||||||
<ProjectCard
|
<ProjectCard
|
||||||
v-for="project in (route.params.projectType !== undefined
|
v-for="project in (route.params.projectType !== undefined
|
||||||
@@ -315,6 +315,7 @@
|
|||||||
...project.additional_categories,
|
...project.additional_categories,
|
||||||
]"
|
]"
|
||||||
:followers="project.followers"
|
:followers="project.followers"
|
||||||
|
:banner="project.gallery.find((element) => element.featured)?.url"
|
||||||
:color="project.color ?? undefined"
|
:color="project.color ?? undefined"
|
||||||
:environment="{
|
:environment="{
|
||||||
clientSide: project.client_side,
|
clientSide: project.client_side,
|
||||||
@@ -328,7 +329,7 @@
|
|||||||
"
|
"
|
||||||
:status="project.status"
|
:status="project.status"
|
||||||
/>
|
/>
|
||||||
</div>
|
</ProjectCardList>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else-if="
|
v-else-if="
|
||||||
@@ -499,6 +500,7 @@ import {
|
|||||||
NewModal,
|
NewModal,
|
||||||
OverflowMenu,
|
OverflowMenu,
|
||||||
ProjectCard,
|
ProjectCard,
|
||||||
|
ProjectCardList,
|
||||||
TagItem,
|
TagItem,
|
||||||
useRelativeTime,
|
useRelativeTime,
|
||||||
useVIntl,
|
useVIntl,
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="smart-clickable" :class="{ 'smart-clickable--has-clickable': !!$slots.clickable }">
|
<div class="smart-clickable" :class="{ 'smart-clickable--has-clickable': !!$slots.clickable }">
|
||||||
<slot name="clickable" />
|
<slot name="clickable" />
|
||||||
<div v-bind="$attrs" class="smart-clickable__contents pointer-events-none">
|
<div
|
||||||
|
v-bind="$attrs"
|
||||||
|
class="smart-clickable__contents"
|
||||||
|
:class="{
|
||||||
|
'pointer-events-none': !!$slots.clickable,
|
||||||
|
}"
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -23,6 +23,6 @@ withDefaults(
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.grid-project-list {
|
.grid-project-list {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, minmax(150px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,123 +1,52 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-full" @mouseenter="$emit('hover')">
|
<SmartClickable class="w-full project-card-container">
|
||||||
<SmartClickable class="w-full project-card-container">
|
<template v-if="link" #clickable>
|
||||||
<template v-if="link" #clickable>
|
<AutoLink
|
||||||
<AutoLink
|
:to="link"
|
||||||
:to="link"
|
class="rounded-xl no-outline no-click-animation custom-focus-indicator"
|
||||||
class="rounded-xl no-outline no-click-animation custom-focus-indicator"
|
@mouseenter="$emit('hover')"
|
||||||
></AutoLink>
|
></AutoLink>
|
||||||
</template>
|
</template>
|
||||||
<div v-if="layout === 'grid'" :class="[baseCardStyle, 'flex flex-col']">
|
<div v-if="layout === 'grid'" :class="[baseCardStyle, 'flex flex-col']">
|
||||||
<div
|
<div
|
||||||
:style="{ '--_project-color': cssColor }"
|
:style="{ '--_project-color': cssColor }"
|
||||||
class="relative bg-project-gradient overflow-clip aspect-[2/1] w-full border-0 border-b-[1px] border-solid border-surface-4"
|
class="relative bg-project-gradient overflow-clip aspect-[2/1] w-full border-0 border-b-[1px] border-solid border-surface-4"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
v-if="banner"
|
v-if="banner"
|
||||||
:src="banner"
|
:src="banner"
|
||||||
alt=""
|
alt=""
|
||||||
class="absolute w-full h-full inset-0 object-cover object-center"
|
class="absolute w-full h-full inset-0 object-cover object-center"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
v-else
|
v-else
|
||||||
src="https://cdn-raw.modrinth.com/landing-new/landing.webp"
|
src="https://cdn-raw.modrinth.com/landing-new/landing.webp"
|
||||||
alt=""
|
alt=""
|
||||||
class="absolute w-full h-full inset-0 object-cover object-center placeholder-banner scale-[200%]"
|
class="absolute w-full h-full inset-0 object-cover object-center placeholder-banner scale-[200%]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-4 flex flex-col gap-3 grow">
|
<div class="p-4 flex flex-col gap-3 grow">
|
||||||
<div class="flex gap-3">
|
<div class="flex gap-3">
|
||||||
<Avatar :src="iconUrl" size="96px" class="project-card__icon" no-shadow />
|
<Avatar :src="iconUrl" size="96px" class="project-card__icon" no-shadow />
|
||||||
<div class="flex flex-col gap-2 w-full">
|
<div class="flex flex-col gap-2 w-full">
|
||||||
<div class="grid grid-cols-[1fr_auto] gap-4">
|
<div class="grid grid-cols-[1fr_auto] gap-4">
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<div class="flex gap-2 items-center">
|
<div class="flex gap-2 items-center">
|
||||||
<ProjectCardTitle :title="title" compact />
|
<ProjectCardTitle :title="title" compact />
|
||||||
<ProjectCardAuthor v-if="author" :author="author" />
|
<ProjectCardAuthor v-if="author" :author="author" />
|
||||||
</div>
|
</div>
|
||||||
<div class="m-0 font-normal line-clamp-2">
|
<div class="m-0 font-normal line-clamp-2">
|
||||||
{{ summary }}
|
{{ summary }}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2 shrink-0 empty:hidden smart-clickable:allow-pointer-events">
|
|
||||||
<slot name="actions" />
|
|
||||||
</div>
|
|
||||||
<div class="mt-auto flex flex-col gap-3 flex-wrap overflow-hidden justify-between grow">
|
|
||||||
<div class="flex items-center gap-1 flex-wrap overflow-hidden">
|
|
||||||
<ProjectCardEnvironment
|
|
||||||
v-if="environment"
|
|
||||||
:client-side="environment.clientSide"
|
|
||||||
:server-side="environment.serverSide"
|
|
||||||
/>
|
|
||||||
<ProjectCardTags
|
|
||||||
v-if="tags"
|
|
||||||
:tags="tags"
|
|
||||||
:exclude-loaders="excludeLoaders"
|
|
||||||
:deprioritized-tags="deprioritizedTags"
|
|
||||||
:max-tags="6 + (!!environment ? 0 : 1)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="downloads !== undefined || followers !== undefined"
|
|
||||||
class="flex items-center gap-3 justify-between flex-wrap"
|
|
||||||
>
|
|
||||||
<div class="flex items-center gap-3 no-wrap flex-wrap">
|
|
||||||
<ProjectCardStats :downloads="downloads" :followers="followers" />
|
|
||||||
</div>
|
|
||||||
<ProjectCardDate
|
|
||||||
v-if="date && autoDisplayDate"
|
|
||||||
:type="autoDisplayDate"
|
|
||||||
:date="date"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="flex gap-2 shrink-0 empty:hidden smart-clickable:allow-pointer-events">
|
||||||
<div
|
|
||||||
v-else
|
|
||||||
:class="[
|
|
||||||
baseCardStyle,
|
|
||||||
'p-4 grid grid-project-card-list gap-x-3 gap-y-2',
|
|
||||||
{ 'has-actions': !!$slots.actions },
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
<Avatar
|
|
||||||
:src="iconUrl"
|
|
||||||
size="100px"
|
|
||||||
class="project-card__icon grid-project-card-list__icon"
|
|
||||||
no-shadow
|
|
||||||
/>
|
|
||||||
<div class="flex flex-col gap-2 grid-project-card-list__info">
|
|
||||||
<div class="flex gap-2 items-center">
|
|
||||||
<ProjectCardTitle :title="title" />
|
|
||||||
<ProjectCardAuthor v-if="author" :author="author" />
|
|
||||||
<ProjectStatusBadge v-if="status" :status="status" />
|
|
||||||
</div>
|
|
||||||
<div class="project-card-summary m-0 font-normal line-clamp-2">
|
|
||||||
{{ summary }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="!!$slots.actions"
|
|
||||||
class="flex gap-1 shrink-0 ml-auto empty:hidden smart-clickable:allow-pointer-events grid-project-card-list__actions"
|
|
||||||
>
|
|
||||||
<slot name="actions" />
|
<slot name="actions" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="mt-auto flex flex-col gap-3 flex-wrap overflow-hidden justify-between grow">
|
||||||
class="flex flex-col gap-3 items-end shrink-0 ml-auto empty:hidden grid-project-card-list__stats"
|
<div class="flex items-center gap-1 flex-wrap overflow-hidden">
|
||||||
:class="{ 'mt-3': !!$slots.actions }"
|
|
||||||
>
|
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<ProjectCardStats :downloads="downloads" :followers="followers" />
|
|
||||||
</div>
|
|
||||||
<ProjectCardDate v-if="date && autoDisplayDate" :type="autoDisplayDate" :date="date" />
|
|
||||||
</div>
|
|
||||||
<div class="mt-auto flex items-center gap-3 grid-project-card-list__tags">
|
|
||||||
<div class="flex items-center gap-1 flex-wrap">
|
|
||||||
<ProjectCardEnvironment
|
<ProjectCardEnvironment
|
||||||
v-if="environment"
|
v-if="environment"
|
||||||
:client-side="environment.clientSide"
|
:client-side="environment.clientSide"
|
||||||
@@ -126,16 +55,82 @@
|
|||||||
<ProjectCardTags
|
<ProjectCardTags
|
||||||
v-if="tags"
|
v-if="tags"
|
||||||
:tags="tags"
|
:tags="tags"
|
||||||
:extra-tags="extraTags"
|
|
||||||
:exclude-loaders="excludeLoaders"
|
:exclude-loaders="excludeLoaders"
|
||||||
:deprioritized-tags="deprioritizedTags"
|
:deprioritized-tags="deprioritizedTags"
|
||||||
:max-tags="(!!$slots.actions ? 4 : 5) + (!!environment ? 0 : 1)"
|
:max-tags="6 + (!!environment ? 0 : 1)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="downloads !== undefined || followers !== undefined"
|
||||||
|
class="flex items-center gap-3 justify-between flex-wrap"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-3 no-wrap flex-wrap">
|
||||||
|
<ProjectCardStats :downloads="downloads" :followers="followers" />
|
||||||
|
</div>
|
||||||
|
<ProjectCardDate v-if="date && autoDisplayDate" :type="autoDisplayDate" :date="date" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SmartClickable>
|
</div>
|
||||||
</div>
|
<div
|
||||||
|
v-else
|
||||||
|
:class="[
|
||||||
|
baseCardStyle,
|
||||||
|
'p-4 grid grid-project-card-list gap-x-3 gap-y-2',
|
||||||
|
{ 'has-actions': !!$slots.actions },
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
:src="iconUrl"
|
||||||
|
size="100px"
|
||||||
|
class="project-card__icon grid-project-card-list__icon"
|
||||||
|
no-shadow
|
||||||
|
/>
|
||||||
|
<div class="flex flex-col gap-2 grid-project-card-list__info">
|
||||||
|
<div class="flex gap-2 items-center">
|
||||||
|
<ProjectCardTitle :title="title" />
|
||||||
|
<ProjectCardAuthor v-if="author" :author="author" />
|
||||||
|
<ProjectStatusBadge v-if="status" :status="status" />
|
||||||
|
</div>
|
||||||
|
<div class="project-card-summary m-0 font-normal line-clamp-2">
|
||||||
|
{{ summary }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="!!$slots.actions"
|
||||||
|
class="flex gap-1 shrink-0 ml-auto empty:hidden smart-clickable:allow-pointer-events grid-project-card-list__actions"
|
||||||
|
>
|
||||||
|
<slot name="actions" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex flex-col gap-3 items-end shrink-0 ml-auto empty:hidden grid-project-card-list__stats"
|
||||||
|
:class="{ 'mt-3': !!$slots.actions }"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<ProjectCardStats :downloads="downloads" :followers="followers" />
|
||||||
|
</div>
|
||||||
|
<ProjectCardDate v-if="date && autoDisplayDate" :type="autoDisplayDate" :date="date" />
|
||||||
|
</div>
|
||||||
|
<div class="mt-auto flex items-center gap-3 grid-project-card-list__tags">
|
||||||
|
<div class="flex items-center gap-1 flex-wrap">
|
||||||
|
<ProjectCardEnvironment
|
||||||
|
v-if="environment"
|
||||||
|
:client-side="environment.clientSide"
|
||||||
|
:server-side="environment.serverSide"
|
||||||
|
/>
|
||||||
|
<ProjectCardTags
|
||||||
|
v-if="tags"
|
||||||
|
:tags="tags"
|
||||||
|
:extra-tags="extraTags"
|
||||||
|
:exclude-loaders="excludeLoaders"
|
||||||
|
:deprioritized-tags="deprioritizedTags"
|
||||||
|
:max-tags="(!!$slots.actions ? 4 : 5) + (!!environment ? 0 : 1)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SmartClickable>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ const VERSIONS: VersionEntry[] = [
|
|||||||
// - Adjusted pop-up design to include a border.
|
// - Adjusted pop-up design to include a border.
|
||||||
// - Updated translations.`,
|
// - Updated translations.`,
|
||||||
// },
|
// },
|
||||||
|
{
|
||||||
|
date: `2026-02-07T12:10:00-08:00`,
|
||||||
|
product: 'web',
|
||||||
|
body: `## Improvements
|
||||||
|
- Fixed grid project lists displaying too narrow sometimes.
|
||||||
|
- Fixed grid project list on user profiles not displaying project banners.
|
||||||
|
- Fixed grid project list cards not matching the height of their neighbor.`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
date: `2026-02-07T11:45:00-08:00`,
|
date: `2026-02-07T11:45:00-08:00`,
|
||||||
product: 'web',
|
product: 'web',
|
||||||
|
|||||||
Reference in New Issue
Block a user