* WIP: Redesign the default layout * Merge old & new default layouts * Fix login logic; add proper user controls dropdown * Fix latest version listing (#31) (#32) Co-authored-by: Aeledfyr <45501007+Aeledfyr@users.noreply.github.com> * First pass of design cleanup * Improve ad integration and fix light theme * Begin splitting up variables, change some styling to new mockup * Continue redesign progress * Work on some more pages * Add missing dark theme variables for text * Continue working on modularizing * Continue progress, redo pagination * Fix auth buttons in navbar layout * Continue progress * Continue progress more * Redo ModResult * Scope ModPage :irritater: * Continue Dashboard * Continue progress on Dashboard and cleanup * Add missing variables for dark theme * Small tweaks, cleanup, and continue mod page progress * Fix user not being able to see hidden mods that they own * Start reworking mod creation * Continue revamp of mod creation page * Yank v-html out * Hotfix markdown rendering and some spacing issues * Move legal; continue with mod creation; create reusable footer * Create README.md * Update README.md * Update README.md * Add in basic usage instructions * Fix some stuff * Continue with mod creation; fix some CSS errors * Start user page * Start transition to vue-select; fix a few bugs * Continue mod creation page * Finish mod pages * Add very raw version editing * Mod editing + creation * Fixed versions that were in processing causing a 404 (#39) Co-authored-by: Mikhail Oleynikov <falseresync@gmail.com> Co-authored-by: Aeledfyr <45501007+Aeledfyr@users.noreply.github.com> Co-authored-by: Jai A <jai.a@tuta.io> Co-authored-by: MulverineX <mulverin3@gmail.com> Co-authored-by: diabolical17 <calumproh28@gmail.com> Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
276 lines
6.3 KiB
Vue
276 lines
6.3 KiB
Vue
<template>
|
|
<div class="project-card">
|
|
<div class="icon">
|
|
<img
|
|
:src="iconUrl ? iconUrl : 'https://cdn.modrinth.com/placeholder.svg'"
|
|
:alt="name"
|
|
/>
|
|
</div>
|
|
<div class="info">
|
|
<div class="top">
|
|
<h2 class="title">
|
|
<nuxt-link v-if="isModrinth" :to="'/mod/' + id">{{ name }}</nuxt-link>
|
|
<a v-else :href="pageUrl">{{ name }}</a>
|
|
</h2>
|
|
<p v-if="author" class="author">
|
|
by <a :href="authorUrl">{{ author }}</a>
|
|
</p>
|
|
</div>
|
|
<p class="description">
|
|
{{ description }}
|
|
</p>
|
|
<div :class="{ vertical: editMode }" class="bottom">
|
|
<div class="stats">
|
|
<div v-if="status !== null" class="stat">
|
|
<div class="info">
|
|
<h4>Status</h4>
|
|
<span v-if="status === 'approved'" class="badge green">
|
|
Approved
|
|
</span>
|
|
<span v-if="status === 'rejected'" class="badge red">
|
|
Rejected
|
|
</span>
|
|
<span v-if="status === 'draft'" class="badge yellow">Draft</span>
|
|
<span v-if="status === 'processing'" class="badge yellow">
|
|
Processing
|
|
</span>
|
|
<span v-if="status === 'unlisted'" class="badge gray">
|
|
Unlisted
|
|
</span>
|
|
<span v-if="status === 'unknown'" class="badge gray">
|
|
Unknown
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="stat">
|
|
<DownloadIcon />
|
|
<div class="info">
|
|
<h4>Downloads</h4>
|
|
<p class="value">{{ formatNumber(downloads) }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="stat">
|
|
<CalendarIcon />
|
|
<div class="info">
|
|
<h4>Created</h4>
|
|
<p
|
|
v-tooltip="
|
|
$dayjs(createdAt).format(
|
|
'[Created on] YYYY-MM-DD [at] HH:mm A'
|
|
)
|
|
"
|
|
class="value"
|
|
>
|
|
{{ $dayjs(createdAt).fromNow() }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="stat">
|
|
<EditIcon />
|
|
<div class="info">
|
|
<h4>Updated</h4>
|
|
<p
|
|
v-tooltip="
|
|
$dayjs(updatedAt).format(
|
|
'[Updated on] YYYY-MM-DD [at] HH:mm A'
|
|
)
|
|
"
|
|
class="value"
|
|
>
|
|
{{ $dayjs(updatedAt).fromNow() }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div v-if="latestVersion" class="stat">
|
|
<TagIcon />
|
|
<div class="info">
|
|
<h4>Available For</h4>
|
|
<p class="value">
|
|
{{ latestVersion }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<Categories :categories="categories" />
|
|
</div>
|
|
</div>
|
|
<div v-if="editMode" class="buttons">
|
|
<nuxt-link class="transparent-button column" :to="'/mod/' + id + '/edit'">
|
|
Edit
|
|
</nuxt-link>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import Categories from '@/components/Categories'
|
|
|
|
import CalendarIcon from '~/assets/images/utils/calendar.svg?inline'
|
|
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
|
import EditIcon from '~/assets/images/utils/edit.svg?inline'
|
|
import TagIcon from '~/assets/images/utils/tag.svg?inline'
|
|
|
|
export default {
|
|
name: 'ProjectCard',
|
|
components: {
|
|
Categories,
|
|
CalendarIcon,
|
|
DownloadIcon,
|
|
EditIcon,
|
|
TagIcon,
|
|
},
|
|
props: {
|
|
id: {
|
|
type: String,
|
|
default: 'modrinth-0',
|
|
},
|
|
name: {
|
|
type: String,
|
|
default: 'Mod Name',
|
|
},
|
|
author: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
description: {
|
|
type: String,
|
|
default: 'A mod description',
|
|
},
|
|
pageUrl: {
|
|
type: String,
|
|
default: '#',
|
|
},
|
|
authorUrl: {
|
|
type: String,
|
|
default: '#',
|
|
},
|
|
iconUrl: {
|
|
type: String,
|
|
default: '#',
|
|
},
|
|
downloads: {
|
|
type: String,
|
|
default: '0',
|
|
},
|
|
createdAt: {
|
|
type: String,
|
|
default: '0000-00-00',
|
|
},
|
|
updatedAt: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
latestVersion: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
categories: {
|
|
type: Array,
|
|
default() {
|
|
return []
|
|
},
|
|
},
|
|
editMode: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
status: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
role: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
isModrinth: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
},
|
|
methods: {
|
|
formatNumber(x) {
|
|
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.project-card {
|
|
@extend %row;
|
|
@extend %card-spaced-b;
|
|
width: 100%;
|
|
.icon {
|
|
margin: auto 0;
|
|
img {
|
|
width: 6rem;
|
|
height: 6rem;
|
|
margin: var(--spacing-card-md);
|
|
border-radius: var(--size-rounded-icon);
|
|
object-fit: contain;
|
|
}
|
|
}
|
|
.info {
|
|
@extend %column;
|
|
.top {
|
|
@extend %row;
|
|
flex-wrap: wrap;
|
|
margin-top: var(--spacing-card-md);
|
|
margin-right: var(--spacing-card-md);
|
|
.title {
|
|
margin: 0;
|
|
color: var(--color-text-dark);
|
|
font-size: var(--font-size-lg);
|
|
}
|
|
.author {
|
|
margin: auto 0 0 0.5rem;
|
|
color: var(--color-text);
|
|
}
|
|
}
|
|
.description {
|
|
margin: var(--spacing-card-sm) var(--spacing-card-md) 0 0;
|
|
height: 100%;
|
|
color: var(--color-text-dark);
|
|
}
|
|
.bottom {
|
|
@extend %column;
|
|
margin-top: var(--spacing-card-sm);
|
|
margin-right: var(--spacing-card-md);
|
|
margin-bottom: var(--spacing-card-md);
|
|
|
|
@media screen and (min-width: 1024px) {
|
|
flex-direction: row;
|
|
&.vertical {
|
|
flex-direction: column;
|
|
.categories {
|
|
margin-top: var(--spacing-card-sm);
|
|
}
|
|
}
|
|
}
|
|
|
|
.stats {
|
|
@extend %row;
|
|
flex-wrap: wrap;
|
|
|
|
@media screen and (min-width: 900px) {
|
|
flex-wrap: nowrap;
|
|
}
|
|
|
|
.stat {
|
|
@extend %stat;
|
|
}
|
|
}
|
|
.categories {
|
|
@media screen and (min-width: 1024px) {
|
|
flex-direction: row;
|
|
margin: auto 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.buttons {
|
|
@extend %column;
|
|
}
|
|
}
|
|
</style>
|