You've already forked AstralRinth
forked from didirus/AstralRinth
Follows + Reports
This commit is contained in:
3
assets/images/utils/heart.svg
Normal file
3
assets/images/utils/heart.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 270 B |
@@ -15,6 +15,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.iconified-button {
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
color: var(--color-button-text);
|
||||||
|
background-color: var(--color-button-bg);
|
||||||
|
border-radius: var(--size-rounded-control);
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background-color: var(--color-button-bg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 1.25rem;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
max-height: 1rem;
|
max-height: 1rem;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
|
|||||||
@@ -287,4 +287,3 @@ button {
|
|||||||
@import "~assets/styles/utils.scss";
|
@import "~assets/styles/utils.scss";
|
||||||
@import "~assets/styles/components.scss";
|
@import "~assets/styles/components.scss";
|
||||||
@import "~assets/styles/normalize.scss";
|
@import "~assets/styles/normalize.scss";
|
||||||
|
|
||||||
|
|||||||
@@ -6,4 +6,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
html { margin-left: calc(100vw - 100%); }
|
html {
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,8 +36,35 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<nuxt-link
|
||||||
|
v-if="this.$auth.loggedIn"
|
||||||
|
:to="`/report/create?id=${mod.id}&t=mod`"
|
||||||
|
class="iconified-button"
|
||||||
|
>
|
||||||
|
<ReportIcon />
|
||||||
|
Report
|
||||||
|
</nuxt-link>
|
||||||
|
<button
|
||||||
|
v-if="userFollows && !userFollows.includes(mod.id)"
|
||||||
|
class="iconified-button"
|
||||||
|
@click="followMod"
|
||||||
|
>
|
||||||
|
<FollowIcon />
|
||||||
|
Follow
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="userFollows && userFollows.includes(mod.id)"
|
||||||
|
class="iconified-button"
|
||||||
|
@click="unfollowMod"
|
||||||
|
>
|
||||||
|
<FollowIcon fill="currentColor" />
|
||||||
|
Unfollow
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Advertisement
|
<Advertisement
|
||||||
|
v-if="mod.status === 'approved' || mod.status === 'unlisted'"
|
||||||
:page-url="
|
:page-url="
|
||||||
'https://modrinth.com/mod/' + (mod.slug ? mod.slug : mod.id)
|
'https://modrinth.com/mod/' + (mod.slug ? mod.slug : mod.id)
|
||||||
"
|
"
|
||||||
@@ -105,6 +132,7 @@
|
|||||||
<div class="mod-content">
|
<div class="mod-content">
|
||||||
<slot />
|
<slot />
|
||||||
<Advertisement
|
<Advertisement
|
||||||
|
v-if="mod.status === 'approved' || mod.status === 'unlisted'"
|
||||||
:page-url="
|
:page-url="
|
||||||
'https://modrinth.com/mod/' + (mod.slug ? mod.slug : mod.id)
|
'https://modrinth.com/mod/' + (mod.slug ? mod.slug : mod.id)
|
||||||
"
|
"
|
||||||
@@ -304,6 +332,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Advertisement
|
<Advertisement
|
||||||
|
v-if="mod.status === 'approved' || mod.status === 'unlisted'"
|
||||||
format="rectangle"
|
format="rectangle"
|
||||||
:page-url="
|
:page-url="
|
||||||
'https://modrinth.com/mod/' + (mod.slug ? mod.slug : mod.id)
|
'https://modrinth.com/mod/' + (mod.slug ? mod.slug : mod.id)
|
||||||
@@ -328,6 +357,8 @@ import ClientIcon from '~/assets/images/utils/client.svg?inline'
|
|||||||
import ServerIcon from '~/assets/images/utils/server.svg?inline'
|
import ServerIcon from '~/assets/images/utils/server.svg?inline'
|
||||||
import FileTextIcon from '~/assets/images/utils/file-text.svg?inline'
|
import FileTextIcon from '~/assets/images/utils/file-text.svg?inline'
|
||||||
import CodeIcon from '~/assets/images/sidebar/mod.svg?inline'
|
import CodeIcon from '~/assets/images/sidebar/mod.svg?inline'
|
||||||
|
import ReportIcon from '~/assets/images/utils/report.svg?inline'
|
||||||
|
import FollowIcon from '~/assets/images/utils/heart.svg?inline'
|
||||||
|
|
||||||
import ExternalIcon from '~/assets/images/utils/external.svg?inline'
|
import ExternalIcon from '~/assets/images/utils/external.svg?inline'
|
||||||
|
|
||||||
@@ -352,6 +383,8 @@ export default {
|
|||||||
ServerIcon,
|
ServerIcon,
|
||||||
FileTextIcon,
|
FileTextIcon,
|
||||||
CodeIcon,
|
CodeIcon,
|
||||||
|
ReportIcon,
|
||||||
|
FollowIcon,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
mod: {
|
mod: {
|
||||||
@@ -390,6 +423,12 @@ export default {
|
|||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
userFollows: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatNumber(x) {
|
formatNumber(x) {
|
||||||
@@ -418,6 +457,39 @@ export default {
|
|||||||
elem.href = url
|
elem.href = url
|
||||||
elem.click()
|
elem.click()
|
||||||
},
|
},
|
||||||
|
async followMod() {
|
||||||
|
const config = {
|
||||||
|
headers: {
|
||||||
|
Authorization: this.$auth.getToken('local')
|
||||||
|
? this.$auth.getToken('local')
|
||||||
|
: '',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
await axios.post(
|
||||||
|
`https://api.modrinth.com/api/v1/mod/${this.mod.id}/follow`,
|
||||||
|
{},
|
||||||
|
config
|
||||||
|
)
|
||||||
|
|
||||||
|
this.userFollows.push(this.mod.id)
|
||||||
|
},
|
||||||
|
async unfollowMod() {
|
||||||
|
const config = {
|
||||||
|
headers: {
|
||||||
|
Authorization: this.$auth.getToken('local')
|
||||||
|
? this.$auth.getToken('local')
|
||||||
|
: '',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
await axios.delete(
|
||||||
|
`https://api.modrinth.com/api/v1/mod/${this.mod.id}/follow`,
|
||||||
|
config
|
||||||
|
)
|
||||||
|
|
||||||
|
this.userFollows.splice(this.userFollows.indexOf(this.mod.id), 1)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -455,6 +527,15 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.buttons {
|
||||||
|
@extend %column;
|
||||||
|
margin: var(--spacing-card-md) var(--spacing-card-md) var(--spacing-card-md)
|
||||||
|
auto;
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin: 0.2rem 0 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mod-navigation {
|
.mod-navigation {
|
||||||
@@ -470,7 +551,6 @@ export default {
|
|||||||
.section {
|
.section {
|
||||||
padding: var(--spacing-card-sm);
|
padding: var(--spacing-card-sm);
|
||||||
@extend %card-spaced-b;
|
@extend %card-spaced-b;
|
||||||
margin-top: var(--spacing-card-lg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
@@ -481,7 +561,6 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-left: 5px;
|
|
||||||
p {
|
p {
|
||||||
max-width: 6rem;
|
max-width: 6rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<a v-else :href="pageUrl">{{ name }}</a>
|
<a v-else :href="pageUrl">{{ name }}</a>
|
||||||
</h2>
|
</h2>
|
||||||
<p v-if="author" class="author">
|
<p v-if="author" class="author">
|
||||||
by <a :href="authorUrl">{{ author }}</a>
|
by <nuxt-link :to="'/user/' + author">{{ author }}</nuxt-link>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="description">
|
<p class="description">
|
||||||
|
|||||||
16654
package-lock.json
generated
16654
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
|||||||
<h3 class="column-grow-1">Mods</h3>
|
<h3 class="column-grow-1">Mods</h3>
|
||||||
</div>
|
</div>
|
||||||
<ModCard
|
<ModCard
|
||||||
v-for="mod in mods"
|
v-for="(mod, index) in mods"
|
||||||
:id="mod.id"
|
:id="mod.id"
|
||||||
:key="mod.id"
|
:key="mod.id"
|
||||||
:author="mod.author"
|
:author="mod.author"
|
||||||
@@ -24,17 +24,49 @@
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="button column approve"
|
class="button column approve"
|
||||||
@click="changeModStatus(mod.id, 'approved')"
|
@click="changeModStatus(mod.id, 'approved', index)"
|
||||||
>
|
>
|
||||||
Approve
|
Approve
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="button column reject"
|
class="button column reject"
|
||||||
@click="changeModStatus(mod.id, 'rejected')"
|
@click="changeModStatus(mod.id, 'rejected', index)"
|
||||||
>
|
>
|
||||||
Reject
|
Reject
|
||||||
</button>
|
</button>
|
||||||
</ModCard>
|
</ModCard>
|
||||||
|
<div class="section-header">
|
||||||
|
<h3 class="column-grow-1">Reports</h3>
|
||||||
|
</div>
|
||||||
|
<div v-for="(report, index) in reports" :key="report.id" class="report">
|
||||||
|
<div class="header">
|
||||||
|
<h5 class="title">
|
||||||
|
Report for {{ report.item_type }}
|
||||||
|
<nuxt-link
|
||||||
|
:to="report.item_type + '/' + report.item_id.replace(/\W/g, '')"
|
||||||
|
>{{ report.item_id }}</nuxt-link
|
||||||
|
>
|
||||||
|
</h5>
|
||||||
|
<p
|
||||||
|
v-tooltip="
|
||||||
|
$dayjs(report.created).format(
|
||||||
|
'[Created at] YYYY-MM-DD [at] HH:mm A'
|
||||||
|
)
|
||||||
|
"
|
||||||
|
class="date"
|
||||||
|
>
|
||||||
|
Created {{ $dayjs(report.created).fromNow() }}
|
||||||
|
</p>
|
||||||
|
<button class="delete iconified-button" @click="deleteReport(index)">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-compiled-markdown="report.body"
|
||||||
|
v-highlightjs
|
||||||
|
class="markdown-body"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
</DashboardPage>
|
</DashboardPage>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -62,12 +94,17 @@ export default {
|
|||||||
await axios.get(`https://api.modrinth.com/api/v1/moderation/mods`, config)
|
await axios.get(`https://api.modrinth.com/api/v1/moderation/mods`, config)
|
||||||
).data
|
).data
|
||||||
|
|
||||||
|
const reports = (
|
||||||
|
await axios.get(`https://api.modrinth.com/api/v1/report`, config)
|
||||||
|
).data
|
||||||
|
|
||||||
return {
|
return {
|
||||||
mods,
|
mods,
|
||||||
|
reports,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async changeModStatus(id, status) {
|
async changeModStatus(id, status, index) {
|
||||||
const config = {
|
const config = {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: this.$auth.getToken('local')
|
Authorization: this.$auth.getToken('local')
|
||||||
@@ -84,7 +121,23 @@ export default {
|
|||||||
config
|
config
|
||||||
)
|
)
|
||||||
|
|
||||||
await this.$router.go(0)
|
this.mods.splice(index, 1)
|
||||||
|
},
|
||||||
|
async deleteReport(index) {
|
||||||
|
const config = {
|
||||||
|
headers: {
|
||||||
|
Authorization: this.$auth.getToken('local')
|
||||||
|
? this.$auth.getToken('local')
|
||||||
|
: '',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
await axios.delete(
|
||||||
|
`https://api.modrinth.com/api/v1/report/${this.reports[index].id}`,
|
||||||
|
config
|
||||||
|
)
|
||||||
|
|
||||||
|
this.reports.splice(index, 1)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -94,4 +147,24 @@ export default {
|
|||||||
.button {
|
.button {
|
||||||
margin: 0.25rem 0;
|
margin: 0.25rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.report {
|
||||||
|
@extend %card-spaced-b;
|
||||||
|
padding: var(--spacing-card-sm) var(--spacing-card-lg);
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: var(--font-size-lg);
|
||||||
|
margin: 0 0.5rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconified-button {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -79,12 +79,8 @@ export default {
|
|||||||
try {
|
try {
|
||||||
if (index) {
|
if (index) {
|
||||||
const config = {
|
const config = {
|
||||||
method: Object.keys(
|
method: notification.actions[index].action_route[0].toLowerCase(),
|
||||||
notification.actions[index].action_route
|
url: `https://api.modrinth.com/api/v1/${notification.actions[index].action_route[1]}`,
|
||||||
)[0].toLowerCase(),
|
|
||||||
url: `https://api.modrinth.com/api/v1/${
|
|
||||||
Object.values(notification.actions[index].action_route)[0]
|
|
||||||
}`,
|
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: this.$auth.getToken('local'),
|
Authorization: this.$auth.getToken('local'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
:members="members"
|
:members="members"
|
||||||
:current-member="currentMember"
|
:current-member="currentMember"
|
||||||
:link-bar="[['Description', '']]"
|
:link-bar="[['Description', '']]"
|
||||||
|
:user-follows="userFollows"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-compiled-markdown="mod.body"
|
v-compiled-markdown="mod.body"
|
||||||
@@ -42,12 +43,18 @@ export default {
|
|||||||
mod.body = (await axios.get(mod.body_url)).data
|
mod.body = (await axios.get(mod.body_url)).data
|
||||||
}
|
}
|
||||||
|
|
||||||
const [members, featuredVersions] = (
|
const [members, featuredVersions, userFollows] = (
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
axios.get(`https://api.modrinth.com/api/v1/team/${mod.team}/members`),
|
axios.get(`https://api.modrinth.com/api/v1/team/${mod.team}/members`),
|
||||||
axios.get(
|
axios.get(
|
||||||
`https://api.modrinth.com/api/v1/mod/${mod.id}/version?featured=true`
|
`https://api.modrinth.com/api/v1/mod/${mod.id}/version?featured=true`
|
||||||
),
|
),
|
||||||
|
axios.get(
|
||||||
|
data.$auth.loggedIn
|
||||||
|
? `https://api.modrinth.com/api/v1/user/${data.$auth.user.id}/follows`
|
||||||
|
: `https://api.modrinth.com`,
|
||||||
|
config
|
||||||
|
),
|
||||||
])
|
])
|
||||||
).map((it) => it.data)
|
).map((it) => it.data)
|
||||||
|
|
||||||
@@ -75,6 +82,7 @@ export default {
|
|||||||
featuredVersions,
|
featuredVersions,
|
||||||
members,
|
members,
|
||||||
currentMember,
|
currentMember,
|
||||||
|
userFollows: userFollows.name ? null : userFollows,
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
data.error({
|
data.error({
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
:members="members"
|
:members="members"
|
||||||
:current-member="currentMember"
|
:current-member="currentMember"
|
||||||
:link-bar="[['New Version', 'newversion']]"
|
:link-bar="[['New Version', 'newversion']]"
|
||||||
|
:user-follows="userFollows"
|
||||||
>
|
>
|
||||||
<div class="new-version">
|
<div class="new-version">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
@@ -157,6 +158,7 @@ export default {
|
|||||||
featuredVersions,
|
featuredVersions,
|
||||||
selectableLoaders,
|
selectableLoaders,
|
||||||
selectableVersions,
|
selectableVersions,
|
||||||
|
userFollows,
|
||||||
] = (
|
] = (
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
axios.get(`https://api.modrinth.com/api/v1/team/${mod.team}/members`),
|
axios.get(`https://api.modrinth.com/api/v1/team/${mod.team}/members`),
|
||||||
@@ -165,6 +167,12 @@ export default {
|
|||||||
),
|
),
|
||||||
axios.get(`https://api.modrinth.com/api/v1/tag/loader`),
|
axios.get(`https://api.modrinth.com/api/v1/tag/loader`),
|
||||||
axios.get(`https://api.modrinth.com/api/v1/tag/game_version`),
|
axios.get(`https://api.modrinth.com/api/v1/tag/game_version`),
|
||||||
|
axios.get(
|
||||||
|
data.$auth.loggedIn
|
||||||
|
? `https://api.modrinth.com/api/v1/user/${data.$auth.user.id}/follows`
|
||||||
|
: `https://api.modrinth.com`,
|
||||||
|
config
|
||||||
|
),
|
||||||
])
|
])
|
||||||
).map((it) => it.data)
|
).map((it) => it.data)
|
||||||
|
|
||||||
@@ -194,6 +202,7 @@ export default {
|
|||||||
selectableLoaders,
|
selectableLoaders,
|
||||||
selectableVersions,
|
selectableVersions,
|
||||||
currentMember,
|
currentMember,
|
||||||
|
userFollows: userFollows.name ? null : userFollows,
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
data.error({
|
data.error({
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
:current-member="currentMember"
|
:current-member="currentMember"
|
||||||
:featured-versions="featuredVersions"
|
:featured-versions="featuredVersions"
|
||||||
:link-bar="[['Settings', 'settings']]"
|
:link-bar="[['Settings', 'settings']]"
|
||||||
|
:user-follows="userFollows"
|
||||||
>
|
>
|
||||||
<div class="section-header columns">
|
<div class="section-header columns">
|
||||||
<h3 class="column-grow-1">General</h3>
|
<h3 class="column-grow-1">General</h3>
|
||||||
@@ -261,7 +262,7 @@ export default {
|
|||||||
)
|
)
|
||||||
).data
|
).data
|
||||||
|
|
||||||
const [members, featuredVersions] = (
|
const [members, featuredVersions, userFollows] = (
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
axios.get(
|
axios.get(
|
||||||
`https://api.modrinth.com/api/v1/team/${mod.team}/members`,
|
`https://api.modrinth.com/api/v1/team/${mod.team}/members`,
|
||||||
@@ -270,6 +271,12 @@ export default {
|
|||||||
axios.get(
|
axios.get(
|
||||||
`https://api.modrinth.com/api/v1/mod/${mod.id}/version?featured=true`
|
`https://api.modrinth.com/api/v1/mod/${mod.id}/version?featured=true`
|
||||||
),
|
),
|
||||||
|
axios.get(
|
||||||
|
data.$auth.loggedIn
|
||||||
|
? `https://api.modrinth.com/api/v1/user/${data.$auth.user.id}/follows`
|
||||||
|
: `https://api.modrinth.com`,
|
||||||
|
config
|
||||||
|
),
|
||||||
])
|
])
|
||||||
).map((it) => it.data)
|
).map((it) => it.data)
|
||||||
|
|
||||||
@@ -299,6 +306,7 @@ export default {
|
|||||||
featuredVersions,
|
featuredVersions,
|
||||||
members,
|
members,
|
||||||
currentMember,
|
currentMember,
|
||||||
|
userFollows: userFollows.name ? null : userFollows,
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
data.error({
|
data.error({
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
[version.name, 'versions/' + version.id],
|
[version.name, 'versions/' + version.id],
|
||||||
['Edit Version', 'versions/' + version.id + '/edit'],
|
['Edit Version', 'versions/' + version.id + '/edit'],
|
||||||
]"
|
]"
|
||||||
|
:user-follows="userFollows"
|
||||||
>
|
>
|
||||||
<div class="new-version">
|
<div class="new-version">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
@@ -147,6 +148,7 @@ export default {
|
|||||||
featuredVersions,
|
featuredVersions,
|
||||||
selectableLoaders,
|
selectableLoaders,
|
||||||
selectableVersions,
|
selectableVersions,
|
||||||
|
userFollows,
|
||||||
] = (
|
] = (
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
axios.get(`https://api.modrinth.com/api/v1/team/${mod.team}/members`),
|
axios.get(`https://api.modrinth.com/api/v1/team/${mod.team}/members`),
|
||||||
@@ -156,6 +158,12 @@ export default {
|
|||||||
),
|
),
|
||||||
axios.get(`https://api.modrinth.com/api/v1/tag/loader`),
|
axios.get(`https://api.modrinth.com/api/v1/tag/loader`),
|
||||||
axios.get(`https://api.modrinth.com/api/v1/tag/game_version`),
|
axios.get(`https://api.modrinth.com/api/v1/tag/game_version`),
|
||||||
|
axios.get(
|
||||||
|
data.$auth.loggedIn
|
||||||
|
? `https://api.modrinth.com/api/v1/user/${data.$auth.user.id}/follows`
|
||||||
|
: `https://api.modrinth.com`,
|
||||||
|
config
|
||||||
|
),
|
||||||
])
|
])
|
||||||
).map((it) => it.data)
|
).map((it) => it.data)
|
||||||
|
|
||||||
@@ -202,6 +210,7 @@ export default {
|
|||||||
currentMember,
|
currentMember,
|
||||||
selectableLoaders,
|
selectableLoaders,
|
||||||
selectableVersions,
|
selectableVersions,
|
||||||
|
userFollows: userFollows.name ? null : userFollows,
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
data.error({
|
data.error({
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
['Versions', 'versions'],
|
['Versions', 'versions'],
|
||||||
[version.name, 'versions/' + version.id],
|
[version.name, 'versions/' + version.id],
|
||||||
]"
|
]"
|
||||||
|
:user-follows="userFollows"
|
||||||
>
|
>
|
||||||
<div class="version">
|
<div class="version">
|
||||||
<div class="version-header">
|
<div class="version-header">
|
||||||
@@ -27,13 +28,25 @@
|
|||||||
</span>
|
</span>
|
||||||
<Categories :categories="version.loaders" />
|
<Categories :categories="version.loaders" />
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button v-if="currentMember" class="action" @click="deleteVersion">
|
<nuxt-link
|
||||||
|
v-if="this.$auth.loggedIn"
|
||||||
|
:to="`/report/create?id=${version.id}&t=version`"
|
||||||
|
class="action iconified-button"
|
||||||
|
>
|
||||||
|
<ReportIcon />
|
||||||
|
Report
|
||||||
|
</nuxt-link>
|
||||||
|
<button
|
||||||
|
v-if="currentMember"
|
||||||
|
class="action iconified-button"
|
||||||
|
@click="deleteVersion"
|
||||||
|
>
|
||||||
<TrashIcon />
|
<TrashIcon />
|
||||||
Delete
|
Delete
|
||||||
</button>
|
</button>
|
||||||
<nuxt-link
|
<nuxt-link
|
||||||
v-if="currentMember"
|
v-if="currentMember"
|
||||||
class="action"
|
class="action iconified-button"
|
||||||
:to="version.id + '/edit'"
|
:to="version.id + '/edit'"
|
||||||
>
|
>
|
||||||
<EditIcon />
|
<EditIcon />
|
||||||
@@ -42,7 +55,7 @@
|
|||||||
<a
|
<a
|
||||||
v-if="primaryFile"
|
v-if="primaryFile"
|
||||||
:href="primaryFile.url"
|
:href="primaryFile.url"
|
||||||
class="action"
|
class="action iconified-button"
|
||||||
@click.prevent="
|
@click.prevent="
|
||||||
downloadFile(primaryFile.hashes.sha1, primaryFile.url)
|
downloadFile(primaryFile.hashes.sha1, primaryFile.url)
|
||||||
"
|
"
|
||||||
@@ -125,6 +138,7 @@ import EditIcon from '~/assets/images/utils/edit.svg?inline'
|
|||||||
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
||||||
import CalendarIcon from '~/assets/images/utils/calendar.svg?inline'
|
import CalendarIcon from '~/assets/images/utils/calendar.svg?inline'
|
||||||
import TagIcon from '~/assets/images/utils/tag.svg?inline'
|
import TagIcon from '~/assets/images/utils/tag.svg?inline'
|
||||||
|
import ReportIcon from '~/assets/images/utils/report.svg?inline'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -136,6 +150,7 @@ export default {
|
|||||||
TagIcon,
|
TagIcon,
|
||||||
TrashIcon,
|
TrashIcon,
|
||||||
EditIcon,
|
EditIcon,
|
||||||
|
ReportIcon,
|
||||||
},
|
},
|
||||||
auth: false,
|
auth: false,
|
||||||
async asyncData(data) {
|
async asyncData(data) {
|
||||||
@@ -155,13 +170,19 @@ export default {
|
|||||||
)
|
)
|
||||||
).data
|
).data
|
||||||
|
|
||||||
const [members, versions, featuredVersions] = (
|
const [members, versions, featuredVersions, userFollows] = (
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
axios.get(`https://api.modrinth.com/api/v1/team/${mod.team}/members`),
|
axios.get(`https://api.modrinth.com/api/v1/team/${mod.team}/members`),
|
||||||
axios.get(`https://api.modrinth.com/api/v1/mod/${mod.id}/version`),
|
axios.get(`https://api.modrinth.com/api/v1/mod/${mod.id}/version`),
|
||||||
axios.get(
|
axios.get(
|
||||||
`https://api.modrinth.com/api/v1/mod/${mod.id}/version?featured=true`
|
`https://api.modrinth.com/api/v1/mod/${mod.id}/version?featured=true`
|
||||||
),
|
),
|
||||||
|
axios.get(
|
||||||
|
data.$auth.loggedIn
|
||||||
|
? `https://api.modrinth.com/api/v1/user/${data.$auth.user.id}/follows`
|
||||||
|
: `https://api.modrinth.com`,
|
||||||
|
config
|
||||||
|
),
|
||||||
])
|
])
|
||||||
).map((it) => it.data)
|
).map((it) => it.data)
|
||||||
|
|
||||||
@@ -206,6 +227,7 @@ export default {
|
|||||||
version,
|
version,
|
||||||
primaryFile,
|
primaryFile,
|
||||||
currentMember,
|
currentMember,
|
||||||
|
userFollows: userFollows.name ? null : userFollows,
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
data.error({
|
data.error({
|
||||||
@@ -397,22 +419,7 @@ export default {
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
|
||||||
.action {
|
.action {
|
||||||
padding: 0.5rem;
|
|
||||||
color: var(--color-button-text);
|
|
||||||
background-color: var(--color-button-bg);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
border-radius: var(--size-rounded-sm);
|
|
||||||
margin: 0 0 0 0.5rem;
|
margin: 0 0 0 0.5rem;
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
background-color: var(--color-button-bg-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
margin-right: 0.25rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
:members="members"
|
:members="members"
|
||||||
:current-member="currentMember"
|
:current-member="currentMember"
|
||||||
:link-bar="[['Versions', 'versions']]"
|
:link-bar="[['Versions', 'versions']]"
|
||||||
|
:user-follows="userFollows"
|
||||||
>
|
>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
@@ -111,13 +112,19 @@ export default {
|
|||||||
)
|
)
|
||||||
).data
|
).data
|
||||||
|
|
||||||
const [members, versions, featuredVersions] = (
|
const [members, versions, featuredVersions, userFollows] = (
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
axios.get(`https://api.modrinth.com/api/v1/team/${mod.team}/members`),
|
axios.get(`https://api.modrinth.com/api/v1/team/${mod.team}/members`),
|
||||||
axios.get(`https://api.modrinth.com/api/v1/mod/${mod.id}/version`),
|
axios.get(`https://api.modrinth.com/api/v1/mod/${mod.id}/version`),
|
||||||
axios.get(
|
axios.get(
|
||||||
`https://api.modrinth.com/api/v1/mod/${mod.id}/version?featured=true`
|
`https://api.modrinth.com/api/v1/mod/${mod.id}/version?featured=true`
|
||||||
),
|
),
|
||||||
|
axios.get(
|
||||||
|
data.$auth.loggedIn
|
||||||
|
? `https://api.modrinth.com/api/v1/user/${data.$auth.user.id}/follows`
|
||||||
|
: `https://api.modrinth.com`,
|
||||||
|
config
|
||||||
|
),
|
||||||
])
|
])
|
||||||
).map((it) => it.data)
|
).map((it) => it.data)
|
||||||
|
|
||||||
@@ -146,6 +153,7 @@ export default {
|
|||||||
featuredVersions,
|
featuredVersions,
|
||||||
members,
|
members,
|
||||||
currentMember,
|
currentMember,
|
||||||
|
userFollows: userFollows.name ? null : userFollows,
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
data.error({
|
data.error({
|
||||||
|
|||||||
252
pages/report/create.vue
Normal file
252
pages/report/create.vue
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page-container">
|
||||||
|
<div class="page-contents">
|
||||||
|
<header class="columns">
|
||||||
|
<h2 class="column-grow-1">File a report</h2>
|
||||||
|
<button
|
||||||
|
title="Create"
|
||||||
|
class="brand-button column"
|
||||||
|
:disabled="!this.$nuxt.$loading"
|
||||||
|
@click="createReport"
|
||||||
|
>
|
||||||
|
Create
|
||||||
|
</button>
|
||||||
|
</header>
|
||||||
|
<section class="info">
|
||||||
|
<h3>Item ID</h3>
|
||||||
|
<label>
|
||||||
|
<span>
|
||||||
|
The ID of the item you are reporting. For example, the item ID of a
|
||||||
|
mod would be it's mod ID.
|
||||||
|
</span>
|
||||||
|
<input v-model="itemId" type="text" placeholder="Enter the Item ID" />
|
||||||
|
</label>
|
||||||
|
<h3>Item Type</h3>
|
||||||
|
<label>
|
||||||
|
<span> The type of the item that is being reported </span>
|
||||||
|
<multiselect
|
||||||
|
id="item-type"
|
||||||
|
v-model="itemType"
|
||||||
|
:options="['mod', 'version', 'user']"
|
||||||
|
:multiple="false"
|
||||||
|
:searchable="false"
|
||||||
|
:show-no-results="false"
|
||||||
|
:show-labels="false"
|
||||||
|
placeholder="Choose item type"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<h3>Report Type</h3>
|
||||||
|
<label>
|
||||||
|
<span>
|
||||||
|
The type of report. This is the category that this report falls
|
||||||
|
under.
|
||||||
|
</span>
|
||||||
|
<multiselect
|
||||||
|
id="report-type"
|
||||||
|
v-model="reportType"
|
||||||
|
:options="reportTypes"
|
||||||
|
:multiple="false"
|
||||||
|
:searchable="false"
|
||||||
|
:show-no-results="false"
|
||||||
|
:show-labels="false"
|
||||||
|
placeholder="Choose report type"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</section>
|
||||||
|
<section class="description">
|
||||||
|
<h3>
|
||||||
|
<label
|
||||||
|
for="body"
|
||||||
|
title="You can type the of the long form of your description here."
|
||||||
|
>
|
||||||
|
Body
|
||||||
|
</label>
|
||||||
|
</h3>
|
||||||
|
<span>
|
||||||
|
You can type the of the long form of your description here. This
|
||||||
|
editor supports markdown. You can find the syntax
|
||||||
|
<a
|
||||||
|
href="https://guides.github.com/features/mastering-markdown/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>here</a
|
||||||
|
>.
|
||||||
|
</span>
|
||||||
|
<div class="columns">
|
||||||
|
<div class="textarea-wrapper">
|
||||||
|
<textarea id="body" v-model="body"></textarea>
|
||||||
|
</div>
|
||||||
|
<div v-compiled-markdown="body" class="markdown-body"></div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Multiselect from 'vue-multiselect'
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Multiselect,
|
||||||
|
},
|
||||||
|
fetch() {
|
||||||
|
if (this.$route.query.id) this.itemId = this.$route.query.id
|
||||||
|
if (this.$route.query.t) this.itemType = this.$route.query.t
|
||||||
|
},
|
||||||
|
async asyncData() {
|
||||||
|
const reportTypes = (
|
||||||
|
await axios.get(`https://api.modrinth.com/api/v1/tag/report_type`)
|
||||||
|
).data
|
||||||
|
|
||||||
|
return {
|
||||||
|
reportTypes,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
itemId: '',
|
||||||
|
itemType: '',
|
||||||
|
reportType: '',
|
||||||
|
body: '',
|
||||||
|
|
||||||
|
reportTypes: ['aaaa'],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async createReport() {
|
||||||
|
this.$nuxt.$loading.start()
|
||||||
|
|
||||||
|
try {
|
||||||
|
const config = {
|
||||||
|
headers: {
|
||||||
|
Authorization: this.$auth.getToken('local')
|
||||||
|
? this.$auth.getToken('local')
|
||||||
|
: '',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
report_type: this.reportType,
|
||||||
|
item_id: this.itemId,
|
||||||
|
item_type: this.itemType,
|
||||||
|
body: this.body,
|
||||||
|
}
|
||||||
|
|
||||||
|
await axios.post('https://api.modrinth.com/api/v1/report', data, config)
|
||||||
|
|
||||||
|
await this.$router.replace(`/${this.itemType}/${this.itemId}`)
|
||||||
|
} catch (err) {
|
||||||
|
this.$notify({
|
||||||
|
group: 'main',
|
||||||
|
title: 'An Error Occurred',
|
||||||
|
text: err.response.data.description,
|
||||||
|
type: 'error',
|
||||||
|
})
|
||||||
|
window.scrollTo({ top: 0, behavior: 'smooth' })
|
||||||
|
}
|
||||||
|
this.$nuxt.$loading.finish()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.title {
|
||||||
|
* {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
span {
|
||||||
|
flex: 2;
|
||||||
|
padding-right: var(--spacing-card-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
.multiselect,
|
||||||
|
.input-group {
|
||||||
|
flex: 3;
|
||||||
|
height: fit-content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
resize: none;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-contents {
|
||||||
|
display: grid;
|
||||||
|
grid-template:
|
||||||
|
'header header header' auto
|
||||||
|
'info info info' auto
|
||||||
|
'description description description' auto
|
||||||
|
'footer footer footer' auto
|
||||||
|
/ 4fr 1fr 4fr;
|
||||||
|
column-gap: var(--spacing-card-md);
|
||||||
|
row-gap: var(--spacing-card-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
@extend %card;
|
||||||
|
|
||||||
|
grid-area: header;
|
||||||
|
padding: var(--spacing-card-md) var(--spacing-card-lg);
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: auto 0;
|
||||||
|
color: var(--color-text-dark);
|
||||||
|
font-weight: var(--font-weight-extrabold);
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
@extend %card;
|
||||||
|
|
||||||
|
padding: var(--spacing-card-md) var(--spacing-card-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
section.info {
|
||||||
|
grid-area: info;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.description {
|
||||||
|
grid-area: description;
|
||||||
|
|
||||||
|
& > .columns {
|
||||||
|
align-items: stretch;
|
||||||
|
min-height: 10rem;
|
||||||
|
max-height: 40rem;
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body {
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0 var(--spacing-card-sm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -17,6 +17,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p v-if="user.bio" class="bio">{{ user.bio }}</p>
|
<p v-if="user.bio" class="bio">{{ user.bio }}</p>
|
||||||
|
<div class="buttons">
|
||||||
|
<nuxt-link
|
||||||
|
v-if="this.$auth.loggedIn"
|
||||||
|
:to="`/report/create?id=${user.id}&t=user`"
|
||||||
|
class="iconified-button"
|
||||||
|
>
|
||||||
|
<ReportIcon />
|
||||||
|
Report
|
||||||
|
</nuxt-link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card stats">
|
<div class="card stats">
|
||||||
<div class="stat">
|
<div class="stat">
|
||||||
@@ -76,6 +86,7 @@ import axios from 'axios'
|
|||||||
import SearchResult from '@/components/ProjectCard'
|
import SearchResult from '@/components/ProjectCard'
|
||||||
import MFooter from '@/components/MFooter'
|
import MFooter from '@/components/MFooter'
|
||||||
|
|
||||||
|
import ReportIcon from '~/assets/images/utils/report.svg?inline'
|
||||||
import CalendarIcon from '~/assets/images/utils/calendar.svg?inline'
|
import CalendarIcon from '~/assets/images/utils/calendar.svg?inline'
|
||||||
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
||||||
import Advertisement from '~/components/Advertisement'
|
import Advertisement from '~/components/Advertisement'
|
||||||
@@ -88,6 +99,7 @@ export default {
|
|||||||
CalendarIcon,
|
CalendarIcon,
|
||||||
DownloadIcon,
|
DownloadIcon,
|
||||||
MFooter,
|
MFooter,
|
||||||
|
ReportIcon,
|
||||||
},
|
},
|
||||||
async asyncData(data) {
|
async asyncData(data) {
|
||||||
const config = {
|
const config = {
|
||||||
@@ -176,6 +188,13 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.buttons {
|
||||||
|
@extend %column;
|
||||||
|
|
||||||
|
.iconified-button {
|
||||||
|
max-width: 4.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
.stats {
|
.stats {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
Reference in New Issue
Block a user