You've already forked AstralRinth
forked from didirus/AstralRinth
Add version filter controls to Changelog and Versions pages (#378)
This commit is contained in:
@@ -55,7 +55,7 @@ export default {
|
|||||||
color: var(--color-badge-green-text);
|
color: var(--color-badge-green-text);
|
||||||
|
|
||||||
.circle {
|
.circle {
|
||||||
background-color: var(--color-badge-green-bg);
|
background-color: var(--color-brand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
132
components/ui/VersionFilterControl.vue
Normal file
132
components/ui/VersionFilterControl.vue
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<template>
|
||||||
|
<div class="card search-controls">
|
||||||
|
<Multiselect
|
||||||
|
v-model="selectedLoaders"
|
||||||
|
:options="getValidLoaders()"
|
||||||
|
:multiple="true"
|
||||||
|
:searchable="true"
|
||||||
|
:show-no-results="false"
|
||||||
|
:close-on-select="false"
|
||||||
|
:clear-search-on-select="false"
|
||||||
|
:show-labels="false"
|
||||||
|
:selectable="() => selectedLoaders.length <= 6"
|
||||||
|
placeholder="Filter loaders..."
|
||||||
|
@input="updateVersionFilters()"
|
||||||
|
></Multiselect>
|
||||||
|
<Multiselect
|
||||||
|
v-model="selectedGameVersions"
|
||||||
|
:options="getValidVersions()"
|
||||||
|
:multiple="true"
|
||||||
|
:searchable="true"
|
||||||
|
:show-no-results="false"
|
||||||
|
:close-on-select="false"
|
||||||
|
:clear-search-on-select="false"
|
||||||
|
:show-labels="false"
|
||||||
|
:selectable="() => selectedGameVersions.length <= 6"
|
||||||
|
placeholder="Filter versions..."
|
||||||
|
@input="updateVersionFilters()"
|
||||||
|
></Multiselect>
|
||||||
|
<Checkbox
|
||||||
|
v-model="showSnapshots"
|
||||||
|
label="Include snapshots"
|
||||||
|
description="Include snapshots"
|
||||||
|
style="margin-bottom: 0.5rem"
|
||||||
|
:border="false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Multiselect from 'vue-multiselect'
|
||||||
|
import Checkbox from '~/components/ui/Checkbox'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VersionFilterControl',
|
||||||
|
components: {
|
||||||
|
Multiselect,
|
||||||
|
Checkbox,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
versions: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
query: '',
|
||||||
|
showSnapshots: false,
|
||||||
|
cachedValidVersions: null,
|
||||||
|
cachedValidLoaders: null,
|
||||||
|
selectedGameVersions: [],
|
||||||
|
selectedLoaders: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getValidVersions() {
|
||||||
|
if (!this.cachedValidVersions) {
|
||||||
|
const temp = new Set()
|
||||||
|
for (const version of this.versions) {
|
||||||
|
version.game_versions.forEach((v) => {
|
||||||
|
temp.add(v)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.cachedValidVersions = Array.from(temp)
|
||||||
|
this.cachedValidVersions.sort().reverse()
|
||||||
|
}
|
||||||
|
return this.cachedValidVersions
|
||||||
|
},
|
||||||
|
getValidLoaders() {
|
||||||
|
if (!this.cachedValidLoaders) {
|
||||||
|
const temp = new Set()
|
||||||
|
for (const version of this.versions) {
|
||||||
|
version.loaders.forEach((v) => {
|
||||||
|
temp.add(v)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.cachedValidLoaders = Array.from(temp)
|
||||||
|
this.cachedValidLoaders.sort()
|
||||||
|
}
|
||||||
|
return this.cachedValidLoaders
|
||||||
|
},
|
||||||
|
updateVersionFilters() {
|
||||||
|
const temp = this.versions.filter(
|
||||||
|
(projectVersion) =>
|
||||||
|
(this.selectedGameVersions.length === 0 ||
|
||||||
|
this.selectedGameVersions.some((gameVersion) =>
|
||||||
|
projectVersion.game_versions.includes(gameVersion)
|
||||||
|
)) &&
|
||||||
|
(this.selectedLoaders.length === 0 ||
|
||||||
|
this.selectedLoaders.some((loader) =>
|
||||||
|
projectVersion.loaders.includes(loader)
|
||||||
|
))
|
||||||
|
)
|
||||||
|
this.$emit('updateVersions', temp)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.search-controls {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: var(--spacing-card-md);
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.multiselect {
|
||||||
|
flex-grow: 1;
|
||||||
|
max-height: unset;
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
|
input::placeholder {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-outer {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,87 +1,77 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="content card">
|
<div class="content">
|
||||||
<ThisOrThat class="filters" v-model="filterMode" :items="filters" />
|
<VersionFilterControl
|
||||||
<div
|
class="card"
|
||||||
v-for="version in versions.filter((x) => x.loaders.includes(filterMode))"
|
:versions="versions"
|
||||||
:key="version.id"
|
@updateVersions="updateVersions"
|
||||||
>
|
/>
|
||||||
<div class="version-header">
|
<div class="card">
|
||||||
<span :class="'circle ' + version.version_type" />
|
<div v-for="version in filteredVersions" :key="version.id">
|
||||||
<div class="version-header-text">
|
<div class="version-header">
|
||||||
<h2 class="name">
|
<span :class="'circle ' + version.version_type" />
|
||||||
<nuxt-link
|
<div class="version-header-text">
|
||||||
:to="`/${project.project_type}/${
|
<h2 class="name">
|
||||||
project.slug ? project.slug : project.id
|
<nuxt-link
|
||||||
}/version/${encodeURIComponent(version.version_number)}`"
|
:to="`/${project.project_type}/${
|
||||||
>{{ version.name }}</nuxt-link
|
project.slug ? project.slug : project.id
|
||||||
|
}/version/${encodeURIComponent(version.version_number)}`"
|
||||||
|
>{{ version.name }}</nuxt-link
|
||||||
|
>
|
||||||
|
</h2>
|
||||||
|
<span v-if="members.find((x) => x.user.id === version.author_id)">
|
||||||
|
by
|
||||||
|
<nuxt-link
|
||||||
|
class="text-link"
|
||||||
|
:to="
|
||||||
|
'/user/' +
|
||||||
|
members.find((x) => x.user.id === version.author_id).user
|
||||||
|
.username
|
||||||
|
"
|
||||||
|
>{{
|
||||||
|
members.find((x) => x.user.id === version.author_id).user
|
||||||
|
.username
|
||||||
|
}}</nuxt-link
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
on
|
||||||
|
{{ $dayjs(version.date_published).format('MMM D, YYYY') }}</span
|
||||||
>
|
>
|
||||||
</h2>
|
</div>
|
||||||
<span v-if="members.find((x) => x.user.id === version.author_id)">
|
<a
|
||||||
by
|
:href="$parent.findPrimary(version).url"
|
||||||
<nuxt-link
|
class="iconified-button download"
|
||||||
class="text-link"
|
:title="`Download ${version.name}`"
|
||||||
:to="
|
|
||||||
'/user/' +
|
|
||||||
members.find((x) => x.user.id === version.author_id).user
|
|
||||||
.username
|
|
||||||
"
|
|
||||||
>{{
|
|
||||||
members.find((x) => x.user.id === version.author_id).user
|
|
||||||
.username
|
|
||||||
}}</nuxt-link
|
|
||||||
>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
on {{ $dayjs(version.date_published).format('MMM D, YYYY') }}</span
|
|
||||||
>
|
>
|
||||||
|
<DownloadIcon aria-hidden="true" />
|
||||||
|
Download
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<a
|
<div
|
||||||
:href="$parent.findPrimary(version).url"
|
v-highlightjs
|
||||||
class="iconified-button download"
|
:class="'markdown-body ' + version.version_type"
|
||||||
:title="`Download ${version.name}`"
|
v-html="
|
||||||
>
|
version.changelog
|
||||||
<DownloadIcon aria-hidden="true" />
|
? $xss($md.render(version.changelog))
|
||||||
Download
|
: 'No changelog specified.'
|
||||||
</a>
|
"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
v-highlightjs
|
|
||||||
:class="'markdown-body ' + version.version_type"
|
|
||||||
v-html="
|
|
||||||
version.changelog
|
|
||||||
? $xss($md.render(version.changelog))
|
|
||||||
: 'No changelog specified.'
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
||||||
import ThisOrThat from '~/components/ui/ThisOrThat'
|
import VersionFilterControl from '~/components/ui/VersionFilterControl'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
DownloadIcon,
|
DownloadIcon,
|
||||||
ThisOrThat,
|
VersionFilterControl,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
filters: [],
|
filteredVersions: this.versions,
|
||||||
filterMode: '',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fetch() {
|
|
||||||
for (const version of this.versions) {
|
|
||||||
for (const loader of version.loaders) {
|
|
||||||
if (!this.filters.includes(loader)) {
|
|
||||||
this.filters.push(loader)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.filterMode === '') {
|
|
||||||
this.filterMode = loader
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
auth: false,
|
auth: false,
|
||||||
@@ -105,18 +95,15 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
updateVersions(updatedVersions) {
|
||||||
|
this.filteredVersions = updatedVersions
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.content {
|
|
||||||
max-width: calc(100% - (2 * var(--spacing-card-lg)));
|
|
||||||
}
|
|
||||||
|
|
||||||
.filters {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.version-header {
|
.version-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="card buttons">
|
||||||
<button
|
<button
|
||||||
v-if="currentMember"
|
v-if="currentMember"
|
||||||
class="iconified-button"
|
class="iconified-button"
|
||||||
@@ -495,13 +495,7 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
button {
|
button {
|
||||||
background-color: var(--color-raised-bg);
|
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
margin-bottom: var(--spacing-card-md);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--color-button-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.brand-button-colors {
|
&.brand-button-colors {
|
||||||
background-color: var(--color-brand);
|
background-color: var(--color-brand);
|
||||||
|
|||||||
@@ -1,124 +1,134 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="content card">
|
<div class="content">
|
||||||
<nuxt-link
|
<div class="card" v-if="currentMember">
|
||||||
v-if="currentMember"
|
<nuxt-link to="version/create" class="iconified-button new-version">
|
||||||
to="version/create"
|
<UploadIcon />
|
||||||
class="iconified-button new-version"
|
Upload
|
||||||
>
|
</nuxt-link>
|
||||||
<UploadIcon />
|
</div>
|
||||||
Upload
|
<VersionFilterControl
|
||||||
</nuxt-link>
|
class="card"
|
||||||
<table>
|
:versions="versions"
|
||||||
<thead>
|
@updateVersions="updateVersions"
|
||||||
<tr>
|
/>
|
||||||
<th role="presentation"></th>
|
<div class="card">
|
||||||
<th>Version</th>
|
<table>
|
||||||
<th>Supports</th>
|
<thead>
|
||||||
<th>Stats</th>
|
<tr>
|
||||||
</tr>
|
<th role="presentation"></th>
|
||||||
</thead>
|
<th>Version</th>
|
||||||
<tbody>
|
<th>Supports</th>
|
||||||
<tr v-for="version in versions" :key="version.id">
|
<th>Stats</th>
|
||||||
<td>
|
</tr>
|
||||||
<a
|
</thead>
|
||||||
:href="$parent.findPrimary(version).url"
|
<tbody>
|
||||||
class="download-button"
|
<tr v-for="version in filteredVersions" :key="version.id">
|
||||||
:title="`Download ${version.name}`"
|
<td>
|
||||||
>
|
<a
|
||||||
<DownloadIcon aria-hidden="true" />
|
:href="$parent.findPrimary(version).url"
|
||||||
</a>
|
class="download-button"
|
||||||
</td>
|
:class="version.version_type"
|
||||||
<td>
|
:title="`Download ${version.name}`"
|
||||||
<div class="info">
|
>
|
||||||
<div class="top">
|
<DownloadIcon aria-hidden="true" />
|
||||||
<nuxt-link
|
</a>
|
||||||
:to="`/${project.project_type}/${
|
</td>
|
||||||
project.slug ? project.slug : project.id
|
<td>
|
||||||
}/version/${encodeURIComponent(version.version_number)}`"
|
<div class="info">
|
||||||
>
|
<div class="top">
|
||||||
{{ version.name }}
|
<nuxt-link
|
||||||
</nuxt-link>
|
:to="`/${project.project_type}/${
|
||||||
|
project.slug ? project.slug : project.id
|
||||||
|
}/version/${encodeURIComponent(version.version_number)}`"
|
||||||
|
>
|
||||||
|
{{ version.name }}
|
||||||
|
</nuxt-link>
|
||||||
|
</div>
|
||||||
|
<div class="bottom">
|
||||||
|
<VersionBadge
|
||||||
|
v-if="version.version_type === 'release'"
|
||||||
|
type="release"
|
||||||
|
color="green"
|
||||||
|
/>
|
||||||
|
<VersionBadge
|
||||||
|
v-else-if="version.version_type === 'beta'"
|
||||||
|
type="beta"
|
||||||
|
color="yellow"
|
||||||
|
/>
|
||||||
|
<VersionBadge
|
||||||
|
v-else-if="version.version_type === 'alpha'"
|
||||||
|
type="alpha"
|
||||||
|
color="red"
|
||||||
|
/>
|
||||||
|
<span class="divider" />
|
||||||
|
<span class="version_number">{{
|
||||||
|
version.version_number
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="mobile-info">
|
||||||
|
<p>
|
||||||
|
{{
|
||||||
|
version.loaders
|
||||||
|
.map((x) => x.charAt(0).toUpperCase() + x.slice(1))
|
||||||
|
.join(', ') +
|
||||||
|
' ' +
|
||||||
|
$formatVersion(version.game_versions)
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
<p></p>
|
||||||
|
<p>
|
||||||
|
<strong>{{ $formatNumber(version.downloads) }}</strong>
|
||||||
|
downloads
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Published on
|
||||||
|
<strong>{{
|
||||||
|
$dayjs(version.date_published).format('MMM D, YYYY')
|
||||||
|
}}</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bottom">
|
</td>
|
||||||
<VersionBadge
|
<td>
|
||||||
v-if="version.version_type === 'release'"
|
<p>
|
||||||
type="release"
|
{{
|
||||||
color="green"
|
version.loaders
|
||||||
/>
|
.map((x) => x.charAt(0).toUpperCase() + x.slice(1))
|
||||||
<VersionBadge
|
.join(', ')
|
||||||
v-else-if="version.version_type === 'beta'"
|
}}
|
||||||
type="beta"
|
</p>
|
||||||
color="yellow"
|
<p>{{ $formatVersion(version.game_versions) }}</p>
|
||||||
/>
|
</td>
|
||||||
<VersionBadge
|
<td>
|
||||||
v-else-if="version.version_type === 'alpha'"
|
<p>
|
||||||
type="alpha"
|
<span>{{ $formatNumber(version.downloads) }}</span>
|
||||||
color="red"
|
downloads
|
||||||
/>
|
</p>
|
||||||
<span class="divider" />
|
<p>
|
||||||
<span class="version_number">{{ version.version_number }}</span>
|
Published on
|
||||||
</div>
|
<span>{{
|
||||||
<div class="mobile-info">
|
$dayjs(version.date_published).format('MMM D, YYYY')
|
||||||
<p>
|
}}</span>
|
||||||
{{
|
</p>
|
||||||
version.loaders
|
</td>
|
||||||
.map((x) => x.charAt(0).toUpperCase() + x.slice(1))
|
</tr>
|
||||||
.join(', ') +
|
</tbody>
|
||||||
' ' +
|
</table>
|
||||||
$formatVersion(version.game_versions)
|
</div>
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
<p></p>
|
|
||||||
<p>
|
|
||||||
<strong>{{ $formatNumber(version.downloads) }}</strong>
|
|
||||||
downloads
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Published on
|
|
||||||
<strong>{{
|
|
||||||
$dayjs(version.date_published).format('MMM D, YYYY')
|
|
||||||
}}</strong>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<p>
|
|
||||||
{{
|
|
||||||
version.loaders
|
|
||||||
.map((x) => x.charAt(0).toUpperCase() + x.slice(1))
|
|
||||||
.join(', ')
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
<p>{{ $formatVersion(version.game_versions) }}</p>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<p>
|
|
||||||
<span>{{ $formatNumber(version.downloads) }}</span>
|
|
||||||
downloads
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Published on
|
|
||||||
<span>{{
|
|
||||||
$dayjs(version.date_published).format('MMM D, YYYY')
|
|
||||||
}}</span>
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import UploadIcon from '~/assets/images/utils/upload.svg?inline'
|
import UploadIcon from '~/assets/images/utils/upload.svg?inline'
|
||||||
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
||||||
import VersionBadge from '~/components/ui/Badge'
|
import VersionBadge from '~/components/ui/Badge'
|
||||||
|
import VersionFilterControl from '~/components/ui/VersionFilterControl'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
UploadIcon,
|
UploadIcon,
|
||||||
DownloadIcon,
|
DownloadIcon,
|
||||||
VersionBadge,
|
VersionBadge,
|
||||||
|
VersionFilterControl,
|
||||||
},
|
},
|
||||||
auth: false,
|
auth: false,
|
||||||
props: {
|
props: {
|
||||||
@@ -141,14 +151,20 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
filteredVersions: this.versions,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateVersions(updatedVersions) {
|
||||||
|
this.filteredVersions = updatedVersions
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.content {
|
|
||||||
max-width: calc(100% - (2 * var(--spacing-card-lg)));
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-version {
|
.new-version {
|
||||||
max-width: 5.25rem;
|
max-width: 5.25rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,7 +142,7 @@
|
|||||||
<section class="normal-page__content">
|
<section class="normal-page__content">
|
||||||
<div class="card search-controls">
|
<div class="card search-controls">
|
||||||
<div class="iconified-input">
|
<div class="iconified-input">
|
||||||
<label class="hidden" for="search">Search Mods</label>
|
<label class="hidden" for="search">Search</label>
|
||||||
<SearchIcon aria-hidden="true" />
|
<SearchIcon aria-hidden="true" />
|
||||||
<input
|
<input
|
||||||
id="search"
|
id="search"
|
||||||
|
|||||||
Reference in New Issue
Block a user