diff --git a/.github/instructions/i18n-convert.instructions.md b/.github/instructions/i18n-convert.instructions.md index b8ce2218c1..91786f4fe3 100644 --- a/.github/instructions/i18n-convert.instructions.md +++ b/.github/instructions/i18n-convert.instructions.md @@ -81,6 +81,6 @@ Please follow these rules precisely: Use existing patterns from our codebase: - Variables/plurals: see `apps/frontend/src/pages/frog.vue` -- Rich-text link tags: see `apps/frontend/src/pages/auth/welcome.vue` and `apps/frontend/src/error.vue` +- Rich-text link tags: see `apps/frontend/src/error.vue` When you finish, there should be no hard-coded English strings left in the template—everything comes from `formatMessage` or ``. diff --git a/Cargo.toml b/Cargo.toml index 7ce30a47f6..2bd07a4848 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,20 +35,30 @@ ariadne = { path = "packages/ariadne" } async-compression = { version = "0.4.32", default-features = false } async-minecraft-ping = { path = "packages/async-minecraft-ping" } async-recursion = "1.1.1" -async-stripe = { version = "0.41.0", default-features = false, features = [ - "runtime-tokio-hyper-rustls", -] } +async-stripe = { + version = "0.41.0", + default-features = false, + features = [ + "runtime-tokio-hyper-rustls", + ] +} async-trait = "0.1.89" -async-tungstenite = { version = "0.31.0", default-features = false, features = [ - "futures-03-sink" -] } +async-tungstenite = { + version = "0.31.0", + default-features = false, + features = ["futures-03-sink"] +} async-walkdir = "2.1.0" async_zip = "0.0.18" -aws-sdk-s3 = { version = "=1.122.0", default-features = false, features = [ - "default-https-client", - "rt-tokio", - "rustls", -] } +aws-sdk-s3 = { + version = "=1.122.0", + default-features = false, + features = [ + "default-https-client", + "rt-tokio", + "rustls", + ] +} base64 = "0.22.1" bitflags = "2.9.4" bytemuck = "1.24.0" @@ -56,9 +66,11 @@ bytes = "1.10.1" censor = "0.3.0" chardetng = "0.1.17" chrono = "0.4.42" -cidre = { version = "0.15.0", default-features = false, features = [ - "macos_15_0" -] } +cidre = { + version = "0.15.0", + default-features = false, + features = ["macos_15_0"] +} clap = "4.5.48" clickhouse = "0.14.0" color-eyre = "0.6.5" @@ -70,7 +82,11 @@ daedalus = { path = "packages/daedalus" } darling = { version = "0.23" } dashmap = "6.1.0" data-url = "0.3.2" -deadpool-redis = { git = "https://github.com/modrinth/deadpool", rev = "db5fb00b036ecc8fe5f18853c559b745ffe47bde", version = "0.22.1" } +deadpool-redis = { + git = "https://github.com/modrinth/deadpool", + rev = "db5fb00b036ecc8fe5f18853c559b745ffe47bde", + version = "0.22.1" +} derive_more = "2.1.1" directories = "6.0.0" dirs = "6.0.0" @@ -92,12 +108,16 @@ hex = "0.4.3" hickory-resolver = "0.25.2" hmac = "0.12.1" hyper = "1.7.0" -hyper-rustls = { version = "0.27.7", default-features = false, features = [ - "aws-lc-rs", - "http1", - "native-tokio", - "tls12", -] } +hyper-rustls = { + version = "0.27.7", + default-features = false, + features = [ + "aws-lc-rs", + "http1", + "native-tokio", + "tls12", + ] +} hyper-util = "0.1.17" iana-time-zone = "0.1.64" image = { version = "0.25.8", default-features = false, features = ["rayon"] } @@ -106,17 +126,21 @@ indicatif = "0.18.0" itertools = "0.14.0" jemalloc_pprof = "0.8.1" json-patch = { version = "4.1.0", default-features = false } -lettre = { version = "0.11.19", default-features = false, features = [ - "aws-lc-rs", - "builder", - "hostname", - "pool", - "rustls", - "rustls-native-certs", - "smtp-transport", - "tokio1", - "tokio1-rustls", -] } +lettre = { + version = "0.11.19", + default-features = false, + features = [ + "aws-lc-rs", + "builder", + "hostname", + "pool", + "rustls", + "rustls-native-certs", + "smtp-transport", + "tokio1", + "tokio1-rustls", + ] +} maxminddb = "0.26.0" meilisearch-sdk = { version = "0.30.0", default-features = false } modrinth-log = { path = "packages/modrinth-log" } @@ -144,27 +168,35 @@ redis = "0.32.7" regex = "1.12.2" reqwest = { version = "0.12.24", default-features = false } rgb = "0.8.52" -rust_decimal = { version = "1.39.0", features = [ - "serde-with-float", - "serde-with-str" -] } +rust_decimal = { + version = "1.39.0", + features = ["serde-with-float", "serde-with-str"] +} rust_iso3166 = "0.1.14" -rust-s3 = { version = "0.37.0", default-features = false, features = [ - "fail-on-err", - "tags", - "tokio-rustls-tls", -] } +rust-s3 = { + version = "0.37.0", + default-features = false, + features = [ + "fail-on-err", + "tags", + "tokio-rustls-tls", + ] +} rustls = "0.23.32" rusty-money = "0.4.1" secrecy = "0.10.3" -sentry = { version = "0.45.0", default-features = false, features = [ - "backtrace", - "contexts", - "debug-images", - "panic", - "reqwest", - "rustls", -] } +sentry = { + version = "0.45.0", + default-features = false, + features = [ + "backtrace", + "contexts", + "debug-images", + "panic", + "reqwest", + "rustls", + ] +} serde = "1.0.228" serde_bytes = "0.11.19" serde_cbor = "0.11.2" @@ -192,10 +224,15 @@ tauri-plugin-http = "2.5.7" tauri-plugin-opener = "2.5.0" tauri-plugin-os = "2.3.1" tauri-plugin-single-instance = "2.3.4" -tauri-plugin-updater = { git = "https://github.com/modrinth/plugins-workspace", rev = "0d30f2aa28ec668ce187d527da1c475da3c01cbc", default-features = false, features = [ - "rustls-tls", - "zip", -] } +tauri-plugin-updater = { + git = "https://github.com/modrinth/plugins-workspace", + rev = "0d30f2aa28ec668ce187d527da1c475da3c01cbc", + default-features = false, + features = [ + "rustls-tls", + "zip", + ] +} tauri-plugin-window-state = "2.4.0" tempfile = "3.23.0" theseus = { path = "packages/app-lib" } @@ -228,12 +265,16 @@ winreg = "0.55.0" woothee = "0.13.0" yaserde = "0.12.0" zbus = "5.11.0" -zip = { version = "6.0.0", default-features = false, features = [ - "bzip2", - "deflate", - "deflate64", - "zstd", -] } +zip = { + version = "6.0.0", + default-features = false, + features = [ + "bzip2", + "deflate", + "deflate64", + "zstd", + ] +} zxcvbn = "3.1.0" [workspace.lints.clippy] @@ -269,6 +310,7 @@ redundant_type_annotations = "warn" result_large_err = "allow" todo = "warn" too_many_arguments = "allow" +type_complexity = "allow" uninlined_format_args = "warn" unnested_or_patterns = "warn" wildcard_dependencies = "warn" diff --git a/apps/app/Cargo.toml b/apps/app/Cargo.toml index 929a191345..e03d74e0fc 100644 --- a/apps/app/Cargo.toml +++ b/apps/app/Cargo.toml @@ -22,11 +22,14 @@ path-util = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } serde_with = { workspace = true } -tauri = { workspace = true, features = [ - "devtools", - "macos-private-api", - "protocol-asset", -] } +tauri = { + workspace = true, + features = [ + "devtools", + "macos-private-api", + "protocol-asset", + ] +} tauri-plugin-deep-link = { workspace = true } tauri-plugin-dialog = { workspace = true } tauri-plugin-fs = { workspace = true } @@ -54,18 +57,24 @@ tauri-plugin-updater = { workspace = true, optional = true } [target.'cfg(target_os = "macos")'.dependencies] core-foundation.workspace = true core-graphics.workspace = true -objc2-app-kit = { workspace = true, features = [ - "NSWindow", -] } +objc2-app-kit = { + workspace = true, + features = [ + "NSWindow", + ] +} [target.'cfg(windows)'.dependencies] webview2-com.workspace = true -windows = { workspace = true, features = [ - "Win32_Foundation", - "Win32_Graphics_Dwm", - "Win32_Graphics_Gdi", - "Win32_UI_WindowsAndMessaging", -] } +windows = { + workspace = true, + features = [ + "Win32_Foundation", + "Win32_Graphics_Dwm", + "Win32_Graphics_Gdi", + "Win32_UI_WindowsAndMessaging", + ] +} windows-core.workspace = true [features] diff --git a/apps/daedalus_client/Cargo.toml b/apps/daedalus_client/Cargo.toml index 1f6aa350df..b91f894ee2 100644 --- a/apps/daedalus_client/Cargo.toml +++ b/apps/daedalus_client/Cargo.toml @@ -4,14 +4,17 @@ version = "0.2.2" edition.workspace = true [dependencies] -async_zip = { workspace = true, features = [ - "bzip2", - "chrono", - "deflate", - "deflate64", - "tokio-fs", - "zstd", -] } +async_zip = { + workspace = true, + features = [ + "bzip2", + "chrono", + "deflate", + "deflate64", + "tokio-fs", + "zstd", + ] +} bytes = { workspace = true } chrono = { workspace = true, features = ["serde"] } daedalus = { workspace = true } @@ -20,11 +23,14 @@ dotenvy = { workspace = true } futures = { workspace = true } indexmap = { workspace = true, features = ["serde"] } itertools = { workspace = true } -reqwest = { workspace = true, features = [ - "json", - "rustls-tls-native-roots", - "stream", -] } +reqwest = { + workspace = true, + features = [ + "json", + "rustls-tls-native-roots", + "stream", + ] +} rust-s3 = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } diff --git a/apps/frontend/src/app.vue b/apps/frontend/src/app.vue index 9cdb763dca..1c4585e3d3 100644 --- a/apps/frontend/src/app.vue +++ b/apps/frontend/src/app.vue @@ -14,6 +14,8 @@ import { I18nDebugPanel, LoadingBar, NotificationPanel } from '@modrinth/ui' import { setupProviders } from '~/providers/setup.ts' +import { useAuth } from './composables/auth' + const auth = await useAuth() setupProviders(auth) diff --git a/apps/frontend/src/components/ui/auth/CreateAccount.vue b/apps/frontend/src/components/ui/auth/CreateAccount.vue new file mode 100644 index 0000000000..1ab2c73366 --- /dev/null +++ b/apps/frontend/src/components/ui/auth/CreateAccount.vue @@ -0,0 +1,279 @@ + + + diff --git a/apps/frontend/src/components/ui/HCaptcha.vue b/apps/frontend/src/components/ui/auth/HCaptcha.vue similarity index 76% rename from apps/frontend/src/components/ui/HCaptcha.vue rename to apps/frontend/src/components/ui/auth/HCaptcha.vue index ebbec75f8f..c07a47a449 100644 --- a/apps/frontend/src/components/ui/HCaptcha.vue +++ b/apps/frontend/src/components/ui/auth/HCaptcha.vue @@ -47,17 +47,34 @@ defineExpose({ > - diff --git a/apps/frontend/src/components/ui/auth/SignIn.vue b/apps/frontend/src/components/ui/auth/SignIn.vue new file mode 100644 index 0000000000..ffb3414653 --- /dev/null +++ b/apps/frontend/src/components/ui/auth/SignIn.vue @@ -0,0 +1,383 @@ + + + + + diff --git a/apps/frontend/src/components/ui/auth/SignUp.vue b/apps/frontend/src/components/ui/auth/SignUp.vue new file mode 100644 index 0000000000..6fedd7d7fc --- /dev/null +++ b/apps/frontend/src/components/ui/auth/SignUp.vue @@ -0,0 +1,236 @@ + + + diff --git a/apps/frontend/src/components/ui/create/ProjectCreateModal.vue b/apps/frontend/src/components/ui/create/ProjectCreateModal.vue index 01ad8a1baf..3599d536a6 100644 --- a/apps/frontend/src/components/ui/create/ProjectCreateModal.vue +++ b/apps/frontend/src/components/ui/create/ProjectCreateModal.vue @@ -164,9 +164,7 @@ defineExpose({ show, }) -const auth = (await useAuth()) as Ref<{ - user: { id: string; username: string; avatar_url: string } | null -}> +const auth = await useAuth() const messages = defineMessages({ title: { diff --git a/apps/frontend/src/components/ui/dashboard/withdraw-stages/LegacyPaypalDetailsStage.vue b/apps/frontend/src/components/ui/dashboard/withdraw-stages/LegacyPaypalDetailsStage.vue index 6278f19a2f..24974b3bba 100644 --- a/apps/frontend/src/components/ui/dashboard/withdraw-stages/LegacyPaypalDetailsStage.vue +++ b/apps/frontend/src/components/ui/dashboard/withdraw-stages/LegacyPaypalDetailsStage.vue @@ -120,7 +120,7 @@ import { computed, onMounted, ref, watch } from 'vue' import RevenueInputField from '@/components/ui/dashboard/RevenueInputField.vue' import WithdrawFeeBreakdown from '@/components/ui/dashboard/WithdrawFeeBreakdown.vue' -import { getAuthUrl, removeAuthProvider, useAuth } from '@/composables/auth.js' +import { getAuthUrl, removeAuthProvider, useAuth } from '@/composables/auth.ts' import { useWithdrawContext } from '@/providers/creator-withdraw.ts' const { withdrawData, maxWithdrawAmount, availableMethods, calculateFees, saveStateToStorage } = @@ -193,7 +193,6 @@ async function saveVenmoHandle() { }, }) - // @ts-expect-error auth.js is not typed await useAuth(auth.value.token) initialVenmoHandle.value = venmoHandle.value.trim() diff --git a/apps/frontend/src/components/ui/dashboard/withdraw-stages/TremendousDetailsStage.vue b/apps/frontend/src/components/ui/dashboard/withdraw-stages/TremendousDetailsStage.vue index a9dfa3e7e7..fdd371148c 100644 --- a/apps/frontend/src/components/ui/dashboard/withdraw-stages/TremendousDetailsStage.vue +++ b/apps/frontend/src/components/ui/dashboard/withdraw-stages/TremendousDetailsStage.vue @@ -358,8 +358,8 @@ import { computed, onMounted, ref, watch } from 'vue' import RevenueInputField from '@/components/ui/dashboard/RevenueInputField.vue' import WithdrawFeeBreakdown from '@/components/ui/dashboard/WithdrawFeeBreakdown.vue' -import { useAuth } from '@/composables/auth.js' import { useWithdrawContext } from '@/providers/creator-withdraw.ts' +import { useAuth } from '~/composables/auth.ts' const debug = useDebugLogger('TremendousDetailsStage') const { withdrawData, maxWithdrawAmount, availableMethods, paymentOptions, calculateFees } = diff --git a/apps/frontend/src/components/ui/moderation/ModerationProjectNags.vue b/apps/frontend/src/components/ui/moderation/ModerationProjectNags.vue index 44a50f083d..33a7dbf92e 100644 --- a/apps/frontend/src/components/ui/moderation/ModerationProjectNags.vue +++ b/apps/frontend/src/components/ui/moderation/ModerationProjectNags.vue @@ -24,7 +24,7 @@
- diff --git a/apps/frontend/src/components/ui/moderation/ModerationReportCard.vue b/apps/frontend/src/components/ui/moderation/ModerationReportCard.vue index 743f7a7131..e459d41cca 100644 --- a/apps/frontend/src/components/ui/moderation/ModerationReportCard.vue +++ b/apps/frontend/src/components/ui/moderation/ModerationReportCard.vue @@ -190,7 +190,6 @@ import { LinkIcon, } from '@modrinth/assets' import { type ExtendedReport, reportQuickReplies } from '@modrinth/moderation' -import { type OverflowMenuOption, useFormatDateTime } from '@modrinth/ui' import { Avatar, ButtonStyled, @@ -198,6 +197,8 @@ import { getProjectTypeIcon, injectNotificationManager, OverflowMenu, + type OverflowMenuOption, + useFormatDateTime, useRelativeTime, } from '@modrinth/ui' import { formatProjectType } from '@modrinth/utils' diff --git a/apps/frontend/src/components/ui/moderation/ModerationTechRevCard.vue b/apps/frontend/src/components/ui/moderation/ModerationTechRevCard.vue index cf799fff26..14f6abd562 100644 --- a/apps/frontend/src/components/ui/moderation/ModerationTechRevCard.vue +++ b/apps/frontend/src/components/ui/moderation/ModerationTechRevCard.vue @@ -26,12 +26,12 @@ import { getProjectTypeIcon, injectModrinthClient, injectNotificationManager, + NavTabs, OverflowMenu, type OverflowMenuOption, useFormatBytes, useFormatDateTime, } from '@modrinth/ui' -import { NavTabs } from '@modrinth/ui' import { capitalizeString, formatProjectType, diff --git a/apps/frontend/src/components/ui/project-settings/ServerCompatibilityModal/stages/SelectPublishedModpack.vue b/apps/frontend/src/components/ui/project-settings/ServerCompatibilityModal/stages/SelectPublishedModpack.vue index 16fd0fa9b6..1346fe17dd 100644 --- a/apps/frontend/src/components/ui/project-settings/ServerCompatibilityModal/stages/SelectPublishedModpack.vue +++ b/apps/frontend/src/components/ui/project-settings/ServerCompatibilityModal/stages/SelectPublishedModpack.vue @@ -87,7 +87,7 @@ const currentProjectId = computed(() => projectV3.value?.id) const { selectedProjectId, selectedVersionId } = injectServerCompatibilityContext() const { labrinth } = injectModrinthClient() const { addNotification } = injectNotificationManager() -const auth = (await useAuth()) as { user?: { id: string } } +const auth = await useAuth() interface VersionInfo { id: string diff --git a/apps/frontend/src/components/ui/thread/ThreadView.vue b/apps/frontend/src/components/ui/thread/ThreadView.vue index a753014aac..0e487bc68d 100644 --- a/apps/frontend/src/components/ui/thread/ThreadView.vue +++ b/apps/frontend/src/components/ui/thread/ThreadView.vue @@ -59,7 +59,7 @@ - Quick Reply + Quick reply diff --git a/apps/frontend/src/composables/auth.js b/apps/frontend/src/composables/auth.js deleted file mode 100644 index aea80a1faa..0000000000 --- a/apps/frontend/src/composables/auth.js +++ /dev/null @@ -1,179 +0,0 @@ -function normalizeAuthToken(value) { - if (typeof value === 'string') { - return value - } - return '' -} - -export const useAuth = async (oldToken = null) => { - const auth = useState('auth', () => ({ - user: null, - token: '', - headers: {}, - })) - - if (!auth.value.user || oldToken) { - auth.value = await initAuth(oldToken) - } - - return auth -} - -export const initAuth = async (oldToken = null) => { - const auth = { - user: null, - token: '', - } - - if (oldToken === 'none') { - return auth - } - - const route = useRoute() - const config = useRuntimeConfig() - const authCookie = useCookie('auth-token', { - maxAge: 60 * 60 * 24 * 365 * 10, - sameSite: 'lax', - secure: config.public.cookieSecure, - httpOnly: false, - path: '/', - }) - - if (oldToken) { - const normalized = normalizeAuthToken(oldToken) - if (normalized) { - authCookie.value = normalized - } - } - - const oauthCode = normalizeAuthToken(route.query.code) - if (oauthCode && !route.fullPath.includes('new_account=true')) { - authCookie.value = oauthCode - } - - if (route.fullPath.includes('new_account=true') && route.path !== '/auth/welcome') { - const redirect = route.path.startsWith('/auth/') ? null : route.fullPath - - await navigateTo( - `/auth/welcome?authToken=${oauthCode}${ - redirect ? `&redirect=${encodeURIComponent(redirect)}` : '' - }`, - ) - } - - const tokenStr = normalizeAuthToken(authCookie.value) - - if (authCookie.value != null && tokenStr === '') { - authCookie.value = null - } else if (tokenStr) { - auth.token = tokenStr - - if (!auth.token.startsWith('mra_')) { - return auth - } - - try { - auth.user = await useBaseFetch( - 'user', - { - apiVersion: 3, - headers: { - Authorization: auth.token, - }, - }, - true, - ) - } catch { - /* empty */ - } - } - - if (!auth.user && auth.token && typeof auth.token === 'string') { - try { - const session = await useBaseFetch( - 'session/refresh', - { - method: 'POST', - headers: { - Authorization: auth.token, - }, - }, - true, - ) - - auth.token = normalizeAuthToken(session.session) - if (auth.token) { - authCookie.value = auth.token - auth.user = await useBaseFetch( - 'user', - { - apiVersion: 3, - headers: { - Authorization: auth.token, - }, - }, - true, - ) - } else { - authCookie.value = null - auth.token = '' - } - } catch { - authCookie.value = null - } - } - - return auth -} - -export const getSignInRedirectPath = (route) => { - const fullPath = route.fullPath - if (fullPath === '/auth' || fullPath.startsWith('/auth/')) { - return '/dashboard' - } - return fullPath -} - -export const getSignInRouteObj = (route, redirectOverride) => ({ - path: '/auth/sign-in', - query: { - redirect: redirectOverride ?? getSignInRedirectPath(route), - }, -}) - -export const getAuthUrl = (provider, redirect = '/dashboard') => { - const config = useRuntimeConfig() - const route = useNativeRoute() - - const fullURL = route.query.launcher - ? getLauncherRedirectUrl(route) - : `${config.public.siteUrl}/auth/sign-in?redirect=${encodeURIComponent(redirect)}` - - return `${config.public.apiBaseUrl}auth/init?provider=${provider}&url=${encodeURIComponent(fullURL)}` -} - -export const removeAuthProvider = async (provider) => { - startLoading() - - const auth = await useAuth() - - await useBaseFetch('auth/provider', { - method: 'DELETE', - body: { - provider, - }, - }) - - await useAuth(auth.value.token) - - stopLoading() -} - -export const getLauncherRedirectUrl = (route) => { - const usesLocalhostRedirectionScheme = - ['4', '6'].includes(route.query.ipver) && Number(route.query.port) < 65536 - - return usesLocalhostRedirectionScheme - ? `http://${route.query.ipver === '4' ? '127.0.0.1' : '[::1]'}:${route.query.port}` - : `https://launcher-files.modrinth.com` -} diff --git a/apps/frontend/src/composables/auth.ts b/apps/frontend/src/composables/auth.ts new file mode 100644 index 0000000000..11f5f5c173 --- /dev/null +++ b/apps/frontend/src/composables/auth.ts @@ -0,0 +1,241 @@ +import type { Labrinth } from '@modrinth/api-client' +import { useStorage } from '@vueuse/core' +import type { LocationQueryValue, RouteLocationNormalizedLoaded } from 'vue-router' + +import type { CookieOptions } from '#app' + +type AuthState = { + user: Labrinth.Users.v2.User | null + token: string +} + +type QueryValue = LocationQueryValue | LocationQueryValue[] | undefined +type FullPathRoute = Pick +type LauncherRoute = Pick + +export const LAST_SIGN_IN_OAUTH_PROVIDER_STORAGE_KEY = 'auth-last-sign-in-oauth-provider' +export const PENDING_SIGN_IN_OAUTH_PROVIDER_STORAGE_KEY = 'auth-pending-sign-in-oauth-provider' + +const AUTH_COOKIE_OPTIONS = { + maxAge: 60 * 60 * 24 * 365 * 10, + sameSite: 'lax', + httpOnly: false, + path: '/', +} satisfies CookieOptions + +const normalizeAuthToken = (value: unknown) => { + if (typeof value === 'string') { + return value + } + return '' +} + +const getQueryString = (value: QueryValue) => { + if (Array.isArray(value)) { + return value[0] ?? null + } + return value ?? null +} + +export const useAuth = async (oldToken: string | null | undefined = null) => { + const auth = useState('auth', () => ({ + user: null, + token: '', + })) + + if (!auth.value.user || oldToken) { + auth.value = await initAuth(oldToken) + } + + return auth +} + +export const initAuth = async (oldToken: string | null | undefined = null) => { + const auth: AuthState = { + user: null, + token: '', + } + + if (oldToken === 'none') { + return auth + } + + const route = useRoute() + const config = useRuntimeConfig() + const authCookie = useCookie('auth-token', { + ...AUTH_COOKIE_OPTIONS, + secure: config.public.cookieSecure, + }) + + if (oldToken) { + const normalized = normalizeAuthToken(oldToken) + if (normalized) { + authCookie.value = normalized + } + } + + const oauthCode = normalizeAuthToken(route.query.code) + if (oauthCode && !route.fullPath.includes('new_account=true')) { + authCookie.value = oauthCode + } + + if (route.fullPath.includes('new_account=true') && route.path !== '/auth/welcome') { + const redirect = route.path.startsWith('/auth/') ? null : route.fullPath + + await navigateTo( + `/auth/welcome?authToken=${oauthCode}${ + redirect ? `&redirect=${encodeURIComponent(redirect)}` : '' + }`, + ) + } + + const tokenStr = normalizeAuthToken(authCookie.value) + + if (authCookie.value != null && tokenStr === '') { + authCookie.value = null + } else if (tokenStr) { + auth.token = tokenStr + + if (!auth.token.startsWith('mra_')) { + return auth + } + + try { + auth.user = (await useBaseFetch( + 'user', + { + apiVersion: 3, + headers: { + Authorization: auth.token, + }, + }, + true, + )) as Labrinth.Users.v2.User + } catch { + /* empty */ + } + } + + if (!auth.user && auth.token) { + try { + const session = (await useBaseFetch( + 'session/refresh', + { + method: 'POST', + headers: { + Authorization: auth.token, + }, + }, + true, + )) as { session: unknown } + + auth.token = normalizeAuthToken(session.session) + if (auth.token) { + authCookie.value = auth.token + auth.user = (await useBaseFetch( + 'user', + { + apiVersion: 3, + headers: { + Authorization: auth.token, + }, + }, + true, + )) as Labrinth.Users.v2.User + } else { + authCookie.value = null + auth.token = '' + } + } catch { + authCookie.value = null + } + } + + return auth +} + +export const getSignInRedirectPath = (route: FullPathRoute) => { + const fullPath = route.fullPath + if (fullPath === '/auth' || fullPath.startsWith('/auth/')) { + return '/dashboard' + } + return fullPath +} + +export const getSignInRouteObj = (route: FullPathRoute, redirectOverride?: string | null) => ({ + path: '/auth/sign-in', + query: { + redirect: redirectOverride ?? getSignInRedirectPath(route), + }, +}) + +export const getAuthUrl = (provider: string, redirect = '/dashboard') => { + const config = useRuntimeConfig() + const route = useNativeRoute() + const launcher = getQueryString(route.query.launcher) + + const fullURL = launcher + ? (() => { + const callbackUrl = new URL('/auth/sign-in', config.public.siteUrl) + callbackUrl.searchParams.set('launcher', launcher) + + const ipver = getQueryString(route.query.ipver) + const port = getQueryString(route.query.port) + + if (ipver) { + callbackUrl.searchParams.set('ipver', ipver) + } + + if (port) { + callbackUrl.searchParams.set('port', port) + } + + return callbackUrl.toString() + })() + : `${config.public.siteUrl}/auth/sign-in?redirect=${encodeURIComponent(redirect)}` + + return `${config.public.apiBaseUrl}auth/init?provider=${provider}&url=${encodeURIComponent(fullURL)}` +} + +export const promotePendingSignInOAuthProvider = () => { + if (!import.meta.client) return + const pending = useStorage( + PENDING_SIGN_IN_OAUTH_PROVIDER_STORAGE_KEY, + null, + undefined, + { initOnMounted: true }, + ) + if (!pending.value) return + const last = useStorage(LAST_SIGN_IN_OAUTH_PROVIDER_STORAGE_KEY, null, undefined, { + initOnMounted: true, + }) + last.value = pending.value + pending.value = null +} + +export const removeAuthProvider = async (provider: string) => { + startLoading() + + const auth = await useAuth() + + await useBaseFetch('auth/provider', { + method: 'DELETE', + body: { + provider, + }, + }) + + await useAuth(auth.value.token) + + stopLoading() +} + +export const getLauncherRedirectUrl = (route: LauncherRoute) => { + const ipver = getQueryString(route.query.ipver) + const port = Number(getQueryString(route.query.port)) + const usesLocalhostRedirectionScheme = ['4', '6'].includes(ipver ?? '') && port < 65536 + + return usesLocalhostRedirectionScheme + ? `http://${ipver === '4' ? '127.0.0.1' : '[::1]'}:${port}` + : 'https://launcher-files.modrinth.com' +} diff --git a/apps/frontend/src/composables/featureFlags.ts b/apps/frontend/src/composables/featureFlags.ts index ba6538ee81..ed8e142016 100644 --- a/apps/frontend/src/composables/featureFlags.ts +++ b/apps/frontend/src/composables/featureFlags.ts @@ -48,7 +48,6 @@ export const DEFAULT_FEATURE_FLAGS = validateValues({ useV1ContentTabAPI: true, labrinthApiCanary: false, dismissedExternalProjectsInfo: false, - modpackPermissionsPage: false, showAllBanners: false, alwaysIgnoreErrorBanner: false, showViewProdRouteBanner: false, @@ -56,6 +55,8 @@ export const DEFAULT_FEATURE_FLAGS = validateValues({ showModeratorPrivateMessageHighlight: true, archonApiStaging: false, showHostingAccessInstanceAuditLog: false, + versionDevInfoCollapsed: true, + alwaysShowVersionDevInfo: false, } as const) export type FeatureFlag = keyof typeof DEFAULT_FEATURE_FLAGS diff --git a/apps/frontend/src/composables/queries/version.ts b/apps/frontend/src/composables/queries/version.ts index 552410fa13..cd612b2c00 100644 --- a/apps/frontend/src/composables/queries/version.ts +++ b/apps/frontend/src/composables/queries/version.ts @@ -8,4 +8,11 @@ export const versionQueryOptions = { queryFn: () => client.labrinth.versions_v3.getVersion(versionId), staleTime: STALE_TIME, }), + + fromProject: (projectId: string, versionIdOrNumber: string, client: AbstractModrinthClient) => ({ + queryKey: ['project', projectId, 'version', 'v3', versionIdOrNumber] as const, + queryFn: () => + client.labrinth.versions_v3.getVersionFromIdOrNumber(projectId, versionIdOrNumber), + staleTime: STALE_TIME, + }), } diff --git a/apps/frontend/src/layouts/default.vue b/apps/frontend/src/layouts/default.vue index 271666927c..6c0a6b01a6 100644 --- a/apps/frontend/src/layouts/default.vue +++ b/apps/frontend/src/layouts/default.vue @@ -799,7 +799,7 @@ import CollectionCreateModal from '~/components/ui/create/CollectionCreateModal. import OrganizationCreateModal from '~/components/ui/create/OrganizationCreateModal.vue' import ProjectCreateModal from '~/components/ui/create/ProjectCreateModal.vue' import ModrinthFooter from '~/components/ui/ModrinthFooter.vue' -import { getSignInRouteObj } from '~/composables/auth.js' +import { getSignInRouteObj } from '~/composables/auth.ts' import { errors as generatedStateErrors } from '~/generated/state.json' import { getProjectTypeMessage } from '~/utils/i18n-project-type.ts' import { hasActiveMidas } from '~/utils/user-membership.ts' diff --git a/apps/frontend/src/locales/de-CH/index.json b/apps/frontend/src/locales/de-CH/index.json index c07eacc8fb..c006332fb9 100644 --- a/apps/frontend/src/locales/de-CH/index.json +++ b/apps/frontend/src/locales/de-CH/index.json @@ -3272,9 +3272,6 @@ "project.moderation.thread.help-center-note.2": { "message": "Wenn du Hilfe benötigst oder weitere Fragen hast, besuche bitte das Hilfezentrum von Modrinth und klicke auf die blaue Sprechblase, um den Support zu kontaktieren." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Benutzer-UI anzeigen" - }, "project.moderation.thread.private-description": { "message": "Dies ist ein privater Unterhaltungsthread mit den Modrinth-Moderatoren. Sie können dich bei Problemen bezüglich dieses Projekts kontaktieren." }, @@ -3404,9 +3401,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {Diese Version ist} other {Diese Versionen sind}} derzeit zurückgehalten und nicht öffentlich gelistet. Bitte stelle einen Nachweis bereit, dass du die Erlaubnis hast, bestimmte Dateien weiterzuverbreiten, die in {count, plural, one {der Modpack-Version} other {den Modpack-Versionen}} enthalten sind." }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Beheben" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {Version {version_name}} other {Versionen}} zurückgehalten aufgrund von unbekannten eingebetteten Inhalten" }, diff --git a/apps/frontend/src/locales/de-DE/index.json b/apps/frontend/src/locales/de-DE/index.json index 479c871dd2..3c851951b6 100644 --- a/apps/frontend/src/locales/de-DE/index.json +++ b/apps/frontend/src/locales/de-DE/index.json @@ -3272,9 +3272,6 @@ "project.moderation.thread.help-center-note.2": { "message": "Falls du Hilfe benötigst oder weitere Fragen hast, besuche bitte das Hilfezentrum von Modrinth und klicke auf die blaue Sprechblase, um den Support zu kontaktieren." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Mitglieder-UI anzeigen" - }, "project.moderation.thread.private-description": { "message": "Dies ist eine private Konversation mit den Moderatoren von Modrinth. Diese können dir Nachrichten zu Problemen bezüglich dieses Projekts senden." }, @@ -3401,9 +3398,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {Diese Version ist} other {Diese Versionen sind}} derzeit zurückgehalten und nicht öffentlich gelistet. Bitte stelle einen Nachweis bereit, dass du die Erlaubnis hast, bestimmte Dateien weiterzuverbreiten, die im Modpack in {count, plural, one {Version} other {Versionen}} enthalten sind." }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Beheben" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {Version {version_name} wurde} other {Versionen wurden}} aufgrund unbekannter eingebetteter Inhalte zurückgehalten" }, diff --git a/apps/frontend/src/locales/en-US/index.json b/apps/frontend/src/locales/en-US/index.json index e6a64f4eee..96e3591dd5 100644 --- a/apps/frontend/src/locales/en-US/index.json +++ b/apps/frontend/src/locales/en-US/index.json @@ -701,12 +701,75 @@ "auth.authorize.authorize-app-name": { "message": "Authorize {appName}" }, + "auth.authorize.error.missing-parameters": { + "message": "Missing required OAuth query parameters." + }, "auth.authorize.error.no-redirect-url": { "message": "No redirect location found in response" }, + "auth.authorize.errro-title": { + "message": "An Error Occured" + }, "auth.authorize.redirect-url": { "message": "You will be redirected to {url}" }, + "auth.continue-with-provider": { + "message": "Continue with {provider}" + }, + "auth.create-account.age-requirement.warning-title": { + "message": "Age requirement" + }, + "auth.create-account.complete-sign-up": { + "message": "Complete sign up" + }, + "auth.create-account.date-of-birth.invalid.text": { + "message": "Please enter a valid date of birth. Year cannot be 0000." + }, + "auth.create-account.date-of-birth.invalid.title": { + "message": "Invalid date of birth" + }, + "auth.create-account.date-of-birth.label": { + "message": "Date of birth" + }, + "auth.create-account.date-of-birth.over13-helper": { + "message": "You must be over 13 years old to use Modrinth." + }, + "auth.create-account.date-of-birth.placeholder": { + "message": "Select your date of birth" + }, + "auth.create-account.date-of-birth.required.text": { + "message": "Please enter your date of birth before continuing." + }, + "auth.create-account.date-of-birth.required.title": { + "message": "Date of birth required" + }, + "auth.create-account.date-of-birth.under13-helper": { + "message": "You cannot create an account at Modrinth unless you are over 13 years old." + }, + "auth.create-account.info-panel.source-code-link": { + "message": "Relevant source code" + }, + "auth.create-account.info-panel.text": { + "message": "We do not store your date of birth, only whether you are over 13 to use Modrinth." + }, + "auth.create-account.page-title": { + "message": "Create Account" + }, + "auth.create-account.security-check.label": { + "message": "Security check" + }, + "auth.create-account.subscribe.label": { + "message": "Keep me updated on the cool things Modrinth is working on via email" + }, + "auth.create-account.title": { + "message": "Create an Account" + }, + "auth.create-account.username.optional-label": { + "message": "Username" + }, + "auth.create-account.username.placeholder": { + "message": "Enter username" + }, "auth.reset-password.method-choice.action": { "message": "Send recovery email" }, @@ -741,53 +804,65 @@ "message": "Reset your password" }, "auth.sign-in.2fa.description": { - "message": "Please enter a two-factor code to proceed." + "message": "Enter the 6-digit code from your authenticator app, or one of your backup codes." }, "auth.sign-in.2fa.label": { - "message": "Enter two-factor code" + "message": "Two-factor authentication" }, "auth.sign-in.2fa.placeholder": { "message": "Enter code..." }, - "auth.sign-in.additional-options": { - "message": "Forgot password?Create an account" + "auth.sign-in.continue-with-email": { + "message": "Continue with Email" + }, + "auth.sign-in.create-account": { + "message": "Sign up" + }, + "auth.sign-in.forgot-password": { + "message": "Forgot password" + }, + "auth.sign-in.last-sign-in": { + "message": "Last sign in" + }, + "auth.sign-in.no-account": { + "message": "Don't have an account?" }, "auth.sign-in.sign-in-with": { - "message": "Sign in with" + "message": "Sign into Modrinth" }, "auth.sign-in.title": { "message": "Sign In" }, - "auth.sign-in.use-password": { - "message": "Or use a password" + "auth.sign-up.age-requirement.warning-title": { + "message": "Age requirement" }, - "auth.sign-up.action.create-account": { - "message": "Create account" + "auth.sign-up.continue-with-email": { + "message": "Continue with Email" }, "auth.sign-up.legal-dislaimer": { "message": "By creating an account, you agree to Modrinth's Terms and Privacy Policy." }, - "auth.sign-up.notification.password-mismatch.text": { - "message": "Passwords do not match!" + "auth.sign-up.show-fewer-options": { + "message": "Show fewer options" + }, + "auth.sign-up.show-other-options": { + "message": "Show other options" }, "auth.sign-up.sign-in-option.title": { "message": "Already have an account?" }, - "auth.sign-up.subscribe.label": { - "message": "Subscribe to updates about Modrinth" - }, "auth.sign-up.title": { "message": "Sign Up" }, - "auth.sign-up.title.create-account": { - "message": "Or create an account yourself" - }, "auth.sign-up.title.sign-up-with": { - "message": "Sign up with" + "message": "Create an Account" }, "auth.verify-email.action.account-settings": { "message": "Account settings" }, + "auth.verify-email.action.discover-mods": { + "message": "Discover mods" + }, "auth.verify-email.already-verified.description": { "message": "Your email is already verified!" }, @@ -806,6 +881,15 @@ "auth.verify-email.failed-verification.title": { "message": "Email verification failed" }, + "auth.verify-email.notification.email-sent.description": { + "message": "An email with a link to verify your account has been sent to {email}." + }, + "auth.verify-email.notification.email-sent.title": { + "message": "Email sent" + }, + "auth.verify-email.notification.error-occurred.title": { + "message": "An error occurred" + }, "auth.verify-email.post-verification.description": { "message": "Your email address has been successfully verified!" }, @@ -815,21 +899,6 @@ "auth.verify-email.title": { "message": "Verify Email" }, - "auth.welcome.checkbox.subscribe": { - "message": "Subscribe to updates about Modrinth" - }, - "auth.welcome.description": { - "message": "You’re now part of the awesome community of creators & explorers already building, downloading, and staying up-to-date with amazing mods." - }, - "auth.welcome.label.tos": { - "message": "By creating an account, you have agreed to Modrinth's Terms and Privacy Policy." - }, - "auth.welcome.long-title": { - "message": "Welcome to Modrinth!" - }, - "auth.welcome.title": { - "message": "Welcome" - }, "collection.button.edit-icon": { "message": "Edit icon" }, @@ -3302,9 +3371,6 @@ "project.moderation.thread.help-center-note.2": { "message": "If you need assistance or have additional inquiries, please visit the Modrinth Help Center and click the blue bubble to contact support." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Show member UI" - }, "project.moderation.thread.private-description": { "message": "This is a private conversation thread with the Modrinth moderators. They may message you with issues concerning this project." }, @@ -3375,43 +3441,64 @@ "message": "URL" }, "project.settings.permissions.attention-needed.description.proj-approved": { - "message": "Please provide proof that you have permission to redistribute all of the following files and any withheld versions will be automatically published." + "message": "Please provide proof that you have permission to redistribute all of the following files. Once completed, withheld versions will be automatically published." }, "project.settings.permissions.attention-needed.description.proj-draft": { - "message": "Please provide proof that you have permission to redistribute all of the following files before you can submit your project for review." + "message": "Please provide proof that you have permission to redistribute all of the following files before submitting your project for review." }, "project.settings.permissions.attention-needed.title": { - "message": "Unknown embedded content" + "message": "Unknown external content" + }, + "project.settings.permissions.collapse-all": { + "message": "Collapse all" }, "project.settings.permissions.completed.description": { - "message": "All external content has attributions provided." + "message": "All external content has permission information and attributions have been provided." }, "project.settings.permissions.completed.title": { - "message": "Attributions completed!" + "message": "Permissions completed!" }, "project.settings.permissions.empty-state.description": { - "message": "None of your versions contain external content, so you don't need to worry about obtaining permissions." + "message": "None of your project's versions contain external content, so you don't need to worry about obtaining permissions." }, "project.settings.permissions.empty-state.heading": { "message": "You're all set!" }, + "project.settings.permissions.expand-all": { + "message": "Expand all" + }, "project.settings.permissions.fail.description": { - "message": "You don't have permission to redistribute some of the external content you've added. In order to publish on Modrinth, remove the infringing content." + "message": "You may not have permission to redistribute some of the external content in your project. In order to publish on Modrinth, please remove this content or provide proof that you do have permission to use it." }, "project.settings.permissions.fail.title": { "message": "Some content can't be included" }, "project.settings.permissions.info-banner.description": { - "message": "If you include content that isn’t hosted on Modrinth, you need to let us know where it’s from and verify that you have permission to distribute the files. Check out our guide to learn about how to do this properly!" + "message": "If you include content that isn’t hosted on Modrinth, you need to let us know where it’s from and verify that you have permission to distribute the files. Check out our guide to learn more and get started!" }, "project.settings.permissions.info-banner.title": { - "message": "Learn how attributions work" + "message": "Learn about distribution permissions" }, "project.settings.permissions.learn-more": { "message": "Learn more" }, + "project.settings.permissions.no-results": { + "message": "No external files match your search." + }, "project.settings.permissions.search-placeholder": { - "message": "Search {count} {count, plural, one {external project} other {external projects}}..." + "message": "Search {count} {count, plural, one {project} other {projects}}..." + }, + "project.settings.permissions.sort.most-files": { + "message": "Most files" + }, + "project.settings.permissions.sort.recently-edited": { + "message": "Recently edited" + }, + "project.settings.permissions.sort.rejected": { + "message": "Rejected" + }, + "project.settings.permissions.sort.status": { + "message": "Status" }, "project.settings.title": { "message": "Settings" @@ -3434,9 +3521,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {This version is} other {These versions are}} currently withheld and not publicly listed. Please provide proof that you have permission to redistribute certain files included in the modpack {count, plural, one {version} other {versions}}." }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Resolve" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {Version {version_name}} other {Versions}} withheld due to unknown embedded content" }, @@ -4586,6 +4670,48 @@ "ui.newsletter-button.tooltip": { "message": "Subscribe to the Modrinth newsletter" }, + "version.all-versions": { + "message": "All versions" + }, + "version.confirm-delete.description": { + "message": "This version will be permanently deleted. This action cannot be undone." + }, + "version.confirm-delete.proceed": { + "message": "Delete version" + }, + "version.confirm-delete.title": { + "message": "Are you sure you want to delete this version?" + }, + "version.dependency.view-project": { + "message": "View project" + }, + "version.dependency.view-version": { + "message": "View version" + }, + "version.download.download-dependency": { + "message": "Download dependency" + }, + "version.download.no-primary-file": { + "message": "Error: No primary file found" + }, + "version.download.optional-resource-pack": { + "message": "Optional resource pack" + }, + "version.download.required-resource-pack": { + "message": "Required resource pack" + }, + "version.edit.button": { + "message": "Edit" + }, + "version.edit.details": { + "message": "Edit details" + }, + "version.edit.files": { + "message": "Edit files" + }, + "version.edit.metadata": { + "message": "Edit metadata" + }, "version.environment.none.description": { "message": "The environment for this version has not been specified." }, @@ -4597,5 +4723,56 @@ }, "version.environment.unknown.title": { "message": "Unknown environment" + }, + "version.package-as-mod.button": { + "message": "Package as mod" + }, + "version.package-as-mod.description": { + "message": "This will create a new version with support for the selected mod loaders. You will be redirected to the new version and can edit it to your liking." + }, + "version.package-as-mod.header": { + "message": "Packaging data pack as a mod" + }, + "version.package-as-mod.mod-loaders": { + "message": "Mod loaders" + }, + "version.package-as-mod.mod-loaders.description": { + "message": "The mod loaders you would like to package your data pack for." + }, + "version.package-as-mod.mod-loaders.placeholder": { + "message": "Choose mod loaders..." + }, + "version.package-as-mod.submit-button": { + "message": "Package data pack" + }, + "version.section.content.dev-info": { + "message": "Developer information" + }, + "version.section.content.dev-info.gradle-snippet": { + "message": "build.gradle:" + }, + "version.section.content.dev-info.maven-coordinates": { + "message": "Maven coordinates:" + }, + "version.section.content.dev-info.maven-description": { + "message": "Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here." + }, + "version.section.content.dev-info.maven-note": { + "message": "Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API." + }, + "version.section.content.dev-info.version-id": { + "message": "Version ID:" + }, + "version.supplementary-resources.copy-hash-sha1": { + "message": "Copy SHA-1" + }, + "version.supplementary-resources.copy-hash-sha512": { + "message": "Copy SHA-512" + }, + "version.unknown-embedded-content.description": { + "message": "This version is currently withheld and not publicly listed. Please provide proof that you have permission to redistribute certain files included." + }, + "version.unknown-embedded-content.title": { + "message": "Withheld due to unknown embedded content" } } diff --git a/apps/frontend/src/locales/es-419/index.json b/apps/frontend/src/locales/es-419/index.json index d8ada6396f..cacdeb4e5e 100644 --- a/apps/frontend/src/locales/es-419/index.json +++ b/apps/frontend/src/locales/es-419/index.json @@ -3269,9 +3269,6 @@ "project.moderation.thread.help-center-note.2": { "message": "Si necesitas ayuda o tienes consultas adicionales, por favor visita el Centro de ayuda de Modrinth y haz click en la burbuja azúl para contactar con soporte." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Mostrar interfaz de miembros" - }, "project.moderation.thread.private-description": { "message": "Este es un hilo de conversación con los moderadores de Modrinth. Es posible que te envíen mensajes sobre cuestiones relacionadas con este proyecto." }, @@ -3401,9 +3398,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {Esta versión está retenida y no listada} other {Estas versiones están retenidas y no listadas}} públicamente. Por favor, proporciona pruebas de que tienes permiso para redistribuir algunos de los archivos incluidos en {count, plural, one {la versión} other {las versiones}} del modpack." }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Resolver" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {Versión {version_name} retenida} other {Versiones retenidas}} debido a que incluye contenido desconocido" }, diff --git a/apps/frontend/src/locales/es-ES/index.json b/apps/frontend/src/locales/es-ES/index.json index e9d9d71edd..77b293915b 100644 --- a/apps/frontend/src/locales/es-ES/index.json +++ b/apps/frontend/src/locales/es-ES/index.json @@ -3263,9 +3263,6 @@ "project.moderation.thread.help-center-note.2": { "message": "Si necesitas ayuda o tienes consultas adicionales, por favor visita el Centro de ayuda de Modrinth y haz click en la burbuja azul para contactar con soporte." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Mostrar interfaz de miembros" - }, "project.moderation.thread.private-description": { "message": "Este es un hilo de conversación privado con los moderadores de Modrinth. Es posible que te envíen mensajes sobre cuestiones relacionadas con este proyecto." }, @@ -3395,9 +3392,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {Esta versión está retenida y no listada} other {Estas versiones están retenidas y no listadas}} públicamente. Por favor, proporciona pruebas de que tienes permiso para redistribuir algunos de los archivos incluidos en {count, plural, one {la versión} other {las versiones}} del modpack." }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Resolver" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {Versión {version_name} retenida} other {Versiones retenidas}} debido a que incluye contenido desconocido" }, diff --git a/apps/frontend/src/locales/fr-FR/index.json b/apps/frontend/src/locales/fr-FR/index.json index ed05baf1e4..9b07a07b1f 100644 --- a/apps/frontend/src/locales/fr-FR/index.json +++ b/apps/frontend/src/locales/fr-FR/index.json @@ -3263,9 +3263,6 @@ "project.moderation.thread.help-center-note.2": { "message": "Si vous avez besoin d'aide ou si vous avez des demandes de renseignements supplémentaires, veuillez visiter le Modrinth Help Center et cliquez sur la bulle bleue pour contacter le support." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Montrer l'interface des membres" - }, "project.moderation.thread.private-description": { "message": "Il s'agit d'un fil de conversation privé avec les modérateurs du Modrinthe. Ils peuvent vous envoyer un message avec des problèmes concernant ce projet." }, @@ -3395,9 +3392,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {Cette version est actuellement indisponible et n'est pas répertoriée} other {Ces versions sont actuellement indisponibles et n'ont pas été répertoriées}} publiquement. Veuillez fournir la preuve que vous avez l'autorisation de redistribuer certains fichiers inclus dans {count, plural, one {la version} other {les versions}} du modpack." }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Résoudre" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {Version {version_name} non disponible} other {Versions non disponibles}} en raison de contenus intégrés inconnus" }, diff --git a/apps/frontend/src/locales/hu-HU/index.json b/apps/frontend/src/locales/hu-HU/index.json index 4dc0ea2422..f0b86db8a3 100644 --- a/apps/frontend/src/locales/hu-HU/index.json +++ b/apps/frontend/src/locales/hu-HU/index.json @@ -3059,9 +3059,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {Ez a verzió} other {Ezek a verziók}} jelenleg vissza van tartva, és nem érhető{count, plural, one {} other {k}} el nyilvánosan. Kérjük, igazold, hogy engedéllyel rendelkezel a modcsomag {count, plural, one {verziójában} other {verzióiban}} található bizonyos fájlok terjesztésére." }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Megoldás" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {A(z) {version_name} verzió} other {A verziók}} ismeretlen beágyazott tartalom miatt vissza lett{count, plural, one {} other {ek}} tartva" }, diff --git a/apps/frontend/src/locales/it-IT/index.json b/apps/frontend/src/locales/it-IT/index.json index 9ca0bbcd57..12e05f029d 100644 --- a/apps/frontend/src/locales/it-IT/index.json +++ b/apps/frontend/src/locales/it-IT/index.json @@ -3251,9 +3251,6 @@ "project.moderation.thread.help-center-note.2": { "message": "Se hai bisogno di assistenza o hai altre richieste, visita il centro assistenza di Modrinth e clicca sulla bolla blu nell'angolo in basso a destra." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Mostra interfaccia degli utenti" - }, "project.moderation.thread.private-description": { "message": "Questa è una conversazione privata con i moderatori di Modrinth. Sarai contattato per eventuali problemi riguardanti questo progetto." }, @@ -3374,9 +3371,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {Questa versione è attualmente sospesa e non elencata} other {Queste versioni sono attualmente sospese e non elencate}} pubblicamente. Devi dimostrare di avere il permesso di ridistribuire alcuni dei file presenti in {count, plural, one {questa versione} other {queste versioni}} del pacchetto." }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Risolvi" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {La versione {version_name} è stata sospesa} other {Alcune versioni sono state sospese}} per attribuzioni incomplete" }, diff --git a/apps/frontend/src/locales/ko-KR/index.json b/apps/frontend/src/locales/ko-KR/index.json index 5041b7d96a..14f921a8b8 100644 --- a/apps/frontend/src/locales/ko-KR/index.json +++ b/apps/frontend/src/locales/ko-KR/index.json @@ -2750,9 +2750,6 @@ "project.moderation.thread.help-center-note.2": { "message": "도움이 필요하거나 추가 문의 사항이 있다면 Modrinth 도움말 센터를 방문하여 파란색 말풍선을 클릭해 지원 센터에 문의해 주세요." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "멤버 UI 표시" - }, "project.moderation.thread.private-description": { "message": "이곳은 Modrinth 운영진과의 비공개 대화 스레드입니다. 운영진이 이 프로젝트와 관련된 사항에 대해 메시지를 보낼 수 있습니다." }, @@ -2870,9 +2867,6 @@ "project.versions.title": { "message": "버전" }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "해결" - }, "report.already-reported": { "message": "이미 {title} 을(를) 신고했습니다" }, diff --git a/apps/frontend/src/locales/ms-MY/index.json b/apps/frontend/src/locales/ms-MY/index.json index df9f3a70f9..09b73d97d1 100644 --- a/apps/frontend/src/locales/ms-MY/index.json +++ b/apps/frontend/src/locales/ms-MY/index.json @@ -3089,9 +3089,6 @@ "project.moderation.thread.help-center-note.2": { "message": "Jika anda memerlukan bantuan atau mempunyai pertanyaan tambahan, sila lawati Pusat Bantuan Modrinth dan klik gelembung biru untuk menghubungi sokongan." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Tunjukkan antara muka ahli" - }, "project.moderation.thread.private-description": { "message": "Ini adalah bebenang perbualan peribadi dengan penyederhana Modrinth. Mereka mungkin akan menghantar mesej kepada anda tentang isu-isu berkaitan projek ini." }, @@ -3209,9 +3206,6 @@ "project.versions.title": { "message": "Versi" }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Selesaikan" - }, "report.already-reported": { "message": "Anda telah melaporkan {title}" }, diff --git a/apps/frontend/src/locales/pl-PL/index.json b/apps/frontend/src/locales/pl-PL/index.json index 9239b27337..e30fb73c8b 100644 --- a/apps/frontend/src/locales/pl-PL/index.json +++ b/apps/frontend/src/locales/pl-PL/index.json @@ -3131,9 +3131,6 @@ "project.moderation.thread.help-center-note.2": { "message": "Jeżeli potrzebujesz pomocy lub masz więcej pytań, odwiedź centrum pomocy Modrinth i kliknij w niebieskie kółko, by skontaktować się z obsługą." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Pokaż UI członków" - }, "project.moderation.thread.private-description": { "message": "Prywatny wątek konwersacji z moderatorami Modrinth. Mogą skontaktować się z Tobą w razie problemów z Twoim projektem." }, @@ -3260,9 +3257,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {Ta wersja jest} other {Te wersje są}} obecnie wstrzymane i nie widnieją na publicznej liście. Proszę o przesłanie potwierdzenia posiadania zgody na redystrybucję określonych plików zawartych w {count, plural, one {tej wersji} other {tych wersjach}} modpacka." }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Rozwiąż" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {Wersja {version_name}} other {Wersje}} wstrzymane ze względu na nieznaną osadzoną zawartość" }, diff --git a/apps/frontend/src/locales/pt-BR/index.json b/apps/frontend/src/locales/pt-BR/index.json index 1f80901c55..b4e5497a06 100644 --- a/apps/frontend/src/locales/pt-BR/index.json +++ b/apps/frontend/src/locales/pt-BR/index.json @@ -3260,9 +3260,6 @@ "project.moderation.thread.help-center-note.2": { "message": "Se precisar de ajuda ou tiver dúvidas adicionais, visite a Central de Ajuda do Modrinth e clique no balão azul para entrar em contato com o suporte." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Exibir interface do membro" - }, "project.moderation.thread.private-description": { "message": "Este é um tópico de conversa privada com os moderadores do Modrinth. Eles podem entrar em contato com você para tratar de assuntos relacionados a este projeto." }, @@ -3386,9 +3383,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {Esta versão está atualmente retida e não listada} other {Estas versões estão atualmente retidas e não listadas}} publicamente. Por favor, forneça prova de que você tem permissão para redistribuir certos arquivos incluídos {count, plural, one {na versão} other {nas versões}} do pacote de mods." }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Resolver" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural,one {Versão {version_name} retida} other {Versões retidas}} por conteúdo incluso desconhecido" }, diff --git a/apps/frontend/src/locales/ru-RU/index.json b/apps/frontend/src/locales/ru-RU/index.json index 914cfffec2..97ab36ab80 100644 --- a/apps/frontend/src/locales/ru-RU/index.json +++ b/apps/frontend/src/locales/ru-RU/index.json @@ -3203,9 +3203,6 @@ "project.moderation.thread.help-center-note.2": { "message": "Если вам нужна помощь или у вас есть дополнительные вопросы, посетите справочный центр Modrinth и нажмите на синий значок, чтобы обратиться в поддержку." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Показать интерфейс участника" - }, "project.moderation.thread.private-description": { "message": "Это приватная переписка с модераторами Modrinth. Они могут связываться с вами по вопросам, связанным с этим проектом." }, @@ -3329,9 +3326,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {Эта версия в настоящее время скрыта и не отображается} other {Эти версии в настоящее время скрыты и не отображаются}} в публичном списке. Пожалуйста, предоставьте доказательства того, что у вас есть разрешение на распространение определённых файлов, включённых в {count, plural, one {эту версию} other {эти версии}}." }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Решить" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {Версия {version_name} скрыта} other {Версии скрыты}} из-за неизвестного встроенного контента" }, diff --git a/apps/frontend/src/locales/tr-TR/index.json b/apps/frontend/src/locales/tr-TR/index.json index 692bd390d5..997a967fa9 100644 --- a/apps/frontend/src/locales/tr-TR/index.json +++ b/apps/frontend/src/locales/tr-TR/index.json @@ -3257,9 +3257,6 @@ "project.moderation.thread.help-center-note.2": { "message": "Yardıma ihtiyacınız varsa veya ek sorularınız varsa, lütfen Modrinth Yardım Merkezi'ni ziyaret edin ve destekle iletişime geçmek için mavi baloncuğa tıklayın." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Üye kullanıcı arayüzünü göster" - }, "project.moderation.thread.private-description": { "message": "Bu, Modrinth moderatörleri ile özel bir konuşma başlığıdır. Bu projeyle ilgili konularda size mesaj gönderebilirler." }, @@ -3389,9 +3386,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {Bu sürüm} other {Bu sürümler}} şu anda gizlenmiş durumda ve herkese açık olarak listelenmiyor. Lütfen {count, plural, one {sürüm} other {sürümler}} mod paketine dahil edilen belirli dosyaları yeniden dağıtma izniniz olduğuna dair kanıt sunun." }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Çöz" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {Sürüm {version_name}} other {Sürümler}} bilinmeyen gömülü içerik nedeniyle gizlendi" }, diff --git a/apps/frontend/src/locales/uk-UA/index.json b/apps/frontend/src/locales/uk-UA/index.json index 20985c12e2..89906e2e1f 100644 --- a/apps/frontend/src/locales/uk-UA/index.json +++ b/apps/frontend/src/locales/uk-UA/index.json @@ -2975,9 +2975,6 @@ "project.moderation.thread.help-center-note.2": { "message": "Якщо вам потрібна допомога або у вас є додаткові запитання, відвідайте довідковий центр Modrinth і натисніть синю підказку, щоб зв’язатися зі службою підтримки." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Показати інтерфейс учасника" - }, "project.moderation.thread.private-description": { "message": "Це тема приватної розмови з модераторами Modrinth. Вони можуть надіслати вам повідомлення про проблеми щодо цього проєкту." }, @@ -3095,9 +3092,6 @@ "project.versions.title": { "message": "Версії" }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Розв'язати" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {Версія{version_name}} other {Версії}} утримано через невідомий убудований уміст" }, diff --git a/apps/frontend/src/locales/vi-VN/index.json b/apps/frontend/src/locales/vi-VN/index.json index ebb29031ca..1994c156f4 100644 --- a/apps/frontend/src/locales/vi-VN/index.json +++ b/apps/frontend/src/locales/vi-VN/index.json @@ -3203,9 +3203,6 @@ "project.moderation.thread.help-center-note.2": { "message": "Nếu bạn cần trợ giúp hoặc có thắc mắc, vui lòng vào trung tâm trợ giúp và bấm vào nút tin nhắn màu xanh để liên hệ hỗ trợ." }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "Hiển thị giao diện thành viên" - }, "project.moderation.thread.private-description": { "message": "Đây là nơi hội thoại riêng tư với bên kiểm duyệt của Modrinth. Họ có thể nhắn cho bạn về những vấn đề trong dự án này." }, @@ -3323,9 +3320,6 @@ "project.versions.title": { "message": "Phiên bản" }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "Khắc phục" - }, "report.already-reported": { "message": "Bạn đã báo cáo {title}" }, diff --git a/apps/frontend/src/locales/zh-CN/index.json b/apps/frontend/src/locales/zh-CN/index.json index 409d09c955..50f50376cd 100644 --- a/apps/frontend/src/locales/zh-CN/index.json +++ b/apps/frontend/src/locales/zh-CN/index.json @@ -3236,9 +3236,6 @@ "project.moderation.thread.help-center-note.2": { "message": "如果你需要帮助或有其他疑问,请访问 Modrinth Help Center,然后点击蓝色气泡以联系支持。" }, - "project.moderation.thread.moderator-see-user-ui-toggle": { - "message": "显示成员图形界面" - }, "project.moderation.thread.private-description": { "message": "这是与 Modrinth 管理员的私人对话消息。他们可能会就此项目的问题向你发送消息。" }, @@ -3365,9 +3362,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {此版本已保留且未公开列出。} other {这些版本已保留且未公开列出。}} 请提供证明,证明你有权重新分发该模组包{count, plural, one {版本} other {各版本}}中包含的某些文件。" }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "完成" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {版本 {version_name}} other {这些版本}} 因未知嵌入内容被保留" }, diff --git a/apps/frontend/src/locales/zh-TW/index.json b/apps/frontend/src/locales/zh-TW/index.json index bc17189759..c6aaae63dc 100644 --- a/apps/frontend/src/locales/zh-TW/index.json +++ b/apps/frontend/src/locales/zh-TW/index.json @@ -2966,9 +2966,6 @@ "project.versions.withheld-versions-warning.description": { "message": "{count, plural, one {這個版本} other {這些版本}}目前被限制存取且不公開。請提供你擁有轉載該模組包{count, plural, other {版本}}版本中特定檔案的許可證明。" }, - "project.versions.withheld-versions-warning.resolve-button": { - "message": "解決" - }, "project.versions.withheld-versions-warning.title": { "message": "{count, plural, one {版本 {version_name}} other {版本}}因未知的嵌入內容而被限制存取" }, diff --git a/apps/frontend/src/pages/[type]/[project].vue b/apps/frontend/src/pages/[type]/[project].vue index c1ad655e77..8c74d10fde 100644 --- a/apps/frontend/src/pages/[type]/[project].vue +++ b/apps/frontend/src/pages/[type]/[project].vue @@ -881,7 +881,9 @@ class="card flex-card" /> {{ formatMessage(messages.threadSectionTitle) }} -
+
- +