Merge branch 'main' into cal/dev-124-project-validation

This commit is contained in:
IMB11 authored and GitHub committed 2025-07-16 20:54:21 +01:00
commit 252b7bf965
118 files changed
+1325 -557

No files matched your search

@@ -118,6 +118,7 @@ import {
type Cape,
type SkinModel,
get_normalized_skin_texture,
determineModelType,
} from '@/helpers/skins.ts'
import { handleError } from '@/store/notifications'
import {
@@ -253,7 +254,7 @@ async function showNew(e: MouseEvent, skinTextureUrl: string) {
mode.value = 'new'
currentSkin.value = null
uploadedTextureUrl.value = skinTextureUrl
variant.value = 'CLASSIC'
variant.value = await determineModelType(skinTextureUrl)
selectedCape.value = undefined
visibleCapeList.value = []
initVisibleCapeList()
@@ -128,6 +128,14 @@ const messages = defineMessages({
id: 'instance.worlds.game_already_open',
defaultMessage: 'Instance is already open',
},
noContact: {
id: 'instance.worlds.no_contact',
defaultMessage: "Server couldn't be contacted",
},
incompatibleServer: {
id: 'instance.worlds.incompatible_server',
defaultMessage: 'Server is incompatible',
},
copyAddress: {
id: 'instance.worlds.copy_address',
defaultMessage: 'Copy address',
@@ -302,39 +310,33 @@ const messages = defineMessages({
</template>
</div>
<div class="flex gap-1 justify-end smart-clickable:allow-pointer-events">
<template v-if="world.type === 'singleplayer' || serverStatus">
<ButtonStyled
v-if="(playingWorld || (locked && playingInstance)) && !startingInstance"
color="red"
>
<button @click="emit('stop')">
<StopCircleIcon aria-hidden="true" />
{{ formatMessage(commonMessages.stopButton) }}
</button>
</ButtonStyled>
<ButtonStyled v-else>
<button
v-tooltip="
serverIncompatible
? 'Server is incompatible'
<ButtonStyled
v-if="(playingWorld || (locked && playingInstance)) && !startingInstance"
color="red"
>
<button @click="emit('stop')">
<StopCircleIcon aria-hidden="true" />
{{ formatMessage(commonMessages.stopButton) }}
</button>
</ButtonStyled>
<ButtonStyled v-else>
<button
v-tooltip="
!serverStatus
? formatMessage(messages.noContact)
: serverIncompatible
? formatMessage(messages.incompatibleServer)
: !supportsQuickPlay
? formatMessage(messages.noQuickPlay)
: playingOtherWorld || locked
? formatMessage(messages.gameAlreadyOpen)
: null
"
:disabled="!supportsQuickPlay || playingOtherWorld || startingInstance"
@click="emit('play')"
>
<SpinnerIcon v-if="startingInstance && playingWorld" class="animate-spin" />
<PlayIcon v-else aria-hidden="true" />
{{ formatMessage(commonMessages.playButton) }}
</button>
</ButtonStyled>
</template>
<ButtonStyled v-else>
<button class="invisible">
<PlayIcon aria-hidden="true" />
"
:disabled="!supportsQuickPlay || playingOtherWorld || startingInstance"
@click="emit('play')"
>
<SpinnerIcon v-if="startingInstance && playingWorld" class="animate-spin" />
<PlayIcon v-else aria-hidden="true" />
{{ formatMessage(commonMessages.playButton) }}
</button>
</ButtonStyled>
+6 -8
View File
@@ -62,16 +62,14 @@ export async function determineModelType(texture: string): Promise<'SLIM' | 'CLA
context.drawImage(image, 0, 0)
const armX = 44
const armY = 16
const armWidth = 4
const armX = 54
const armY = 20
const armWidth = 2
const armHeight = 12
const imageData = context.getImageData(armX, armY, armWidth, armHeight).data
for (let y = 0; y < armHeight; y++) {
const alphaIndex = (3 + y * armWidth) * 4 + 3
if (imageData[alphaIndex] !== 0) {
for (let index = 1; index <= imageData.length; index++) {
//every fourth value in RGBA is the alpha channel
if (index % 4 == 0 && imageData[index - 1] !== 0) {
resolve('CLASSIC')
return
}
@@ -377,6 +377,12 @@
"instance.worlds.hardcore": {
"message": "Hardcore mode"
},
"instance.worlds.incompatible_server": {
"message": "Server is incompatible"
},
"instance.worlds.no_contact": {
"message": "Server couldn't be contacted"
},
"instance.worlds.no_quick_play": {
"message": "You can only jump straight into worlds on Minecraft 1.20+"
},
+3 -2
View File
@@ -38,10 +38,10 @@
"@intercom/messenger-js-sdk": "^0.0.14",
"@ltd/j-toml": "^1.38.0",
"@modrinth/assets": "workspace:*",
"@modrinth/ui": "workspace:*",
"@modrinth/utils": "workspace:*",
"@modrinth/blog": "workspace:*",
"@modrinth/moderation": "workspace:*",
"@modrinth/ui": "workspace:*",
"@modrinth/utils": "workspace:*",
"@pinia/nuxt": "^0.5.1",
"@types/three": "^0.172.0",
"@vintl/vintl": "^4.4.1",
@@ -59,6 +59,7 @@
"markdown-it": "14.1.0",
"pathe": "^1.1.2",
"pinia": "^2.1.7",
"prettier": "^3.6.2",
"qrcode.vue": "^3.4.0",
"semver": "^7.5.4",
"three": "^0.172.0",
@@ -197,13 +197,13 @@
}
> :where(
input + *,
.input-group + *,
.textarea-wrapper + *,
.chips + *,
.resizable-textarea-wrapper + *,
.input-div + *
) {
input + *,
.input-group + *,
.textarea-wrapper + *,
.chips + *,
.resizable-textarea-wrapper + *,
.input-div + *
) {
&:not(:empty) {
margin-block-start: var(--spacing-card-md);
}
+15 -9
View File
@@ -115,10 +115,12 @@ html {
--shadow-inset-sm: inset 0px -1px 2px hsla(221, 39%, 11%, 0.15);
--shadow-raised-lg: 0px 2px 4px hsla(221, 39%, 11%, 0.2);
--shadow-raised: 0.3px 0.5px 0.6px hsl(var(--shadow-color) / 0.15),
--shadow-raised:
0.3px 0.5px 0.6px hsl(var(--shadow-color) / 0.15),
1px 2px 2.2px -1.7px hsl(var(--shadow-color) / 0.12),
4.4px 8.8px 9.7px -3.4px hsl(var(--shadow-color) / 0.09);
--shadow-floating: hsla(0, 0%, 0%, 0) 0px 0px 0px 0px, hsla(0, 0%, 0%, 0) 0px 0px 0px 0px,
--shadow-floating:
hsla(0, 0%, 0%, 0) 0px 0px 0px 0px, hsla(0, 0%, 0%, 0) 0px 0px 0px 0px,
hsla(0, 0%, 0%, 0.1) 0px 4px 6px -1px, hsla(0, 0%, 0%, 0.1) 0px 2px 4px -1px;
--shadow-card: rgba(50, 50, 100, 0.1) 0px 2px 4px 0px;
@@ -150,8 +152,8 @@ html {
rgba(255, 255, 255, 0.35) 0%,
rgba(255, 255, 255, 0.2695) 100%
);
--landing-blob-shadow: 2px 2px 12px rgba(0, 0, 0, 0.16),
inset 2px 2px 64px rgba(255, 255, 255, 0.45);
--landing-blob-shadow:
2px 2px 12px rgba(0, 0, 0, 0.16), inset 2px 2px 64px rgba(255, 255, 255, 0.45);
--landing-card-bg: rgba(255, 255, 255, 0.8);
--landing-card-shadow: 2px 2px 12px rgba(0, 0, 0, 0.16);
@@ -251,13 +253,15 @@ html {
--shadow-raised-lg: 0px 2px 4px hsla(221, 39%, 11%, 0.2);
--shadow-raised: 0px -2px 4px hsla(221, 39%, 11%, 0.1);
--shadow-floating: hsla(0, 0%, 0%, 0) 0px 0px 0px 0px, hsla(0, 0%, 0%, 0) 0px 0px 0px 0px,
--shadow-floating:
hsla(0, 0%, 0%, 0) 0px 0px 0px 0px, hsla(0, 0%, 0%, 0) 0px 0px 0px 0px,
hsla(0, 0%, 0%, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
--shadow-card: rgba(0, 0, 0, 0.25) 0px 2px 4px 0px;
--landing-maze-bg: url("https://cdn.modrinth.com/landing-new/landing.webp");
--landing-maze-gradient-bg: linear-gradient(0deg, #31375f 0%, rgba(8, 14, 55, 0) 100%),
--landing-maze-gradient-bg:
linear-gradient(0deg, #31375f 0%, rgba(8, 14, 55, 0) 100%),
url("https://cdn.modrinth.com/landing-new/landing-lower.webp");
--landing-maze-outer-bg: linear-gradient(180deg, #06060d 0%, #000000 100%);
@@ -284,7 +288,8 @@ html {
rgba(44, 48, 79, 0.35) 0%,
rgba(32, 35, 50, 0.2695) 100%
);
--landing-blob-shadow: 2px 2px 12px rgba(0, 0, 0, 0.16), inset 2px 2px 64px rgba(57, 61, 94, 0.45);
--landing-blob-shadow:
2px 2px 12px rgba(0, 0, 0, 0.16), inset 2px 2px 64px rgba(57, 61, 94, 0.45);
--landing-card-bg: rgba(59, 63, 85, 0.15);
--landing-card-shadow: 2px 2px 12px rgba(0, 0, 0, 0.16);
@@ -360,8 +365,9 @@ body {
// Defaults
background-color: var(--color-bg);
color: var(--color-text);
--font-standard: Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto,
Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
--font-standard:
Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell,
Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
--mono-font: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;
font-family: var(--font-standard);
font-size: 16px;
@@ -365,26 +365,24 @@ function getJudgements(): ModerationJudgements {
const judgements: ModerationJudgements = {};
modPackData.value.forEach((item) => {
if (item.status && item.status !== "unidentified") {
if (item.type === "flame") {
judgements[item.sha1] = {
type: "flame",
id: item.id,
status: item.status,
link: item.url,
title: item.title,
file_name: item.file_name,
};
} else if (item.type === "unknown") {
judgements[item.sha1] = {
type: "unknown",
status: item.status,
proof: item.proof,
link: item.url,
title: item.title,
file_name: item.file_name,
};
}
if (item.type === "flame") {
judgements[item.sha1] = {
type: "flame",
id: item.id,
status: item.status,
link: item.url,
title: item.title,
file_name: item.file_name,
};
} else if (item.type === "unknown") {
judgements[item.sha1] = {
type: "unknown",
status: item.status,
proof: item.proof,
link: item.url,
title: item.title,
file_name: item.file_name,
};
}
});
@@ -116,8 +116,10 @@
<span class="label__title">{{ action.label }}</span>
</label>
<DropdownSelect
:max-visible-options="3"
render-up
:name="`dropdown-${getActionId(action)}`"
:options="action.options"
:options="getVisibleDropdownOptions(action)"
:model-value="getDropdownValue(action)"
:placeholder="'Select an option'"
:disabled="false"
@@ -138,7 +140,7 @@
<div class="mb-2 font-semibold">{{ action.label }}</div>
<div class="flex flex-wrap gap-2">
<ButtonStyled
v-for="(option, optIndex) in action.options"
v-for="(option, optIndex) in getVisibleMultiSelectOptions(action)"
:key="`${getActionId(action)}-chip-${optIndex}`"
:color="isChipSelected(action, optIndex) ? 'brand' : 'standard'"
@click="toggleChip(action, optIndex)"
@@ -380,6 +382,7 @@ import type {
import ModpackPermissionsFlow from "./ModpackPermissionsFlow.vue";
import KeybindsModal from "./ChecklistKeybindsModal.vue";
import { finalPermissionMessages } from "@modrinth/moderation/data/modpack-permissions-stage";
import prettier from "prettier";
const keybindsModal = ref<InstanceType<typeof KeybindsModal>>();
@@ -461,7 +464,7 @@ const stageTextExpanded = computedAsync(async () => {
const stage = checklist[stageIndex];
if (stage.text) {
return renderHighlightedString(
expandVariables(await stage.text(), props.project, variables.value),
expandVariables(await stage.text(props.project), props.project, variables.value),
);
}
return null;
@@ -559,14 +562,20 @@ function handleKeybinds(event: KeyboardEvent) {
},
trySelectDropdownOption: (actionIndex: number, optionIndex: number) => {
const action = visibleActions.value[actionIndex] as DropdownAction;
if (action && action.type === "dropdown" && action.options[optionIndex]) {
selectDropdownOption(action, action.options[optionIndex]);
if (action && action.type === "dropdown") {
const visibleOptions = getVisibleDropdownOptions(action);
if (optionIndex < visibleOptions.length) {
selectDropdownOption(action, visibleOptions[optionIndex]);
}
}
},
tryToggleChip: (actionIndex: number, chipIndex: number) => {
const action = visibleActions.value[actionIndex] as MultiSelectChipsAction;
if (action && action.type === "multi-select-chips") {
toggleChip(action, chipIndex);
const visibleOptions = getVisibleMultiSelectOptions(action);
if (chipIndex < visibleOptions.length) {
toggleChip(action, chipIndex);
}
}
},
@@ -733,13 +742,17 @@ const multiSelectActions = computed(() =>
function getDropdownValue(action: DropdownAction) {
const actionId = getActionId(action);
const visibleOptions = getVisibleDropdownOptions(action);
const currentValue = actionStates.value[actionId]?.value ?? action.defaultOption ?? 0;
if (action.options && action.options[currentValue]) {
return action.options[currentValue];
const allOptions = action.options;
const storedOption = allOptions[currentValue];
if (storedOption && visibleOptions.includes(storedOption)) {
return storedOption;
}
return action.options?.[0] || null;
return visibleOptions[0] || null;
}
function isActionSelected(action: Action): boolean {
@@ -775,20 +788,31 @@ function selectDropdownOption(action: DropdownAction, selected: any) {
function isChipSelected(action: MultiSelectChipsAction, optionIndex: number): boolean {
const actionId = getActionId(action);
const selectedSet = actionStates.value[actionId]?.value as Set<number> | undefined;
return selectedSet?.has(optionIndex) || false;
const visibleOptions = getVisibleMultiSelectOptions(action);
const visibleOption = visibleOptions[optionIndex];
const originalIndex = action.options.findIndex((opt) => opt === visibleOption);
return selectedSet?.has(originalIndex) || false;
}
function toggleChip(action: MultiSelectChipsAction, optionIndex: number) {
const actionId = getActionId(action);
const state = actionStates.value[actionId];
if (state && state.value instanceof Set) {
if (state.value.has(optionIndex)) {
state.value.delete(optionIndex);
} else {
state.value.add(optionIndex);
const visibleOptions = getVisibleMultiSelectOptions(action);
const visibleOption = visibleOptions[optionIndex];
const originalIndex = action.options.findIndex((opt) => opt === visibleOption);
if (originalIndex !== -1) {
if (state.value.has(originalIndex)) {
state.value.delete(originalIndex);
} else {
state.value.add(originalIndex);
}
state.selected = state.value.size > 0;
persistState();
}
state.selected = state.value.size > 0;
persistState();
}
}
@@ -869,9 +893,23 @@ async function processAction(
stageIndex: number,
messageParts: MessagePart[],
) {
const allValidActionIds: string[] = [];
checklist.forEach((stage, stageIdx) => {
stage.actions.forEach((stageAction, actionIdx) => {
allValidActionIds.push(getActionIdForStage(stageAction, stageIdx, actionIdx));
if (stageAction.enablesActions) {
stageAction.enablesActions.forEach((enabledAction, enabledIdx) => {
allValidActionIds.push(
getActionIdForStage(enabledAction, stageIdx, actionIdx, enabledIdx),
);
});
}
});
});
if (action.type === "button" || action.type === "toggle") {
const buttonAction = action as ButtonAction | ToggleAction;
const message = await getActionMessage(buttonAction, selectedActionIds);
const message = await getActionMessage(buttonAction, selectedActionIds, allValidActionIds);
if (message) {
messageParts.push({
weight: buttonAction.weight,
@@ -885,16 +923,29 @@ async function processAction(
const matchingVariant = findMatchingVariant(
conditionalAction.messageVariants,
selectedActionIds,
allValidActionIds,
stageIndex,
);
let message: string;
let weight: number;
if (matchingVariant) {
const message = (await matchingVariant.message()) as string;
messageParts.push({
weight: matchingVariant.weight,
content: processMessage(message, action, stageIndex, textInputValues.value),
actionId,
stageIndex,
});
message = (await matchingVariant.message()) as string;
weight = matchingVariant.weight;
} else if (conditionalAction.fallbackMessage) {
message = (await conditionalAction.fallbackMessage()) as string;
weight = conditionalAction.fallbackWeight ?? 0;
} else {
return;
}
messageParts.push({
weight,
content: processMessage(message, action, stageIndex, textInputValues.value),
actionId,
stageIndex,
});
} else if (action.type === "dropdown") {
const dropdownAction = action as DropdownAction;
const selectedIndex = state.value ?? 0;
@@ -929,6 +980,18 @@ async function processAction(
}
function shouldShowStage(stage: Stage): boolean {
let hasVisibleActions = false;
for (const a of stage.actions) {
if (shouldShowAction(a)) {
hasVisibleActions = true;
}
}
if (!hasVisibleActions) {
return false;
}
if (typeof stage.shouldShow === "function") {
return stage.shouldShow(props.project);
}
@@ -944,6 +1007,24 @@ function shouldShowAction(action: Action): boolean {
return true;
}
function getVisibleDropdownOptions(action: DropdownAction) {
return action.options.filter((option) => {
if (typeof option.shouldShow === "function") {
return option.shouldShow(props.project);
}
return true;
});
}
function getVisibleMultiSelectOptions(action: MultiSelectChipsAction) {
return action.options.filter((option) => {
if (typeof option.shouldShow === "function") {
return option.shouldShow(props.project);
}
return true;
});
}
function shouldShowStageIndex(stageIndex: number): boolean {
return shouldShowStage(checklist[stageIndex]);
}
@@ -1021,7 +1102,20 @@ async function generateMessage() {
}
}
message.value = fullMessage;
try {
const formattedMessage = await prettier.format(fullMessage, {
parser: "markdown",
printWidth: 80,
proseWrap: "always",
tabWidth: 2,
useTabs: false,
});
message.value = formattedMessage;
} catch (formattingError) {
console.warn("Failed to format markdown, using original:", formattingError);
message.value = fullMessage;
}
generatedMessage.value = true;
} catch (error) {
console.error("Error generating message:", error);
@@ -172,6 +172,7 @@ const flags = useFeatureFlags();
.markdown-body {
grid-area: body;
max-width: 100%;
}
.reporter-info {
@@ -31,9 +31,9 @@
class="flex cursor-pointer items-center gap-1 bg-transparent p-0"
@click="
versionFilter &&
(unlockFilterAccordion.isOpen
? unlockFilterAccordion.close()
: unlockFilterAccordion.open())
(unlockFilterAccordion.isOpen
? unlockFilterAccordion.close()
: unlockFilterAccordion.open())
"
>
<TagItem
@@ -194,13 +194,12 @@ export class ModrinthServer {
}
async testNodeReachability(): Promise<boolean> {
if (!this.general?.datacenter) {
console.warn("No datacenter info available for ping test");
if (!this.general?.node?.instance) {
console.warn("No node instance available for ping test");
return false;
}
const datacenter = this.general.datacenter;
const wsUrl = `wss://${datacenter}.nodes.modrinth.com/pingtest`;
const wsUrl = `wss://${this.general.node.instance}/pingtest`;
try {
return await new Promise((resolve) => {
@@ -112,7 +112,8 @@ export async function useServersFetch<T>(
const response = await $fetch<T>(fullUrl, {
method,
headers,
body: body && contentType === "application/json" ? JSON.stringify(body) : body ?? undefined,
body:
body && contentType === "application/json" ? JSON.stringify(body) : (body ?? undefined),
timeout: 10000,
});
+9
View File
@@ -1346,6 +1346,15 @@ const footerLinks = [
}),
),
},
{
href: "/legal/copyright",
label: formatMessage(
defineMessage({
id: "layout.footer.legal.copyright-policy",
defaultMessage: "Copyright Policy and DMCA",
}),
),
},
],
},
];
@@ -404,6 +404,9 @@
"layout.footer.legal-disclaimer": {
"message": "NOT AN OFFICIAL MINECRAFT SERVICE. NOT APPROVED BY OR ASSOCIATED WITH MOJANG OR MICROSOFT."
},
"layout.footer.legal.copyright-policy": {
"message": "Copyright Policy and DMCA"
},
"layout.footer.legal.privacy-policy": {
"message": "Privacy Policy"
},
+36 -45
View File
@@ -29,12 +29,11 @@
class="settings-header__icon"
/>
<div class="settings-header__text">
<h1 class="wrap-as-needed">
{{ project.title }}
</h1>
<h1 class="wrap-as-needed">{{ project.title }}</h1>
<ProjectStatusBadge :status="project.status" />
</div>
</div>
<h2>Project settings</h2>
<NavStack>
<NavStackItem
@@ -111,6 +110,7 @@
</NavStack>
</aside>
</div>
<div class="normal-page__content">
<ProjectMemberHeader
v-if="currentMember"
@@ -145,6 +145,7 @@
/>
</div>
</div>
<div v-else class="experimental-styles-within">
<NewModal ref="settingsModal">
<template #title>
@@ -174,9 +175,11 @@
<div
class="animation-ring-3 flex items-center justify-center rounded-full border-4 border-solid border-brand bg-brand-highlight opacity-40"
></div>
<div
class="animation-ring-2 flex items-center justify-center rounded-full border-4 border-solid border-brand bg-brand-highlight opacity-60"
></div>
<div
class="animation-ring-1 flex items-center justify-center rounded-full border-4 border-solid border-brand bg-brand-highlight"
>
@@ -219,8 +222,7 @@
:href="`modrinth://mod/${project.slug}`"
@click="() => installWithApp()"
>
<ModrinthIcon aria-hidden="true" />
Install with Modrinth App
<ModrinthIcon aria-hidden="true" /> Install with Modrinth App
<ExternalIcon aria-hidden="true" />
</a>
</ButtonStyled>
@@ -240,6 +242,7 @@
<div class="flex h-[2px] w-full rounded-2xl bg-button-bg"></div>
</div>
</div>
<div class="mx-auto flex w-fit flex-col gap-2">
<ButtonStyled v-if="project.game_versions.length === 1">
<div class="disabled button-like">
@@ -327,8 +330,7 @@
}
"
>
{{ gameVersion }}
<CheckIcon v-if="userSelectedGameVersion === gameVersion" />
{{ gameVersion }} <CheckIcon v-if="userSelectedGameVersion === gameVersion" />
</button>
</ButtonStyled>
</ScrollablePanel>
@@ -419,7 +421,6 @@
</ScrollablePanel>
</Accordion>
</div>
<AutomaticAccordion div class="flex flex-col gap-2">
<VersionSummary
v-if="filteredRelease"
@@ -489,11 +490,11 @@
:color="route.name === 'type-id-version-version' ? `standard` : `brand`"
>
<button @click="(event) => downloadModal.show(event)">
<DownloadIcon aria-hidden="true" />
Download
<DownloadIcon aria-hidden="true" /> Download
</button>
</ButtonStyled>
</div>
<div class="contents sm:hidden">
<ButtonStyled
size="large"
@@ -558,9 +559,11 @@
</button>
</ButtonStyled>
</div>
<p class="m-0 text-wrap text-sm font-medium leading-tight text-secondary">
Modrinth Servers is the easiest way to play with your friends without hassle!
</p>
<p class="m-0 text-wrap text-sm font-bold text-primary">
Starting at $5<span class="text-xs"> / month</span>
</p>
@@ -625,6 +628,7 @@
{{ option.name }}
</Checkbox>
</div>
<div v-else class="menu-text">
<p class="popout-text">No collections found.</p>
</div>
@@ -632,8 +636,7 @@
class="btn collection-button"
@click="(event) => $refs.modal_collection.show(event)"
>
<PlusIcon aria-hidden="true" />
Create new collection
<PlusIcon aria-hidden="true" /> Create new collection
</button>
</template>
</PopoutMenu>
@@ -716,25 +719,14 @@
:dropdown-id="`${baseId}-more-options`"
>
<MoreVerticalIcon aria-hidden="true" />
<template #analytics>
<ChartIcon aria-hidden="true" />
Analytics
</template>
<template #analytics> <ChartIcon aria-hidden="true" /> Analytics </template>
<template #moderation-checklist>
<ScaleIcon aria-hidden="true" />
Review project
</template>
<template #report>
<ReportIcon aria-hidden="true" />
Report
</template>
<template #copy-id>
<ClipboardCopyIcon aria-hidden="true" />
Copy ID
<ScaleIcon aria-hidden="true" /> Review project
</template>
<template #report> <ReportIcon aria-hidden="true" /> Report </template>
<template #copy-id> <ClipboardCopyIcon aria-hidden="true" /> Copy ID </template>
<template #copy-permalink>
<ClipboardCopyIcon aria-hidden="true" />
Copy permanent link
<ClipboardCopyIcon aria-hidden="true" /> Copy permanent link
</template>
</OverflowMenu>
</ButtonStyled>
@@ -760,6 +752,7 @@
updates unless the author decides to unarchive the project.
</MessageBanner>
</div>
<div class="normal-page__sidebar">
<ProjectSidebarCompatibility
:project="project"
@@ -789,6 +782,7 @@
/>
<div class="card flex-card experimental-styles-within">
<h2>{{ formatMessage(detailsMessages.title) }}</h2>
<div class="details-list">
<div class="details-list__item">
<BookTextIcon aria-hidden="true" />
@@ -817,53 +811,48 @@
<span v-else>{{ licenseIdDisplay }}</span>
</div>
</div>
<div
v-if="project.approved"
v-tooltip="$dayjs(project.approved).format('MMMM D, YYYY [at] h:mm A')"
class="details-list__item"
>
<CalendarIcon aria-hidden="true" />
<div>
{{ formatMessage(detailsMessages.published, { date: publishedDate }) }}
</div>
<div>{{ formatMessage(detailsMessages.published, { date: publishedDate }) }}</div>
</div>
<div
v-else
v-tooltip="$dayjs(project.published).format('MMMM D, YYYY [at] h:mm A')"
class="details-list__item"
>
<CalendarIcon aria-hidden="true" />
<div>
{{ formatMessage(detailsMessages.created, { date: createdDate }) }}
</div>
<div>{{ formatMessage(detailsMessages.created, { date: createdDate }) }}</div>
</div>
<div
v-if="project.status === 'processing' && project.queued"
v-tooltip="$dayjs(project.queued).format('MMMM D, YYYY [at] h:mm A')"
class="details-list__item"
>
<ScaleIcon aria-hidden="true" />
<div>
{{ formatMessage(detailsMessages.submitted, { date: submittedDate }) }}
</div>
<div>{{ formatMessage(detailsMessages.submitted, { date: submittedDate }) }}</div>
</div>
<div
v-if="versions.length > 0 && project.updated"
v-tooltip="$dayjs(project.updated).format('MMMM D, YYYY [at] h:mm A')"
class="details-list__item"
>
<VersionIcon aria-hidden="true" />
<div>
{{ formatMessage(detailsMessages.updated, { date: updatedDate }) }}
</div>
<div>{{ formatMessage(detailsMessages.updated, { date: updatedDate }) }}</div>
</div>
</div>
</div>
</div>
<div class="normal-page__content">
<div class="overflow-x-auto">
<NavTabs :links="navLinks" class="mb-4" />
</div>
<div class="overflow-x-auto"><NavTabs :links="navLinks" class="mb-4" /></div>
<NuxtPage
v-model:project="project"
v-model:versions="versions"
@@ -881,6 +870,7 @@
@delete-version="deleteVersion"
/>
</div>
<div class="normal-page__ultimate-sidebar">
<!-- Uncomment this to enable the old moderation checklist. -->
<!-- <ModerationChecklist
@@ -895,6 +885,7 @@
</div>
</div>
</div>
<div
v-if="auth.user && tags.staffRoles.includes(auth.user.role) && showModerationChecklist"
class="moderation-checklist"
@@ -908,6 +899,7 @@
/>
</div>
</template>
<script setup>
import {
BookmarkIcon,
@@ -1570,8 +1562,6 @@ async function copyPermalink() {
const collapsedChecklist = ref(false);
console.log(project.value.id);
const showModerationChecklist = useLocalStorage(
`show-moderation-checklist-${project.value.id}`,
false,
@@ -1663,6 +1653,7 @@ const navLinks = computed(() => {
];
});
</script>
<style lang="scss" scoped>
.settings-header {
display: flex;
@@ -705,9 +705,9 @@ export default defineNuxtComponent({
}
.gallery-body {
flex-grow: 1;
width: calc(100% - 2 * var(--spacing-card-md));
padding: var(--spacing-card-sm) var(--spacing-card-md);
overflow-wrap: anywhere;
.gallery-info {
h2 {
+2 -1
View File
@@ -1421,7 +1421,8 @@ useSeoMeta({
width: 25rem;
height: 25rem;
opacity: 0.75;
background: radial-gradient(
background:
radial-gradient(
50% 50% at 50% 50%,
rgba(5, 206, 69, 0.19) 0%,
rgba(15, 19, 49, 0.25) 100%
@@ -266,12 +266,12 @@ const getRangeOfMethod = (method) => {
const maxWithdrawAmount = computed(() => {
const interval = selectedMethod.value.interval;
return interval?.standard ? interval.standard.max : interval?.fixed?.values.slice(-1)[0] ?? 0;
return interval?.standard ? interval.standard.max : (interval?.fixed?.values.slice(-1)[0] ?? 0);
});
const minWithdrawAmount = computed(() => {
const interval = selectedMethod.value.interval;
return interval?.standard ? interval.standard.min : interval?.fixed?.values?.[0] ?? fees.value;
return interval?.standard ? interval.standard.min : (interval?.fixed?.values?.[0] ?? fees.value);
});
const withdrawAccount = computed(() => {
+2 -1
View File
@@ -149,7 +149,8 @@ onMounted(() => {
</script>
<style lang="scss" scoped>
.main-hero {
background: linear-gradient(360deg, rgba(199, 138, 255, 0.2) 10.92%, var(--color-bg) 100%),
background:
linear-gradient(360deg, rgba(199, 138, 255, 0.2) 10.92%, var(--color-bg) 100%),
var(--color-accent-contrast);
margin-top: -5rem;
padding: 11.25rem 1rem 8rem;
+5 -7
View File
@@ -427,11 +427,8 @@
Do Modrinth Servers have DDoS protection?
</summary>
<p class="m-0 ml-6 leading-[160%]">
Yes. All Modrinth Servers come with DDoS protection powered by
<a href="https://us.ovhcloud.com/security/anti-ddos/" target="_blank"
>OVHcloud® Anti-DDoS infrastructure</a
>
which has over 17Tbps capacity. Your server is safe on Modrinth.
Yes. All Modrinth Servers come with DDoS protection, with up to 17Tbps capacity in
some locations.
</p>
</details>
@@ -443,8 +440,9 @@
Where are Modrinth Servers located? Can I choose a region?
</summary>
<p class="m-0 ml-6 leading-[160%]">
We have servers in both North America in Vint Hill, Virginia, and Europe in Limburg,
Germany. More regions to come in the future!
We have servers available in North America and Europe at the moment that you can
choose upon purchase. More regions to come in the future! If you'd like to switch
your region, please contact support.
</p>
</details>
@@ -1020,7 +1020,7 @@ const nodeUnavailableDetails = computed(() => [
{
label: "Error message",
value: nodeAccessible.value
? server.moduleErrors?.general?.error.message ?? "Unknown"
? (server.moduleErrors?.general?.error.message ?? "Unknown")
: "Unable to reach node. Ping test failed.",
type: "block" as const,
},
@@ -1277,7 +1277,8 @@ useHead({
background-repeat: no-repeat;
filter: blur(1rem);
content: "";
background-image: linear-gradient(
background-image:
linear-gradient(
to bottom,
rgba(from var(--color-raised-bg) r g b / 0.2),
rgb(from var(--color-raised-bg) r g b / 0.8)
@@ -101,7 +101,7 @@
<span :class="{ invisible: 'current_file' in op && !op.current_file }">
{{
"current_file" in op
? op.current_file?.split("/")?.pop() ?? "unknown"
? (op.current_file?.split("/")?.pop() ?? "unknown")
: "unknown"
}}
</span>
@@ -98,13 +98,6 @@
"date": "2023-02-01T20:00:00.000Z",
"link": "https://modrinth.com/news/article/accelerating-development"
},
{
"title": "Two years of Modrinth: a retrospective",
"summary": "The history of Modrinth as we know it from December 2020 to December 2022.",
"thumbnail": "https://modrinth.com/news/default.webp",
"date": "2023-01-07T00:00:00.000Z",
"link": "https://modrinth.com/news/article/two-years-of-modrinth-history"
},
{
"title": "Modrinth's Anniversary Update",
"summary": "Marking two years of Modrinth and discussing our New Year's Resolutions for 2023.",
@@ -112,6 +105,13 @@
"date": "2023-01-07T00:00:00.000Z",
"link": "https://modrinth.com/news/article/two-years-of-modrinth"
},
{
"title": "Two years of Modrinth: a retrospective",
"summary": "The history of Modrinth as we know it from December 2020 to December 2022.",
"thumbnail": "https://modrinth.com/news/default.webp",
"date": "2023-01-07T00:00:00.000Z",
"link": "https://modrinth.com/news/article/two-years-of-modrinth-history"
},
{
"title": "Creators can now make money on Modrinth!",
"summary": "Introducing the Creator Monetization Program allowing creators to earn revenue from their projects.",
+15 -15
View File
@@ -4,7 +4,7 @@
<description><![CDATA[Keep up-to-date on the latest news from Modrinth.]]></description>
<link>https://modrinth.com/news/</link>
<generator>@modrinth/blog</generator>
<lastBuildDate>Sat, 05 Jul 2025 21:04:25 GMT</lastBuildDate>
<lastBuildDate>Tue, 15 Jul 2025 12:02:34 GMT</lastBuildDate>
<atom:link href="https://modrinth.com/news/feed/rss.xml" rel="self" type="application/rss+xml"/>
<language><![CDATA[en]]></language>
<item>
@@ -12,7 +12,7 @@
<description><![CDATA[Customize your look, save your favorite skins, and swap them out in a flash, all within Modrinth App.]]></description>
<link>https://modrinth.com/news/article/skins-now-in-modrinth-app/</link>
<guid isPermaLink="false">https://modrinth.com/news/article/skins-now-in-modrinth-app/</guid>
<pubDate>Sat, 05 Jul 2025 19:19:00 GMT</pubDate>
<pubDate>Sun, 06 Jul 2025 23:45:00 GMT</pubDate>
<content:encoded>&lt;![CDATA[&lt;p&gt;We&apos;re thrilled to roll out Modrinth App &lt;strong&gt;v0.10&lt;/strong&gt; with a beta release of one of our most highly requested features, the &lt;strong&gt;Skins page&lt;/strong&gt;. The Skins page allows you to manage all of your Minecraft skins directly within Modrinth App. You can see all your saved custom skins and the default Minecraft skins in one convenient place.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./skins-page.webp&quot; alt=&quot;The new skins page, featuring a cute animated player model, your custom skins &amp;amp; default skins.&quot;&gt;&lt;/p&gt;&lt;p&gt;Adding a new skin is simple, even Herobrine could do it! When you add or edit a skin, you can &lt;strong&gt;upload&lt;/strong&gt; your custom texture file directly from your computer, &lt;strong&gt;choose&lt;/strong&gt; between the wide or slim arm style to match your preferred character model, and even &lt;strong&gt;assign&lt;/strong&gt; a specific cape to that look for the perfect finishing touch.&lt;/p&gt;&lt;p&gt;The interface makes it easy to preview your changes in real-time with the animated player model, so you can see exactly how your skin will look in-game before saving it.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./edit-skin.webp&quot; alt=&quot;The edit skin modal that shows when you go to add or edit a skin.&quot;&gt;&lt;/p&gt;&lt;h2&gt;Fixes and More!&lt;/h2&gt;&lt;p&gt;Alongside this major new feature, &lt;strong&gt;v0.10&lt;/strong&gt; includes a host of improvements and bug fixes to make your experience smoother. We&apos;ve updated the news feed to use our new system, fixed issues with project descriptions, and tidied up how data is handled. For a full breakdown of all the changes, you can &lt;a href=&quot;https://modrinth.com/news/changelog?filter=app&quot;&gt;check out the complete changelog here.&lt;/a&gt;&lt;/p&gt;&lt;p&gt;As the skins feature is in &lt;em&gt;beta&lt;/em&gt;, we&apos;re eager to hear your feedback! &lt;strong&gt;Jump in, give it a try&lt;/strong&gt;, and let us know what you think. You can share your thoughts on our &lt;a href=&quot;https://discord.modrinth.com/&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Discord server&lt;/a&gt; or &lt;a href=&quot;https://support.modrinth.com&quot; rel=&quot;noopener nofollow ugc&quot;&gt;start a support chat&lt;/a&gt; if you&apos;re running into issues.&lt;/p&gt;&lt;p&gt;Thank you! We can&apos;t wait to see your skins in action. Happy customizing!&lt;/p&gt;]]&gt;</content:encoded>
</item>
<item>
@@ -25,7 +25,7 @@
</item>
<item>
<title><![CDATA[A Pride Month Success: Over $8,400 Raised for The Trevor Project!]]></title>
<description><![CDATA[A reflection on our Pride Month fundraiser campaign, which raised thousands for LGBTQ+ youth.]]></description>
<description><![CDATA[Reflecting on our Pride Month fundraiser campaign for LGBTQ+ youth.]]></description>
<link>https://modrinth.com/news/article/pride-campaign-2025/</link>
<guid isPermaLink="false">https://modrinth.com/news/article/pride-campaign-2025/</guid>
<pubDate>Tue, 01 Jul 2025 18:00:00 GMT</pubDate>
@@ -119,14 +119,6 @@
<pubDate>Wed, 01 Feb 2023 20:00:00 GMT</pubDate>
<content:encoded>&lt;![CDATA[&lt;p&gt;&lt;strong&gt;Update: On &lt;a href=&quot;/news/article/capital-return&quot; rel=&quot;noopener nofollow ugc&quot;&gt;April 4, 2024&lt;/a&gt; we announced that we had returned the remaining $800k in investor capital back to our investors to take a different path. &lt;a href=&quot;/news/article/capital-return&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Read that announcement here&lt;/a&gt;. This article remains here for archival purposes.&lt;/strong&gt;&lt;/p&gt;&lt;hr&gt;&lt;p&gt;There are over 3 billion gamers worldwide, but only a small fraction ever go further and mod the games they play. Modrinth is here to bring modding to every player on the planet—all the while allowing mod creators to make a living off of it.&lt;/p&gt;&lt;p&gt;Since our founding in 2020 and up until a few months ago, Modrinth has been a purely volunteer project. In the past couple months, the Modrinth team has been more productive than ever. We&apos;ve released the &lt;a href=&quot;../two-years-of-modrinth&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Anniversary Update&lt;/a&gt;, we&apos;re actively working on the launcher once more, and we&apos;re laying out plans for how to multiply Modrinth creator payouts.&lt;/p&gt;&lt;p&gt;The vision we have for the future of Modrinth is great, and right alongside that is the need for an amazing team to build out this vision. That&apos;s why we &lt;a href=&quot;https://x.com/modrinth/status/1615416957905342472&quot; rel=&quot;noopener nofollow ugc&quot;&gt;recently announced&lt;/a&gt; that &lt;a href=&quot;https://careers.modrinth.com&quot; rel=&quot;noopener nofollow ugc&quot;&gt;we&apos;re hiring&lt;/a&gt;—we&apos;ve already come so far on just volunteer work, but for Modrinth to be sustainable and for its growth to be sustainable, we need to pick up the pace.&lt;/p&gt;&lt;p&gt;That&apos;s why we&apos;re excited to announce that we&apos;ve raised a pre-seed round of funding led by &lt;a href=&quot;https://www.makersfund.com/&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Makers Fund&lt;/a&gt;, with investors including &lt;a href=&quot;https://x.com/ryanmjohnson&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Ryan Johnson&lt;/a&gt;, &lt;a href=&quot;https://x.com/sthenc&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Stephen Cole&lt;/a&gt;, &lt;a href=&quot;https://x.com/PimDeWitte&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Pim de Witte&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/leechris1/&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Chris Lee&lt;/a&gt;, and &lt;a href=&quot;https://x.com/andreas&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Andreas Thorstensson&lt;/a&gt; to accelerate development and expand to new horizons for Modrinth.&lt;/p&gt;&lt;h2&gt;What&apos;s next?&lt;/h2&gt;&lt;p&gt;We&apos;re thrilled to keep on building and iterating on Modrinth over the next few years. Here&apos;s a look into what we have in store over the next few months for Modrinth:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;A feature-packed launcher&lt;/li&gt;&lt;li&gt;Creator organizations (like GitHub), wikis, graphs (with playtime, views, downloads, etc)&lt;/li&gt;&lt;li&gt;More creator payouts, through the growth of Adrinth&lt;/li&gt;&lt;li&gt;Discovery/recommendation of mods (especially up-and-coming content)&lt;/li&gt;&lt;li&gt;Comments (with built-in moderation and spam protection)&lt;/li&gt;&lt;li&gt;[Redacted]&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Support for new games!&lt;/p&gt;&lt;p&gt;We are excited that we are able to build a product that will manage to grow us to sustainability and create the best modding experience for creators and users. Being able to pay ourselves and bring on new people is a big step in making that happen. There is still a lot to do, so let&apos;s get to it!&lt;/p&gt;&lt;h2&gt;Q&amp;amp;A:&lt;/h2&gt;&lt;p&gt;We know there might be some concerns so we included a short Q&amp;amp;A section below for some common ones. Feel free to ask in our &lt;a href=&quot;https://discord.modrinth.com&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Discord&lt;/a&gt; if you have any more questions!&lt;/p&gt;&lt;h3&gt;Why does Modrinth need funding?&lt;/h3&gt;&lt;p&gt;Our main expense is and will continue to be salaries. The labor cost has always been the main bottleneck for Modrinth. Having paid employees will allow us to develop Modrinth faster, bringing Modrinth to a point of sustainability and growing the platform. For example, we&apos;re planning to release our launcher this year, and eventually we&apos;re hoping to expand into more games. Those won&apos;t be possible without having paid employees.&lt;/p&gt;&lt;h3&gt;Is Modrinth still community-first?&lt;/h3&gt;&lt;p&gt;We started and always will have the goal of creating a community-oriented, open-source modding platform. Simply put, there isn&apos;t any reason for us not to be. It&apos;s clear that the previous impersonal, corporate approaches to video game modding have not worked, andLine truncated
</item>
<item>
<title><![CDATA[Two years of Modrinth: a retrospective]]></title>
<description><![CDATA[The history of Modrinth as we know it from December 2020 to December 2022.]]></description>
<link>https://modrinth.com/news/article/two-years-of-modrinth-history/</link>
<guid isPermaLink="false">https://modrinth.com/news/article/two-years-of-modrinth-history/</guid>
<pubDate>Sat, 07 Jan 2023 00:00:00 GMT</pubDate>
<content:encoded>&lt;![CDATA[&lt;p&gt;Let&apos;s rewind a bit and take a look at the past two years of Modrinth&apos;s history. We&apos;ve come so far from our pre-beta HexFabric days to today. A good portion of our pre-beta history can be found in the &lt;a href=&quot;../what-is-modrinth&quot; rel=&quot;noopener nofollow ugc&quot;&gt;What is Modrinth&lt;/a&gt; blog post, but Modrinth obviously is not the same platform it was two years ago.&lt;/p&gt;&lt;h2&gt;December 2020: Modrinth Beta begins&lt;/h2&gt;&lt;p&gt;&lt;img src=&quot;../modrinth-beta/new-design.jpg&quot; alt=&quot;Modrinth&apos;s brand new design, rolling out with the launch of Beta&quot;&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Modrinth&apos;s brand new design, rolling out with the launch of Beta&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;December was the release of the initial &lt;a href=&quot;../modrinth-beta&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Modrinth Beta&lt;/a&gt;, bringing a completely different interface and the ability for mods to be created for the first time. This interface has since been completely discarded, but this is what Modrinth looked like for well over a year. It&apos;s hard to believe!&lt;/p&gt;&lt;p&gt;December also brought the introduction of the &lt;a href=&quot;https://github.com/modrinth/minotaur&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Minotaur&lt;/a&gt; Gradle plugin for the first time for upload automation. Minotaur today also looks nothing like it did when it was introduced, but it still accomplishes the same exact thing.&lt;/p&gt;&lt;h2&gt;January 2021: Improvements to mod uploading&lt;/h2&gt;&lt;p&gt;An announcement in mid-January brought several essential additions and improvements to Modrinth which we consider commonplace today. Among these were:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;A separate version creation page&lt;/li&gt;&lt;li&gt;The ability to edit and delete existing versions&lt;/li&gt;&lt;li&gt;The ability to delete existing mods and users&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;January also brought the introduction of Google AdSense onto Modrinth. The eventual results, including our switch after to EthicalAds, solidified Modrinth&apos;s stance that ads should be unobtrusive and generally friendly to users.&lt;/p&gt;&lt;h2&gt;February-March 2021: Follows, reports, notifications, oh my!&lt;/h2&gt;&lt;p&gt;March brought the first introduction of the abilities to follow and report projects, as well as the automatic featuring of some versions depending on loader and Minecraft version. These systems have largely remained unchanged since their introduction, though the notification system will likely be getting a refresh come 2023.&lt;/p&gt;&lt;h2&gt;April-December 2021: Season of silence&lt;/h2&gt;&lt;p&gt;After follows, reports, and all that jazz, Modrinth largely went silent for a good while. This time period had some of the largest growth Modrinth had ever seen, and yet it seemed Modrinth&apos;s development had ground to a halt. Modrinth Team members were dropping like flies until there was a point where there was a single person on the team. What happened?&lt;/p&gt;&lt;p&gt;For various reasons, whether it be lack of free time or a lack of interest in Minecraft in general, people ended up leaving to pursue other things. It&apos;s not quite as apocalyptic or barren as these descriptions make it seem, but it&apos;s more fun to describe it like this.&lt;/p&gt;&lt;p&gt;Picking up the remnants from what others had left behind, one man was destined to continue developing for Modrinth. The one who began the whole operation in the first place, Geometrically, stood up and began developing. Thus came the development of project types, gallery images, API v2, and modpacks.&lt;/p&gt;&lt;h2&gt;January 2022: API v2 introduction&lt;/h2&gt;&lt;p&gt;Right around the corner came 2022. Perchance this would be the time for the silence to be broken? Indeed, the world would be able to hear about all that was brewing over the past few months.&lt;/p&gt;&lt;p&gt;Of course, this wasn&apos;t all introduced at once—it was a gradual rollout over several months. First was the introduction of v2 of Modrinth&apos;s API, allowing many breaking changes to occur, including namely the renaming of &lt;em&gt;mods&lt;/em&gt; to &lt;em&gt;projects&lt;/em&gt;. Wait, why was this necessary?&lt;/p&gt;&lt;p&gt;Up until this point, Modrinth only hosted mods. Project types, as we call them, allow projects to be given the designation of something other than &lt;em&gt;mod&lt;/em&gt;; for example, &lt;em&gt;modpack&lt;/em&gt; or &lt;em&gt;resourcepack&lt;/em&gt;, like we have today. This simple field, alongside all of the infrastructure which was needed to support it, was the first step to allow modpacks on Modrinth.&lt;/p&gt;&lt;h2&gt;February 2022: Redesign&lt;/h2&gt;&lt;p&gt;Remember the interface introduced in December 2020? Let&apos;s scrap it! Actually, it wasn&apos;t entirely scrapped, but it got a treatment similar to the &lt;a href=&quotLine truncated
</item>
<item>
<title><![CDATA[Modrinth's Anniversary Update]]></title>
<description><![CDATA[Marking two years of Modrinth and discussing our New Year's Resolutions for 2023.]]></description>
@@ -135,9 +127,17 @@
<pubDate>Sat, 07 Jan 2023 00:00:00 GMT</pubDate>
<content:encoded>&lt;![CDATA[&lt;p&gt;Modrinth initially &lt;a href=&quot;../modrinth-beta&quot; rel=&quot;noopener nofollow ugc&quot;&gt;went into beta&lt;/a&gt; on November 30th, 2020. Just over a month ago was November 30th, 2022, marking &lt;strong&gt;two years&lt;/strong&gt; since Modrinth was generally available as a platform for everyone to use. Today, we&apos;re proud to announce the Anniversary Update, celebrating both two years of Modrinth as well as the coming of the new year, and we&apos;ll be discussing our New Year&apos;s Resolutions for 2023.&lt;/p&gt;&lt;p&gt;Before you read this post, though, we recommend taking a look at &lt;a href=&quot;../two-years-of-modrinth-history&quot; rel=&quot;noopener nofollow ugc&quot;&gt;our retrospective on Modrinth&apos;s history through 2020—2022&lt;/a&gt;. It just wouldn&apos;t be right to take a look at the present and the future without also taking a look at our past, seeing how far we&apos;ve come from our humble beginnings.&lt;/p&gt;&lt;p&gt;With that out of the way, this post primarily serves to announce a few of the smaller features we&apos;ve been working on after the release of creator monetization. We&apos;ve bundled these all together as the &lt;strong&gt;Anniversary Update&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Looking just at what&apos;s already done is boring, though, so we&apos;ll also be looking at what&apos;s yet to come. Modrinth&apos;s future is even brighter than any of us can imagine, so we&apos;ll be focusing on what we&apos;re gonna do in order to get to that bright future. If you&apos;ve ever made &lt;strong&gt;New Year&apos;s Resolutions&lt;/strong&gt;, we&apos;re going to briefly discuss our resolutions for 2023.&lt;/p&gt;&lt;p&gt;Without further adieu, let&apos;s get right into what&apos;s new with this new year!&lt;/p&gt;&lt;h2&gt;Shader packs and data packs&lt;/h2&gt;&lt;p&gt;The long-awaited arrival of shader packs and data packs is now here on Modrinth!&lt;/p&gt;&lt;p&gt;Shader packs can be viewed in the &lt;a href=&quot;/shaders&quot; rel=&quot;noopener nofollow ugc&quot;&gt;shaders tab&lt;/a&gt;. This includes shaders that support &lt;a href=&quot;/mod/iris&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Iris&lt;/a&gt;, &lt;a href=&quot;/mod/canvas&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Canvas&lt;/a&gt;, and OptiFine, as well as vanilla core shaders. (Even though they&apos;re installed via the resource pack system, we have decided to put Canvas and core shaders in shader packs since most users will not search in resource packs for shader packs, even if that&apos;s how they&apos;re installed.)&lt;/p&gt;&lt;p&gt;Data packs can be found in the &lt;a href=&quot;/datapacks&quot; rel=&quot;noopener nofollow ugc&quot;&gt;data packs tab&lt;/a&gt;. These are implemented similarly to plugins, in that projects with a mod version can also upload a data pack version (and vice versa). Additionally, data pack authors can choose to have their data packs packaged as a mod using the handy-dandy button on the site.&lt;/p&gt;&lt;p&gt;Data packs can optionally upload a corresponding resource pack as a separate file. We discourage bundling data files and asset files in the same zip file.&lt;/p&gt;&lt;h2&gt;New landing page&lt;/h2&gt;&lt;p&gt;The &lt;a href=&quot;/&quot; rel=&quot;noopener nofollow ugc&quot;&gt;homepage&lt;/a&gt; has been completely remade, featuring a scrolling list of random projects from Modrinth. Feel free to use this to discover new projects—just make sure you refresh occasionally, because they loop after a little while until you refresh!&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./landing-page.jpg&quot; alt=&quot;A screenshot of the new homepage, with a maze background and projects scrolling across the bottom. Bold across the front is &amp;quot;The place for Minecraft mods&amp;quot;.&quot;&gt;&lt;/p&gt;&lt;h2&gt;Project overhaul for creators&lt;/h2&gt;&lt;p&gt;We&apos;re continuing to bring expansions to the creator dashboard introduced with monetization. The new &lt;strong&gt;Projects&lt;/strong&gt; tab allows you to view all of your projects in a table and quickly access their information and settings.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;/dashboard/projects&quot; rel=&quot;noopener nofollow ugc&quot;&gt;&lt;img src=&quot;./projects-dashboard.jpg&quot; alt=&quot;The new Modrinth project dashboard&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The same page also introduces the ability to bulk-edit the external resource links without having to edit each page individually. For example, if your Discord invite expires, you used to have to edit each of your projects individually to add it back. Now you can just select the projects you want to edit the links for and edit them all at the same time!&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./bulk-edit.jpg&quot; alt=&quot;A modal with several input fields for external resource links, listing multiple projects the input changes will be applied to.&quot;&gt;&lt;/p&gt;&lt;p&gt;Even better Line truncated
</item>
<item>
<title><![CDATA[Two years of Modrinth: a retrospective]]></title>
<description><![CDATA[The history of Modrinth as we know it from December 2020 to December 2022.]]></description>
<link>https://modrinth.com/news/article/two-years-of-modrinth-history/</link>
<guid isPermaLink="false">https://modrinth.com/news/article/two-years-of-modrinth-history/</guid>
<pubDate>Sat, 07 Jan 2023 00:00:00 GMT</pubDate>
<content:encoded>&lt;![CDATA[&lt;p&gt;Let&apos;s rewind a bit and take a look at the past two years of Modrinth&apos;s history. We&apos;ve come so far from our pre-beta HexFabric days to today. A good portion of our pre-beta history can be found in the &lt;a href=&quot;../what-is-modrinth&quot; rel=&quot;noopener nofollow ugc&quot;&gt;What is Modrinth&lt;/a&gt; blog post, but Modrinth obviously is not the same platform it was two years ago.&lt;/p&gt;&lt;h2&gt;December 2020: Modrinth Beta begins&lt;/h2&gt;&lt;p&gt;&lt;img src=&quot;../modrinth-beta/new-design.jpg&quot; alt=&quot;Modrinth&apos;s brand new design, rolling out with the launch of Beta&quot;&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Modrinth&apos;s brand new design, rolling out with the launch of Beta&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;December was the release of the initial &lt;a href=&quot;../modrinth-beta&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Modrinth Beta&lt;/a&gt;, bringing a completely different interface and the ability for mods to be created for the first time. This interface has since been completely discarded, but this is what Modrinth looked like for well over a year. It&apos;s hard to believe!&lt;/p&gt;&lt;p&gt;December also brought the introduction of the &lt;a href=&quot;https://github.com/modrinth/minotaur&quot; rel=&quot;noopener nofollow ugc&quot;&gt;Minotaur&lt;/a&gt; Gradle plugin for the first time for upload automation. Minotaur today also looks nothing like it did when it was introduced, but it still accomplishes the same exact thing.&lt;/p&gt;&lt;h2&gt;January 2021: Improvements to mod uploading&lt;/h2&gt;&lt;p&gt;An announcement in mid-January brought several essential additions and improvements to Modrinth which we consider commonplace today. Among these were:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;A separate version creation page&lt;/li&gt;&lt;li&gt;The ability to edit and delete existing versions&lt;/li&gt;&lt;li&gt;The ability to delete existing mods and users&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;January also brought the introduction of Google AdSense onto Modrinth. The eventual results, including our switch after to EthicalAds, solidified Modrinth&apos;s stance that ads should be unobtrusive and generally friendly to users.&lt;/p&gt;&lt;h2&gt;February-March 2021: Follows, reports, notifications, oh my!&lt;/h2&gt;&lt;p&gt;March brought the first introduction of the abilities to follow and report projects, as well as the automatic featuring of some versions depending on loader and Minecraft version. These systems have largely remained unchanged since their introduction, though the notification system will likely be getting a refresh come 2023.&lt;/p&gt;&lt;h2&gt;April-December 2021: Season of silence&lt;/h2&gt;&lt;p&gt;After follows, reports, and all that jazz, Modrinth largely went silent for a good while. This time period had some of the largest growth Modrinth had ever seen, and yet it seemed Modrinth&apos;s development had ground to a halt. Modrinth Team members were dropping like flies until there was a point where there was a single person on the team. What happened?&lt;/p&gt;&lt;p&gt;For various reasons, whether it be lack of free time or a lack of interest in Minecraft in general, people ended up leaving to pursue other things. It&apos;s not quite as apocalyptic or barren as these descriptions make it seem, but it&apos;s more fun to describe it like this.&lt;/p&gt;&lt;p&gt;Picking up the remnants from what others had left behind, one man was destined to continue developing for Modrinth. The one who began the whole operation in the first place, Geometrically, stood up and began developing. Thus came the development of project types, gallery images, API v2, and modpacks.&lt;/p&gt;&lt;h2&gt;January 2022: API v2 introduction&lt;/h2&gt;&lt;p&gt;Right around the corner came 2022. Perchance this would be the time for the silence to be broken? Indeed, the world would be able to hear about all that was brewing over the past few months.&lt;/p&gt;&lt;p&gt;Of course, this wasn&apos;t all introduced at once—it was a gradual rollout over several months. First was the introduction of v2 of Modrinth&apos;s API, allowing many breaking changes to occur, including namely the renaming of &lt;em&gt;mods&lt;/em&gt; to &lt;em&gt;projects&lt;/em&gt;. Wait, why was this necessary?&lt;/p&gt;&lt;p&gt;Up until this point, Modrinth only hosted mods. Project types, as we call them, allow projects to be given the designation of something other than &lt;em&gt;mod&lt;/em&gt;; for example, &lt;em&gt;modpack&lt;/em&gt; or &lt;em&gt;resourcepack&lt;/em&gt;, like we have today. This simple field, alongside all of the infrastructure which was needed to support it, was the first step to allow modpacks on Modrinth.&lt;/p&gt;&lt;h2&gt;February 2022: Redesign&lt;/h2&gt;&lt;p&gt;Remember the interface introduced in December 2020? Let&apos;s scrap it! Actually, it wasn&apos;t entirely scrapped, but it got a treatment similar to the &lt;a href=&quotLine truncated
</item>
<item>
<title><![CDATA[Creators can now make money on Modrinth!]]></title>
<description><![CDATA[Yes, you read the title correctly: Modrinth's creator monetization program, also known as payouts, is now in an open beta phase. Read on for more information!]]></description>
<description><![CDATA[Introducing the Creator Monetization Program allowing creators to earn revenue from their projects.]]></description>
<link>https://modrinth.com/news/article/creator-monetization/</link>
<guid isPermaLink="false">https://modrinth.com/news/article/creator-monetization/</guid>
<pubDate>Sat, 12 Nov 2022 00:00:00 GMT</pubDate>
@@ -145,7 +145,7 @@
</item>
<item>
<title><![CDATA[Modrinth's Carbon Ads experiment]]></title>
<description><![CDATA[As a step towards implementing author payouts, we're experimenting with a couple different ad providers to see which one works the best for us.]]></description>
<description><![CDATA[Experimenting with a different ad providers to find one which one works for us.]]></description>
<link>https://modrinth.com/news/article/carbon-ads/</link>
<guid isPermaLink="false">https://modrinth.com/news/article/carbon-ads/</guid>
<pubDate>Thu, 08 Sep 2022 00:00:00 GMT</pubDate>
@@ -177,7 +177,7 @@
</item>
<item>
<title><![CDATA[This week in Modrinth development: Filters and Fixes]]></title>
<description><![CDATA[After a great first week since Modrinth launched out of beta, we have continued to improve the user interface based on feedback.]]></description>
<description><![CDATA[Continuing to improve the user interface after a great first week since Modrinth launched out of beta.]]></description>
<link>https://modrinth.com/news/article/knossos-v2.1.0/</link>
<guid isPermaLink="false">https://modrinth.com/news/article/knossos-v2.1.0/</guid>
<pubDate>Wed, 09 Mar 2022 00:00:00 GMT</pubDate>
@@ -185,7 +185,7 @@
</item>
<item>
<title><![CDATA[Now showing on Modrinth: A new look!]]></title>
<description><![CDATA[After months of relatively quiet development, Modrinth has released many new features and improvements, including a redesign. Read on to learn more!]]></description>
<description><![CDATA[Releasing many new features and improvements, including a redesign!]]></description>
<link>https://modrinth.com/news/article/redesign/</link>
<guid isPermaLink="false">https://modrinth.com/news/article/redesign/</guid>
<pubDate>Sun, 27 Feb 2022 00:00:00 GMT</pubDate>
+1
View File
@@ -13,6 +13,7 @@
"app:build": "turbo run build --filter=@modrinth/app",
"app:fix": "turbo run fix --filter=@modrinth/app",
"app:intl:extract": "pnpm run --filter=@modrinth/app-frontend intl:extract",
"blog:fix": "turbo run fix --filter=@modrinth/blog",
"pages:build": "NITRO_PRESET=cloudflare-pages pnpm --filter frontend run build",
"build": "turbo run build --continue",
"lint": "turbo run lint --continue",
+8 -8
View File
@@ -1,16 +1,16 @@
import { promises as fs } from 'fs'
import * as path from 'path'
import fastGlob from 'fast-glob'
import { repoPath, toVarName } from './utils'
import { glob } from 'glob'
import { PUBLIC_SRC, PUBLIC_LOCATIONS, ARTICLES_GLOB, COMPILED_DIR } from './blog.config'
async function checkPublicAssets() {
const srcFiles = await fastGlob(['**/*'], { cwd: PUBLIC_SRC, dot: true })
const srcFiles = await glob('**/*', { cwd: PUBLIC_SRC, dot: true })
let allOk = true
for (const target of PUBLIC_LOCATIONS) {
for (const relativeFile of srcFiles) {
const shouldExist = path.join(target, relativeFile)
const shouldExist = path.posix.join(target, relativeFile)
try {
await fs.access(shouldExist)
} catch {
@@ -26,15 +26,15 @@ async function checkPublicAssets() {
}
async function checkCompiledArticles() {
const mdFiles = await fastGlob([ARTICLES_GLOB])
const compiledFiles = await fastGlob([`${COMPILED_DIR}/*.ts`])
const mdFiles = await glob(ARTICLES_GLOB)
const compiledFiles = await glob(`${COMPILED_DIR}/*.ts`)
const compiledVarNames = compiledFiles.map((f) => path.basename(f, '.ts'))
// Check all .md have compiled .ts and .content.ts and the proper public thumbnail
for (const file of mdFiles) {
const varName = toVarName(path.basename(file, '.md'))
const compiledPath = path.join(COMPILED_DIR, varName + '.ts')
const contentPath = path.join(COMPILED_DIR, varName + '.content.ts')
const compiledPath = path.posix.join(COMPILED_DIR, varName + '.ts')
const contentPath = path.posix.join(COMPILED_DIR, varName + '.content.ts')
if (!compiledVarNames.includes(varName)) {
console.error(`⚠️ Missing compiled article for: ${file} (should be: ${compiledPath})`)
process.exit(1)
@@ -59,7 +59,7 @@ async function checkCompiledArticles() {
if (varName === 'index' || varName.endsWith('.content')) continue
const mdPathGlob = repoPath(`packages/blog/articles/**/${varName.replace(/_/g, '*')}.md`)
const found = await fastGlob([mdPathGlob])
const found = await glob(mdPathGlob)
if (!found.length) {
console.error(`❌ Compiled article ${compiled} has no matching markdown source!`)
process.exit(1)
+6 -6
View File
@@ -1,12 +1,12 @@
import { promises as fs } from 'fs'
import * as path from 'path'
import fg from 'fast-glob'
import matter from 'gray-matter'
import { md } from '@modrinth/utils'
import { minify } from 'html-minifier-terser'
import { copyDir, toVarName } from './utils'
import RSS from 'rss'
import { parseStringPromise } from 'xml2js'
import { glob } from 'glob'
import {
ARTICLES_GLOB,
@@ -24,7 +24,7 @@ async function ensureCompiledDir() {
}
async function hasThumbnail(slug: string): Promise<boolean> {
const thumbnailPath = path.join(PUBLIC_SRC, slug, 'thumbnail.webp')
const thumbnailPath = path.posix.join(PUBLIC_SRC, slug, 'thumbnail.webp')
try {
await fs.access(thumbnailPath)
return true
@@ -48,7 +48,7 @@ function getThumbnailUrl(slug: string, hasThumb: boolean): string {
async function compileArticles() {
await ensureCompiledDir()
const files = await fg([ARTICLES_GLOB])
const files = await glob(ARTICLES_GLOB)
console.log(`🔎 Found ${files.length} markdown articles!`)
const articleExports: string[] = []
const articlesArray: string[] = []
@@ -75,8 +75,8 @@ async function compileArticles() {
const slug = frontSlug || path.basename(file, '.md')
const varName = toVarName(slug)
const exportFile = path.join(COMPILED_DIR, `${varName}.ts`)
const contentFile = path.join(COMPILED_DIR, `${varName}.content.ts`)
const exportFile = path.posix.join(COMPILED_DIR, `${varName}.ts`)
const contentFile = path.posix.join(COMPILED_DIR, `${varName}.content.ts`)
const thumbnailPresent = await hasThumbnail(slug)
const contentTs = `
@@ -221,7 +221,7 @@ async function deleteDirContents(dir: string) {
const entries = await fs.readdir(dir, { withFileTypes: true })
await Promise.all(
entries.map(async (entry) => {
const fullPath = path.join(dir, entry.name)
const fullPath = path.posix.join(dir, entry.name)
if (entry.isDirectory()) {
await fs.rm(fullPath, { recursive: true, force: true })
} else {
+50 -50
View File
@@ -1,56 +1,56 @@
// AUTO-GENERATED FILE - DO NOT EDIT
import { article as a_new_chapter_for_modrinth_servers } from './a_new_chapter_for_modrinth_servers'
import { article as accelerating_development } from './accelerating_development'
import { article as becoming_sustainable } from './becoming_sustainable'
import { article as capital_return } from './capital_return'
import { article as carbon_ads } from './carbon_ads'
import { article as creator_monetization } from './creator_monetization'
import { article as creator_update } from './creator_update'
import { article as creator_updates_july_2025 } from './creator_updates_july_2025'
import { article as design_refresh } from './design_refresh'
import { article as download_adjustment } from './download_adjustment'
import { article as knossos_v2_1_0 } from './knossos_v2_1_0'
import { article as licensing_guide } from './licensing_guide'
import { article as modpack_changes } from './modpack_changes'
import { article as modpacks_alpha } from './modpacks_alpha'
import { article as modrinth_app_beta } from './modrinth_app_beta'
import { article as modrinth_beta } from './modrinth_beta'
import { article as modrinth_servers_beta } from './modrinth_servers_beta'
import { article as new_site_beta } from './new_site_beta'
import { article as plugins_resource_packs } from './plugins_resource_packs'
import { article as pride_campaign_2025 } from './pride_campaign_2025'
import { article as redesign } from './redesign'
import { article as skins_now_in_modrinth_app } from './skins_now_in_modrinth_app'
import { article as two_years_of_modrinth_history } from './two_years_of_modrinth_history'
import { article as two_years_of_modrinth } from './two_years_of_modrinth'
import { article as whats_modrinth } from './whats_modrinth'
import { article as windows_borderless_malware_disclosure } from './windows_borderless_malware_disclosure'
import { article as whats_modrinth } from './whats_modrinth'
import { article as two_years_of_modrinth } from './two_years_of_modrinth'
import { article as two_years_of_modrinth_history } from './two_years_of_modrinth_history'
import { article as skins_now_in_modrinth_app } from './skins_now_in_modrinth_app'
import { article as redesign } from './redesign'
import { article as pride_campaign_2025 } from './pride_campaign_2025'
import { article as plugins_resource_packs } from './plugins_resource_packs'
import { article as new_site_beta } from './new_site_beta'
import { article as modrinth_servers_beta } from './modrinth_servers_beta'
import { article as modrinth_beta } from './modrinth_beta'
import { article as modrinth_app_beta } from './modrinth_app_beta'
import { article as modpacks_alpha } from './modpacks_alpha'
import { article as modpack_changes } from './modpack_changes'
import { article as licensing_guide } from './licensing_guide'
import { article as knossos_v2_1_0 } from './knossos_v2_1_0'
import { article as download_adjustment } from './download_adjustment'
import { article as design_refresh } from './design_refresh'
import { article as creator_updates_july_2025 } from './creator_updates_july_2025'
import { article as creator_update } from './creator_update'
import { article as creator_monetization } from './creator_monetization'
import { article as carbon_ads } from './carbon_ads'
import { article as capital_return } from './capital_return'
import { article as becoming_sustainable } from './becoming_sustainable'
import { article as accelerating_development } from './accelerating_development'
import { article as a_new_chapter_for_modrinth_servers } from './a_new_chapter_for_modrinth_servers'
export const articles = [
a_new_chapter_for_modrinth_servers,
accelerating_development,
becoming_sustainable,
capital_return,
carbon_ads,
creator_monetization,
creator_update,
creator_updates_july_2025,
design_refresh,
download_adjustment,
knossos_v2_1_0,
licensing_guide,
modpack_changes,
modpacks_alpha,
modrinth_app_beta,
modrinth_beta,
modrinth_servers_beta,
new_site_beta,
plugins_resource_packs,
pride_campaign_2025,
redesign,
skins_now_in_modrinth_app,
two_years_of_modrinth_history,
two_years_of_modrinth,
whats_modrinth,
windows_borderless_malware_disclosure,
whats_modrinth,
two_years_of_modrinth,
two_years_of_modrinth_history,
skins_now_in_modrinth_app,
redesign,
pride_campaign_2025,
plugins_resource_packs,
new_site_beta,
modrinth_servers_beta,
modrinth_beta,
modrinth_app_beta,
modpacks_alpha,
modpack_changes,
licensing_guide,
knossos_v2_1_0,
download_adjustment,
design_refresh,
creator_updates_july_2025,
creator_update,
creator_monetization,
carbon_ads,
capital_return,
becoming_sustainable,
accelerating_development,
a_new_chapter_for_modrinth_servers,
]
+2 -1
View File
@@ -9,6 +9,7 @@
"fix": "jiti ./compile.ts && eslint . --fix && prettier --write ."
},
"devDependencies": {
"@types/glob": "^9.0.0",
"@types/html-minifier-terser": "^7.0.2",
"@types/rss": "^0.0.32",
"@types/xml2js": "^0.4.14",
@@ -19,7 +20,7 @@
},
"dependencies": {
"@modrinth/utils": "workspace:*",
"fast-glob": "^3.3.3",
"glob": "^10.2.7",
"gray-matter": "^4.0.3",
"html-minifier-terser": "^7.2.0",
"rss": "^1.2.2",
+3 -3
View File
@@ -8,7 +8,7 @@ export function getRepoRoot(): string {
}
export function repoPath(...segments: string[]): string {
return path.join(getRepoRoot(), ...segments)
return path.posix.join(getRepoRoot(), ...segments)
}
export async function copyDir(
@@ -20,8 +20,8 @@ export async function copyDir(
await fs.mkdir(dest, { recursive: true })
const entries = await fs.readdir(src, { withFileTypes: true })
for (const entry of entries) {
const srcPath = path.join(src, entry.name)
const destPath = path.join(dest, entry.name)
const srcPath = path.posix.join(src, entry.name)
const destPath = path.posix.join(dest, entry.name)
if (entry.isDirectory()) {
await copyDir(srcPath, destPath, logFn)
} else if (entry.isFile()) {
+10 -6
View File
@@ -1,28 +1,32 @@
import type { Stage } from '../types/stage'
import modpackPermissionsStage from './modpack-permissions-stage'
import categories from './stages/categories'
import copyright from './stages/copyright'
import reupload from './stages/reupload'
import description from './stages/description'
import gallery from './stages/gallery'
import links from './stages/links'
import ruleFollowing from './stages/rule-following'
import sideTypes from './stages/side-types'
import slug from './stages/slug'
import summary from './stages/summary'
import title from './stages/title'
import titleSlug from './stages/title-slug'
import versions from './stages/versions'
import license from './stages/license'
import undefinedProject from './stages/undefined-project'
import statusAlerts from './stages/status-alerts'
export default [
title,
slug,
titleSlug,
summary,
description,
links,
license,
categories,
sideTypes,
gallery,
versions,
copyright,
reupload,
ruleFollowing,
modpackPermissionsStage,
statusAlerts,
undefinedProject,
] as ReadonlyArray<Stage>
@@ -1,3 +1,3 @@
## Misuse of Tags
Per section 5.1 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous), it is important that the metadata of your projects is accurate. Including that selected tags honestly represent your project.
Per section 5.1 of %RULES%, it is important that the metadata of your projects is accurate. Including that selected tags honestly represent your project.
@@ -0,0 +1 @@
It looks like the Optimization tag is not accurate for this project.
@@ -0,0 +1,5 @@
Currently, your pack has multiple Resolutions selected, in most cases, this will misrepresent your project.
For a brief rundown of how this works:
Vanilla Minecraft textures like blocks and items have a width and height of 16 pixels.
This means that packs with textures the same size as the default are considered 16x.
Some packs make the resolution of textures smaller than the default, such as 8x, and some bigger, such as 32x.
@@ -0,0 +1,2 @@
**Featured Tags:** %PROJECT_CATEGORIES% \
**Additional Tags:** %PROJECT_ADDITIONAL_CATEGORIES%
@@ -0,0 +1 @@
**License id:** %PROJECT_LICENSE_ID% \
@@ -0,0 +1 @@
**License Link:** %PROJECT_LICENSE_URL%
@@ -0,0 +1,4 @@
**Discord:** %PROJECT_DISCORD_URL% \
**Issues:** %PROJECT_ISSUES_URL% \
**Source:** %PROJECT_SOURCE_URL% \
**Wiki:** %PROJECT_WIKI_URL%
@@ -0,0 +1 @@
> **{PLATFORM}:** {URL}
@@ -0,0 +1 @@
<u>**Donation Links:**</u>
@@ -0,0 +1 @@
**Applying for:** `%PROJECT_REQUESTED_STATUS%`
@@ -0,0 +1,2 @@
**Summary:**
`%PROJECT_SUMMARY%`
@@ -0,0 +1,4 @@
**Title:** %PROJECT_TITLE% \
**Slug:** `%PROJECT_SLUG%`
**Title issues?**
@@ -1,7 +1,6 @@
## Insufficient Description
Per section 2.1 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#general-expectations) your project's Description should clearly inform the reader of the content, purpose, and appeal of your project.
Per section 2.1 of %RULES% your project's Description should clearly inform the reader of the content, purpose, and appeal of your project.
Currently, it looks like there are some missing details.
> %EXPLAINER%
%EXPLAINER%
@@ -1,5 +1,5 @@
## No English Description
Per section 2.2 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#accessibility) a project's Summary and Description must be in English, unless meant exclusively for non-English use, such as translations.
Per section 2.2 of %RULES% a project's Summary and Description must be in English, unless meant exclusively for non-English use, such as translations.
You may include your non-English Description if you would like but we ask that you also add an English translation of the Description to your Description page, if you would like to use an online translator to do this, we recommend [DeepL](https://www.deepl.com/translator).
@@ -1,6 +1,6 @@
## Description Accessibility
Per section 2 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#clear-and-honest-function) your description must be plainly readable and accessible.
Per section 2 of %RULES% your description must be plainly readable and accessible.
Using non-standard text characters like Zalgo or "fancy text" in place of text anywhere in your project, including the Description, Summary, or Title can make your project pages inaccessible.
@@ -1,7 +1,4 @@
## Unfinished Description
It looks like your project Description is still a WIP (Work In Progress).
> %REASON%
Please remember to submit only when ready, as it is important your project meets the requirements of Section 2.1 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#general-expectations), if you have any questions on this feel free to reach out!
It looks like your project Description is still a Work In Progress.
Please remember to submit only when ready, as it is important your project meets the requirements of Section 2.1 of %RULES%.
@@ -1,6 +1,6 @@
## Insufficient Gallery Images
We ask that projects like yours show off their content using images in the Gallery, or optionally in the Description, in order to effectively and clearly inform users of its content per section 2.1 of [Modrinth's content rules](https://modrinth.com/legal/rules#general-expectations).
We ask that projects like yours show off their content using images in the Gallery, or optionally in the Description, in order to effectively and clearly inform users of its content per section 2.1 of %RULES%.
Keep in mind that you should:
- Set a featured image that best represents your project.
@@ -1,3 +1,3 @@
## Unrelated Gallery Images
Per section 5.5 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) any images in your project's Gallery must be relevant to the project and also include a Title.
Per section 5.5 of %RULES% any images in your project's Gallery must be relevant to the project and also include a Title.
@@ -0,0 +1 @@
If this is a project-specific License you've written yourself, you must host the full License in a way that makes it publicly available, for instance, in a public source repository on a platform like GitHub.
@@ -0,0 +1,4 @@
## Invalid License Link
It's important that your project's License link is accurate and leads directly to a valid license for this content.
Your current link: `%PROJECT_LICENSE_URL%` does not appear to lead to a valid license for this project, or it is not publicly accessable.
@@ -0,0 +1,5 @@
## No Source Code Provided
Your project's license of `%PROJECT_LICENSE_NAME%`, requires source disclosure.
Consider adding a Source link to your project's repository, or including a Sources file for each version as an Additional File.
Keep in mind this may be a requirement of the source work's licensing, which must be abided per section 4 of %RULES%.
@@ -0,0 +1,4 @@
## No Source Code Provided
Your project's license of `%PROJECT_LICENSE_NAME%`, requires source disclosure.
Consider adding a Source link to your project's repository, or including a Sources file for each version as an Additional File. You may also want to refer to %LICENSING_GUIDE% if you wish to select a different License, remember to make sure your selected License is consistent with the license in your project's files as well.
@@ -1,3 +1,4 @@
## Misuse of External Resources
## Misuse of Links
Per section 5.4 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) all links must lead to correctly labeled publicly available resources that are directly related to your project.
Per section 5.4 of %RULES% all %PROJECT_LINKS_FLINK% must lead to correctly labeled publicly available resources that are directly related to your project.
Currently it looks like your %MISUSED_LINKS% link(s) are misused or incorrectly labeled.
@@ -1,5 +0,0 @@
## Unreachable Links
Per section 5.4 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) all links must lead to correctly labeled publicly available resources that are directly related to your project.
Currently, your %LINK% link is inaccessible!
@@ -1,5 +0,0 @@
## Unreachable Links
Per section 5.4 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) all links must lead to correctly labeled publicly available resources that are directly related to your project.
Currently, your Source link directs to a Page Not Found error, likely because your repository is private, make sure to make your repository public before resubmitting your project!
@@ -0,0 +1 @@
Currently, your Discord link directs to an invalid invite, likely because your invite has expired. Make sure to set your invite link to permanent with unlimited uses before resubmitting your project.
@@ -0,0 +1 @@
Currently, your Source link directs to a Page Not Found error, likely because your repository is private. Make sure to set your repository to public before resubmitting your project.
@@ -0,0 +1,3 @@
## Unreachable Links
Per section 5.4 of %RULES% all %PROJECT_LINKS_FLINK% must lead to correctly labeled publicly available resources that are directly related to your project.
@@ -0,0 +1,4 @@
## Forks and Reuploads
Per section 4 of %RULES%, please provide proof that this project is both license-abiding and significantly divergent from the source work.
Alternatively, please provide proof of your explicit permission from the author of the source work to distribute this content on Modrinth.
@@ -0,0 +1,4 @@
## Insufficient Fork
This project does not appear to significantly diverge from the source work, or does not abide by the license of the source work as required by section 4 of %RULES%.
Please provide proof of your explicit permission to distribute this project from the creator(s) of the source work.
@@ -0,0 +1,5 @@
## Proof of permissions
This project appears to contain content from other creators.
Per section 4 of %RULES%, we ask that you provide proof of your permission to distribute this content, or derivatives of this content in your project on Modrinth.
Either implicit permission abiding by the terms of the content's license(s) or explicit permission from the original creator of the content.
@@ -1,7 +1,5 @@
## Reuploads are forbidden
This project appears to contain content from %ORIGINAL_PROJECT% by %ORIGINAL_AUTHOR%.
Per section 4 of [Modrinth's Content Rules](https://modrinth.com/legal/rules) this is strictly forbidden.
If you believe this is an error, or you can verify you are the creator and rightful owner of this content please let us know. Otherwise, we ask that you **do not resubmit this project**.`,
This project appears to contain content from %ORIGINAL_PROJECT% by %ORIGINAL_AUTHOR%.
Per section 4 of %RULES% this is strictly forbidden.
If you believe this is an error, or you can verify you are the creator and rightful owner of this content please let us know. Otherwise, we ask that you **do not resubmit this project**.
@@ -1,5 +1 @@
# Does not follow content rules
Our moderators have determined that your project does not follow Modrinth's Content Rules, and has been rejected.
%MESSAGE%
@@ -1,6 +1,6 @@
## Environment Information
Per section 5.1 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous), it is important that the metadata of your projects is accurate, including whether the project runs on the client or server side.
Per section 5.1 of %RULES%, it is important that the metadata of your projects is accurate, including whether the project runs on the client or server side.
For a brief rundown of how this works:
@@ -1,6 +1,6 @@
## Incorrect Environment Information
Per section 5.1 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous), it is important that the metadata of your projects is accurate, including whether the project runs on the client or server side.
Per section 5.1 of %RULES%, it is important that the metadata of your projects is accurate, including whether the project runs on the client or server side.
For a brief rundown of how this works:
@@ -1,3 +1,3 @@
## Misuse of Slug
Per section 5.2 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) your project slug (URL) must accurately represent your project.
Per section 5.2 of %RULES% must accurately represent your project.
@@ -0,0 +1,6 @@
---
## Account Issues Indicated
We're sorry to hear you're having trouble accessing your accounts, unfortunately, our moderation team is unable to assist with account-related issues.
Before resubmitting your project, %SUPPORT%.
@@ -0,0 +1,5 @@
---
Unfortunately, our AutoMod cannot read your project's Description or your messages to moderation.
AutoMod will warn both you and our Moderation Staff about potential issues, but if you've already followed the necessary steps these warnings can safely be ignored.
Note that if your project is being rejected by AutoMod this means your project has content that can not be included in your modpack and must be removed before resubmission, including deleting versions of your modpack that include the content.
@@ -0,0 +1,5 @@
---
## Corrections Applied
I've gone ahead and corrected the issues listed above so your project can be Approved.
@@ -0,0 +1,8 @@
---
## Private Use
Under normal circumstances, your project would be rejected due to the issues listed above.
However, since your project is not intended for for public use, these requirements will be waived and your project will be unlisted. This means it will remain accessible through a direct link without appearing in public search results, allowing you to share it privately.
If you're okay with this, or submitted your project to be unlisted already, than no further action is necessary.
If you would like to publish your project publicly, please address all moderation concerns before resubmitting this project.
@@ -1,6 +1,6 @@
## Insufficient Summary
Per section 5.3 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) your Summary can not include any extra formatting such as lists, or links.
Per section 5.3 of %RULES% your Summary can not include any extra formatting such as lists, or links.
Your project summary should provide a brief overview of your project that informs and entices users.
@@ -1,5 +1,5 @@
## Insufficient Summary
Per section 5.3 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) your project summary should provide a brief overview of your project that informs and entices users.
Per section 5.3 of %RULES% your project summary should provide a brief overview of your project that informs and entices users.
This is the first thing most people will see about your mod other than the Logo, so it's important it be accurate, reasonably detailed, and exciting.
@@ -1,5 +1,5 @@
## No English Summary
Per section 2.2 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#accessibility) a project's Summary and Description must be in English, unless meant exclusively for non-English use, such as translations.
Per section 2.2 of %RULES% a project's Summary and Description must be in English, unless meant exclusively for non-English use, such as translations.
You may include your non-English Summary but we ask that you also add an English translation.
@@ -1,6 +1,6 @@
## Insufficient Summary
Per section 5.3 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) your Summary can not be the same as your project's Title.
Per section 5.3 of %RULES% your Summary can not be the same as your project's Title.
Your project summary should provide a brief overview of your project that informs and entices users.
@@ -1,7 +1,6 @@
## Project Title
## Minecraft Project Names
Projects must not use Minecraft's branding or include "Minecraft" as a significant part of the title.
The title of your project may be confusingly similar to the game, and we encourage you to change your title to avoid a potential violation of Minecraft's Usage Guidelines.
Abbreviations like "MC" or elaborate titles that do not make the name Minecraft a significant portion of the name are okay.
Projects must not use Minecraft's branding or include "Minecraft" as a significant part of the title.
Your project's current Name of `%PROJECT_TITLE%` may be confusingly similar to, or imply association with, the game Minecraft. We encourage you to change your project's [Name](%PROJECT_SETTINGS_LINK%) to avoid a potential violation of Minecraft's Usage Guidelines.
Abbreviations like "MC" or elaborate titles that do not make the name Minecraft a significant portion of the name are okay.
When editing your project's Name, remember to update its [URL](%PROJECT_SETTINGS_LINK%) to match.
@@ -0,0 +1,2 @@
You may reference the source work in the Description of your fork, however, you must do so in a way that is unlikely to cause confusion or imply association with or endorsement from the author of the source work.
Additionally, per section 4 of %RULES%, we ask that you ensure your project's Name and Branding abide by the license of the source work.
@@ -0,0 +1 @@
You may reference the projects that make up the focus point of your modpack, however, you must do so in a way that is unlikely to cause confusion or imply association with or endorsement from the author of that content.
@@ -1,3 +1,5 @@
## Project Branding
Per section 1.8 of [Modrinth's Content Rules](https://modrinth.com/legal/rules) we ask that you change your project title and other relevant branding to avoid causing confusion or implying association with existing projects.
Per section 1.8 of %RULES%, your project or its branding must not imply association or be easily confused with any other person or organization.
We ask that you change your project's [Name](%PROJECT_SETTINGS_LINK%) and other relevant branding to avoid causing confusion or implying association with existing projects or individuals.
When editing your project's Name, remember to update its [URL](%PROJECT_SETTINGS_LINK%) to match.
@@ -1,7 +1,6 @@
## Misuse of Title
## Misuse of Project Name
Per section 5.2 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) we ask that you limit the title to just the name of your project.
Additional information, such as themes, tags, supported versions or loaders, etc. should be saved for the Summary or Description.
When changing your project title, remember to also ensure that your project slug (URL) matches and accurately represents your project.
Per section 5.2 of %RULES%, your project's [Name](%PROJECT_SETTINGS_LINK%) should not include unnecessary information such as loaders, themes, tags, or versions.
Your project's current Name of `%PROJECT_TITLE%` appears to contain extra information.
We ask that you remove all additional information from the [Name](%PROJECT_SETTINGS_LINK%). Instead, consider including this in your project's Summary or Description, or as a part of its relevant metadata.
When editing your project's Name, remember to update its [URL](%PROJECT_SETTINGS_LINK%) to match.
@@ -0,0 +1,4 @@
## No Versions
It looks like all versions of your project have been deleted, meaning that our Moderation Team cannot finish reviewing your project.
Please resubmit your project once you've uploaded a new version.
@@ -0,0 +1,5 @@
## Unsupported Project
Per section 5.7 of [Modrinth's Content Rules](https://modrinth.com/legal/rules), Modrinth does not support uploading multiple variations of your project as Additional files.
Having alternate versions of your content on the same project will hurt the functionality of the Modrinth App and other supported launchers as it would prevent users from updating your content, and may make it harder for your users to find the content they want.
We ask that you upload each alternate version of your project as a new project, ensuring that all users will be able to access and easily find your content.
@@ -0,0 +1,5 @@
## Unsupported Project
Modrinth does not support uploading projects that have unnecessary or extraneous installation steps.
Having alternate versions of your content on the same project will hurt the functionality of the Modrinth App and other supported launchers as it would prevent users from updating your content, and may make it harder for your users to find the content they want.
We ask that you upload each alternate version of your project as a new project, ensuring that all users will be able to access and easily find your content.
@@ -0,0 +1,6 @@
## Unsupported Project
Modrinth does not support uploading multiple variations of your project as separate versions.
New Versions of your project should strictly be a linear upgrade of the same content.
Having alternate versions of your content on the same project will hurt the functionality of the Modrinth App and other supported launchers as it would prevent users from updating your content, and may make it harder for your users to find the content they want.
We ask that you upload each alternate version of your project as a new project, ensuring that all users will be able to access and easily find your content.
@@ -0,0 +1,4 @@
## Incorrect Additional Files
Per section 5.7 of [Modrinth's Content Rules](https://modrinth.com/legal/rules) the additional files section should only be used for specific designated purposes such as a `Sources.jar`.
To ensure a smooth experience for you and your users, please upload each alternate version of your modpack as its own Modpack project, thank you.
@@ -0,0 +1,6 @@
## Unsupported Project
Modrinth does not support uploading multiple variations of your project as separate versions.
New Versions of your project should strictly be a linear upgrade of the same content.
Having alternate versions of your content on the same project will hurt the functionality of the Modrinth App and other supported launchers as it would prevent users from updating your content, and may make it harder for your users to find the content they want.
To ensure a smooth experience for you and your users, please upload each alternate version of your modpack as its own Modpack project, thank you.
@@ -0,0 +1,5 @@
## Incorrect Additional Files
Per section 5.7 of [Modrinth's Content Rules](https://modrinth.com/legal/rules) the additional files section should only be used for specific designated purposes such as a `Sources.jar`.
Modrinth does not support the upload of modpacks in the `.zip` format, as this may cause issues for Modrinth users or distribute copyrighted content without the proper permissions.
If you would like to upload a server-specific version of your modpack, consider creating a separate Modpack project.
@@ -0,0 +1,5 @@
## Broken Version
It looks like you've uploaded multiple files with the same name to the same version. This triggers a bug that produces duplicate primary file entries.
This may cause issues for users and creators as it would prevent Modpacks that include this content from functioning in the Modrinth App and other launchers.
We ask that you delete and reupload all applicable versions. Be sure to only upload one file to each version before resubmission.
@@ -1,7 +0,0 @@
## Incorrect Use of Additional Files
It looks like you've uploaded multiple `mod.jar` files to one Version as Additional Files. Per section 5.7 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) each Version of your project must include only one `mod.jar` that corresponds to its respective Minecraft and loader versions.
This allows users to easily find and download the file they need for the version they're on with ease. The Additional Files feature can be used for things like a `Sources.jar`.
Please upload each version of your mod separately, thank you.
@@ -0,0 +1,5 @@
## Incorrect Use of Additional Files
It looks like you've uploaded multiple primary files to one Version as Additional Files. Per section 5.7 of %RULES% each Version of your project must include only one primary file that corresponds to its respective Minecraft and loader versions.
This allows users to easily find and download the content they need for their game profile with ease. The Additional Files feature can be used for things like a `Sources.jar`.
Please upload each version of your project separately, thank you.
@@ -0,0 +1,3 @@
## Data Packs on Modrinth
It looks like you've selected loaders for your Data Pack that are causing it to be marked as a different project type. Data Packs must only be uploaded with the "Data Pack" loader selected. Please re-upload all versions of your data pack and make sure to only select "Data Pack" as the loader.
@@ -1,3 +1,5 @@
## Modpacks on Modrinth
It looks like you've uploaded your Modpack as a `.zip`, unfortunately, this is invalid and is why your project type is "Mod". I recommend taking a look at our support page about [Modrinth Modpacks](https://support.modrinth.com/en/articles/8802250-modpacks-on-modrinth), and once you're ready feel free to resubmit your project as a `.mrpack`. Don't forget to delete the old files from your Versions!
It looks like you've uploaded your Modpack as a `.zip`, unfortunately, this is invalid and is why your project type is "Mod". Please refer to our support article to learn more about %MODPACKS_ON_MODRINTH%.
Once you're ready feel free to resubmit your project as a `.mrpack`.
Don't forget to delete the old files from your %PROJECT_VERSIONS_FLINK%!
@@ -0,0 +1,5 @@
## Excessive File Size
This project appears to include libs or dependencies, unnecessarily redistributing their entire contents.
This is often due to an error in project structure or compilation, and in some cases, may violate the copyrights or licensing agreements of these libraries.
We ask that you remove all unnecessary files, assets, and code from your project before resubmission.
@@ -0,0 +1,4 @@
## Vanilla Assets
Your resource pack currently includes an excessive amount of unmodified assets from vanilla Minecraft.
Please remove these from your pack and ensure your project only contains original assets created by you, thank you.
@@ -1,15 +1,22 @@
import type { ModerationModpackPermissionApprovalType, Project } from '@modrinth/utils'
import type { Stage } from '../types/stage'
import { BoxIcon } from '@modrinth/assets'
import { PackageOpenIcon } from '@modrinth/assets'
export default {
id: 'modpack-permissions',
title: 'Modpack Permissions',
icon: BoxIcon,
icon: PackageOpenIcon,
// Replace me please.
guidance_url: 'https://docs.modrinth.com/moderation/modpack-permissions',
guidance_url:
'https://www.notion.so/Content-Moderation-Cheat-Sheets-22d5ee711bf081a4920ef08879fe6bf5?source=copy_link#22d5ee711bf08116bd8bc1186f357062',
shouldShow: (project: Project) => project.project_type === 'modpack',
actions: [],
actions: [
{
id: 'button',
type: 'button',
label: 'This dummy button must be present or the stage will not appear.',
},
],
} as Stage
export const finalPermissionMessages: Record<
@@ -18,7 +25,7 @@ export const finalPermissionMessages: Record<
> = {
yes: undefined,
'with-attribution-and-source': undefined,
'with-attribution': `The following content has attribution requirements, meaning that you must link back to the page where you originally found this content in your modpack description or version changelog (e.g. linking a mod's CurseForge page if you got it from CurseForge):`,
'with-attribution': `The following content has attribution requirements, meaning that you must link back to the page where you originally found this content in your Modpack's description or version changelog (e.g. linking a mod's CurseForge page if you got it from CurseForge):`,
no: 'The following content is not allowed in Modrinth modpacks due to licensing restrictions. Please contact the author(s) directly for permission or remove the content from your modpack:',
'permanent-no': `The following content is not allowed in Modrinth modpacks, regardless of permission obtained. This may be because it breaks Modrinth's content rules or because the authors, upon being contacted for permission, have declined. Please remove the content from your modpack:`,
unidentified: `The following content could not be identified. Please provide proof of its origin along with proof that you have permission to include it:`,
+34 -2
View File
@@ -3,21 +3,53 @@ import type { ButtonAction } from '../../types/actions'
import { TagsIcon } from '@modrinth/assets'
const categories: Stage = {
title: "Are the project's tags/categories accurate?",
title: "Are the project's tags accurate?",
id: 'tags',
icon: TagsIcon,
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous',
navigate: '/settings/tags',
shouldShow: (project) =>
project.categories.length > 0 || project.additional_categories.length > 0,
text: async () => {
return (await import('../messages/checklist-text/categories.md?raw')).default
},
actions: [
{
id: 'categories_inaccurate',
type: 'button',
label: 'Inaccurate',
weight: 10,
weight: 700,
suggestedStatus: 'flagged',
severity: 'low',
message: async () => (await import('../messages/categories/inaccurate.md?raw')).default,
disablesActions: ['categories_optimization_misused', 'categories_resolutions_misused'],
} as ButtonAction,
{
id: 'categories_optimization_misused',
type: 'button',
label: 'Optimization',
weight: 701,
suggestedStatus: 'flagged',
severity: 'low',
shouldShow: (project) => project.categories.includes('optimization'),
message: async () =>
(await import('../messages/categories/inaccurate.md?raw')).default +
(await import('../messages/categories/optimization_misused.md?raw')).default,
disablesActions: ['categories_inaccurate', 'categories_resolutions_misused'],
} as ButtonAction,
{
id: 'categories_resolutions_misused',
type: 'button',
label: 'Resolutions',
weight: 702,
suggestedStatus: 'flagged',
severity: 'low',
shouldShow: (project) => project.project_type === 'resourcepack',
message: async () =>
(await import('../messages/categories/inaccurate.md?raw')).default +
(await import('../messages/categories/resolutions_misused.md?raw')).default,
disablesActions: ['categories_inaccurate', 'categories_optimization_misused'],
},
],
}
@@ -1,37 +0,0 @@
import type { Stage } from '../../types/stage'
import type { ButtonAction } from '../../types/actions'
import { CopyrightIcon } from '@modrinth/assets'
const copyright: Stage = {
title: 'Does the author have proper permissions to post this project?',
id: 'copyright',
icon: CopyrightIcon,
guidance_url: 'https://modrinth.com/legal/rules',
actions: [
{
id: 'copyright_reupload',
type: 'button',
label: 'Re-upload',
weight: 10,
suggestedStatus: 'rejected',
severity: 'high',
message: async () => (await import('../messages/copyright/reupload.md?raw')).default,
relevantExtraInput: [
{
label: 'What is the title of the original project?',
variable: 'ORIGINAL_PROJECT',
required: true,
suggestions: ['Vanilla Tweaks'],
},
{
label: 'What is the author of the original project?',
variable: 'ORIGINAL_AUTHOR',
required: true,
suggestions: ['Vanilla Tweaks Team'],
},
],
} as ButtonAction,
],
}
export default copyright
+9 -16
View File
@@ -3,7 +3,7 @@ import type { ButtonAction } from '../../types/actions'
import { LibraryIcon } from '@modrinth/assets'
const description: Stage = {
title: "Is the project's description sufficient?",
title: 'Is the description sufficient, accurate, and accessible?',
id: 'description',
icon: LibraryIcon,
guidance_url: 'https://modrinth.com/legal/rules#general-expectations',
@@ -13,7 +13,7 @@ const description: Stage = {
id: 'description_insufficient',
type: 'button',
label: 'Insufficient (custom)',
weight: 10,
weight: 400,
suggestedStatus: 'flagged',
severity: 'medium',
message: async () => (await import('../messages/description/insufficient.md?raw')).default,
@@ -30,7 +30,7 @@ const description: Stage = {
id: 'description_insufficient_packs',
type: 'button',
label: 'Insufficient',
weight: 10,
weight: 401,
suggestedStatus: 'flagged',
severity: 'medium',
shouldShow: (project) => project.project_type === 'modpack',
@@ -41,7 +41,7 @@ const description: Stage = {
id: 'description_insufficient_projects',
type: 'button',
label: 'Insufficient',
weight: 10,
weight: 401,
suggestedStatus: 'flagged',
severity: 'medium',
shouldShow: (project) => project.project_type !== 'modpack',
@@ -52,7 +52,7 @@ const description: Stage = {
id: 'description_non_english',
type: 'button',
label: 'Non-english',
weight: 10,
weight: 402,
suggestedStatus: 'flagged',
severity: 'medium',
message: async () => (await import('../messages/description/non-english.md?raw')).default,
@@ -61,23 +61,16 @@ const description: Stage = {
id: 'description_unfinished',
type: 'button',
label: 'Unfinished',
weight: 10,
weight: 403,
suggestedStatus: 'flagged',
severity: 'low',
message: async () => (await import('../messages/description/unfinished.md?raw')).default,
relevantExtraInput: [
{
label: 'Please specify the reason the description appears unfinished.',
variable: 'REASON',
required: true,
},
],
} as ButtonAction,
{
id: 'description_headers_as_body',
type: 'button',
label: 'Headers as body text',
weight: 10,
weight: 404,
suggestedStatus: 'flagged',
severity: 'low',
message: async () => (await import('../messages/description/headers-as-body.md?raw')).default,
@@ -86,7 +79,7 @@ const description: Stage = {
id: 'description_image_only',
type: 'button',
label: 'Image-only',
weight: 10,
weight: 405,
suggestedStatus: 'flagged',
severity: 'medium',
message: async () => (await import('../messages/description/image-only.md?raw')).default,
@@ -95,7 +88,7 @@ const description: Stage = {
id: 'description_non_standard_text',
type: 'button',
label: 'Non-standard text',
weight: 10,
weight: 406,
suggestedStatus: 'flagged',
severity: 'medium',
message: async () =>
+2 -2
View File
@@ -13,7 +13,7 @@ const gallery: Stage = {
id: 'gallery_insufficient',
type: 'button',
label: 'Insufficient',
weight: 10,
weight: 900,
suggestedStatus: 'flagged',
severity: 'low',
message: async () => (await import('../messages/gallery/insufficient.md?raw')).default,
@@ -22,7 +22,7 @@ const gallery: Stage = {
id: 'gallery_not_relevant',
type: 'button',
label: 'Not relevant',
weight: 10,
weight: 901,
suggestedStatus: 'flagged',
severity: 'low',
message: async () => (await import('../messages/gallery/not-relevant.md?raw')).default,
Loaded 100 of 118 files, more files were not shown because too many files have changed in this diff. Show more