You've already forked AstralRinth
forked from didirus/AstralRinth
refactor: move nags out of main project member header for perf (#4222)
This commit is contained in:
@@ -20,113 +20,33 @@
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
<ModerationProjectNags
|
||||
v-if="
|
||||
currentMember &&
|
||||
visibleNags.length > 0 &&
|
||||
(project.status === 'draft' || tags.rejectedStatuses.includes(project.status))
|
||||
(currentMember && project.status === 'draft') ||
|
||||
tags.rejectedStatuses.includes(project.status)
|
||||
"
|
||||
class="universal-card my-4"
|
||||
>
|
||||
<div class="flex max-w-full flex-wrap items-center gap-x-6 gap-y-4">
|
||||
<div class="flex flex-auto flex-wrap items-center gap-x-6 gap-y-4">
|
||||
<h2 class="my-0 mr-auto">
|
||||
{{ getFormattedMessage(messages.publishingChecklist) }}
|
||||
</h2>
|
||||
<div class="flex flex-row gap-2">
|
||||
<div class="flex items-center gap-1">
|
||||
<AsteriskIcon class="size-4 text-red" />
|
||||
<span class="text-secondary">{{ getFormattedMessage(messages.required) }}</span>
|
||||
</div>
|
||||
|
|
||||
<div class="flex items-center gap-1">
|
||||
<TriangleAlertIcon class="size-4 text-orange" />
|
||||
<span class="text-secondary">{{ getFormattedMessage(messages.warning) }}</span>
|
||||
</div>
|
||||
|
|
||||
<div class="flex items-center gap-1">
|
||||
<LightBulbIcon class="size-4 text-purple" />
|
||||
<span class="text-secondary">{{ getFormattedMessage(messages.suggestion) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<ButtonStyled circular>
|
||||
<button :class="!collapsed && '[&>svg]:rotate-180'" @click="handleToggleCollapsed()">
|
||||
<DropdownIcon class="duration-250 transition-transform ease-in-out" />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!collapsed" class="grid-display width-16 mt-4">
|
||||
<div v-for="nag in visibleNags" :key="nag.id" class="grid-display__item">
|
||||
<span class="flex items-center gap-2 font-semibold">
|
||||
<component
|
||||
:is="nag.icon || getDefaultIcon(nag.status)"
|
||||
v-tooltip="getStatusTooltip(nag.status)"
|
||||
:class="[
|
||||
'size-4',
|
||||
nag.status === 'required' && 'text-red',
|
||||
nag.status === 'warning' && 'text-orange',
|
||||
nag.status === 'suggestion' && 'text-purple',
|
||||
]"
|
||||
:aria-label="getStatusTooltip(nag.status)"
|
||||
/>
|
||||
{{ getFormattedMessage(nag.title) }}
|
||||
</span>
|
||||
{{ getNagDescription(nag) }}
|
||||
<NuxtLink
|
||||
v-if="nag.link && shouldShowLink(nag)"
|
||||
:to="`/${project.project_type}/${project.slug ? project.slug : project.id}/${
|
||||
nag.link.path
|
||||
}`"
|
||||
class="goto-link"
|
||||
>
|
||||
{{ getFormattedMessage(nag.link.title) }}
|
||||
<ChevronRightIcon aria-hidden="true" class="featured-header-chevron" />
|
||||
</NuxtLink>
|
||||
<ButtonStyled
|
||||
v-if="nag.status === 'special-submit-action' && nag.id === 'submit-for-review'"
|
||||
color="orange"
|
||||
@click="submitForReview"
|
||||
>
|
||||
<button
|
||||
v-tooltip="
|
||||
!canSubmitForReview ? getFormattedMessage(messages.submitChecklistTooltip) : undefined
|
||||
"
|
||||
:disabled="!canSubmitForReview"
|
||||
>
|
||||
<SendIcon />
|
||||
{{ getFormattedMessage(messages.submitForReview) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
:project="project"
|
||||
:versions="versions"
|
||||
:current-member="currentMember"
|
||||
:collapsed="collapsed"
|
||||
:route-name="routeName"
|
||||
:tags="tags"
|
||||
@toggle-collapsed="handleToggleCollapsed"
|
||||
@set-processing="handleSetProcessing"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
AsteriskIcon,
|
||||
CheckIcon,
|
||||
ChevronRightIcon,
|
||||
DropdownIcon,
|
||||
LightBulbIcon,
|
||||
ScaleIcon,
|
||||
SendIcon,
|
||||
TriangleAlertIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import type { Nag, NagContext, NagStatus } from '@modrinth/moderation'
|
||||
import { nags } from '@modrinth/moderation'
|
||||
import { CheckIcon, XIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, injectNotificationManager } from '@modrinth/ui'
|
||||
import type { Project, User, Version } from '@modrinth/utils'
|
||||
import { defineMessages, type MessageDescriptor, useVIntl } from '@vintl/vintl'
|
||||
import type { Component } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { acceptTeamInvite, removeTeamMember } from '~/helpers/teams.js'
|
||||
|
||||
import ModerationProjectNags from './moderation/ModerationProjectNags.vue'
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
|
||||
interface Tags {
|
||||
@@ -182,48 +102,6 @@ const messages = defineMessages({
|
||||
id: 'project-member-header.decline',
|
||||
defaultMessage: 'Decline',
|
||||
},
|
||||
publishingChecklist: {
|
||||
id: 'project-member-header.publishing-checklist',
|
||||
defaultMessage: 'Publishing checklist',
|
||||
},
|
||||
submitForReview: {
|
||||
id: 'project-member-header.submit-for-review',
|
||||
defaultMessage: 'Submit for review',
|
||||
},
|
||||
submitForReviewDesc: {
|
||||
id: 'project-member-header.submit-for-review-desc',
|
||||
defaultMessage:
|
||||
'Your project is only viewable by members of the project. It must be reviewed by moderators in order to be published.',
|
||||
},
|
||||
resubmitForReview: {
|
||||
id: 'project-member-header.resubmit-for-review',
|
||||
defaultMessage: 'Resubmit for review',
|
||||
},
|
||||
resubmitForReviewDesc: {
|
||||
id: 'project-member-header.resubmit-for-review-desc',
|
||||
defaultMessage:
|
||||
"Your project has been {status} by Modrinth's staff. In most cases, you can resubmit for review after addressing the staff's message.",
|
||||
},
|
||||
showKey: {
|
||||
id: 'project-member-header.show-key',
|
||||
defaultMessage: 'Toggle key',
|
||||
},
|
||||
keyTitle: {
|
||||
id: 'project-member-header.key-title',
|
||||
defaultMessage: 'Status Key',
|
||||
},
|
||||
action: {
|
||||
id: 'project-member-header.action',
|
||||
defaultMessage: 'Action',
|
||||
},
|
||||
visitModerationPage: {
|
||||
id: 'project-member-header.visit-moderation-page',
|
||||
defaultMessage: 'Visit moderation page',
|
||||
},
|
||||
submitChecklistTooltip: {
|
||||
id: 'project-member-header.submit-checklist-tooltip',
|
||||
defaultMessage: 'You must complete the required steps in the publishing checklist!',
|
||||
},
|
||||
successJoin: {
|
||||
id: 'project-member-header.success-join',
|
||||
defaultMessage: 'You have joined the project team',
|
||||
@@ -248,29 +126,10 @@ const messages = defineMessages({
|
||||
id: 'project-member-header.error',
|
||||
defaultMessage: 'Error',
|
||||
},
|
||||
required: {
|
||||
id: 'project-member-header.required',
|
||||
defaultMessage: 'Required',
|
||||
},
|
||||
warning: {
|
||||
id: 'project-member-header.warning',
|
||||
defaultMessage: 'Warning',
|
||||
},
|
||||
suggestion: {
|
||||
id: 'project-member-header.suggestion',
|
||||
defaultMessage: 'Suggestion',
|
||||
},
|
||||
})
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
function getNagDescription(nag: Nag): string {
|
||||
if (typeof nag.description === 'function') {
|
||||
return nag.description(nagContext.value)
|
||||
}
|
||||
return formatMessage(nag.description)
|
||||
}
|
||||
|
||||
function getFormattedMessage(message: string | MessageDescriptor): string {
|
||||
if (typeof message === 'string') {
|
||||
return message
|
||||
@@ -296,108 +155,6 @@ const emit = defineEmits<{
|
||||
setProcessing: [processing: boolean]
|
||||
}>()
|
||||
|
||||
const nagContext = computed<NagContext>(() => ({
|
||||
project: props.project,
|
||||
versions: props.versions,
|
||||
currentMember: props.currentMember as User,
|
||||
currentRoute: props.routeName,
|
||||
tags: props.tags,
|
||||
submitProject: submitForReview,
|
||||
}))
|
||||
|
||||
const canSubmitForReview = computed(() => {
|
||||
return (
|
||||
applicableNags.value.filter((nag) => nag.status === 'required' && !isNagComplete(nag))
|
||||
.length === 0
|
||||
)
|
||||
})
|
||||
|
||||
async function submitForReview() {
|
||||
if (canSubmitForReview.value) {
|
||||
await handleSetProcessing(true)
|
||||
}
|
||||
}
|
||||
|
||||
const applicableNags = computed<Nag[]>(() => {
|
||||
return nags.filter((nag) => {
|
||||
return nag.shouldShow(nagContext.value)
|
||||
})
|
||||
})
|
||||
|
||||
function isNagComplete(nag: Nag): boolean {
|
||||
const context = nagContext.value
|
||||
return !nag.shouldShow(context)
|
||||
}
|
||||
|
||||
const visibleNags = computed<Nag[]>(() => {
|
||||
const finalNags = applicableNags.value.filter((nag) => !isNagComplete(nag))
|
||||
|
||||
if (props.project.status === 'draft') {
|
||||
finalNags.push({
|
||||
id: 'submit-for-review',
|
||||
title: messages.submitForReview,
|
||||
description: () => formatMessage(messages.submitForReviewDesc),
|
||||
status: 'special-submit-action',
|
||||
shouldShow: (ctx) => ctx.project.status === 'draft',
|
||||
})
|
||||
}
|
||||
|
||||
if (props.tags.rejectedStatuses.includes(props.project.status)) {
|
||||
finalNags.push({
|
||||
id: 'resubmit-for-review',
|
||||
title: messages.resubmitForReview,
|
||||
description: (ctx) =>
|
||||
formatMessage(messages.resubmitForReviewDesc, { status: ctx.project.status }),
|
||||
status: 'special-submit-action',
|
||||
shouldShow: (ctx) => ctx.tags.rejectedStatuses.includes(ctx.project.status),
|
||||
link: {
|
||||
path: 'moderation',
|
||||
title: messages.visitModerationPage,
|
||||
shouldShow: () => props.routeName !== 'type-id-moderation',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
finalNags.sort((a, b) => {
|
||||
const statusOrder = { required: 0, warning: 1, suggestion: 2, 'special-submit-action': 3 }
|
||||
return statusOrder[a.status] - statusOrder[b.status]
|
||||
})
|
||||
|
||||
return finalNags
|
||||
})
|
||||
|
||||
function shouldShowLink(nag: Nag): boolean {
|
||||
return nag.link?.shouldShow ? nag.link.shouldShow(nagContext.value) : false
|
||||
}
|
||||
|
||||
function getDefaultIcon(status: NagStatus): Component {
|
||||
switch (status) {
|
||||
case 'required':
|
||||
return AsteriskIcon
|
||||
case 'warning':
|
||||
return TriangleAlertIcon
|
||||
case 'suggestion':
|
||||
return LightBulbIcon
|
||||
case 'special-submit-action':
|
||||
return ScaleIcon
|
||||
default:
|
||||
return AsteriskIcon
|
||||
}
|
||||
}
|
||||
|
||||
function getStatusTooltip(status: NagStatus): string {
|
||||
switch (status) {
|
||||
case 'required':
|
||||
return formatMessage(messages.required)
|
||||
case 'warning':
|
||||
return formatMessage(messages.warning)
|
||||
case 'suggestion':
|
||||
return formatMessage(messages.suggestion)
|
||||
default:
|
||||
return formatMessage(messages.required)
|
||||
}
|
||||
}
|
||||
|
||||
const showInvitation = computed<boolean>(() => {
|
||||
if (props.allMembers && props.auth) {
|
||||
const member = props.allMembers.find((x) => x?.user?.id === props.auth.user.id)
|
||||
@@ -472,9 +229,3 @@ async function declineInvite(): Promise<void> {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.duration-250 {
|
||||
transition-duration: 250ms;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
<template>
|
||||
<div v-if="visibleNags.length > 0" class="universal-card my-4">
|
||||
<div class="flex max-w-full flex-wrap items-center gap-x-6 gap-y-4">
|
||||
<div class="flex flex-auto flex-wrap items-center gap-x-6 gap-y-4">
|
||||
<h2 class="my-0 mr-auto">
|
||||
{{ getFormattedMessage(messages.publishingChecklist) }}
|
||||
</h2>
|
||||
<div class="flex flex-row gap-2">
|
||||
<div class="flex items-center gap-1">
|
||||
<AsteriskIcon class="size-4 text-red" />
|
||||
<span class="text-secondary">{{ getFormattedMessage(messages.required) }}</span>
|
||||
</div>
|
||||
|
|
||||
<div class="flex items-center gap-1">
|
||||
<TriangleAlertIcon class="size-4 text-orange" />
|
||||
<span class="text-secondary">{{ getFormattedMessage(messages.warning) }}</span>
|
||||
</div>
|
||||
|
|
||||
<div class="flex items-center gap-1">
|
||||
<LightBulbIcon class="size-4 text-purple" />
|
||||
<span class="text-secondary">{{ getFormattedMessage(messages.suggestion) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<ButtonStyled circular>
|
||||
<button :class="!collapsed && '[&>svg]:rotate-180'" @click="$emit('toggleCollapsed')">
|
||||
<DropdownIcon class="duration-250 transition-transform ease-in-out" />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!collapsed" class="grid-display width-16 mt-4">
|
||||
<div v-for="nag in visibleNags" :key="nag.id" class="grid-display__item">
|
||||
<span class="flex items-center gap-2 font-semibold">
|
||||
<component
|
||||
:is="nag.icon || getDefaultIcon(nag.status)"
|
||||
v-tooltip="getStatusTooltip(nag.status)"
|
||||
:class="[
|
||||
'size-4',
|
||||
nag.status === 'required' && 'text-red',
|
||||
nag.status === 'warning' && 'text-orange',
|
||||
nag.status === 'suggestion' && 'text-purple',
|
||||
]"
|
||||
:aria-label="getStatusTooltip(nag.status)"
|
||||
/>
|
||||
{{ getFormattedMessage(nag.title) }}
|
||||
</span>
|
||||
{{ getNagDescription(nag) }}
|
||||
<NuxtLink
|
||||
v-if="nag.link && shouldShowLink(nag)"
|
||||
:to="`/${project.project_type}/${project.slug ? project.slug : project.id}/${
|
||||
nag.link.path
|
||||
}`"
|
||||
class="goto-link"
|
||||
>
|
||||
{{ getFormattedMessage(nag.link.title) }}
|
||||
<ChevronRightIcon aria-hidden="true" class="featured-header-chevron" />
|
||||
</NuxtLink>
|
||||
<ButtonStyled
|
||||
v-if="nag.status === 'special-submit-action' && nag.id === 'submit-for-review'"
|
||||
color="orange"
|
||||
@click="submitForReview"
|
||||
>
|
||||
<button
|
||||
v-tooltip="
|
||||
!canSubmitForReview ? getFormattedMessage(messages.submitChecklistTooltip) : undefined
|
||||
"
|
||||
:disabled="!canSubmitForReview"
|
||||
>
|
||||
<SendIcon />
|
||||
{{ getFormattedMessage(messages.submitForReview) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
AsteriskIcon,
|
||||
ChevronRightIcon,
|
||||
DropdownIcon,
|
||||
LightBulbIcon,
|
||||
ScaleIcon,
|
||||
SendIcon,
|
||||
TriangleAlertIcon,
|
||||
} from '@modrinth/assets'
|
||||
import type { Nag, NagContext, NagStatus } from '@modrinth/moderation'
|
||||
import { nags } from '@modrinth/moderation'
|
||||
import { ButtonStyled } from '@modrinth/ui'
|
||||
import type { Project, User, Version } from '@modrinth/utils'
|
||||
import { defineMessages, type MessageDescriptor, useVIntl } from '@vintl/vintl'
|
||||
import type { Component } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
interface Tags {
|
||||
rejectedStatuses: string[]
|
||||
}
|
||||
|
||||
interface Member {
|
||||
accepted?: boolean
|
||||
project_role?: string
|
||||
user?: Partial<User>
|
||||
}
|
||||
|
||||
interface Props {
|
||||
project: Project
|
||||
versions?: Version[]
|
||||
currentMember?: Member | null
|
||||
collapsed?: boolean
|
||||
routeName?: string
|
||||
tags: Tags
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
publishingChecklist: {
|
||||
id: 'project-moderation-nags.publishing-checklist',
|
||||
defaultMessage: 'Publishing checklist',
|
||||
},
|
||||
submitForReview: {
|
||||
id: 'project-moderation-nags.submit-for-review',
|
||||
defaultMessage: 'Submit for review',
|
||||
},
|
||||
submitForReviewDesc: {
|
||||
id: 'project-moderation-nags.submit-for-review-desc',
|
||||
defaultMessage:
|
||||
'Your project is only viewable by members of the project. It must be reviewed by moderators in order to be published.',
|
||||
},
|
||||
resubmitForReview: {
|
||||
id: 'project-moderation-nags.resubmit-for-review',
|
||||
defaultMessage: 'Resubmit for review',
|
||||
},
|
||||
resubmitForReviewDesc: {
|
||||
id: 'project-moderation-nags.resubmit-for-review-desc',
|
||||
defaultMessage:
|
||||
"Your project has been {status} by Modrinth's staff. In most cases, you can resubmit for review after addressing the staff's message.",
|
||||
},
|
||||
visitModerationPage: {
|
||||
id: 'project-moderation-nags.visit-moderation-page',
|
||||
defaultMessage: 'Visit moderation page',
|
||||
},
|
||||
submitChecklistTooltip: {
|
||||
id: 'project-moderation-nags.submit-checklist-tooltip',
|
||||
defaultMessage: 'You must complete the required steps in the publishing checklist!',
|
||||
},
|
||||
required: {
|
||||
id: 'project-moderation-nags.required',
|
||||
defaultMessage: 'Required',
|
||||
},
|
||||
warning: {
|
||||
id: 'project-moderation-nags.warning',
|
||||
defaultMessage: 'Warning',
|
||||
},
|
||||
suggestion: {
|
||||
id: 'project-moderation-nags.suggestion',
|
||||
defaultMessage: 'Suggestion',
|
||||
},
|
||||
})
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
versions: () => [],
|
||||
currentMember: null,
|
||||
collapsed: false,
|
||||
routeName: '',
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
toggleCollapsed: []
|
||||
setProcessing: [processing: boolean]
|
||||
}>()
|
||||
|
||||
const nagContext = computed<NagContext>(() => ({
|
||||
project: props.project,
|
||||
versions: props.versions,
|
||||
currentMember: props.currentMember as User,
|
||||
currentRoute: props.routeName,
|
||||
tags: props.tags,
|
||||
submitProject: submitForReview,
|
||||
}))
|
||||
|
||||
const canSubmitForReview = computed(() => {
|
||||
return (
|
||||
applicableNags.value.filter((nag) => nag.status === 'required' && !isNagComplete(nag))
|
||||
.length === 0
|
||||
)
|
||||
})
|
||||
|
||||
async function submitForReview() {
|
||||
if (canSubmitForReview.value) {
|
||||
emit('setProcessing', true)
|
||||
}
|
||||
}
|
||||
|
||||
const applicableNags = computed<Nag[]>(() => {
|
||||
return nags.filter((nag) => {
|
||||
return nag.shouldShow(nagContext.value)
|
||||
})
|
||||
})
|
||||
|
||||
function isNagComplete(nag: Nag): boolean {
|
||||
const context = nagContext.value
|
||||
return !nag.shouldShow(context)
|
||||
}
|
||||
|
||||
const visibleNags = computed<Nag[]>(() => {
|
||||
const finalNags = applicableNags.value.filter((nag) => !isNagComplete(nag))
|
||||
|
||||
if (props.project.status === 'draft') {
|
||||
finalNags.push({
|
||||
id: 'submit-for-review',
|
||||
title: messages.submitForReview,
|
||||
description: () => formatMessage(messages.submitForReviewDesc),
|
||||
status: 'special-submit-action',
|
||||
shouldShow: (ctx) => ctx.project.status === 'draft',
|
||||
})
|
||||
}
|
||||
|
||||
if (props.tags.rejectedStatuses.includes(props.project.status)) {
|
||||
finalNags.push({
|
||||
id: 'resubmit-for-review',
|
||||
title: messages.resubmitForReview,
|
||||
description: (ctx) =>
|
||||
formatMessage(messages.resubmitForReviewDesc, { status: ctx.project.status }),
|
||||
status: 'special-submit-action',
|
||||
shouldShow: (ctx) => ctx.tags.rejectedStatuses.includes(ctx.project.status),
|
||||
link: {
|
||||
path: 'moderation',
|
||||
title: messages.visitModerationPage,
|
||||
shouldShow: () => props.routeName !== 'type-id-moderation',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
finalNags.sort((a, b) => {
|
||||
const statusOrder = { required: 0, warning: 1, suggestion: 2, 'special-submit-action': 3 }
|
||||
return statusOrder[a.status] - statusOrder[b.status]
|
||||
})
|
||||
|
||||
return finalNags
|
||||
})
|
||||
|
||||
function shouldShowLink(nag: Nag): boolean {
|
||||
return nag.link?.shouldShow ? nag.link.shouldShow(nagContext.value) : false
|
||||
}
|
||||
|
||||
function getDefaultIcon(status: NagStatus): Component {
|
||||
switch (status) {
|
||||
case 'required':
|
||||
return AsteriskIcon
|
||||
case 'warning':
|
||||
return TriangleAlertIcon
|
||||
case 'suggestion':
|
||||
return LightBulbIcon
|
||||
case 'special-submit-action':
|
||||
return ScaleIcon
|
||||
default:
|
||||
return AsteriskIcon
|
||||
}
|
||||
}
|
||||
|
||||
function getStatusTooltip(status: NagStatus): string {
|
||||
switch (status) {
|
||||
case 'required':
|
||||
return formatMessage(messages.required)
|
||||
case 'warning':
|
||||
return formatMessage(messages.warning)
|
||||
case 'suggestion':
|
||||
return formatMessage(messages.suggestion)
|
||||
default:
|
||||
return formatMessage(messages.required)
|
||||
}
|
||||
}
|
||||
|
||||
function getNagDescription(nag: Nag): string {
|
||||
if (typeof nag.description === 'function') {
|
||||
return nag.description(nagContext.value)
|
||||
}
|
||||
return formatMessage(nag.description)
|
||||
}
|
||||
|
||||
function getFormattedMessage(message: string | MessageDescriptor): string {
|
||||
if (typeof message === 'string') {
|
||||
return message
|
||||
}
|
||||
return formatMessage(message)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.duration-250 {
|
||||
transition-duration: 250ms;
|
||||
}
|
||||
</style>
|
||||
@@ -557,9 +557,6 @@
|
||||
"project-member-header.accept": {
|
||||
"message": "Accept"
|
||||
},
|
||||
"project-member-header.action": {
|
||||
"message": "Action"
|
||||
},
|
||||
"project-member-header.decline": {
|
||||
"message": "Decline"
|
||||
},
|
||||
@@ -581,33 +578,6 @@
|
||||
"project-member-header.invitation-with-role": {
|
||||
"message": "You've been invited be a member of this project with the role of '{role}'."
|
||||
},
|
||||
"project-member-header.key-title": {
|
||||
"message": "Status Key"
|
||||
},
|
||||
"project-member-header.publishing-checklist": {
|
||||
"message": "Publishing checklist"
|
||||
},
|
||||
"project-member-header.required": {
|
||||
"message": "Required"
|
||||
},
|
||||
"project-member-header.resubmit-for-review": {
|
||||
"message": "Resubmit for review"
|
||||
},
|
||||
"project-member-header.resubmit-for-review-desc": {
|
||||
"message": "Your project has been {status} by Modrinth's staff. In most cases, you can resubmit for review after addressing the staff's message."
|
||||
},
|
||||
"project-member-header.show-key": {
|
||||
"message": "Toggle key"
|
||||
},
|
||||
"project-member-header.submit-checklist-tooltip": {
|
||||
"message": "You must complete the required steps in the publishing checklist!"
|
||||
},
|
||||
"project-member-header.submit-for-review": {
|
||||
"message": "Submit for review"
|
||||
},
|
||||
"project-member-header.submit-for-review-desc": {
|
||||
"message": "Your project is only viewable by members of the project. It must be reviewed by moderators in order to be published."
|
||||
},
|
||||
"project-member-header.success": {
|
||||
"message": "Success"
|
||||
},
|
||||
@@ -617,13 +587,34 @@
|
||||
"project-member-header.success-join": {
|
||||
"message": "You have joined the project team"
|
||||
},
|
||||
"project-member-header.suggestion": {
|
||||
"project-moderation-nags.publishing-checklist": {
|
||||
"message": "Publishing checklist"
|
||||
},
|
||||
"project-moderation-nags.required": {
|
||||
"message": "Required"
|
||||
},
|
||||
"project-moderation-nags.resubmit-for-review": {
|
||||
"message": "Resubmit for review"
|
||||
},
|
||||
"project-moderation-nags.resubmit-for-review-desc": {
|
||||
"message": "Your project has been {status} by Modrinth's staff. In most cases, you can resubmit for review after addressing the staff's message."
|
||||
},
|
||||
"project-moderation-nags.submit-checklist-tooltip": {
|
||||
"message": "You must complete the required steps in the publishing checklist!"
|
||||
},
|
||||
"project-moderation-nags.submit-for-review": {
|
||||
"message": "Submit for review"
|
||||
},
|
||||
"project-moderation-nags.submit-for-review-desc": {
|
||||
"message": "Your project is only viewable by members of the project. It must be reviewed by moderators in order to be published."
|
||||
},
|
||||
"project-moderation-nags.suggestion": {
|
||||
"message": "Suggestion"
|
||||
},
|
||||
"project-member-header.visit-moderation-page": {
|
||||
"project-moderation-nags.visit-moderation-page": {
|
||||
"message": "Visit moderation page"
|
||||
},
|
||||
"project-member-header.warning": {
|
||||
"project-moderation-nags.warning": {
|
||||
"message": "Warning"
|
||||
},
|
||||
"project-type.collection.plural": {
|
||||
|
||||
Reference in New Issue
Block a user