diff --git a/assets/styles/components.scss b/assets/styles/components.scss
index 975d0f947..d4305c32a 100644
--- a/assets/styles/components.scss
+++ b/assets/styles/components.scss
@@ -513,8 +513,10 @@ tr.button-transparent {
box-shadow: var(--shadow-inset-sm), 0 0 0 0 transparent;
svg {
- width: 1.25rem;
- height: 1.25rem;
+ min-width: 1.25rem;
+ max-width: 1.25rem;
+ min-height: 1.25rem;
+ max-height: 1.25rem;
margin: auto;
}
diff --git a/components/ui/DropArea.vue b/components/ui/DropArea.vue
index 4d2245744..45ae34778 100644
--- a/components/ui/DropArea.vue
+++ b/components/ui/DropArea.vue
@@ -6,7 +6,7 @@
(event) => {
$refs.drop_area.style.visibility = 'hidden'
- if (event.dataTransfer && event.dataTransfer.files) {
+ if (event.dataTransfer && event.dataTransfer.files && fileAllowed) {
$emit('change', event.dataTransfer.files)
}
}
@@ -26,30 +26,40 @@ export default {
default: '',
},
},
- mounted() {
- // eslint-disable-next-line nuxt/no-env-in-hooks
- if (process.client) {
- document.addEventListener('dragenter', () => {
- this.$refs.drop_area.style.visibility = 'visible'
- })
+ data() {
+ return {
+ fileAllowed: false,
}
},
+ mounted() {
+ document.addEventListener('dragenter', this.allowDrag)
+ },
methods: {
allowDrag(event) {
const file = event.dataTransfer?.items[0]
+ console.log(file)
if (
file &&
this.accept
.split(',')
.reduce(
- (acc, t) => acc || file.type.startsWith(t) || file.type === t,
+ (acc, t) =>
+ acc || file.type.startsWith(t) || file.type === t || t === '*',
false
)
) {
- // Adds file dropping indicator
+ this.fileAllowed = true
event.dataTransfer.dropEffect = 'copy'
event.preventDefault()
+
+ if (this.$refs.drop_area)
+ this.$refs.drop_area.style.visibility = 'visible'
+ } else {
+ this.fileAllowed = false
+
+ if (this.$refs.drop_area)
+ this.$refs.drop_area.style.visibility = 'hidden'
}
},
},
diff --git a/components/ui/ModalCreation.vue b/components/ui/ModalCreation.vue
index eee6843d3..ac86d054b 100644
--- a/components/ui/ModalCreation.vue
+++ b/components/ui/ModalCreation.vue
@@ -206,7 +206,14 @@ Questions? [Join the Modrinth Discord for support!](https://discord.gg/EUHuJHt)`
})
this.$refs.modal.hide()
- await this.$router.replace(`/${projectType.actual}/${this.slug}`)
+ await this.$router.push({
+ name: 'type-id',
+ params: {
+ type: projectType.id,
+ id: this.slug,
+ overrideProjectType: projectType.id,
+ },
+ })
} catch (err) {
this.$notify({
group: 'main',
diff --git a/components/ui/ProjectCard.vue b/components/ui/ProjectCard.vue
index 2985576a2..8a470d136 100644
--- a/components/ui/ProjectCard.vue
+++ b/components/ui/ProjectCard.vue
@@ -15,12 +15,9 @@
class="gallery"
tabindex="-1"
:to="`/${$getProjectTypeForUrl(type, categories)}/${id}`"
+ :style="color ? `background-color: ${toColor};` : ''"
>
-
+
@@ -99,6 +96,14 @@
Server
+
+
+ Unsupported
+
A {{ projectTypeDisplay }}
@@ -258,12 +263,10 @@ export default {
required: false,
default: false,
},
- galleryImages: {
- type: Array,
+ featuredImage: {
+ type: String,
required: false,
- default() {
- return []
- },
+ default: null,
},
showUpdatedDate: {
type: Boolean,
@@ -275,11 +278,25 @@ export default {
required: false,
default: false,
},
+ color: {
+ type: Number,
+ required: false,
+ default: null,
+ },
},
computed: {
projectTypeDisplay() {
return this.$getProjectTypeForDisplay(this.type, this.categories)
},
+ toColor() {
+ let color = this.color
+
+ color >>>= 0
+ const b = color & 0xff
+ const g = (color & 0xff00) >>> 8
+ const r = (color & 0xff0000) >>> 16
+ return 'rgba(' + [r, g, b, 1].join(',') + ')'
+ },
},
}
@@ -338,7 +355,10 @@ export default {
height: 10rem;
background-color: var(--color-button-bg-active);
+ filter: brightness(0.7);
+
img {
+ box-shadow: none;
width: 100%;
height: 10rem;
object-fit: cover;
@@ -349,6 +369,13 @@ export default {
margin-left: var(--spacing-card-bg);
margin-top: -3rem;
z-index: 1;
+
+ img,
+ svg {
+ border-radius: var(--size-rounded-lg);
+ border: 0.25rem solid var(--color-raised-bg);
+ border-bottom: none;
+ }
}
.title {
diff --git a/layouts/default.vue b/layouts/default.vue
index 6d4c7952a..393c1371e 100644
--- a/layouts/default.vue
+++ b/layouts/default.vue
@@ -508,9 +508,9 @@ export default {
}
},
},
- beforeCreate() {
+ async beforeCreate() {
if (this.$route.query.code) {
- this.$router.push(this.$route.path)
+ await this.$router.push(this.$route.path)
}
},
created() {
@@ -619,10 +619,6 @@ export default {
margin-left: auto;
margin-right: auto;
- @media screen and (max-width: 750px) {
- justify-content: center;
- }
-
section.logo {
display: flex;
justify-content: space-between;
@@ -1082,7 +1078,7 @@ export default {
&.active {
display: flex;
- @media screen and (min-width: 750px) {
+ @media screen and (min-width: 1024px) {
display: none;
}
}
diff --git a/pages/_type/_id.vue b/pages/_type/_id.vue
index fcedb604c..d9526c20c 100644
--- a/pages/_type/_id.vue
+++ b/pages/_type/_id.vue
@@ -755,10 +755,12 @@ export default {
JSON.stringify(project.project_type)
)
- project.project_type = data.$getProjectTypeForUrl(
- project.project_type,
- Object.keys(projectLoaders)
- )
+ project.project_type = data.params.overrideProjectType
+ ? data.params.overrideProjectType
+ : data.$getProjectTypeForUrl(
+ project.project_type,
+ Object.keys(projectLoaders)
+ )
if (
project.project_type !== data.params.type ||
@@ -922,6 +924,33 @@ export default {
},
},
methods: {
+ async resetProject() {
+ const project = (
+ await this.$axios.get(
+ `project/${this.project.id}`,
+ this.$defaultHeaders()
+ )
+ ).data
+
+ const projectLoaders = {}
+
+ for (const version of this.versions) {
+ for (const loader of version.loaders) {
+ projectLoaders[loader] = true
+ }
+ }
+
+ project.actualProjectType = JSON.parse(
+ JSON.stringify(project.project_type)
+ )
+
+ project.project_type = this.$getProjectTypeForUrl(
+ project.project_type,
+ Object.keys(projectLoaders)
+ )
+
+ this.project = project
+ },
findPrimary(version) {
let file = version.files.find((x) => x.primary)
diff --git a/pages/_type/_id/changelog.vue b/pages/_type/_id/changelog.vue
index 7f6fa1c35..c81ef33af 100644
--- a/pages/_type/_id/changelog.vue
+++ b/pages/_type/_id/changelog.vue
@@ -150,9 +150,9 @@ export default {
}
},
methods: {
- switchPage(page, toTop) {
+ async switchPage(page, toTop) {
this.currentPage = page
- this.$router.replace(this.getPageLink(page))
+ await this.$router.replace(this.getPageLink(page))
if (toTop) {
setTimeout(() => window.scrollTo({ top: 0, behavior: 'smooth' }), 50)
diff --git a/pages/_type/_id/edit.vue b/pages/_type/_id/edit.vue
index 647a90f00..3d753c7b0 100644
--- a/pages/_type/_id/edit.vue
+++ b/pages/_type/_id/edit.vue
@@ -829,19 +829,7 @@ export default {
)
}
- // While the emit below will take care of most changes,
- // some items require manually updating
- this.newProject.license.id = this.licenseId
- 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.newProject.client_side = this.clientSideType.toLowerCase()
- this.newProject.server_side = this.serverSideType.toLowerCase()
-
- this.$emit('update:project', this.newProject)
+ await this.$parent.resetProject()
this.isEditing = false
diff --git a/pages/_type/_id/gallery.vue b/pages/_type/_id/gallery.vue
index e975cc2d1..219a31f47 100644
--- a/pages/_type/_id/gallery.vue
+++ b/pages/_type/_id/gallery.vue
@@ -1,5 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
@@ -142,22 +236,7 @@
/>
-
-
+
{{ item.title }}
{{ item.description }}
@@ -169,22 +248,16 @@
-
-
-
![]()
-
-
-
showPreviewImage(files, index)"
- >
-
-
-
-
-
@@ -267,24 +287,29 @@ import CrossIcon from '~/assets/images/utils/x.svg?inline'
import RightArrowIcon from '~/assets/images/utils/right-arrow.svg?inline'
import LeftArrowIcon from '~/assets/images/utils/left-arrow.svg?inline'
import EditIcon from '~/assets/images/utils/edit.svg?inline'
-import CheckIcon from '~/assets/images/utils/check.svg?inline'
+import SaveIcon from '~/assets/images/utils/save.svg?inline'
import ExternalIcon from '~/assets/images/utils/external.svg?inline'
import ExpandIcon from '~/assets/images/utils/expand.svg?inline'
import ContractIcon from '~/assets/images/utils/contract.svg?inline'
+import StarIcon from '~/assets/images/utils/star.svg?inline'
import UploadIcon from '~/assets/images/utils/upload.svg?inline'
+import InfoIcon from '~/assets/images/utils/info.svg?inline'
+import ImageIcon from '~/assets/images/utils/image.svg?inline'
+import TransferIcon from '~/assets/images/utils/transfer.svg?inline'
import FileInput from '~/components/ui/FileInput'
-import Checkbox from '~/components/ui/Checkbox'
+import DropArea from '~/components/ui/DropArea'
+import ModalConfirm from '~/components/ui/ModalConfirm'
+import Modal from '~/components/ui/Modal'
export default {
components: {
CalendarIcon,
PlusIcon,
- Checkbox,
EditIcon,
TrashIcon,
- CheckIcon,
- FileInput,
+ SaveIcon,
+ StarIcon,
CrossIcon,
RightArrowIcon,
LeftArrowIcon,
@@ -292,13 +317,15 @@ export default {
ExpandIcon,
ContractIcon,
UploadIcon,
+ InfoIcon,
+ ImageIcon,
+ TransferIcon,
+ ModalConfirm,
+ Modal,
+ FileInput,
+ DropArea,
},
auth: false,
- beforeRouteLeave(to, from, next) {
- this.resetGallery()
-
- next()
- },
props: {
project: {
type: Object,
@@ -315,18 +342,21 @@ export default {
},
data() {
return {
- gallery: [],
- newGalleryItems: [],
- editGalleryIndexes: [],
- deleteGalleryUrls: [],
expandedGalleryItem: null,
expandedGalleryIndex: 0,
zoomedIn: false,
+
+ deleteIndex: -1,
+
+ editIndex: -1,
+ editTitle: '',
+ editDescription: '',
+ editFeatured: false,
+ editOrder: null,
+ editFile: null,
+ previewImage: null,
}
},
- fetch() {
- this.gallery = JSON.parse(JSON.stringify(this.project.gallery))
- },
head() {
const title = `${this.project.title} - Gallery`
const description = `View ${this.project.gallery.length} images of ${this.project.title} on Modrinth.`
@@ -357,6 +387,11 @@ export default {
],
}
},
+ computed: {
+ acceptFileTypes() {
+ return 'image/png,image/jpeg,image/gif,image/webp,.png,.jpeg,.gif,.webp'
+ },
+ },
mounted() {
this._keyListener = function (e) {
if (this.expandedGalleryItem) {
@@ -371,125 +406,156 @@ export default {
}
}
- // eslint-disable-next-line nuxt/no-env-in-hooks
- if (process.client) {
- document.addEventListener('keydown', this._keyListener.bind(this))
- }
+ document.addEventListener('keydown', this._keyListener.bind(this))
},
methods: {
- showPreviewImage(files, index) {
- const reader = new FileReader()
- this.newGalleryItems[index].icon = files[0]
-
- if (this.newGalleryItems[index].icon instanceof Blob) {
- reader.readAsDataURL(this.newGalleryItems[index].icon)
-
- reader.onload = (event) => {
- this.newGalleryItems[index].preview = event.target.result
-
- // TODO: Find an alternative for this!
- this.$forceUpdate()
- }
- }
- },
- async saveGallery() {
- this.$nuxt.$loading.start()
-
- try {
- for (const item of this.newGalleryItems) {
- let url = `project/${this.project.id}/gallery?ext=${
- item.icon
- ? item.icon.type.split('/')[item.icon.type.split('/').length - 1]
- : null
- }&featured=${item.featured}`
-
- if (item.title) url += `&title=${encodeURIComponent(item.title)}`
- if (item.description)
- url += `&description=${encodeURIComponent(item.description)}`
-
- await this.$axios.post(url, item.icon, this.$defaultHeaders())
- }
-
- for (const index of this.editGalleryIndexes) {
- const item = this.gallery[index]
-
- let url = `project/${
- this.project.id
- }/gallery?url=${encodeURIComponent(item.url)}&featured=${
- item.featured
- }`
-
- if (item.title) url += `&title=${encodeURIComponent(item.title)}`
- if (item.description)
- url += `&description=${encodeURIComponent(item.description)}`
-
- await this.$axios.patch(url, {}, this.$defaultHeaders())
- }
-
- for (const url of this.deleteGalleryUrls) {
- await this.$axios.delete(
- `project/${this.project.id}/gallery?url=${encodeURIComponent(url)}`,
- this.$defaultHeaders()
- )
- }
-
- const project = (
- await this.$axios.get(
- `project/${this.project.id}`,
- this.$defaultHeaders()
- )
- ).data
- this.$emit('update:project', project)
- this.gallery = JSON.parse(JSON.stringify(project.gallery))
-
- this.deleteGalleryUrls = []
- this.editGalleryIndexes = []
- this.newGalleryItems = []
- } catch (err) {
- const description = err.response.data.description
-
- this.$notify({
- group: 'main',
- title: 'An error occurred',
- text: description,
- type: 'error',
- })
-
- window.scrollTo({ top: 0, behavior: 'smooth' })
- }
-
- this.$nuxt.$loading.finish()
- },
- resetGallery() {
- this.newGalleryItems = []
- this.editGalleryIndexes = []
- this.deleteGalleryUrls = []
- this.gallery = JSON.parse(JSON.stringify(this.project.gallery))
- },
nextImage() {
this.expandedGalleryIndex++
- if (this.expandedGalleryIndex >= this.gallery.length) {
+ if (this.expandedGalleryIndex >= this.project.gallery.length) {
this.expandedGalleryIndex = 0
}
- this.expandedGalleryItem = this.gallery[this.expandedGalleryIndex]
+ this.expandedGalleryItem = this.project.gallery[this.expandedGalleryIndex]
},
previousImage() {
this.expandedGalleryIndex--
if (this.expandedGalleryIndex < 0) {
- this.expandedGalleryIndex = this.gallery.length - 1
+ this.expandedGalleryIndex = this.project.gallery.length - 1
}
- this.expandedGalleryItem = this.gallery[this.expandedGalleryIndex]
+ this.expandedGalleryItem = this.project.gallery[this.expandedGalleryIndex]
},
expandImage(item, index) {
this.expandedGalleryItem = item
this.expandedGalleryIndex = index
this.zoomedIn = false
},
+ resetEdit() {
+ this.editIndex = -1
+ this.editTitle = ''
+ this.editDescription = ''
+ this.editFeatured = false
+ this.editOrder = null
+ this.editFile = null
+ this.previewImage = null
+ },
+ handleFiles(files) {
+ this.resetEdit()
+ this.editFile = files[0]
+
+ this.showPreviewImage()
+ this.$refs.modal_edit_item.show()
+ },
+ showPreviewImage() {
+ const reader = new FileReader()
+ if (this.editFile instanceof Blob) {
+ reader.readAsDataURL(this.editFile)
+ reader.onload = (event) => {
+ this.previewImage = event.target.result
+ }
+ }
+ },
+ async createGalleryItem() {
+ this.$nuxt.$loading.start()
+
+ try {
+ let url = `project/${this.project.id}/gallery?ext=${
+ this.editFile
+ ? this.editFile.type.split('/')[
+ this.editFile.type.split('/').length - 1
+ ]
+ : null
+ }&featured=${this.editFeatured}`
+
+ if (this.editTitle) url += `&title=${this.editTitle}`
+ if (this.editDescription) url += `&description=${this.editDescription}`
+ if (this.editOrder) url += `&ordering=${this.editOrder}`
+
+ await this.$axios.post(url, this.editFile, this.$defaultHeaders())
+ await this.updateProject()
+
+ this.$refs.modal_edit_item.hide()
+ } catch (err) {
+ this.$notify({
+ group: 'main',
+ title: 'An error occurred',
+ text: err.response ? err.response.data.description : err,
+ type: 'error',
+ })
+ }
+
+ this.$nuxt.$loading.finish()
+ },
+ async editGalleryItem() {
+ this.$nuxt.$loading.start()
+
+ try {
+ let url = `project/${this.project.id}/gallery?url=${encodeURIComponent(
+ this.project.gallery[this.editIndex].url
+ )}&featured=${this.editFeatured}`
+
+ if (this.editTitle) url += `&title=${this.editTitle}`
+ if (this.editDescription) url += `&description=${this.editDescription}`
+ if (this.editOrder) url += `&ordering=${this.editOrder}`
+
+ await this.$axios.patch(url, {}, this.$defaultHeaders())
+
+ await this.updateProject()
+ this.$refs.modal_edit_item.hide()
+ } catch (err) {
+ this.$notify({
+ group: 'main',
+ title: 'An error occurred',
+ text: err.response ? err.response.data.description : err,
+ type: 'error',
+ })
+ }
+
+ this.$nuxt.$loading.finish()
+ },
+ async deleteGalleryImage() {
+ this.$nuxt.$loading.start()
+
+ try {
+ await this.$axios.delete(
+ `project/${this.project.id}/gallery?url=${encodeURIComponent(
+ this.project.gallery[this.deleteIndex].url
+ )}`,
+ this.$defaultHeaders()
+ )
+
+ await this.updateProject()
+ } catch (err) {
+ this.$notify({
+ group: 'main',
+ title: 'An error occurred',
+ text: err.response ? err.response.data.description : err,
+ type: 'error',
+ })
+ }
+
+ this.$nuxt.$loading.finish()
+ },
+ async updateProject() {
+ await this.$parent.resetProject()
+ this.resetEdit()
+ },
},
}
diff --git a/pages/_type/_id/version.vue b/pages/_type/_id/version.vue
index bf578ed50..8e27f4eff 100644
--- a/pages/_type/_id/version.vue
+++ b/pages/_type/_id/version.vue
@@ -1287,7 +1287,7 @@ export default {
for (const hash of this.deleteFiles) {
await this.$axios.delete(
- `version_file/${hash}`,
+ `version_file/${hash}?version_id=${this.version.id}`,
this.$defaultHeaders()
)
}
diff --git a/pages/_type/_id/versions.vue b/pages/_type/_id/versions.vue
index 30fbe1bf8..f8ac1b618 100644
--- a/pages/_type/_id/versions.vue
+++ b/pages/_type/_id/versions.vue
@@ -197,8 +197,8 @@ export default {
updateVersions(updatedVersions) {
this.filteredVersions = updatedVersions
},
- handleFiles(files) {
- this.$router.push({
+ async handleFiles(files) {
+ await this.$router.push({
name: 'type-id-version-create',
params: {
type: this.project.project_type,
diff --git a/pages/moderation.vue b/pages/moderation.vue
index 1f7df44b8..4ee748b0d 100644
--- a/pages/moderation.vue
+++ b/pages/moderation.vue
@@ -86,6 +86,7 @@
:client-side="project.client_side"
:server-side="project.server_side"
:type="project.project_type"
+ :color="project.color"
:moderation="true"
>
No results found for your query!
@@ -966,6 +971,11 @@ export default {
white-space: nowrap;
}
}
+
+ .square-button {
+ margin-top: auto;
+ margin-bottom: 0.25rem;
+ }
}
}
diff --git a/pages/settings/follows.vue b/pages/settings/follows.vue
index ca6fbd16e..cd0fa1e43 100644
--- a/pages/settings/follows.vue
+++ b/pages/settings/follows.vue
@@ -14,6 +14,7 @@
:name="project.title"
:client-side="project.client_side"
:server-side="project.server_side"
+ :color="project.color"
>
b.featured - a.featured)
- .map((x) => x.url)
+ .map((x) => x.url)[0]
"
:description="project.description"
:created-at="project.published"
@@ -234,6 +234,7 @@
"
:has-mod-message="project.moderator_message"
:type="project.project_type"
+ :color="project.color"
/>
diff --git a/plugins/fileUtils.js b/plugins/fileUtils.js
index 0f21df1ef..3ce43652b 100644
--- a/plugins/fileUtils.js
+++ b/plugins/fileUtils.js
@@ -31,9 +31,9 @@ export const fileIsValid = (file, validationOptions) => {
export const acceptFileFromProjectType = (projectType) => {
switch (projectType) {
case 'mod':
- return '.jar,.zip,.litemod,application/java-archive,application/zip'
+ return '.jar,.zip,.litemod,application/java-archive,application/x-java-archive,application/zip'
case 'plugin':
- return '.jar,.zip,application/java-archive,application/zip'
+ return '.jar,.zip,application/java-archive,application/x-java-archive,application/zip'
case 'resourcepack':
return '.zip,application/zip'
case 'shader':
@@ -41,7 +41,7 @@ export const acceptFileFromProjectType = (projectType) => {
case 'datapack':
return '.zip,application/zip'
case 'modpack':
- return '.mrpack,application/x-modrinth-modpack+zip'
+ return '.mrpack,application/x-modrinth-modpack+zip,application/zip'
default:
return '*'
}
@@ -437,7 +437,7 @@ export const createDataPackVersion = async function (
modLoader: newForge ? 'lowcodefml' : 'javafml',
loaderVersion: newForge ? '[40,)' : '[25,)',
license: project.license.id,
- showAsResourcePack: true,
+ showAsResourcePack: false,
mods: [
{
modId: newSlug,
diff --git a/plugins/shorthands.js b/plugins/shorthands.js
index 73145e828..26bc9f1f7 100644
--- a/plugins/shorthands.js
+++ b/plugins/shorthands.js
@@ -287,7 +287,7 @@ export const formatCategory = (name) => {
} else if (name === 'pbr') {
return 'PBR'
} else if (name === 'datapack') {
- return 'Data pack'
+ return 'Data Pack'
}
return capitalizeString(name)
diff --git a/store/tag.js b/store/tag.js
index 5a646c205..15eb756ee 100644
--- a/store/tag.js
+++ b/store/tag.js
@@ -20,7 +20,7 @@ export const state = () => ({
{
actual: 'mod',
id: 'datapack',
- display: 'datapack',
+ display: 'data pack',
},
{
actual: 'resourcepack',