diff --git a/.github/workflows/turbo-ci.yml b/.github/workflows/turbo-ci.yml index b812cff92..6f82db1b2 100644 --- a/.github/workflows/turbo-ci.yml +++ b/.github/workflows/turbo-ci.yml @@ -76,3 +76,8 @@ jobs: - name: 🔍 Lint and test run: pnpm run ci + + - name: 🔍 Verify intl:extract has been run + run: | + pnpm intl:extract + git diff --exit-code */*/src/locales/en-US/index.json diff --git a/Cargo.lock b/Cargo.lock index e9cbeac2d..f6519c3b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1706,7 +1706,7 @@ dependencies = [ "bitflags 2.9.1", "core-foundation 0.10.0", "core-graphics-types", - "foreign-types 0.5.0", + "foreign-types", "libc", ] @@ -2699,15 +2699,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared 0.1.1", -] - [[package]] name = "foreign-types" version = "0.5.0" @@ -2715,7 +2706,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared 0.3.1", + "foreign-types-shared", ] [[package]] @@ -2729,12 +2720,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -3678,11 +3663,10 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "futures-util", "http 1.3.1", "hyper 1.6.0", "hyper-util", @@ -3692,7 +3676,7 @@ dependencies = [ "tokio", "tokio-rustls 0.26.2", "tower-service", - "webpki-roots 0.26.11", + "webpki-roots 1.0.0", ] [[package]] @@ -3708,22 +3692,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.6.0", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.14" @@ -4389,7 +4357,7 @@ dependencies = [ "futures-util", "hex", "hmac", - "hyper-tls", + "hyper-rustls 0.27.7", "hyper-util", "iana-time-zone", "image", @@ -4986,23 +4954,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework 2.11.1", - "security-framework-sys", - "tempfile", -] - [[package]] name = "ndk" version = "0.9.0" @@ -5577,50 +5528,12 @@ dependencies = [ "pathdiff", ] -[[package]] -name = "openssl" -version = "0.10.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" -dependencies = [ - "bitflags 2.9.1", - "cfg-if", - "foreign-types 0.3.2", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "openssl-probe" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" -[[package]] -name = "openssl-sys" -version = "0.9.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "option-ext" version = "0.2.0" @@ -6850,7 +6763,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.6.0", - "hyper-rustls 0.27.5", + "hyper-rustls 0.27.7", "hyper-util", "js-sys", "log", @@ -7980,7 +7893,7 @@ dependencies = [ "bytemuck", "cfg_aliases", "core-graphics", - "foreign-types 0.5.0", + "foreign-types", "js-sys", "log", "objc2 0.5.2", @@ -9292,16 +9205,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.24.1" diff --git a/Cargo.toml b/Cargo.toml index 040e12d0b..d95e9b601 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,12 @@ heck = "0.5.0" hex = "0.4.3" hickory-resolver = "0.25.2" hmac = "0.12.1" -hyper-tls = "0.6.0" +hyper-rustls = { version = "0.27.7", default-features = false, features = [ + "http1", + "native-tokio", + "ring", + "tls12", +] } hyper-util = "0.1.14" iana-time-zone = "0.1.63" image = { version = "0.25.6", default-features = false, features = ["rayon"] } diff --git a/apps/app-frontend/src/components/ui/world/WorldItem.vue b/apps/app-frontend/src/components/ui/world/WorldItem.vue index f30aca810..c8c1893f7 100644 --- a/apps/app-frontend/src/components/ui/world/WorldItem.vue +++ b/apps/app-frontend/src/components/ui/world/WorldItem.vue @@ -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({
- - - diff --git a/apps/app-frontend/src/locales/en-US/index.json b/apps/app-frontend/src/locales/en-US/index.json index 0952c26e7..72f24aa1d 100644 --- a/apps/app-frontend/src/locales/en-US/index.json +++ b/apps/app-frontend/src/locales/en-US/index.json @@ -413,6 +413,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+" }, diff --git a/apps/docs/src/content/docs/contributing/labrinth.md b/apps/docs/src/content/docs/contributing/labrinth.md index f29c71255..1be7dd3ed 100644 --- a/apps/docs/src/content/docs/contributing/labrinth.md +++ b/apps/docs/src/content/docs/contributing/labrinth.md @@ -19,8 +19,6 @@ From there, you can create the database and perform all database migrations with sqlx database setup ``` -Finally, if on Linux, you will need the OpenSSL library. On Debian-based systems, this involves the `pkg-config` and `libssl-dev` packages. - To enable labrinth to create a project, you need to add two things. 1. An entry in the `loaders` table. diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 334c6317a..9b376700c 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -38,9 +38,10 @@ "@intercom/messenger-js-sdk": "^0.0.14", "@ltd/j-toml": "^1.38.0", "@modrinth/assets": "workspace:*", + "@modrinth/blog": "workspace:*", + "@modrinth/moderation": "workspace:*", "@modrinth/ui": "workspace:*", "@modrinth/utils": "workspace:*", - "@modrinth/blog": "workspace:*", "@pinia/nuxt": "^0.5.1", "@types/three": "^0.172.0", "@vintl/vintl": "^4.4.1", @@ -58,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", diff --git a/apps/frontend/src/assets/styles/components.scss b/apps/frontend/src/assets/styles/components.scss index a1ea3a1e9..f647e7e25 100644 --- a/apps/frontend/src/assets/styles/components.scss +++ b/apps/frontend/src/assets/styles/components.scss @@ -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); } diff --git a/apps/frontend/src/assets/styles/global.scss b/apps/frontend/src/assets/styles/global.scss index b52b738ed..cefb9460c 100644 --- a/apps/frontend/src/assets/styles/global.scss +++ b/apps/frontend/src/assets/styles/global.scss @@ -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; diff --git a/apps/frontend/src/components/ui/Notifications.vue b/apps/frontend/src/components/ui/Notifications.vue index eae6faace..ebb43c2e0 100644 --- a/apps/frontend/src/components/ui/Notifications.vue +++ b/apps/frontend/src/components/ui/Notifications.vue @@ -1,7 +1,10 @@ + + + + diff --git a/apps/frontend/src/components/ui/moderation/ModpackPermissionsFlow.vue b/apps/frontend/src/components/ui/moderation/ModpackPermissionsFlow.vue new file mode 100644 index 000000000..124a49336 --- /dev/null +++ b/apps/frontend/src/components/ui/moderation/ModpackPermissionsFlow.vue @@ -0,0 +1,422 @@ + + + + + diff --git a/apps/frontend/src/components/ui/moderation/NewModerationChecklist.vue b/apps/frontend/src/components/ui/moderation/NewModerationChecklist.vue new file mode 100644 index 000000000..1b1d0fb6d --- /dev/null +++ b/apps/frontend/src/components/ui/moderation/NewModerationChecklist.vue @@ -0,0 +1,1330 @@ + + + + + diff --git a/apps/frontend/src/components/ui/servers/ContentVersionEditModal.vue b/apps/frontend/src/components/ui/servers/ContentVersionEditModal.vue index b142bb814..d204e7aee 100644 --- a/apps/frontend/src/components/ui/servers/ContentVersionEditModal.vue +++ b/apps/frontend/src/components/ui/servers/ContentVersionEditModal.vue @@ -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()) " > ( const response = await $fetch(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, }); diff --git a/apps/frontend/src/composables/util.ts b/apps/frontend/src/composables/util.ts new file mode 100644 index 000000000..5bf1f4dd8 --- /dev/null +++ b/apps/frontend/src/composables/util.ts @@ -0,0 +1,12 @@ +export const useNotificationRightwards = () => { + const isVisible = useState("moderation-checklist-notifications", () => false); + + const setVisible = (visible: boolean) => { + isVisible.value = visible; + }; + + return { + isVisible: readonly(isVisible), + setVisible, + }; +}; diff --git a/apps/frontend/src/layouts/default.vue b/apps/frontend/src/layouts/default.vue index 643765456..842eaf376 100644 --- a/apps/frontend/src/layouts/default.vue +++ b/apps/frontend/src/layouts/default.vue @@ -1346,6 +1346,15 @@ const footerLinks = [ }), ), }, + { + href: "/legal/copyright", + label: formatMessage( + defineMessage({ + id: "layout.footer.legal.copyright-policy", + defaultMessage: "Copyright Policy and DMCA", + }), + ), + }, ], }, ]; diff --git a/apps/frontend/src/locales/en-US/index.json b/apps/frontend/src/locales/en-US/index.json index 828e3ffdc..6ba936c22 100644 --- a/apps/frontend/src/locales/en-US/index.json +++ b/apps/frontend/src/locales/en-US/index.json @@ -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" }, diff --git a/apps/frontend/src/pages/[type]/[id].vue b/apps/frontend/src/pages/[type]/[id].vue index cf25969bf..7167610ee 100644 --- a/apps/frontend/src/pages/[type]/[id].vue +++ b/apps/frontend/src/pages/[type]/[id].vue @@ -29,12 +29,11 @@ class="settings-header__icon" />
-

- {{ project.title }} -

+

{{ project.title }}

+

Project settings

+
+
@@ -712,25 +719,14 @@ :dropdown-id="`${baseId}-more-options`" >
+

{{ formatMessage(detailsMessages.title) }}

+
+
+
+
+
+
-
- -
+
+
- +
+ +
+ +
+ + diff --git a/apps/frontend/src/pages/[type]/[id]/gallery.vue b/apps/frontend/src/pages/[type]/[id]/gallery.vue index 4f355236c..35eb72a2c 100644 --- a/apps/frontend/src/pages/[type]/[id]/gallery.vue +++ b/apps/frontend/src/pages/[type]/[id]/gallery.vue @@ -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 { diff --git a/apps/frontend/src/pages/app.vue b/apps/frontend/src/pages/app.vue index 5fca6ca08..448c493af 100644 --- a/apps/frontend/src/pages/app.vue +++ b/apps/frontend/src/pages/app.vue @@ -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% diff --git a/apps/frontend/src/pages/dashboard/revenue/withdraw.vue b/apps/frontend/src/pages/dashboard/revenue/withdraw.vue index 8fa83a25b..032a39357 100644 --- a/apps/frontend/src/pages/dashboard/revenue/withdraw.vue +++ b/apps/frontend/src/pages/dashboard/revenue/withdraw.vue @@ -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(() => { diff --git a/apps/frontend/src/pages/moderation/review.vue b/apps/frontend/src/pages/moderation/review.vue index cf5fb2ec5..0613982d4 100644 --- a/apps/frontend/src/pages/moderation/review.vue +++ b/apps/frontend/src/pages/moderation/review.vue @@ -212,6 +212,10 @@ if (projects.value) { async function goToProjects() { const project = projectsFiltered.value[0]; + const remainingProjectIds = projectsFiltered.value.slice(1).map((p) => p.id); + + localStorage.setItem("moderation-future-projects", JSON.stringify(remainingProjectIds)); + await router.push({ name: "type-id", params: { @@ -220,7 +224,6 @@ async function goToProjects() { }, state: { showChecklist: true, - projects: projectsFiltered.value.slice(1).map((x) => (x.slug ? x.slug : x.id)), }, }); } diff --git a/apps/frontend/src/pages/plus.vue b/apps/frontend/src/pages/plus.vue index 9d4f1b88e..864af2656 100644 --- a/apps/frontend/src/pages/plus.vue +++ b/apps/frontend/src/pages/plus.vue @@ -149,7 +149,8 @@ onMounted(() => {