diff --git a/apps/app-frontend/src/helpers/skins.ts b/apps/app-frontend/src/helpers/skins.ts index 9b5953f53..e31b67b1c 100644 --- a/apps/app-frontend/src/helpers/skins.ts +++ b/apps/app-frontend/src/helpers/skins.ts @@ -67,9 +67,8 @@ export async function determineModelType(texture: string): Promise<'SLIM' | 'CLA const armWidth = 2 const armHeight = 12 const imageData = context.getImageData(armX, armY, armWidth, armHeight).data - 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) { + for (let alphaIndex = 3; alphaIndex < imageData.length; alphaIndex += 4) { + if (imageData[alphaIndex] !== 0) { resolve('CLASSIC') return } diff --git a/apps/app-frontend/src/pages/Browse.vue b/apps/app-frontend/src/pages/Browse.vue index f11e2c044..16bfefac1 100644 --- a/apps/app-frontend/src/pages/Browse.vue +++ b/apps/app-frontend/src/pages/Browse.vue @@ -220,7 +220,7 @@ async function refreshSearch() { } } results.value = rawResults.result - currentPage.value = Math.max(1, Math.min(pageCount.value, currentPage.value)) + currentPage.value = 1 const persistentParams: LocationQuery = {} @@ -266,6 +266,7 @@ async function onSearchChangeToTop() { function clearSearch() { query.value = '' + currentPage.value = 1 } watch( diff --git a/apps/frontend/nuxt.config.ts b/apps/frontend/nuxt.config.ts index 269ee2e7b..4175e4992 100644 --- a/apps/frontend/nuxt.config.ts +++ b/apps/frontend/nuxt.config.ts @@ -34,7 +34,7 @@ const enabledLocales: string[] = []; /** * Overrides for the categories of the certain locales. */ -const localesCategoriesOverrides: Partial> = { +const localesCategoriesOverrides: Partial = { "en-x-pirate": "fun", "en-x-updown": "fun", "en-x-lolcat": "fun", @@ -260,21 +260,28 @@ export default defineNuxtConfig({ const omorphiaLocales: string[] = []; const omorphiaLocaleSets = new Map(); - for await (const localeDir of globIterate("node_modules/@modrinth/ui/src/locales/*", { - posix: true, - })) { - const tag = basename(localeDir); - omorphiaLocales.push(tag); + const externalLocales = [ + "node_modules/@modrinth/ui/src/locales/en-US", + "node_modules/@modrinth/moderation/locales/en-US", + ]; - const localeFiles: { from: string; format?: string }[] = []; + for (const localePath of externalLocales) { + for await (const localeDir of globIterate(localePath, { + posix: true, + })) { + const tag = basename(localeDir); + omorphiaLocales.push(tag); - omorphiaLocaleSets.set(tag, { files: localeFiles }); + const localeFiles: { from: string; format?: string }[] = []; - for await (const localeFile of globIterate(`${localeDir}/*`, { posix: true })) { - localeFiles.push({ - from: pathToFileURL(localeFile).toString(), - format: "default", - }); + omorphiaLocaleSets.set(tag, { files: localeFiles }); + + for await (const localeFile of globIterate(`${localeDir}/*`, { posix: true })) { + localeFiles.push({ + from: pathToFileURL(localeFile).toString(), + format: "default", + }); + } } } @@ -301,7 +308,7 @@ export default defineNuxtConfig({ format: "crowdin", }); } else if (fileName === "meta.json") { - const meta: Record = await fs + const meta: Record = await fs .readFile(localeFile, "utf8") .then((date) => JSON.parse(date)); const localeMeta = (locale.meta ??= {}); diff --git a/apps/frontend/src/components/ui/ProjectMemberHeader.vue b/apps/frontend/src/components/ui/ProjectMemberHeader.vue index 9bef20859..9afe2d16d 100644 --- a/apps/frontend/src/components/ui/ProjectMemberHeader.vue +++ b/apps/frontend/src/components/ui/ProjectMemberHeader.vue @@ -1,510 +1,442 @@ - diff --git a/apps/frontend/src/components/ui/moderation/NewModerationChecklist.vue b/apps/frontend/src/components/ui/moderation/NewModerationChecklist.vue index 1b1d0fb6d..2126091ad 100644 --- a/apps/frontend/src/components/ui/moderation/NewModerationChecklist.vue +++ b/apps/frontend/src/components/ui/moderation/NewModerationChecklist.vue @@ -464,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; @@ -980,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); } diff --git a/apps/frontend/src/components/ui/report/ReportInfo.vue b/apps/frontend/src/components/ui/report/ReportInfo.vue index 5e2b924c1..74bdfd0d8 100644 --- a/apps/frontend/src/components/ui/report/ReportInfo.vue +++ b/apps/frontend/src/components/ui/report/ReportInfo.vue @@ -172,6 +172,7 @@ const flags = useFeatureFlags(); .markdown-body { grid-area: body; + max-width: 100%; } .reporter-info { diff --git a/apps/frontend/src/composables/servers/modrinth-servers.ts b/apps/frontend/src/composables/servers/modrinth-servers.ts index 8d07648d5..d0e3cd921 100644 --- a/apps/frontend/src/composables/servers/modrinth-servers.ts +++ b/apps/frontend/src/composables/servers/modrinth-servers.ts @@ -194,13 +194,12 @@ export class ModrinthServer { } async testNodeReachability(): Promise { - 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) => { diff --git a/apps/frontend/src/layouts/default.vue b/apps/frontend/src/layouts/default.vue index 842eaf376..308b7e3a9 100644 --- a/apps/frontend/src/layouts/default.vue +++ b/apps/frontend/src/layouts/default.vue @@ -700,7 +700,6 @@ import { PackageOpenIcon, DiscordIcon, BlueskyIcon, - TumblrIcon, TwitterIcon, MastodonIcon, GithubIcon, @@ -1185,13 +1184,6 @@ const socialLinks = [ icon: MastodonIcon, rel: "me", }, - { - label: formatMessage( - defineMessage({ id: "layout.footer.social.tumblr", defaultMessage: "Tumblr" }), - ), - href: "https://tumblr.com/modrinth", - icon: TumblrIcon, - }, { label: formatMessage(defineMessage({ id: "layout.footer.social.x", defaultMessage: "X" })), href: "https://x.com/modrinth", diff --git a/apps/frontend/src/locales/en-US/index.json b/apps/frontend/src/locales/en-US/index.json index 6ba936c22..bf910c1e9 100644 --- a/apps/frontend/src/locales/en-US/index.json +++ b/apps/frontend/src/locales/en-US/index.json @@ -461,9 +461,6 @@ "layout.footer.social.mastodon": { "message": "Mastodon" }, - "layout.footer.social.tumblr": { - "message": "Tumblr" - }, "layout.footer.social.x": { "message": "X" }, @@ -536,6 +533,69 @@ "profile.user-id": { "message": "User ID: {id}" }, + "project-member-header.accept": { + "message": "Accept" + }, + "project-member-header.decline": { + "message": "Decline" + }, + "project-member-header.error": { + "message": "Error" + }, + "project-member-header.error-decline": { + "message": "Failed to decline team invitation" + }, + "project-member-header.error-join": { + "message": "Failed to accept team invitation" + }, + "project-member-header.invitation-no-role": { + "message": "You've been invited to join this project. Please accept or decline the invitation." + }, + "project-member-header.invitation-title": { + "message": "Invitation to join project" + }, + "project-member-header.invitation-with-role": { + "message": "You've been invited be a member of this project with the role of '{role}'." + }, + "project-member-header.publishing-checklist": { + "message": "Publishing checklist" + }, + "project-member-header.required": { + "message": "Required" + }, + "project-member-header.resubmit-for-review": { + "message": "Resubmit for review" + }, + "project-member-header.resubmit-for-review-desc": { + "message": "Your project has been {status} by Modrinth's staff. In most cases, you can resubmit for review after addressing the staff's message." + }, + "project-member-header.submit-checklist-tooltip": { + "message": "You must complete the required steps in the publishing checklist!" + }, + "project-member-header.submit-for-review": { + "message": "Submit for review" + }, + "project-member-header.submit-for-review-desc": { + "message": "Your project is only viewable by members of the project. It must be reviewed by moderators in order to be published." + }, + "project-member-header.success": { + "message": "Success" + }, + "project-member-header.success-decline": { + "message": "You have declined the team invitation" + }, + "project-member-header.success-join": { + "message": "You have joined the project team" + }, + "project-member-header.suggestion": { + "message": "Suggestion" + }, + "project-member-header.visit-moderation-page": { + "message": "Visit moderation page" + }, + "project-member-header.warning": { + "message": "Warning" + }, "project-type.collection.plural": { "message": "Collections" }, diff --git a/apps/frontend/src/pages/[type]/[id]/settings/description.vue b/apps/frontend/src/pages/[type]/[id]/settings/description.vue index 174d4bc9c..45f0a8eb8 100644 --- a/apps/frontend/src/pages/[type]/[id]/settings/description.vue +++ b/apps/frontend/src/pages/[type]/[id]/settings/description.vue @@ -22,6 +22,10 @@ " :on-image-upload="onUploadHandler" /> +
+ + {{ descriptionWarning }} +