Datapack support (#815)

* Shader support PR

* Make search page work

* Fix env showing

* Make moderation look reasonable

* Fix search for shaders

* Datapack support

* Make file types work + datapack inferring

* Add editing to file types

* Finish datapack file generation

* Fix bugs, make forge support work

* Fix inconsistent data pack label

* Final fixes
This commit is contained in:
Geometrically
2022-12-29 09:59:41 -07:00
committed by GitHub
parent 879576b613
commit 1f133dbcd0
22 changed files with 978 additions and 262 deletions

View File

@@ -45,7 +45,9 @@
<div
v-if="
project.project_type !== 'resourcepack' &&
project.project_type !== 'plugin'
project.project_type !== 'plugin' &&
project.project_type !== 'shader' &&
project.project_type !== 'datapack'
"
>
<div
@@ -502,7 +504,8 @@
v-if="
project.project_type !== 'resourcepack' &&
project.project_type !== 'plugin' &&
project.project_type !== 'shader'
project.project_type !== 'shader' &&
project.project_type !== 'datapack'
"
class="info"
>
@@ -515,7 +518,8 @@
v-if="
project.project_type !== 'resourcepack' &&
project.project_type !== 'plugin' &&
project.project_type !== 'shader'
project.project_type !== 'shader' &&
project.project_type !== 'datapack'
"
class="info"
>
@@ -843,10 +847,9 @@ export default {
this.featuredVersions = this.$computeVersions(this.featuredVersions)
},
head() {
const title = `${this.project.title} - Minecraft ${
this.projectTypeDisplay.charAt(0).toUpperCase() +
this.projectTypeDisplay.slice(1)
}`
const title = `${this.project.title} - Minecraft ${this.$formatProjectType(
this.projectTypeDisplay
)}`
return {
title,
@@ -869,9 +872,11 @@ export default {
{
hid: 'description',
name: 'description',
content: `${this.project.description} - Download the Minecraft ${
content: `${
this.project.description
} - Download the Minecraft ${this.$formatProjectType(
this.projectTypeDisplay
} ${this.project.title} by ${
)} ${this.project.title} by ${
this.members.find((x) => x.role === 'Owner').user.username
} on Modrinth`,
},

View File

@@ -209,7 +209,8 @@
<section
v-if="
project.project_type !== 'resourcepack' &&
project.project_type !== 'shader'
project.project_type !== 'shader' &&
project.project_type !== 'datapack'
"
class="card game-sides"
>
@@ -833,6 +834,9 @@ export default {
this.newProject.client_side = this.clientSideType.toLowerCase()
this.newProject.server_side = this.serverSideType.toLowerCase()
this.newProject.client_side = this.clientSideType.toLowerCase()
this.newProject.server_side = this.serverSideType.toLowerCase()
this.$emit('update:project', this.newProject)
this.isEditing = false

View File

@@ -371,7 +371,10 @@ export default {
}
}
document.addEventListener('keydown', this._keyListener.bind(this))
// eslint-disable-next-line nuxt/no-env-in-hooks
if (process.client) {
document.addEventListener('keydown', this._keyListener.bind(this))
}
},
methods: {
showPreviewImage(files, index) {

View File

@@ -1,6 +1,7 @@
<template>
<div v-if="version" class="version-page">
<ModalConfirm
v-if="$auth.user && currentMember"
ref="modal_confirm"
title="Are you sure you want to delete this version?"
description="This will remove this version forever (like really forever)."
@@ -14,6 +15,58 @@
:item-id="version.id"
item-type="version"
/>
<Modal
v-if="$auth.user && currentMember"
ref="modal_package_mod"
header="Package data pack"
>
<div class="modal-package-mod universal-labels">
<div class="markdown-body">
<p>
Package your data pack as a mod. This will create a new version with
support for the selected mod loaders. You will be redirected to the
new version and can edit it to your liking.
</p>
</div>
<label for="package-mod-loaders">
<span class="label__title">Mod loaders</span>
<span class="label__description">
The mod loaders you would like to package your data pack for.
</span>
</label>
<multiselect
id="package-mod-loaders"
v-model="packageLoaders"
:options="['fabric', 'forge', 'quilt']"
:custom-label="
(value) => value.charAt(0).toUpperCase() + value.slice(1)
"
:multiple="true"
:searchable="false"
:show-no-results="false"
:show-labels="false"
placeholder="Choose loaders.."
open-direction="top"
/>
<div class="button-group">
<button
class="iconified-button"
@click="$refs.modal_package_mod.hide()"
>
<CrossIcon />
Cancel
</button>
<button
class="iconified-button brand-button"
:disabled="!$nuxt.$loading"
@click="createDataPackVersion"
>
<RightArrowIcon />
Begin packaging data pack
</button>
</div>
</div>
</Modal>
<div class="version-page__title universal-card">
<div class="version-header">
<template v-if="isEditing">
@@ -143,7 +196,7 @@
Back to list
</nuxt-link>
<button
v-if="$auth.user"
v-if="$auth.user && !currentMember"
class="iconified-button"
@click="$refs.modal_version_report.show()"
>
@@ -164,6 +217,19 @@
<EditIcon aria-hidden="true" />
Edit
</nuxt-link>
<button
v-if="
currentMember &&
version.loaders.some((x) =>
$tag.loaderData.dataPackLoaders.includes(x)
)
"
class="iconified-button"
@click="$refs.modal_package_mod.show()"
>
<BoxIcon aria-hidden="true" />
Package as mod
</button>
<button
v-if="currentMember"
class="iconified-button danger-button"
@@ -222,7 +288,10 @@
></div>
</div>
<div
v-if="version.dependencies.length > 0 || isEditing"
v-if="
version.dependencies.length > 0 ||
(isEditing && project.project_type !== 'modpack')
"
class="version-page__dependencies universal-card"
>
<h3>Dependencies</h3>
@@ -269,7 +338,7 @@
</span>
</div>
<button
v-if="isEditing"
v-if="isEditing && project.project_type !== 'modpack'"
class="iconified-button"
@click="version.dependencies.splice(index, 1)"
>
@@ -308,7 +377,7 @@
:searchable="false"
:close-on-select="true"
:show-labels="false"
:allow-empty="false"
:allow-empty="true"
/>
<input
v-model="newDependencyId"
@@ -334,7 +403,7 @@
:searchable="false"
:close-on-select="true"
:show-labels="false"
:allow-empty="false"
:allow-empty="true"
/>
</div>
<div class="input-group">
@@ -385,7 +454,48 @@
<span class="filename">
<strong>{{ file.filename }}</strong>
<span class="file-size">({{ $formatBytes(file.size) }})</span>
<span
v-if="primaryFile.hashes.sha1 === file.hashes.sha1"
class="file-type"
>
Primary
</span>
<span
v-else-if="
file.file_type === 'required-resource-pack' && !isEditing
"
class="file-type"
>
Required resource pack
</span>
<span
v-else-if="
file.file_type === 'optional-resource-pack' && !isEditing
"
class="file-type"
>
Optional resource pack
</span>
</span>
<multiselect
v-if="
version.loaders.some((x) =>
$tag.loaderData.dataPackLoaders.includes(x)
) &&
isEditing &&
primaryFile.hashes.sha1 !== file.hashes.sha1
"
v-model="oldFileTypes[index]"
class="raised-multiselect"
placeholder="Select file type"
:options="fileTypes"
track-by="value"
label="display"
:searchable="false"
:close-on-select="true"
:show-labels="false"
:allow-empty="false"
/>
<FileInput
v-if="isEditing && primaryFile.hashes.sha1 === file.hashes.sha1"
class="iconified-button raised-button"
@@ -397,6 +507,8 @@
(x) => {
deleteFiles.push(file.hashes.sha1)
version.files.splice(index, 1)
oldFileTypes.splice(index, 1)
replaceFile = x[0]
}
"
@@ -409,6 +521,7 @@
@click="
deleteFiles.push(file.hashes.sha1)
version.files.splice(index, 1)
oldFileTypes.splice(index, 1)
"
>
<TrashIcon />
@@ -432,9 +545,29 @@
<strong>{{ file.name }}</strong>
<span class="file-size">({{ $formatBytes(file.size) }})</span>
</span>
<multiselect
v-if="
version.loaders.some((x) =>
$tag.loaderData.dataPackLoaders.includes(x)
)
"
v-model="newFileTypes[index]"
class="raised-multiselect"
placeholder="Select file type"
:options="fileTypes"
track-by="value"
label="display"
:searchable="false"
:close-on-select="true"
:show-labels="false"
:allow-empty="false"
/>
<button
class="iconified-button raised-button"
@click="newFiles.splice(index, 1)"
@click="
newFiles.splice(index, 1)
newFileTypes.splice(index, 1)
"
>
<TrashIcon />
Remove
@@ -442,14 +575,29 @@
</div>
<div class="additional-files">
<h4>Upload additional files</h4>
<span>Used for files such as sources or Javadocs.</span>
<span
v-if="
version.loaders.some((x) =>
$tag.loaderData.dataPackLoaders.includes(x)
)
"
>
Used for additional files such as required/optional resource packs
</span>
<span v-else>Used for files such as sources or Javadocs.</span>
<FileInput
prompt="Drag and drop to upload or click to select"
multiple
long-style
:accept="acceptFileFromProjectType(project.project_type)"
:max-size="524288000"
@change="(x) => x.forEach((y) => newFiles.push(y))"
@change="
(x) =>
x.forEach((y) => {
newFiles.push(y)
newFileTypes.push(null)
})
"
>
<UploadIcon />
</FileInput>
@@ -629,6 +777,7 @@ import Multiselect from 'vue-multiselect'
import {
acceptFileFromProjectType,
inferVersionInfo,
createDataPackVersion,
} from '~/plugins/fileUtils'
import VersionBadge from '~/components/ui/Badge'
@@ -654,9 +803,13 @@ import PlusIcon from '~/assets/images/utils/plus.svg?inline'
import TransferIcon from '~/assets/images/utils/transfer.svg?inline'
import UploadIcon from '~/assets/images/utils/upload.svg?inline'
import BackIcon from '~/assets/images/utils/left-arrow.svg?inline'
import BoxIcon from '~/assets/images/utils/box.svg?inline'
import RightArrowIcon from '~/assets/images/utils/right-arrow.svg?inline'
import Modal from '~/components/ui/Modal.vue'
export default {
components: {
Modal,
FileInput,
Checkbox,
Chips,
@@ -680,6 +833,8 @@ export default {
ModalConfirm,
ModalReport,
Multiselect,
BoxIcon,
RightArrowIcon,
},
props: {
project: {
@@ -722,6 +877,7 @@ export default {
data() {
return {
primaryFile: {},
alternateFile: {},
version: {},
isEditing: false,
@@ -738,6 +894,21 @@ export default {
deleteFiles: [],
replaceFile: null,
newFileTypes: [],
oldFileTypes: [],
fileTypes: [
{
display: 'Required resource pack',
value: 'required-resource-pack',
},
{
display: 'Optional resource pack',
value: 'optional-resource-pack',
},
],
packageLoaders: ['forge', 'fabric', 'quilt'],
showKnownErrors: false,
}
},
@@ -814,6 +985,7 @@ export default {
acceptFileFromProjectType,
reset() {
this.primaryFile = {}
this.alternateFile = {}
this.version = {}
this.changelogViewMode = 'source'
@@ -827,10 +999,14 @@ export default {
this.newFiles = []
this.deleteFiles = []
this.replaceFile = null
this.oldFileTypes = []
this.newFileTypes = []
this.isEditing = false
this.isCreating = false
this.packageLoaders = ['forge', 'fabric', 'quilt']
this.showKnownErrors = false
},
async setVersion() {
@@ -916,6 +1092,9 @@ export default {
this.version = JSON.parse(JSON.stringify(this.version))
this.primaryFile =
this.version.files.find((file) => file.primary) ?? this.version.files[0]
this.alternateFile = this.version.files.find(
(file) => file.file_type && file.file_type.includes('resource-pack')
)
this.version.author_member = this.members.find(
(x) => x.user.id === this.version.author_id
@@ -948,6 +1127,10 @@ export default {
}`
: ''
}
this.oldFileTypes = this.version.files.map((x) =>
this.fileTypes.find((y) => y.value === x.file_type)
)
},
async addDependency(
dependencyAddMode,
@@ -1037,12 +1220,24 @@ export default {
if (this.newFiles.length > 0 || this.replaceFile) {
const formData = new FormData()
const fileParts = this.newFiles.map((f, idx) => `${f.name}-${idx}`)
formData.append('data', JSON.stringify({}))
formData.append(
'data',
JSON.stringify({
file_types: this.newFileTypes.reduce(
(acc, x, i) => ({
...acc,
[fileParts[i]]: x ? x.value : null,
}),
{}
),
})
)
for (let i = 0; i < this.newFiles.length; i++) {
formData.append(
this.newFiles[i].name.concat('-' + i),
fileParts[i],
new Blob([this.newFiles[i]]),
this.newFiles[i].name
)
@@ -1079,6 +1274,13 @@ export default {
loaders: this.version.loaders,
primary_file: ['sha1', this.primaryFile.hashes.sha1],
featured: this.version.featured,
file_types: this.oldFileTypes.map((x, i) => {
return {
algorithm: 'sha1',
hash: this.version.files[i].hashes.sha1,
file_type: x ? x.value : null,
}
}),
},
this.$defaultHeaders()
)
@@ -1090,7 +1292,7 @@ export default {
)
}
const [versions, featuredVersions] = (
const [versions, featuredVersions, dependencies] = (
await Promise.all([
this.$axios.get(
`project/${this.version.project_id}/version`,
@@ -1100,12 +1302,17 @@ export default {
`project/${this.version.project_id}/version?featured=true`,
this.$defaultHeaders()
),
this.$axios.get(
`project/${this.version.project_id}/dependencies`,
this.$defaultHeaders()
),
])
).map((it) => it.data)
const newEditedVersions = this.$computeVersions(versions)
this.$emit('update:versions', newEditedVersions)
this.$emit('update:featuredVersions', featuredVersions)
this.$emit('update:dependencies', dependencies)
await this.$router.replace(
`/${this.project.project_type}/${
@@ -1128,7 +1335,6 @@ export default {
},
async createVersion() {
this.$nuxt.$loading.start()
if (this.fieldErrors) {
this.showKnownErrors = true
@@ -1136,6 +1342,21 @@ export default {
return
}
try {
await this.createVersionRaw(this.version)
} catch (err) {
this.$notify({
group: 'main',
title: 'An error occurred',
text: err.response ? err.response.data.description : err,
type: 'error',
})
window.scrollTo({ top: 0, behavior: 'smooth' })
}
this.$nuxt.$loading.finish()
},
async createVersionRaw(version) {
const formData = new FormData()
const fileParts = this.newFiles.map((f, idx) => `${f.name}-${idx}`)
@@ -1144,20 +1365,27 @@ export default {
}
if (this.project.project_type === 'resourcepack') {
this.version.loaders = ['minecraft']
version.loaders = ['minecraft']
}
const newVersion = {
project_id: this.version.project_id,
project_id: version.project_id,
file_parts: fileParts,
version_number: this.version.version_number,
version_title: this.version.name || this.version.version_number,
version_body: this.version.changelog,
dependencies: this.version.dependencies,
game_versions: this.version.game_versions,
loaders: this.version.loaders,
release_channel: this.version.version_type,
featured: this.version.featured,
version_number: version.version_number,
version_title: version.name || version.version_number,
version_body: version.changelog,
dependencies: version.dependencies,
game_versions: version.game_versions,
loaders: version.loaders,
release_channel: version.version_type,
featured: version.featured,
file_types: this.newFileTypes.reduce(
(acc, x, i) => ({
...acc,
[fileParts[this.replaceFile ? i + 1 : i]]: x ? x.value : null,
}),
{}
),
}
formData.append('data', JSON.stringify(newVersion))
@@ -1172,58 +1400,51 @@ export default {
for (let i = 0; i < this.newFiles.length; i++) {
formData.append(
fileParts[i],
fileParts[this.replaceFile ? i + 1 : i],
new Blob([this.newFiles[i]]),
this.newFiles[i].name
)
}
try {
const data = (
await this.$axios({
url: 'version',
method: 'POST',
data: formData,
headers: {
'Content-Type': 'multipart/form-data',
Authorization: this.$auth.token,
},
})
).data
const [versions, featuredVersions] = (
await Promise.all([
this.$axios.get(
`project/${this.version.project_id}/version`,
this.$defaultHeaders()
),
this.$axios.get(
`project/${this.version.project_id}/version?featured=true`,
this.$defaultHeaders()
),
])
).map((it) => it.data)
const newCreatedVersions = this.$computeVersions(versions)
this.$emit('update:versions', newCreatedVersions)
this.$emit('update:featuredVersions', featuredVersions)
await this.$router.push(
`/${this.project.project_type}/${
this.project.slug ? this.project.slug : this.project.project_id
}/version/${data.id}`
)
} catch (err) {
this.$notify({
group: 'main',
title: 'An error occurred',
text: err.response.data.description,
type: 'error',
const data = (
await this.$axios({
url: 'version',
method: 'POST',
data: formData,
headers: {
'Content-Type': 'multipart/form-data',
Authorization: this.$auth.token,
},
})
window.scrollTo({ top: 0, behavior: 'smooth' })
}
).data
this.$nuxt.$loading.finish()
const [versions, featuredVersions, dependencies] = (
await Promise.all([
this.$axios.get(
`project/${this.version.project_id}/version`,
this.$defaultHeaders()
),
this.$axios.get(
`project/${this.version.project_id}/version?featured=true`,
this.$defaultHeaders()
),
this.$axios.get(
`project/${this.version.project_id}/dependencies`,
this.$defaultHeaders()
),
])
).map((it) => it.data)
const newCreatedVersions = this.$computeVersions(versions)
this.$emit('update:versions', newCreatedVersions)
this.$emit('update:featuredVersions', featuredVersions)
this.$emit('update:dependencies', dependencies)
await this.$router.push(
`/${this.project.project_type}/${
this.project.slug ? this.project.slug : this.project.project_id
}/version/${data.id}`
)
},
async deleteVersion() {
this.$nuxt.$loading.start()
@@ -1238,6 +1459,56 @@ export default {
)
this.$nuxt.$loading.finish()
},
async createDataPackVersion() {
this.$nuxt.$loading.start()
try {
const blob = await createDataPackVersion(
this.project,
this.version,
this.primaryFile,
this.members,
this.$tag.gameVersions,
this.packageLoaders
)
this.newFiles = []
this.newFileTypes = []
this.replaceFile = new File(
[blob],
`${this.project.slug}-${this.version.version_number}.jar`
)
await this.createVersionRaw({
project_id: this.project.id,
author_id: this.currentMember.user.id,
name: this.version.name,
version_number: `${this.version.version_number}+mod`,
changelog: this.version.changelog,
version_type: this.version.version_type,
dependencies: this.version.dependencies,
game_versions: this.version.game_versions,
loaders: this.packageLoaders,
featured: this.version.featured,
})
this.$refs.modal_package_mod.hide()
this.$notify({
group: 'main',
title: 'Packaging Success',
text: 'Your data pack was successfully packaged as a mod! Make sure to playtest to check for errors.',
type: 'success',
})
} catch (err) {
this.$notify({
group: 'main',
title: 'An error occurred',
text: err.response ? err.response.data.description : err,
type: 'error',
})
}
this.$nuxt.$loading.finish()
},
},
}
</script>
@@ -1383,8 +1654,7 @@ export default {
}
.filename {
word-wrap: break-word;
overflow-wrap: anywhere;
word-wrap: anywhere;
}
.file-size {
@@ -1392,6 +1662,19 @@ export default {
white-space: nowrap;
}
.file-type {
font-style: italic;
font-weight: 300;
}
.raised-multiselect {
display: none;
margin: 0 0.5rem;
height: 40px;
max-height: 40px;
min-width: 235px;
}
.iconified-button {
margin-left: auto;
}
@@ -1399,6 +1682,13 @@ export default {
&:not(:nth-child(2)) {
margin-top: 0.5rem;
}
// TODO: Make file type editing work on mobile
@media (min-width: 600px) {
.raised-multiselect {
display: block;
}
}
}
.additional-files {
@@ -1454,4 +1744,23 @@ export default {
.separator {
margin: var(--spacing-card-sm) 0;
}
.modal-package-mod {
padding: var(--spacing-card-bg);
display: flex;
flex-direction: column;
.markdown-body {
margin-bottom: 1rem;
}
.multiselect {
max-width: 20rem;
}
.button-group {
margin-left: auto;
margin-top: 1.5rem;
}
}
</style>

View File

@@ -1,98 +0,0 @@
<template>
<div class="main">
<div class="card">
<h1>About</h1>
<p>
Founded in 2020, Modrinth was created to provide modders with an open
and intuitive platform to publish their projects on.
</p>
<p>
Our primary goal is to be as open as possible, with all our code being
<a :target="$external()" href="https://github.com/modrinth">
open source</a
>, while giving back to the modding community as much as possible.
</p>
<p>
While we still are in beta, we hope we can be a major modding platform
for all modders.
</p>
<h2>How does Modrinth work?</h2>
<p>
Modrinth is not just a website: it is made of several different
components that all come together to make a fast and flexible modding
platform.
</p>
<p>
On the technical level, Modrinth is made up of two main components: the
Rust-based backend named
<a :target="$external()" href="https://github.com/modrinth/labrinth"
>Labrinth</a
>, and the Vue-based frontend named
<a :target="$external()" href="https://github.com/modrinth/knossos">
Knossos</a
>.
</p>
<p>
Additionally, some other custom-created resources exist, including but
not limited to:
<a :target="$external()" href="https://github.com/modrinth/minotaur"
>Minotaur</a
>, a Gradle plugin for easily publishing mods to Modrinth, and
<a :target="$external()" href="https://github.com/modrinth/minos">
Minos</a
>, an authentication provider. All of Modrinth's code can be found on
<a :target="$external()" href="https://github.com/modrinth"
>our GitHub page</a
>.
</p>
<h2>Backend Documentation</h2>
<p>
Documentation for the Modrinth API (Labrinth) can be found on the GitHub
repository's wiki
<a :target="$external()" href="https://docs.modrinth.com">here</a>.
</p>
</div>
</div>
</template>
<script>
export default {
auth: false,
head: {
title: 'About - Modrinth',
meta: [
{
hid: 'apple-mobile-web-app-title',
name: 'apple-mobile-web-app-title',
content: 'About',
},
{
hid: 'og:title',
name: 'og:title',
content: 'About',
},
{
hid: 'og:url',
name: 'og:url',
content: `https://modrinth.com/about`,
},
],
},
}
</script>
<style lang="scss" scoped>
.main {
margin: var(--spacing-card-sm) auto;
max-width: 800px;
}
a {
text-decoration: underline;
color: var(--color-link);
}
</style>

View File

@@ -126,7 +126,7 @@
<div class="title">
<h3>
{{ item.item_type }}
<a :href="item.url">{{ item.item_id }}</a>
<nuxt-link :to="item.url">{{ item.item_id }}</nuxt-link>
</h3>
reported by
<a :href="`/user/${item.reporter}`">{{ item.reporter }}</a>

View File

@@ -78,7 +78,9 @@
</div>
</section>
<section
v-if="projectType.id !== 'resourcepack'"
v-if="
projectType.id !== 'resourcepack' && projectType.id !== 'datapack'
"
aria-label="Loader filters"
>
<h3
@@ -101,15 +103,15 @@
x.name !== 'quilt'
) {
return false
}
if (projectType.id === 'mod' && showAllLoaders) {
} else if (projectType.id === 'mod' && showAllLoaders) {
return $tag.loaderData.modLoaders.includes(x.name)
} else if (projectType.id === 'plugin') {
return $tag.loaderData.pluginLoaders.includes(x.name)
} else if (projectType.id === 'datapack') {
return $tag.loaderData.dataPackLoaders.includes(x.name)
} else {
return x.supported_project_types.includes(projectType.actual)
}
return projectType.id === 'plugin'
? $tag.loaderData.pluginLoaders.includes(x.name)
: x.supported_project_types.includes(projectType.actual)
})"
:key="loader.name"
ref="loaderFilters"
@@ -158,7 +160,9 @@
</section>
<section
v-if="
!['resourcepack', 'plugin', 'shader'].includes(projectType.id)
!['resourcepack', 'plugin', 'shader', 'datapack'].includes(
projectType.id
)
"
aria-label="Environment filters"
>
@@ -376,6 +380,9 @@
:categories="result.display_categories"
:search="true"
:show-updated-date="sortType.name !== 'newest'"
:hide-loaders="
['resourcepack', 'datapack'].includes(projectType.id)
"
/>
<div v-if="results && results.length === 0" class="no-results">
<p>No results found for your query!</p>
@@ -714,6 +721,12 @@ export default {
(x) => `categories:'${encodeURIComponent(x)}'`
)
)
} else if (this.projectType.id === 'datapack') {
formattedFacets.push(
this.$tag.loaderData.dataPackLoaders.map(
(x) => `categories:'${encodeURIComponent(x)}'`
)
)
}
if (this.selectedVersions.length > 0) {

View File

@@ -0,0 +1,11 @@
<template>
<div></div>
</template>
<script>
export default {
name: 'Datapacks',
}
</script>
<style lang="scss" scoped></style>

View File

@@ -161,6 +161,7 @@ export default {
resourcepack: 'gallery',
modpack: 'list',
shader: 'gallery',
datapack: 'list',
user: 'list',
},
}

View File

@@ -160,7 +160,7 @@
},
...projectTypes.map((x) => {
return {
label: x === 'resourcepack' ? 'Resource Packs' : x + 's',
label: $formatProjectType(x) + 's',
href: x,
}
}),
@@ -326,13 +326,47 @@ export default {
}
let gitHubUser = {}
let versions = []
try {
gitHubUser = (
await data.$axios.get(`https://api.github.com/user/` + user.github_id)
).data
const [gitHubUserData, versionsData] = (
await Promise.all([
data.$axios.get(`https://api.github.com/user/` + user.github_id),
data.$axios.get(
`versions?ids=${JSON.stringify(
[].concat.apply(
[],
projects.map((x) => x.versions)
)
)}`
),
])
).map((it) => it.data)
gitHubUser = gitHubUserData
versions = versionsData
} catch {}
for (const version of versions) {
const projectIndex = projects.findIndex(
(x) => x.id === version.project_id
)
if (projects[projectIndex].loaders) {
for (const loader of version.loaders) {
if (!projects[projectIndex].loaders.includes(loader)) {
projects[projectIndex].loaders.push(loader)
}
}
} else {
projects[projectIndex].loaders = version.loaders
}
}
for (const project of projects) {
project.categories = project.categories.concat(project.loaders)
project.project_type = data.$getProjectTypeForUrl(
project.project_type,
project.categories
)
}
return {
user,
projects,