diff --git a/.agents/skills/api-module/SKILL.md b/.agents/skills/api-module/SKILL.md
new file mode 100644
index 0000000000..32cc16756b
--- /dev/null
+++ b/.agents/skills/api-module/SKILL.md
@@ -0,0 +1,23 @@
+---
+name: api-module
+description: Add an API endpoint module to packages/api-client from an OpenAPI schema. Use for new backend endpoints, API client modules, or tasks that provide an OpenAPI schema.
+---
+
+# Add an API Module
+
+Read the applicable `AGENTS.md` files before you edit code.
+
+Read [the API module standard](../../../standards/frontend/ADDING_API_MODULES.md) in full.
+
+1. Identify the OpenAPI schema from the request. If more than one schema is possible, ask the user to select one.
+2. Read the schema. Identify each endpoint, HTTP method, request type, response type, and path parameter.
+3. Get the service and version from the URL prefix. For example, map `/v3/projects` to `labrinth/v3/`.
+4. Define the API types in `types.ts`. Make each type match the schema exactly.
+5. Do not change, rename, or remove API fields.
+6. Make a module class that extends `AbstractModule`. Implement each endpoint with `this.client.request()` or `this.client.upload()`.
+7. Use the request-option pattern from the standard. Do not call `$fetch`, `fetch`, or another HTTP client directly.
+8. Add the module to `MODULE_REGISTRY` so the client can instantiate it.
+9. Export new service types from the applicable barrel `index.ts`.
+10. Check the module paths, registry key, public type exports, and endpoint types.
+
+Run only the checks that the user or the applicable `AGENTS.md` permits.
diff --git a/.agents/skills/api-module/agents/openai.yaml b/.agents/skills/api-module/agents/openai.yaml
new file mode 100644
index 0000000000..c8dd768afe
--- /dev/null
+++ b/.agents/skills/api-module/agents/openai.yaml
@@ -0,0 +1,4 @@
+interface:
+ display_name: "Add API Module"
+ short_description: "Add typed API client modules from OpenAPI"
+ default_prompt: "Use $api-module to add an API client module from this OpenAPI schema."
diff --git a/.agents/skills/cross-platform-pages/SKILL.md b/.agents/skills/cross-platform-pages/SKILL.md
new file mode 100644
index 0000000000..2399604821
--- /dev/null
+++ b/.agents/skills/cross-platform-pages/SKILL.md
@@ -0,0 +1,38 @@
+---
+name: cross-platform-pages
+description: Convert a page to the shared Modrinth page system for the website and desktop app. Use for shared layouts, wrapped layouts, or platform dependency-injection contracts.
+---
+
+# Convert a Cross-Platform Page
+
+Read the applicable `AGENTS.md` files before you edit code.
+
+Read these standards in full:
+
+- [Cross-platform pages](../../../standards/frontend/CROSS_PLATFORM_PAGES.md)
+- [Dependency injection](../../../standards/frontend/DEPENDENCY_INJECTION.md)
+
+1. Identify the target page from the request.
+2. Read the page and its route shell. Identify data sources, mutations, navigation, and platform APIs.
+3. Use a wrapped layout when both platforms use the same API source and page logic.
+4. Use a shared layout when platform data or operations have different implementations.
+
+For a shared layout:
+
+1. Define a provider contract for all platform operations.
+2. Put common UI and state logic in the shared layout.
+3. Put reusable search, filter, and selection logic in local composables.
+4. Implement the contract in `apps/frontend/` and `apps/app-frontend/`.
+5. Use optional contract fields only for capabilities that are not available on both platforms.
+
+For a wrapped layout:
+
+1. Move the page to `packages/ui/src/layouts/wrapped/` and preserve its route structure.
+2. Replace platform-only imports with common utilities or provider calls.
+3. Make each frontend route shell render the wrapped component.
+4. Match primary query options in both route shells when the layout uses `ReadyTransition` and `useReadyState`.
+5. Prefetch these queries with `ensureQueryData`, as the standard specifies.
+
+Check that both route shells resolve their imports. Check that all required provider fields have implementations.
+
+Run only the checks that the user or the applicable `AGENTS.md` permits.
diff --git a/.agents/skills/cross-platform-pages/agents/openai.yaml b/.agents/skills/cross-platform-pages/agents/openai.yaml
new file mode 100644
index 0000000000..ad15d4df68
--- /dev/null
+++ b/.agents/skills/cross-platform-pages/agents/openai.yaml
@@ -0,0 +1,4 @@
+interface:
+ display_name: "Convert Cross-Platform Page"
+ short_description: "Share pages across the web and desktop app"
+ default_prompt: "Use $cross-platform-pages to convert this page for the website and desktop app."
diff --git a/.agents/skills/figma-mcp/SKILL.md b/.agents/skills/figma-mcp/SKILL.md
new file mode 100644
index 0000000000..b6d99eecca
--- /dev/null
+++ b/.agents/skills/figma-mcp/SKILL.md
@@ -0,0 +1,21 @@
+---
+name: figma-mcp
+description: Convert a Figma design into a Modrinth Vue page or component. Use when a request provides a Figma URL or asks to implement a Figma layout.
+---
+
+# Implement a Figma Design
+
+Read the applicable `AGENTS.md` files before you edit code.
+
+Read `packages/ui/AGENTS.md` in full.
+
+1. Load the available Figma design-to-code instructions and follow the MCP tool guidance.
+2. Call `get_design_context` first with `clientLanguages: "typescript,html,css"` and `clientFrameworks: "vue"`.
+3. Treat the result as reference code and adapt it to the Modrinth codebase.
+4. Map Figma color variables to the applicable `surface-*` and `text-*` tokens. Do not use aliased Figma names directly.
+5. Reuse applicable components from `packages/ui/src/components/` before creating new ones. Also refer to `standards/frontend/COMPONENT_STRUCTURE.md`
+6. Read `packages/assets/styles/variables.scss` when Figma does not supply a required token.
+7. Use exact spacing values from the design.
+8. Implement the result as a Vue SFC with Tailwind classes and the existing component library.
+
+Run only the checks that the user or the applicable `AGENTS.md` permits.
diff --git a/.agents/skills/figma-mcp/agents/openai.yaml b/.agents/skills/figma-mcp/agents/openai.yaml
new file mode 100644
index 0000000000..1a7c61d304
--- /dev/null
+++ b/.agents/skills/figma-mcp/agents/openai.yaml
@@ -0,0 +1,4 @@
+interface:
+ display_name: "Implement Figma Design"
+ short_description: "Build Modrinth Vue UI from Figma designs"
+ default_prompt: "Use $figma-mcp to implement this Figma design as a Modrinth Vue component."
diff --git a/.agents/skills/i18n-pass/SKILL.md b/.agents/skills/i18n-pass/SKILL.md
new file mode 100644
index 0000000000..05f69de695
--- /dev/null
+++ b/.agents/skills/i18n-pass/SKILL.md
@@ -0,0 +1,32 @@
+---
+name: i18n-pass
+description: Convert hard-coded English text in changed Vue components to the @modrinth/ui localization system. Use for an i18n pass, untranslated-string review, pull request, or component migration.
+---
+
+# Do an Internationalization Pass
+
+Read the applicable `AGENTS.md` files before you edit code.
+
+Read [the internationalization standard](../../../standards/frontend/INTERNATIONALIZATION.md) in full.
+
+1. Identify the scope from the request.
+2. For a pull request, use `gh pr diff ` to identify changed files.
+3. For a file path, inspect that file.
+4. When the request gives no scope, inspect the current uncommitted diff.
+5. Limit the pass to changed `.vue` files.
+6. Find user-visible text in templates and scripts.
+
+Check inner text, `alt`, `placeholder`, `aria-label`, buttons, tooltips, notifications, dropdown labels, and error messages.
+
+Do not change dynamic expressions, HTML tag names, CSS classes, internal identifiers, or log messages.
+
+1. Define stable message IDs with `defineMessage` or `defineMessages`.
+2. Replace simple text with `formatMessage()` calls.
+3. Use `` for text that contains links or markup.
+4. Use ICU selections and plurals when grammar depends on a value.
+5. Add a space before `}}` when an ICU placeholder ends at the Vue delimiter.
+6. Do not change component logic, layout, or reactivity.
+7. Do not edit localization JSON files. The user maintains those files.
+8. Check the changed templates again for hard-coded English text.
+
+Run only the checks that the user or the applicable `AGENTS.md` permits.
diff --git a/.agents/skills/i18n-pass/agents/openai.yaml b/.agents/skills/i18n-pass/agents/openai.yaml
new file mode 100644
index 0000000000..347ef98b2d
--- /dev/null
+++ b/.agents/skills/i18n-pass/agents/openai.yaml
@@ -0,0 +1,4 @@
+interface:
+ display_name: "Run Internationalization Pass"
+ short_description: "Localize user-visible text in Vue files"
+ default_prompt: "Use $i18n-pass to localize the user-visible text in these changed Vue files."
diff --git a/.agents/skills/review-changelog/SKILL.md b/.agents/skills/review-changelog/SKILL.md
new file mode 100644
index 0000000000..5ab041c1c9
--- /dev/null
+++ b/.agents/skills/review-changelog/SKILL.md
@@ -0,0 +1,40 @@
+---
+name: review-changelog
+description: Review the latest packages/blog/changelog.ts entry against the Modrinth changelog standard. Use before a pull request or when asked to review or lint a changelog entry.
+---
+
+# Review a Changelog Entry
+
+Read [the changelog standard](../../../standards/maintaining/CHANGELOG.md) in full before the review.
+
+1. Open `packages/blog/changelog.ts`.
+2. Find the first entry in the `VERSIONS` array.
+3. If the request names `web`, `hosting`, or `app`, review the latest entry for that product.
+4. Otherwise, review the latest entry and all adjacent entries with the same date.
+
+Check the entry structure:
+
+- `date` contains a valid ISO 8601 timestamp.
+- `product` is `web`, `hosting`, or `app`.
+- An `app` entry has a `version` value.
+- A `web` or `hosting` entry does not have a `version` value.
+- Standard headings are `## Added`, `## Changed`, `## Fixed`, and `## Security`.
+- A featured release can use a linked heading.
+- Flag the legacy `## Improvements` heading.
+
+Check each bullet:
+
+- The voice and tense agree with the section.
+- The first verb agrees with the section.
+- The bullet describes user-visible behavior, not implementation.
+- The bullet identifies the applicable page, tab, modal, or feature.
+- The bullet contains one sentence, uses sentence case, and ends with a period.
+- Product and UI names use the public labels.
+- The bullet does not contain filler, vague intensifiers, apologies, or internal references.
+- The bullet is not a duplicate detail of a larger listed change.
+
+Group findings by entry. For each finding, show the original bullet and a proposed replacement.
+
+If the entry has no findings, state this result. Do not edit the changelog unless the user asks you to apply fixes.
+
+When the user asks for fixes, preserve tab indentation and template-literal formatting.
diff --git a/.agents/skills/review-changelog/agents/openai.yaml b/.agents/skills/review-changelog/agents/openai.yaml
new file mode 100644
index 0000000000..421afc3587
--- /dev/null
+++ b/.agents/skills/review-changelog/agents/openai.yaml
@@ -0,0 +1,4 @@
+interface:
+ display_name: "Review Changelog"
+ short_description: "Review changelog entries for style problems"
+ default_prompt: "Use $review-changelog to review the latest changelog entry."
diff --git a/.agents/skills/tanstack-query/SKILL.md b/.agents/skills/tanstack-query/SKILL.md
new file mode 100644
index 0000000000..71c3ecc71b
--- /dev/null
+++ b/.agents/skills/tanstack-query/SKILL.md
@@ -0,0 +1,39 @@
+---
+name: tanstack-query
+description: Convert Vue server-state code to TanStack Query. Use for useQuery, useMutation, cache invalidation, optimistic updates, or replacement of useAsyncData and manual ref patterns.
+---
+
+# Convert Data Code to TanStack Query
+
+Read the applicable `AGENTS.md` files before you edit code.
+
+Read [the TanStack Query standard](../../../standards/frontend/FETCHING_DATA.md) in full.
+
+1. Identify the target file from the request.
+2. Find `useAsyncData`, `useFetch`, manual API refs, and fetch calls in `onMounted`.
+3. Identify mutations that use manual loading, error, or result refs.
+
+For queries:
+
+1. Replace manual fetch logic with `useQuery`.
+2. Get `api-client` with `injectModrinthClient()`.
+3. Use a hierarchical query key with the resource, qualifier, and parameters.
+4. Use a computed query key for reactive parameters.
+5. Use a computed `enabled` option when the query depends on other data.
+6. Use a shared query-option factory when multiple components use the query.
+
+For mutations:
+
+1. Replace manual mutation state with `useMutation`.
+2. Invalidate or update related query data after success.
+3. Use an optimistic update only when the UI needs an immediate response.
+4. Cancel the applicable query and save its prior data before an optimistic update.
+5. Restore the prior data after an error. Invalidate the query after settlement.
+
+Remove manual loading and error refs that TanStack Query replaces. Remove obsolete `onMounted` fetch calls.
+
+Keep Nuxt SSR behavior. Match route-shell prefetch options when `ReadyTransition` and `useReadyState` depend on the query.
+
+Check query keys, invalidation prefixes, reactive values, and rollback data.
+
+Run only the checks that the user or the applicable `AGENTS.md` permits.
diff --git a/.agents/skills/tanstack-query/agents/openai.yaml b/.agents/skills/tanstack-query/agents/openai.yaml
new file mode 100644
index 0000000000..2db5ece878
--- /dev/null
+++ b/.agents/skills/tanstack-query/agents/openai.yaml
@@ -0,0 +1,4 @@
+interface:
+ display_name: "Migrate to TanStack Query"
+ short_description: "Migrate Vue server state to TanStack Query"
+ default_prompt: "Use $tanstack-query to migrate this Vue component to TanStack Query."
diff --git a/.claude/skills/api-module/SKILL.md b/.claude/skills/api-module/SKILL.md
deleted file mode 100644
index 37b4ac7788..0000000000
--- a/.claude/skills/api-module/SKILL.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-name: api-module
-description: Add a new API endpoint module to packages/api-client from an OpenAPI schema. Use when adding new backend endpoints, creating API client modules, or when an openapi.yml is provided.
-argument-hint:
----
-
-Refer to the standard: @standards/frontend/ADDING_API_MODULES.md
-
-## Steps
-
-1. **Read the OpenAPI schema** at `$ARGUMENTS` — identify the endpoints, request/response shapes, and path parameters.
-2. **Read the standard above** for naming conventions, type rules, and the module registration pattern.
-3. **Determine the service and version** — the URL path prefix tells you which service directory and version namespace to use (e.g. `/v3/projects` → `labrinth/v3/`).
-4. **Define types in `types.ts`** — types must match the API response 1:1. Use the OpenAPI schema as the source of truth. Do not reshape or rename fields.
-5. **Create the module class** — extend `BaseModule`, implement each endpoint as a method. Use the correct HTTP verb and request options pattern from the standard.
-6. **Register in `MODULE_REGISTRY`** — add the module entry so it's auto-instantiated on the client.
-7. **Export types** from the service's barrel `index.ts`.
-8. **Verify** — check that the module compiles and the types are accessible from `@modrinth/api-client`.
diff --git a/.claude/skills/cross-platform-pages/SKILL.md b/.claude/skills/cross-platform-pages/SKILL.md
deleted file mode 100644
index 6558eed3c3..0000000000
--- a/.claude/skills/cross-platform-pages/SKILL.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-name: cross-platform-pages
-description: Convert a page to the cross-platform page system so it works in both the website and the desktop app. Use when moving a page into packages/ui/src/layouts/, creating shared or wrapped layouts, or setting up DI contracts for platform abstraction.
-argument-hint:
----
-
-Refer to the standards: @standards/frontend/CROSS_PLATFORM_PAGES.md and @standards/frontend/DEPENDENCY_INJECTION.md
-
-## Steps
-
-1. **Read the target page** at `$ARGUMENTS` and understand its data sources, mutations, and navigation.
-2. **Read the standards above** to understand the shared vs wrapped distinction and the DI pattern.
-3. **Decide the category:**
- - **Wrapped** (`layouts/wrapped/`) — if the page uses the same API source on both platforms (e.g. web requests, not Tauri plugins). Just move the page component into `packages/ui` and import it from both frontends.
- - **Shared** (`layouts/shared/`) — if the page has different data-fetching logic per platform (e.g. website uses `api-client`, app uses Tauri `invoke`). Requires a DI contract.
-4. **For shared layouts:**
- - Define a DI contract interface in `providers/` capturing all platform-specific operations.
- - Create the layout component that injects the context and handles all UI logic.
- - Extract reusable stateful logic (search, filtering, selection) into `composables/`.
- - Implement the contract separately in each frontend (`apps/frontend/`, `apps/app-frontend/`).
-5. **For wrapped pages:**
- - Move the page component into `packages/ui/src/layouts/wrapped/` matching the route structure.
- - Replace any platform-specific imports with shared utilities.
- - Import and render the wrapped page from both frontends as a simple component.
- - If the layout uses TanStack Query for initial route paint with `ReadyTransition` / `useReadyState`, each platform route shell must call `ensureQueryData` for those queries with matching keys and fetchers — see **Platform route shells: prefetch with `ensureQueryData`** in `standards/frontend/CROSS_PLATFORM_PAGES.md`.
-6. **Verify** the page renders correctly by checking for missing imports and that all DI contracts are satisfied.
diff --git a/.claude/skills/figma-mcp/SKILL.md b/.claude/skills/figma-mcp/SKILL.md
deleted file mode 100644
index defabf8d2e..0000000000
--- a/.claude/skills/figma-mcp/SKILL.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-name: figma-mcp
-description: Use the Figma MCP server to translate a Figma design into a Vue page or component layout. Use when the user provides a Figma URL, asks to implement a design, or wants to draft a page layout from Figma.
-argument-hint:
----
-
-Refer to the standard: @standards/frontend/FIGMA_MCP_USAGE.md
-Also read @packages/ui/CLAUDE.md for color token mapping and component conventions.
-
-## Steps
-
-1. **Parse the Figma URL** from `$ARGUMENTS` — extract the `fileKey` and `nodeId`. Convert `-` to `:` in the node ID.
-2. **Read the standards above** for the available tools, adaptation rules, and color usage.
-3. **Call `get_design_context`** with the extracted `nodeId` and `fileKey`, using `clientLanguages: "typescript,html,css"` and `clientFrameworks: "vue"`. This is always the first tool to call.
-5. **Adapt the output to the Modrinth codebase:**
- - Map Figma color variables to `surface-*` / `text-*` tokens — never use Figma's aliased names directly.
- - Check `packages/ui/src/components/` for existing components that match elements in the design (buttons, cards, modals, inputs, etc.).
- - Check `packages/assets/styles/variables.scss` for tokens not exposed in Figma.
- - Match spacing values exactly from the design.
-6. **Use `get_screenshot`** if you need a closer visual reference of specific nodes.
-7. **Use `get_variable_defs`** to verify which design tokens are applied to ambiguous elements.
-8. **Build the component** as a Vue SFC using Tailwind classes and the project's existing component library.
diff --git a/.claude/skills/i18n-pass/SKILL.md b/.claude/skills/i18n-pass/SKILL.md
deleted file mode 100644
index 7edd69996c..0000000000
--- a/.claude/skills/i18n-pass/SKILL.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-name: i18n-pass
-description: Perform an i18n localization pass on changed files or a pull request, converting hard-coded English strings to the @modrinth/ui i18n system. Use when internationalizing a set of changes, reviewing a PR for untranslated strings, or converting a specific component.
-argument-hint: [file-path-or-pr-number]
----
-
-Refer to the standard: @standards/frontend/INTERNATIONALIZATION.md
-
-## Steps
-
-1. **Identify the scope of changes:**
- - If `$ARGUMENTS` is a PR number, run `gh pr diff $ARGUMENTS` to get the changed files.
- - If `$ARGUMENTS` is a file path, use that directly.
- - If no argument, check `git diff` for uncommitted changes.
-2. **Read the standard above** for the message definition pattern, ICU format rules, and `IntlFormatted` usage.
-3. **Filter to Vue SFCs** — only `.vue` files need i18n passes. Skip non-component files.
-4. **For each file, scan for hard-coded strings:**
- - ``: inner text, `alt`, `placeholder`, `aria-label`, button labels, tooltip text.
- - `
@@ -278,26 +198,24 @@ function isExportCandidateDisabled(path) {
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
- {{ formatMessage(messages.exportButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+ {{ formatMessage(messages.exportButton) }}
+
diff --git a/apps/app-frontend/src/components/ui/Instance.vue b/apps/app-frontend/src/components/ui/Instance.vue
index 6845a00f2b..7c82504eb1 100644
--- a/apps/app-frontend/src/components/ui/Instance.vue
+++ b/apps/app-frontend/src/components/ui/Instance.vue
@@ -7,7 +7,7 @@ import {
StopCircleIcon,
TimerIcon,
} from '@modrinth/assets'
-import { Avatar, ButtonStyled, injectNotificationManager, useRelativeTime } from '@modrinth/ui'
+import { Avatar, IconButton, injectNotificationManager, useRelativeTime } from '@modrinth/ui'
import { convertFileSrc } from '@tauri-apps/api/core'
import dayjs from 'dayjs'
import { computed, onMounted, onUnmounted, ref } from 'vue'
@@ -168,30 +168,37 @@ onUnmounted(() => unlisten())
{{ instance.name }}
-
- stop(e, 'InstanceCard')">
-
-
-
-
-
-
-
-
-
stop(e, 'InstanceCard')"
>
- play(e, 'InstanceCard')"
- @mousehover="checkProcess"
- >
-
-
-
-
+
+
+
+
+
+
play(e, 'InstanceCard')"
+ @mouseenter="checkProcess"
+ >
+
+
+
@@ -219,47 +226,51 @@ onUnmounted(() => unlisten())
:class="`transition-all ${modLoading || installing ? `brightness-[0.25] scale-[0.85]` : `group-hover:brightness-75`}`"
/>
-
- stop(e, 'InstanceCard')"
- @mousehover="checkProcess"
- >
-
-
-
+
stop(e, 'InstanceCard')"
+ @mouseenter="checkProcess"
+ >
+
+
-
repair(e)"
>
- repair(e)"
- >
-
-
-
-
- play(e, 'InstanceCard')"
- @mousehover="checkProcess"
- >
-
-
-
+
+
+
play(e, 'InstanceCard')"
+ @mouseenter="checkProcess"
+ >
+
+
diff --git a/apps/app-frontend/src/components/ui/InstanceIndicator.vue b/apps/app-frontend/src/components/ui/InstanceIndicator.vue
index 2787635117..cb077c4bfb 100644
--- a/apps/app-frontend/src/components/ui/InstanceIndicator.vue
+++ b/apps/app-frontend/src/components/ui/InstanceIndicator.vue
@@ -1,6 +1,6 @@
diff --git a/apps/app-frontend/src/components/ui/instance/instance-admonitions/index.vue b/apps/app-frontend/src/pages/instance/components/admonitions/index.vue
similarity index 91%
rename from apps/app-frontend/src/components/ui/instance/instance-admonitions/index.vue
rename to apps/app-frontend/src/pages/instance/components/admonitions/index.vue
index e16171bc5b..5e4d996ad6 100644
--- a/apps/app-frontend/src/components/ui/instance/instance-admonitions/index.vue
+++ b/apps/app-frontend/src/pages/instance/components/admonitions/index.vue
@@ -36,11 +36,11 @@ import { computed, ref, watch } from 'vue'
import type { SharedInstanceUnavailableReason } from '@/helpers/install'
import type { GameInstance } from '@/helpers/types'
-import InstanceAdmonitionsSharedInstanceStale from './instance-admonitions-shared-instance-stale.vue'
-import InstanceAdmonitionsSharedInstanceUnavailable from './instance-admonitions-shared-instance-unavailable.vue'
-import InstanceAdmonitionsSharedInstanceUpdateAvailable from './instance-admonitions-shared-instance-update-available.vue'
-import InstanceAdmonitionsSharedInstanceWrongAccount from './instance-admonitions-shared-instance-wrong-account.vue'
-import type { InstanceAdmonitionItem, SharedInstanceRole } from './types'
+import InstanceAdmonitionsSharedInstanceStale from './shared-instance-stale.vue'
+import InstanceAdmonitionsSharedInstanceUnavailable from './shared-instance-unavailable.vue'
+import InstanceAdmonitionsSharedInstanceUpdateAvailable from './shared-instance-update-available.vue'
+import InstanceAdmonitionsSharedInstanceWrongAccount from './shared-instance-wrong-account.vue'
+import type { InstanceAdmonitionItem, SharedInstanceRole } from './types.ts'
defineOptions({
inheritAttrs: false,
diff --git a/apps/app-frontend/src/components/ui/instance/instance-admonitions/instance-admonitions-messages.ts b/apps/app-frontend/src/pages/instance/components/admonitions/messages.ts
similarity index 100%
rename from apps/app-frontend/src/components/ui/instance/instance-admonitions/instance-admonitions-messages.ts
rename to apps/app-frontend/src/pages/instance/components/admonitions/messages.ts
diff --git a/apps/app-frontend/src/components/ui/instance/instance-admonitions/instance-admonitions-shared-instance-stale.vue b/apps/app-frontend/src/pages/instance/components/admonitions/shared-instance-stale.vue
similarity index 63%
rename from apps/app-frontend/src/components/ui/instance/instance-admonitions/instance-admonitions-shared-instance-stale.vue
rename to apps/app-frontend/src/pages/instance/components/admonitions/shared-instance-stale.vue
index e437bfe1cf..63d053a91e 100644
--- a/apps/app-frontend/src/components/ui/instance/instance-admonitions/instance-admonitions-shared-instance-stale.vue
+++ b/apps/app-frontend/src/pages/instance/components/admonitions/shared-instance-stale.vue
@@ -6,23 +6,27 @@
>
{{ formatMessage(messages.sharedInstanceChangesBody) }}
-
-
-
-
- {{
- isPublishing
- ? formatMessage(messages.sharedInstancePublishingButton)
- : isReviewingPublish
- ? formatMessage(messages.sharedInstanceReviewingButton)
- : formatMessage(messages.sharedInstancePublishButton)
- }}
-
-
+
+
+
+ {{
+ isPublishing
+ ? formatMessage(messages.sharedInstancePublishingButton)
+ : isReviewingPublish
+ ? formatMessage(messages.sharedInstanceReviewingButton)
+ : formatMessage(messages.sharedInstancePublishButton)
+ }}
+
@@ -36,13 +40,13 @@
-
-
diff --git a/apps/app-frontend/src/pages/instance/Logs.vue b/apps/app-frontend/src/pages/instance/logs/index.vue
similarity index 73%
rename from apps/app-frontend/src/pages/instance/Logs.vue
rename to apps/app-frontend/src/pages/instance/logs/index.vue
index 6a08117dd7..fd8add17f7 100644
--- a/apps/app-frontend/src/pages/instance/Logs.vue
+++ b/apps/app-frontend/src/pages/instance/logs/index.vue
@@ -11,51 +11,20 @@ import {
injectNotificationManager,
provideConsoleManager,
} from '@modrinth/ui'
+import { useQuery } from '@tanstack/vue-query'
import { computed, onUnmounted, ref, shallowRef, triggerRef, watch, watchEffect } from 'vue'
-import { useRoute } from 'vue-router'
import { useInstanceConsole } from '@/composables/useInstanceConsole'
import { log_listener, process_listener } from '@/helpers/events.js'
import { delete_logs_by_filename, get_output_by_filename } from '@/helpers/logs.js'
+import { injectInstancePage } from '../instance-context'
+import { instanceKeys } from '../query-options'
+
const client = injectModrinthClient()
const { handleError } = injectNotificationManager()
-const route = useRoute()
-
-const props = defineProps({
- instance: {
- type: Object,
- default() {
- return {}
- },
- },
- options: {
- type: Object,
- default() {
- return {}
- },
- },
- offline: {
- type: Boolean,
- default() {
- return false
- },
- },
- playing: {
- type: Boolean,
- default() {
- return false
- },
- },
- installed: {
- type: Boolean,
- default() {
- return false
- },
- },
-})
-
-const instanceId = computed(() => route.params.id)
+const instancePage = injectInstancePage()
+const instanceId = instancePage.instanceId
const {
liveConsole,
historicalConsole,
@@ -66,7 +35,17 @@ const {
clearLive,
} = useInstanceConsole(instanceId.value)
-await hydrate()
+const consoleHydrationQuery = useQuery({
+ queryKey: computed(() => instanceKeys.console(instanceId.value)),
+ queryFn: async () => {
+ await hydrate()
+ return true
+ },
+ staleTime: 0,
+ refetchOnMount: 'always',
+})
+
+await consoleHydrationQuery.suspense()
function buildLogList(rawLogs) {
return [
@@ -88,18 +67,29 @@ function buildLogList(rawLogs) {
}
const logs = ref(buildLogList([]))
-
-void getHistoricalLogs()
- .then((allLogs) => {
- logs.value = buildLogList(allLogs)
- })
- .catch(handleError)
+const historicalLogsQuery = useQuery({
+ queryKey: computed(() => instanceKeys.logs(instanceId.value)),
+ queryFn: getHistoricalLogs,
+ staleTime: 0,
+})
+watch(
+ historicalLogsQuery.data,
+ (allLogs) => {
+ if (allLogs) logs.value = buildLogList(allLogs)
+ },
+ { immediate: true },
+)
+watch(historicalLogsQuery.error, (error) => {
+ if (error) handleError(error)
+})
const selectedLogIndex = ref(0)
const isLive = computed(() => selectedLogIndex.value === 0)
const filteredLogs = computed(() =>
- props.playing ? logs.value.filter((l) => l.live || l.name !== 'latest.log') : logs.value,
+ instancePage.playing.value
+ ? logs.value.filter((l) => l.live || l.name !== 'latest.log')
+ : logs.value,
)
const logSources = computed(() =>
@@ -140,16 +130,16 @@ const selectedLog = computed(() => filteredLogs.value[selectedLogIndex.value])
const deleteDisabled = computed(() => {
const log = selectedLog.value
if (!log || log.live) return true
- return log.filename === 'latest.log' && props.playing
+ return log.filename === 'latest.log' && instancePage.playing.value
})
async function deleteSelectedLog() {
const log = selectedLog.value
if (!log || log.live) return
- await delete_logs_by_filename(props.instance.id, log.log_type, log.filename)
+ await delete_logs_by_filename(instanceId.value, log.log_type, log.filename)
invalidate()
- const freshLogs = await getHistoricalLogs()
- logs.value = buildLogList(freshLogs)
+ const { data } = await historicalLogsQuery.refetch()
+ if (data) logs.value = buildLogList(data)
selectedLogIndex.value = 0
}
@@ -166,7 +156,7 @@ provideConsoleManager({
onDelete: deleteSelectedLog,
deleteDisabled,
deleteDisabledTooltip: 'Cannot delete latest.log while the instance is running',
- shareDisabled: computed(() => props.offline),
+ shareDisabled: instancePage.offline,
emptyStateType: 'instance',
crashAnalysis,
onDismissCrash: () => {
@@ -186,7 +176,7 @@ watch(selectedLogIndex, async (newIndex) => {
return
}
- const output = await get_output_by_filename(props.instance.id, log.log_type, log.filename).catch(
+ const output = await get_output_by_filename(instanceId.value, log.log_type, log.filename).catch(
handleError,
)
if (output) {
@@ -197,7 +187,7 @@ watch(selectedLogIndex, async (newIndex) => {
selectedLogIndex.value = 0
-if (!props.playing) {
+if (!instancePage.playing.value) {
void analyseForCrash()
}
@@ -216,12 +206,13 @@ const unlistenProcesses = await process_listener(async (e) => {
if (e.event === 'launched') {
liveConsole.clear()
invalidate()
+ void historicalLogsQuery.refetch()
selectedLogIndex.value = 0
}
if (e.event === 'finished') {
invalidate()
- const freshLogs = await getHistoricalLogs()
- logs.value = buildLogList(freshLogs)
+ const { data } = await historicalLogsQuery.refetch()
+ if (data) logs.value = buildLogList(data)
void analyseForCrash()
}
})
diff --git a/apps/app-frontend/src/pages/instance/query-options.ts b/apps/app-frontend/src/pages/instance/query-options.ts
new file mode 100644
index 0000000000..6848ccb7ac
--- /dev/null
+++ b/apps/app-frontend/src/pages/instance/query-options.ts
@@ -0,0 +1,81 @@
+import { queryOptions } from '@tanstack/vue-query'
+
+import { get_project_v3 } from '@/helpers/cache.js'
+import { get as getInstance } from '@/helpers/instance'
+import { loadInstanceContentData } from '@/helpers/instance-content'
+import { get_by_instance_id } from '@/helpers/process'
+import { refreshWorlds } from '@/helpers/worlds'
+
+export const instanceKeys = {
+ all: ['instances'] as const,
+ detail: (instanceId: string) => [...instanceKeys.all, 'summary', instanceId] as const,
+ processes: (instanceId: string) => [...instanceKeys.all, 'processes', instanceId] as const,
+ content: (instanceId: string) => [...instanceKeys.all, 'content', instanceId] as const,
+ contentUpdateCheck: (instanceId: string) =>
+ [...instanceKeys.all, 'content-update-check', instanceId] as const,
+ rootPath: (instanceId: string) => [...instanceKeys.detail(instanceId), 'root-path'] as const,
+ files: (instanceId: string, path: string) =>
+ [...instanceKeys.detail(instanceId), 'files', path] as const,
+ console: (instanceId: string) => [...instanceKeys.detail(instanceId), 'console'] as const,
+ logs: (instanceId: string) => [...instanceKeys.detail(instanceId), 'logs'] as const,
+ installedProjectIds: (instanceId: string, source: 'content' | 'worlds') =>
+ [...instanceKeys.detail(instanceId), 'installed-project-ids', source] as const,
+ linkedContent: (instanceId: string) => ['linkedModpackContent', instanceId] as const,
+ worlds: (instanceId: string) => ['worlds', instanceId] as const,
+ linkedProject: (projectId: string) => ['project', 'v3', projectId] as const,
+ sharedEligibility: (userId: string | null | undefined) =>
+ ['shared-instance-eligibility', userId] as const,
+ sharedUpdatePreview: (instanceId: string, userId: string | null | undefined) =>
+ [...instanceKeys.detail(instanceId), 'shared-update-preview', userId] as const,
+ sharedMembers: (instanceId: string) => ['sharedInstanceUsers', instanceId] as const,
+}
+
+export function instanceDetailQueryOptions(instanceId: string) {
+ return queryOptions({
+ queryKey: instanceKeys.detail(instanceId),
+ queryFn: async () => {
+ const instance = await getInstance(instanceId)
+ if (!instance) throw new Error(`Instance ${instanceId} is not managed`)
+ return instance
+ },
+ staleTime: 30_000,
+ })
+}
+
+export function instanceProcessesQueryOptions(instanceId: string) {
+ return queryOptions({
+ queryKey: instanceKeys.processes(instanceId),
+ queryFn: async () => {
+ const processes = await get_by_instance_id(instanceId)
+ return Array.isArray(processes) ? processes : []
+ },
+ staleTime: 0,
+ })
+}
+
+export function instanceLinkedProjectQueryOptions(projectId: string) {
+ return queryOptions({
+ queryKey: instanceKeys.linkedProject(projectId),
+ queryFn: () => get_project_v3(projectId, 'must_revalidate'),
+ staleTime: 30_000,
+ })
+}
+
+export function instanceContentQueryOptions(
+ instanceId: string,
+ onError?: (error: Error) => unknown,
+) {
+ return queryOptions({
+ queryKey: instanceKeys.content(instanceId),
+ queryFn: () => loadInstanceContentData(instanceId, undefined, onError),
+ staleTime: 30_000,
+ })
+}
+
+export function instanceWorldsQueryOptions(instanceId: string) {
+ return queryOptions({
+ queryKey: instanceKeys.worlds(instanceId),
+ queryFn: () => refreshWorlds(instanceId),
+ staleTime: 0,
+ })
+}
diff --git a/apps/app-frontend/src/pages/instance/share/index.vue b/apps/app-frontend/src/pages/instance/share/index.vue
index b6addbe3bf..d88eed0d3c 100644
--- a/apps/app-frontend/src/pages/instance/share/index.vue
+++ b/apps/app-frontend/src/pages/instance/share/index.vue
@@ -55,20 +55,7 @@
-
+
-
- {{ formatMessage(lockedActionButton) }}
-
+
+ {{ formatMessage(lockedActionButton) }}
+
@@ -123,21 +108,21 @@
:description="formatMessage(messages.noFriendsInvitedDescription)"
>
-
- {{
- formatMessage(messages.inviteFriendsButton)
- }}
-
+ {{
+ formatMessage(messages.inviteFriendsButton)
+ }}
+
@@ -147,7 +132,7 @@
import { LogInIcon, SpinnerIcon, UserPlusIcon } from '@modrinth/assets'
import {
Avatar,
- ButtonStyled,
+ Button,
ConfirmUnlinkModal,
defineMessages,
injectAuth,
@@ -156,8 +141,8 @@ import {
type InvitePlayersUser,
useVIntl,
} from '@modrinth/ui'
-import { useQuery, useQueryClient } from '@tanstack/vue-query'
-import { computed, ref, toRef, watch } from 'vue'
+import { useQueryClient } from '@tanstack/vue-query'
+import { computed, ref, watch } from 'vue'
import ModrinthAccountRequiredModal from '@/components/ui/modal/ModrinthAccountRequiredModal.vue'
import SharedInstancePublishModal from '@/components/ui/shared-instances/SharedInstancePublishModal.vue'
@@ -166,16 +151,16 @@ import {
isSharedInstancesApiError,
isSharedInstanceUnavailableError,
} from '@/helpers/install'
-import { can_current_user_use_shared_instances, edit } from '@/helpers/instance'
+import { edit } from '@/helpers/instance'
import type { ModrinthAuthFlow } from '@/helpers/mr_auth.ts'
import {
sharedInstanceErrorMessages,
useSharedInstanceErrors,
} from '@/helpers/shared-instance-errors'
-import type { GameInstance } from '@/helpers/types'
-import { provideInstanceBackup } from '@/providers/instance-backup'
-import { injectSharedInstanceState } from '../use-shared-instance-state'
+import { injectInstancePage } from '../instance-context'
+import { injectSharedInstance } from '../shared-instance-context'
+import { provideSharedInstanceManagement } from './shared-instance-management-context'
import SharedInstanceMembersTable from './shared-instance-members-table.vue'
import SharedInstanceRemoveMemberModal from './shared-instance-remove-member-modal.vue'
import SharedInstanceShareEmptyState from './shared-instance-share-empty-state.vue'
@@ -184,10 +169,7 @@ import { useSharedInstanceInviteCandidates } from './use-shared-instance-invite-
import { useSharedInstanceInviteLink } from './use-shared-instance-invite-link'
import { useSharedInstanceMembers } from './use-shared-instance-members'
-const props = defineProps<{
- instance: GameInstance
- offline?: boolean
-}>()
+const instancePage = injectInstancePage()
const auth = injectAuth()
const queryClient = useQueryClient()
const { formatMessage } = useVIntl()
@@ -196,8 +178,9 @@ const {
notifySharedInstanceError,
notifySharedInstanceUnavailable,
} = useSharedInstanceErrors()
-const sharedInstanceState = injectSharedInstanceState()
-const instance = toRef(props, 'instance')
+const sharedInstanceState = injectSharedInstance()
+const instance = computed(() => instancePage.instance.value!)
+const offline = instancePage.offline
const actionsLocked = sharedInstanceState.shareActionsLocked
const sharedInstanceActionsLocked = actionsLocked
const currentUserId = computed(() => auth.user.value?.id ?? null)
@@ -224,16 +207,7 @@ function notifyOperationError(error: unknown) {
}
}
-const eligibilityQuery = useQuery({
- queryKey: computed(() => ['shared-instance-eligibility', currentUserId.value]),
- queryFn: can_current_user_use_shared_instances,
- enabled: () => isSignedIn.value && !!currentUserId.value,
- retry: false,
- staleTime: Infinity,
- refetchOnMount: 'always',
- refetchOnWindowFocus: false,
- refetchOnReconnect: false,
-})
+const eligibilityQuery = sharedInstanceState.eligibilityQuery
const members = useSharedInstanceMembers({
instance,
@@ -257,7 +231,7 @@ const {
actionsLocked,
})
const inviteLink = useSharedInstanceInviteLink(
- computed(() => props.instance.id),
+ computed(() => instance.value.id),
remainingUserSlots,
notifyOperationError,
)
@@ -286,7 +260,7 @@ const unableToConnect = computed(
const membersTableLoading = computed(
() =>
members.rows.value.length === 0 &&
- !!props.instance.shared_instance &&
+ !!instance.value.shared_instance &&
(members.query.data.value === undefined || members.query.isFetching.value) &&
!sharedInstanceUnavailable.value &&
!sharedInstanceActionsLocked.value,
@@ -294,7 +268,7 @@ const membersTableLoading = computed(
const showMembersTable = computed(
() =>
members.rows.value.length > 0 ||
- (!!props.instance.shared_instance &&
+ (!!instance.value.shared_instance &&
members.query.data.value !== undefined &&
!members.query.isFetching.value &&
!sharedInstanceUnavailable.value &&
@@ -302,13 +276,13 @@ const showMembersTable = computed(
)
const requiresUnlink = computed(
() =>
- props.instance.link?.type === 'imported_modpack' &&
- !props.instance.shared_instance &&
+ instance.value.link?.type === 'imported_modpack' &&
+ !instance.value.shared_instance &&
!importedModpackUnlinked.value,
)
const importedModpackBackupTip = computed(() =>
- props.instance.link?.type === 'imported_modpack'
- ? (props.instance.link.name ?? props.instance.link.filename ?? undefined)
+ instance.value.link?.type === 'imported_modpack'
+ ? (instance.value.link.name ?? instance.value.link.filename ?? undefined)
: undefined,
)
@@ -395,9 +369,9 @@ async function showInvitePlayers(event?: MouseEvent) {
}
async function unlinkImportedModpack() {
try {
- await edit(props.instance.id, { link: null as unknown as undefined })
+ await edit(instance.value.id, { link: null as unknown as undefined })
importedModpackUnlinked.value = true
- await queryClient.invalidateQueries({ queryKey: ['linkedModpackInfo', props.instance.id] })
+ await queryClient.invalidateQueries({ queryKey: ['linkedModpackInfo', instance.value.id] })
if (await inviteLink.ensure()) invitePlayersModal.value?.show()
} catch (error) {
notifyOperationError(error)
@@ -419,7 +393,7 @@ function userProfileLink(username: string) {
return !username || username.includes('@') ? undefined : `/user/${encodeURIComponent(username)}`
}
async function requestAuth(flow: ModrinthAuthFlow) {
- await auth.requestSignIn(`/instance/${encodeURIComponent(props.instance.id)}/share`, flow, {
+ await auth.requestSignIn(`/instance/${encodeURIComponent(instance.value.id)}/share`, flow, {
showModal: false,
})
return !!auth.session_token.value
@@ -428,6 +402,23 @@ function signInToShare(event?: MouseEvent) {
void accountRequiredModal.value?.show(event)
}
+provideSharedInstanceManagement({
+ rows: members.rows,
+ actionsLocked: sharedInstanceActionsLocked,
+ inviteDisabled: computed(() => !hasRemainingUserSlots.value),
+ invitePending: inviteLink.pending,
+ pushUpdateDisabled: computed(
+ () =>
+ instance.value.install_stage !== 'installed' ||
+ publishState.value !== 'idle' ||
+ offline.value,
+ ),
+ pushUpdatePending: computed(() => publishState.value !== 'idle'),
+ invite: (event) => void showInvitePlayers(event),
+ remove: showRemoveMemberModal,
+ pushUpdate: reviewUpdate,
+})
+
watch(
[eligibilityQuery.error, members.query.error],
(errors) => {
@@ -443,7 +434,7 @@ watch([eligibilityQuery.data, members.query.data], ([eligibility, memberRows]) =
}
})
watch(
- () => props.instance.id,
+ () => instance.value.id,
() => {
importedModpackUnlinked.value = false
},
@@ -455,6 +446,4 @@ watch(
},
{ immediate: true, flush: 'post' },
)
-
-provideInstanceBackup(() => props.instance)
diff --git a/apps/app-frontend/src/pages/instance/share/shared-instance-management-context.ts b/apps/app-frontend/src/pages/instance/share/shared-instance-management-context.ts
new file mode 100644
index 0000000000..615d66e16e
--- /dev/null
+++ b/apps/app-frontend/src/pages/instance/share/shared-instance-management-context.ts
@@ -0,0 +1,19 @@
+import { createContext } from '@modrinth/ui'
+import type { ComputedRef, Ref } from 'vue'
+
+import type { ShareRow } from './shared-instance-share-types'
+
+export interface SharedInstanceManagementContext {
+ readonly rows: ComputedRef
+ readonly actionsLocked: Ref
+ readonly inviteDisabled: ComputedRef
+ readonly invitePending: Ref
+ readonly pushUpdateDisabled: ComputedRef
+ readonly pushUpdatePending: ComputedRef
+ invite: (event: MouseEvent) => void
+ remove: (row: ShareRow) => void
+ pushUpdate: (event: MouseEvent) => void
+}
+
+export const [injectSharedInstanceManagement, provideSharedInstanceManagement] =
+ createContext('InstanceSharePage')
diff --git a/apps/app-frontend/src/pages/instance/share/shared-instance-members-table.vue b/apps/app-frontend/src/pages/instance/share/shared-instance-members-table.vue
index 85cc02c8c2..fb35a9457a 100644
--- a/apps/app-frontend/src/pages/instance/share/shared-instance-members-table.vue
+++ b/apps/app-frontend/src/pages/instance/share/shared-instance-members-table.vue
@@ -11,28 +11,29 @@
clearable
/>
-
-
-
-
- {{ formatMessage(messages.pushUpdate) }}
-
-
-
-
-
-
- Invite friends
-
-
+
+
+
+ {{ formatMessage(messages.pushUpdate) }}
+
+
+
+
+ Invite friends
+
@@ -120,15 +121,15 @@
-
-
+
+
@@ -145,10 +146,10 @@ import {
UserPlusIcon,
XIcon,
} from '@modrinth/assets'
+import { Button, IconButton } from '@modrinth/ui'
import {
AutoLink,
Avatar,
- ButtonStyled,
defineMessages,
type SortDirection,
StyledInput,
@@ -161,6 +162,7 @@ import {
} from '@modrinth/ui'
import { computed, ref, watch } from 'vue'
+import { injectSharedInstanceManagement } from './shared-instance-management-context'
import {
type MethodFilter,
methodLabels,
@@ -169,19 +171,15 @@ import {
type ShareTableColumn,
} from './shared-instance-share-types'
-const props = defineProps<{
- rows: ShareRow[]
- actionsLocked?: boolean
- inviteDisabled?: boolean
- invitePending?: boolean
- pushUpdateDisabled?: boolean
- pushUpdatePending?: boolean
-}>()
-const emit = defineEmits<{
- invite: [event: MouseEvent]
- remove: [row: ShareRow]
- 'push-update': [event: MouseEvent]
-}>()
+const management = injectSharedInstanceManagement()
+const {
+ rows,
+ actionsLocked,
+ inviteDisabled,
+ invitePending,
+ pushUpdateDisabled,
+ pushUpdatePending,
+} = management
const search = ref('')
const methodFilter = ref
('all')
const sortColumn = ref('joined')
@@ -194,7 +192,7 @@ const methodFilterOptions: Array<{ id: ShareMethod; label: string }> = [
{ id: 'direct', label: methodLabels.direct },
{ id: 'link', label: methodLabels.link },
]
-const hasMultipleMethods = computed(() => new Set(props.rows.map((row) => row.method)).size > 1)
+const hasMultipleMethods = computed(() => new Set(rows.value.map((row) => row.method)).size > 1)
const columns = computed[]>(() => {
const result: TableColumn[] = [
{
@@ -230,7 +228,7 @@ const columns = computed[]>(() => {
cellClass: 'whitespace-nowrap !px-2',
},
]
- if (!props.actionsLocked)
+ if (!actionsLocked.value)
result.push({
key: 'actions',
label: 'Actions',
@@ -243,7 +241,7 @@ const columns = computed[]>(() => {
})
const filteredRows = computed(() => {
const query = search.value.trim().toLowerCase()
- return props.rows.filter((row) => {
+ return rows.value.filter((row) => {
if (methodFilter.value !== 'all' && row.method !== methodFilter.value) return false
if (!query) return true
return [
@@ -285,7 +283,7 @@ function filterClass(active: boolean) {
return [
'cursor-pointer rounded-full border border-solid px-3 py-1.5 text-base font-semibold leading-5 transition-all duration-100 active:scale-[0.97]',
active
- ? 'border-green bg-brand-highlight text-brand'
+ ? 'border-brand bg-brand-highlight text-brand'
: 'border-surface-5 bg-surface-4 text-primary hover:bg-surface-5',
]
}
diff --git a/apps/app-frontend/src/pages/instance/share/shared-instance-remove-member-modal.vue b/apps/app-frontend/src/pages/instance/share/shared-instance-remove-member-modal.vue
index 1f7983dcdd..96d67be712 100644
--- a/apps/app-frontend/src/pages/instance/share/shared-instance-remove-member-modal.vue
+++ b/apps/app-frontend/src/pages/instance/share/shared-instance-remove-member-modal.vue
@@ -32,16 +32,12 @@
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
- {{ formatMessage(messages.removeButton) }}
-
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+ {{ formatMessage(messages.removeButton) }}
+
@@ -52,7 +48,7 @@ import { UserXIcon, XIcon } from '@modrinth/assets'
import {
Admonition,
Avatar,
- ButtonStyled,
+ Button,
commonMessages,
defineMessages,
NewModal,
diff --git a/apps/app-frontend/src/pages/instance/share/use-shared-instance-members.ts b/apps/app-frontend/src/pages/instance/share/use-shared-instance-members.ts
index 801f9a3552..cd0c43304c 100644
--- a/apps/app-frontend/src/pages/instance/share/use-shared-instance-members.ts
+++ b/apps/app-frontend/src/pages/instance/share/use-shared-instance-members.ts
@@ -12,13 +12,14 @@ import {
} from '@/helpers/instance'
import type { GameInstance } from '@/helpers/types'
+import { instanceKeys } from '../query-options'
import {
normalizeInviteKey,
SHARED_INSTANCE_USER_LIMIT,
type ShareRow,
} from './shared-instance-share-types'
-type MembersQueryKey = readonly ['sharedInstanceUsers', string]
+type MembersQueryKey = ReturnType
type OptimisticChange = {
queryKey: MembersQueryKey
@@ -48,7 +49,7 @@ export function useSharedInstanceMembers(options: {
onError: (error: unknown) => void
}) {
const queryClient = useQueryClient()
- const queryKey = computed(() => ['sharedInstanceUsers', options.instance.value.id] as const)
+ const queryKey = computed(() => instanceKeys.sharedMembers(options.instance.value.id))
const invitingUserIds = new Set()
const removingUserIds = new Set()
const exclusiveMutationPending = ref(false)
diff --git a/apps/app-frontend/src/pages/instance/shared-instance-context.ts b/apps/app-frontend/src/pages/instance/shared-instance-context.ts
new file mode 100644
index 0000000000..683a7a0686
--- /dev/null
+++ b/apps/app-frontend/src/pages/instance/shared-instance-context.ts
@@ -0,0 +1,181 @@
+import { createContext, injectAuth } from '@modrinth/ui'
+import { useQuery, useQueryClient } from '@tanstack/vue-query'
+import { computed, type Ref, ref, watch } from 'vue'
+
+import { useUserQuery } from '@/composables/users/use-user-query'
+import {
+ getSharedInstanceUnavailableReason,
+ install_get_shared_instance_update_preview,
+ isSharedInstanceUnavailableError,
+ type SharedInstanceUnavailableReason,
+} from '@/helpers/install'
+import { can_current_user_use_shared_instances } from '@/helpers/instance'
+import type { GameInstance } from '@/helpers/types'
+
+import { instanceKeys } from './query-options'
+
+export type SharedInstanceManager =
+ | {
+ type: 'user'
+ name: string
+ avatarUrl?: string
+ tintBy: string
+ }
+ | {
+ type: 'server'
+ name: string
+ avatarUrl?: string
+ tintBy: string
+ }
+
+export function createSharedInstanceContext(
+ instance: Ref,
+ offline: Ref,
+ notifyError: (error: unknown) => void,
+) {
+ const auth = injectAuth()
+ const queryClient = useQueryClient()
+ const forcedUnavailableReason = ref(null)
+
+ const expectedUserId = computed(() => instance.value?.shared_instance?.linked_user_id ?? null)
+ const wrongAccount = computed(() => {
+ if (auth.isReady && !auth.isReady.value) return false
+ if (!expectedUserId.value) return false
+ return auth.user.value?.id !== expectedUserId.value
+ })
+ const actionsLocked = computed(() => wrongAccount.value)
+ const signedOut = computed(() => !auth.session_token.value)
+ const managerUserId = computed(() => {
+ const attachment = instance.value?.shared_instance
+ if (!attachment) return null
+ if (attachment.role === 'owner') {
+ return actionsLocked.value ? (attachment.linked_user_id ?? null) : null
+ }
+ return attachment.manager_id ?? null
+ })
+ const managerUserQuery = useUserQuery(managerUserId)
+ const manager = computed(() => {
+ const attachment = instance.value?.shared_instance
+ if (!attachment) return null
+
+ if (attachment.server_manager_name) {
+ return {
+ type: 'server',
+ name: attachment.server_manager_name,
+ avatarUrl: attachment.server_manager_icon_url ?? undefined,
+ tintBy: attachment.server_manager_name,
+ }
+ }
+
+ const user = managerUserQuery.data.value
+ if (!user) return null
+ return {
+ type: 'user',
+ name: user.username,
+ avatarUrl: user.avatar_url ?? undefined,
+ tintBy: user.id,
+ }
+ })
+ const unavailableManager = computed(() => manager.value?.name ?? null)
+
+ const eligibilityQuery = useQuery({
+ queryKey: computed(() => instanceKeys.sharedEligibility(auth.user.value?.id)),
+ queryFn: can_current_user_use_shared_instances,
+ enabled: () => !!auth.session_token.value && !!auth.user.value?.id,
+ retry: false,
+ staleTime: Infinity,
+ refetchOnWindowFocus: false,
+ refetchOnReconnect: false,
+ })
+ const currentUserCanUseSharedInstances = computed(
+ () => !auth.session_token.value || eligibilityQuery.data.value !== false,
+ )
+
+ const updatePreviewQuery = useQuery({
+ queryKey: computed(() =>
+ instanceKeys.sharedUpdatePreview(instance.value?.id ?? '', auth.user.value?.id),
+ ),
+ queryFn: () => install_get_shared_instance_update_preview(instance.value!.id),
+ enabled: computed(
+ () =>
+ !!instance.value?.id &&
+ !!instance.value.shared_instance &&
+ !actionsLocked.value &&
+ !offline.value &&
+ (auth.isReady?.value ?? true) &&
+ !!auth.session_token.value &&
+ !!auth.user.value?.id,
+ ),
+ retry: false,
+ staleTime: 30_000,
+ refetchOnWindowFocus: false,
+ })
+
+ watch(updatePreviewQuery.data, (preview) => {
+ if (preview !== undefined) forcedUnavailableReason.value = null
+ })
+ watch(updatePreviewQuery.error, (error) => {
+ if (!error) return
+ if (isSharedInstanceUnavailableError(error)) {
+ forcedUnavailableReason.value = getSharedInstanceUnavailableReason(error)
+ } else {
+ notifyError(error)
+ }
+ })
+
+ const unavailableReason = computed(() => forcedUnavailableReason.value)
+ const shareActionsLocked = computed(() => actionsLocked.value || unavailableReason.value !== null)
+ const updatePreview = computed(() =>
+ unavailableReason.value ? null : (updatePreviewQuery.data.value ?? null),
+ )
+
+ watch(
+ () => instance.value?.id,
+ () => {
+ forcedUnavailableReason.value = null
+ },
+ )
+
+ async function refreshAvailability() {
+ forcedUnavailableReason.value = null
+ if (!instance.value?.id) return
+ await queryClient.invalidateQueries({
+ queryKey: instanceKeys.sharedUpdatePreview(instance.value.id, auth.user.value?.id),
+ })
+ }
+
+ async function refreshUpdatePreview() {
+ forcedUnavailableReason.value = null
+ if (!instance.value?.id || !auth.user.value?.id) return null
+ const result = await updatePreviewQuery.refetch({ throwOnError: true })
+ return result.data ?? null
+ }
+
+ function setUnavailable(reason: SharedInstanceUnavailableReason | null) {
+ forcedUnavailableReason.value = reason
+ }
+
+ return {
+ actionsLocked,
+ shareActionsLocked,
+ unavailableReason,
+ unavailableManager,
+ manager,
+ updatePreview,
+ expectedUserId,
+ wrongAccount,
+ signedOut,
+ eligibilityQuery,
+ currentUserCanUseSharedInstances,
+ refreshAvailability,
+ refreshUpdatePreview,
+ setUnavailable,
+ }
+}
+
+export type SharedInstanceContext = ReturnType
+
+export const [injectSharedInstance, provideSharedInstance] = createContext(
+ 'InstancePage',
+ 'sharedInstance',
+)
diff --git a/apps/app-frontend/src/pages/instance/use-shared-instance-state.ts b/apps/app-frontend/src/pages/instance/use-shared-instance-state.ts
deleted file mode 100644
index 408bd3c2cc..0000000000
--- a/apps/app-frontend/src/pages/instance/use-shared-instance-state.ts
+++ /dev/null
@@ -1,228 +0,0 @@
-import { injectAuth } from '@modrinth/ui'
-import { computed, inject, type InjectionKey, provide, type Ref, ref, watch } from 'vue'
-
-import { useUserQuery } from '@/composables/users/use-user-query'
-import {
- getSharedInstanceUnavailableReason,
- install_get_shared_instance_update_preview,
- isSharedInstanceUnavailableError,
- type SharedInstanceUnavailableReason,
-} from '@/helpers/install'
-import type { GameInstance } from '@/helpers/types'
-
-export type SharedInstanceManager =
- | {
- type: 'user'
- name: string
- avatarUrl?: string
- tintBy: string
- }
- | {
- type: 'server'
- name: string
- avatarUrl?: string
- tintBy: string
- }
-
-export function useSharedInstanceState(
- instance: Ref,
- offline: Ref,
- notifyError: (error: unknown) => void,
-) {
- const auth = injectAuth()
- const updatePreview =
- ref>>(null)
- const updatePreviewLoaded = ref(false)
- const unavailableReason = ref(null)
- const availabilityCheckKey = ref(null)
- const availabilityRefresh = ref(0)
- let availabilityRequestId = 0
- let availabilityRequest: {
- key: string
- promise: Promise<{
- preview: Awaited>
- error: unknown | null
- }>
- } | null = null
-
- const expectedUserId = computed(() => instance.value?.shared_instance?.linked_user_id ?? null)
- const wrongAccount = computed(() => {
- if (auth.isReady && !auth.isReady.value) return false
- if (!expectedUserId.value) return false
- return auth.user.value?.id !== expectedUserId.value
- })
- const actionsLocked = computed(() => wrongAccount.value)
- const shareActionsLocked = computed(() => actionsLocked.value || unavailableReason.value !== null)
- const signedOut = computed(() => !auth.session_token.value)
- const managerUserId = computed(() => {
- const attachment = instance.value?.shared_instance
- if (!attachment) return null
- if (attachment.role === 'owner') {
- return actionsLocked.value ? (attachment.linked_user_id ?? null) : null
- }
- return attachment.manager_id ?? null
- })
- const managerUserQuery = useUserQuery(managerUserId)
- const manager = computed(() => {
- const attachment = instance.value?.shared_instance
- if (!attachment) return null
-
- if (attachment.server_manager_name) {
- return {
- type: 'server',
- name: attachment.server_manager_name,
- avatarUrl: attachment.server_manager_icon_url ?? undefined,
- tintBy: attachment.server_manager_name,
- }
- }
-
- const user = managerUserQuery.data.value
- if (!user) return null
- return {
- type: 'user',
- name: user.username,
- avatarUrl: user.avatar_url ?? undefined,
- tintBy: user.id,
- }
- })
- const unavailableManager = computed(() => manager.value?.name ?? null)
-
- function reset() {
- availabilityRequestId++
- availabilityRequest = null
- availabilityCheckKey.value = null
- updatePreview.value = null
- updatePreviewLoaded.value = false
- unavailableReason.value = null
- }
-
- function refreshAvailability() {
- availabilityCheckKey.value = null
- updatePreviewLoaded.value = false
- availabilityRefresh.value++
- }
-
- function setUnavailable(reason: SharedInstanceUnavailableReason | null) {
- availabilityRequestId++
- availabilityRequest = null
- availabilityCheckKey.value = null
- updatePreview.value = null
- updatePreviewLoaded.value = false
- unavailableReason.value = reason
- }
-
- async function checkAvailability(instanceId: string, key: string, throwError = false) {
- const requestId = ++availabilityRequestId
- let request = availabilityRequest
- if (!request || request.key !== key) {
- const promise = install_get_shared_instance_update_preview(instanceId).then(
- (preview) => ({ preview, error: null }),
- (error: unknown) => ({ preview: null, error }),
- )
- request = { key, promise }
- availabilityRequest = request
- void promise.finally(() => {
- if (availabilityRequest?.promise === promise) availabilityRequest = null
- })
- }
-
- const result = await request.promise
- if (!isCurrentRequest(requestId, instanceId, key)) return null
-
- if (result.error !== null) {
- updatePreviewLoaded.value = false
- if (isSharedInstanceUnavailableError(result.error)) {
- updatePreview.value = null
- unavailableReason.value = getSharedInstanceUnavailableReason(result.error)
- } else if (!throwError) {
- notifyError(result.error)
- }
-
- if (throwError) throw result.error
- return null
- }
-
- updatePreview.value = result.preview
- updatePreviewLoaded.value = true
- unavailableReason.value = null
- return result.preview
- }
-
- async function refreshUpdatePreview() {
- const instanceId = instance.value?.id
- const userId = auth.user.value?.id
- if (!instanceId || !userId) return null
-
- const key = `${instanceId}:${userId}`
- availabilityCheckKey.value = key
- return await checkAvailability(instanceId, key, true)
- }
-
- function isCurrentRequest(requestId: number, instanceId: string, key: string) {
- return (
- requestId === availabilityRequestId &&
- instance.value?.id === instanceId &&
- availabilityCheckKey.value === key
- )
- }
-
- watch(
- () => ({
- refresh: availabilityRefresh.value,
- instanceId: instance.value?.id,
- role: instance.value?.shared_instance?.role,
- locked: actionsLocked.value,
- offline: offline.value,
- signedIn: !!auth.session_token.value,
- userId: auth.user.value?.id ?? null,
- authReady: auth.isReady?.value ?? true,
- }),
- async ({ instanceId, role, locked, offline, signedIn, userId, authReady }) => {
- if (!instanceId || !role || locked || offline || !authReady || !signedIn || !userId) {
- availabilityRequestId++
- availabilityRequest = null
- availabilityCheckKey.value = null
- updatePreview.value = null
- updatePreviewLoaded.value = false
- if (instanceId && role) unavailableReason.value = null
- return
- }
-
- const key = `${instanceId}:${userId}`
- if (availabilityCheckKey.value === key) return
- availabilityCheckKey.value = key
- await checkAvailability(instanceId, key)
- },
- { immediate: true },
- )
-
- return {
- actionsLocked,
- shareActionsLocked,
- unavailableReason,
- unavailableManager,
- manager,
- updatePreview,
- expectedUserId,
- wrongAccount,
- signedOut,
- reset,
- refreshAvailability,
- refreshUpdatePreview,
- setUnavailable,
- }
-}
-
-export type SharedInstanceState = ReturnType
-
-const sharedInstanceStateKey: InjectionKey = Symbol('shared-instance-state')
-
-export function provideSharedInstanceState(state: SharedInstanceState) {
- provide(sharedInstanceStateKey, state)
-}
-
-export function injectSharedInstanceState() {
- const state = inject(sharedInstanceStateKey)
- if (!state) throw new Error('Shared instance state has not been provided.')
- return state
-}
diff --git a/apps/app-frontend/src/pages/instance/Worlds.vue b/apps/app-frontend/src/pages/instance/worlds/index.vue
similarity index 87%
rename from apps/app-frontend/src/pages/instance/Worlds.vue
rename to apps/app-frontend/src/pages/instance/worlds/index.vue
index 1ddcb5e943..10f9118401 100644
--- a/apps/app-frontend/src/pages/instance/Worlds.vue
+++ b/apps/app-frontend/src/pages/instance/worlds/index.vue
@@ -35,23 +35,14 @@
"
/>
-
-
-
- {{ formatMessage(messages.addServer) }}
-
-
-
-
-
- {{ formatMessage(messages.browseServers) }}
-
-
+
+
+ {{ formatMessage(messages.addServer) }}
+
+
+
+ {{ formatMessage(messages.browseServers) }}
+
@@ -72,12 +63,17 @@
{{ option.label }}
-
-
-
- {{ formatMessage(commonMessages.refreshButton) }}
-
-
+
+
+ {{
+ formatMessage(refreshingAll ? messages.refreshingButton : commonMessages.refreshButton)
+ }}
+
joinWorld(world)"
- @stop="() => emit('stop')"
+ @stop="() => instancePage.stop('InstanceWorlds')"
@refresh="() => refreshServer((world as ServerWorld).address)"
@edit="
() =>
@@ -123,31 +119,22 @@
:description="formatMessage(messages.noWorldsDescription)"
>
-
-
-
- {{ formatMessage(messages.addServer) }}
-
-
-
-
-
- {{ formatMessage(messages.browseServers) }}
-
-
+
+
+ {{ formatMessage(messages.addServer) }}
+
+
+
+ {{ formatMessage(messages.browseServers) }}
+
-
-
diff --git a/apps/frontend/src/components/ui/ConfirmTransferOrgModal.vue b/apps/frontend/src/components/ui/ConfirmTransferOrgModal.vue
index e4f62b43f0..606be33b05 100644
--- a/apps/frontend/src/components/ui/ConfirmTransferOrgModal.vue
+++ b/apps/frontend/src/components/ui/ConfirmTransferOrgModal.vue
@@ -57,18 +57,14 @@
-
-
-
- Cancel
-
-
-
-
-
- Transfer ownership
-
-
+
+
+ Cancel
+
+
+
+ Transfer ownership
+
@@ -76,7 +72,7 @@
-
-
-
- {{ formatMessage(messages.subscribe) }}
-
- {{ formatMessage(messages.subscribed) }}
-
-
+
+
+ {{ formatMessage(messages.subscribe) }}
+
+ {{ formatMessage(messages.subscribed) }}
+
diff --git a/apps/frontend/src/components/ui/NotificationItem.vue b/apps/frontend/src/components/ui/NotificationItem.vue
index 1bbac8bf38..4f3cfa001b 100644
--- a/apps/frontend/src/components/ui/NotificationItem.vue
+++ b/apps/frontend/src/components/ui/NotificationItem.vue
@@ -46,18 +46,18 @@
class="flex flex-wrap items-center gap-3"
:class="{ 'gap-2': compact }"
>
-
-
-
- Accept
-
-
-
-
-
- Decline
-
-
+
+
+ Accept
+
+
+
+ Decline
+
-
- {
+ acceptTeamInvite(notification.body.team_id)
+ read()
+ }
+ "
+ >
+
+
+ {
+ removeSelfFromTeam(notification.body.team_id)
+ read()
+ }
+ "
+ >
+
+
+
+
+
+
+
+
+
+
+ {
acceptTeamInvite(notification.body.team_id)
@@ -287,11 +331,11 @@
"
>
-
-
-
-
+ {
removeSelfFromTeam(notification.body.team_id)
@@ -300,75 +344,40 @@
"
>
-
-
-
-
-
-
-
-
-
-
-
-
-
- {
- acceptTeamInvite(notification.body.team_id)
- read()
- }
- "
- >
-
- Accept
-
-
-
- {
- removeSelfFromTeam(notification.body.team_id)
- read()
- }
- "
- >
-
- Decline
-
-
+ Decline
+
-
-
-
- Mark as read
-
-
+
+
+ Mark as read
+
-
-
-
- Open link
-
-
-
-
-
-
- {{ action.title }}
-
-
-
-
-
- Mark as read
-
-
+
+
+ Open link
+
+
+
+
+ {{ action.title }}
+
+
+
+ Mark as read
+
@@ -390,10 +399,12 @@ import {
} from '@modrinth/assets'
import {
Avatar,
- ButtonStyled,
+ Button,
+ ButtonLink,
Categories,
CopyCode,
DoubleIcon,
+ IconButton,
injectModrinthClient,
injectNotificationManager,
ProjectStatusBadge,
diff --git a/apps/frontend/src/components/ui/OptionGroup.vue b/apps/frontend/src/components/ui/OptionGroup.vue
deleted file mode 100644
index 36313921ef..0000000000
--- a/apps/frontend/src/components/ui/OptionGroup.vue
+++ /dev/null
@@ -1,128 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/apps/frontend/src/components/ui/OrganizationPageHeader.vue b/apps/frontend/src/components/ui/OrganizationPageHeader.vue
index c5f74542df..6063423a50 100644
--- a/apps/frontend/src/components/ui/OrganizationPageHeader.vue
+++ b/apps/frontend/src/components/ui/OrganizationPageHeader.vue
@@ -38,21 +38,19 @@
-
-
-
- {{ formatMessage(messages.manage) }}
-
-
-
-
-
-
-
+
+
+ {{ formatMessage(messages.manage) }}
+
+
+
+
@@ -68,18 +66,17 @@ import {
SettingsIcon,
UsersIcon,
} from '@modrinth/assets'
+import { ButtonLink, TeleportOverflowMenu } from '@modrinth/ui'
import {
Avatar,
- ButtonStyled,
commonMessages,
defineMessages,
+ type OverflowMenuOption,
PageHeader,
PageHeaderActions,
PageHeaderBadgeItem,
PageHeaderMetadata,
PageHeaderMetadataNumberItem,
- TeleportOverflowMenu,
- type TeleportOverflowMenuItem,
useFormatNumber,
useVIntl,
} from '@modrinth/ui'
@@ -135,7 +132,7 @@ const emit = defineEmits<{
const { formatMessage } = useVIntl()
const formatNumber = useFormatNumber()
-const moreActions = computed
(() => [
+const moreActions = computed(() => [
{
id: 'manage-projects',
label: formatMessage(messages.manageProjects),
@@ -143,10 +140,7 @@ const moreActions = computed(() => [
action: () => emit('manageProjects'),
shown: props.canManage,
},
- {
- divider: true,
- shown: props.canManage,
- },
+ { type: 'divider', shown: props.canManage },
{
id: 'copy-id',
label: formatMessage(commonMessages.copyIdButton),
diff --git a/apps/frontend/src/components/ui/OrganizationProjectTransferModal.vue b/apps/frontend/src/components/ui/OrganizationProjectTransferModal.vue
index 6f66486fd0..46524dbff5 100644
--- a/apps/frontend/src/components/ui/OrganizationProjectTransferModal.vue
+++ b/apps/frontend/src/components/ui/OrganizationProjectTransferModal.vue
@@ -65,38 +65,37 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
- {{
- formatMessage(messages.transferSelectedProjects, {
- count: selectedProjects.length,
- })
- }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+ {{
+ formatMessage(messages.transferSelectedProjects, {
+ count: selectedProjects.length,
+ })
+ }}
+
-
-
-
- {{ formatMessage(messages.transferProjectsTitle) }}
-
-
+
+
+ {{ formatMessage(messages.transferProjectsTitle) }}
+
+
+
+
+
+
+
Completed ({{ completedEntries.length }})
+
+
+ {{
+ entry.title
+ }}
+
+
+
+
+
+
Skipped ({{ skippedEntries.length }})
+
+
+ {{
+ entry.title
+ }}
+
+
+
+
+
+ No projects were reviewed during this queue.
+
+
+
+
+
+ Review skipped ({{ skippedEntries.length }})
+
+
+
+ Close
+
+
+
+
+
diff --git a/apps/frontend/src/components/ui/moderation/SharedInstanceReportContext.vue b/apps/frontend/src/components/ui/moderation/SharedInstanceReportContext.vue
index 3f3b0d9ad5..247b350a73 100644
--- a/apps/frontend/src/components/ui/moderation/SharedInstanceReportContext.vue
+++ b/apps/frontend/src/components/ui/moderation/SharedInstanceReportContext.vue
@@ -11,9 +11,9 @@ import {
UsersIcon,
VersionIcon,
} from '@modrinth/assets'
+import { Button, IconButton } from '@modrinth/ui'
import {
Avatar,
- ButtonStyled,
ConfirmLeaveModal,
type ContentItem,
injectModrinthClient,
@@ -322,12 +322,14 @@ function formattedLoader(version: SharedInstanceReportVersion) {
-
-
-
- View content
-
-
+
+
+ View content
+
@@ -363,15 +365,14 @@ function formattedLoader(version: SharedInstanceReportVersion) {
{{ instance.member_count === 1 ? 'member' : 'members' }}
-
-
-
-
-
+
+
+
@@ -392,12 +393,16 @@ function formattedLoader(version: SharedInstanceReportVersion) {
launching them.
-
-
-
- {{ banButtonLabel }}
-
-
+
+
+ {{ banButtonLabel }}
+
diff --git a/apps/frontend/src/components/ui/moderation/checklist/ModerationChecklist.vue b/apps/frontend/src/components/ui/moderation/checklist/ModerationChecklist.vue
index 3727b6197c..e5790e3e84 100644
--- a/apps/frontend/src/components/ui/moderation/checklist/ModerationChecklist.vue
+++ b/apps/frontend/src/components/ui/moderation/checklist/ModerationChecklist.vue
@@ -24,9 +24,13 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
- Take over
-
-
+
+
+ Take over
+
-
-
-
- Next project ({{ moderationQueue.queueLength }} left)
-
-
+
+ Next project ({{ moderationQueue.queueLength }} left)
+
@@ -161,24 +197,21 @@
class="mt-4 flex grow justify-between gap-2 border-0 border-t-[1px] border-solid border-surface-5 pt-4"
>
-
-
-
- Review anyway
-
-
+
+
+ Review anyway
+
-
-
-
- Next project ({{ moderationQueue.queueLength }} left)
-
-
+
+ Next project ({{ moderationQueue.queueLength }} left)
+
@@ -196,18 +229,16 @@
-
-
-
-
- Use simple mode
-
-
-
- Use advanced mode
-
-
-
+
+
+
+ Use simple mode
+
+
+
+ Use advanced mode
+
+
@@ -250,110 +278,120 @@
class="mt-4 flex grow justify-between gap-2 border-0 border-t-[1px] border-solid border-surface-5 pt-4"
>
-
-
-
- Skip ({{ moderationQueue.queueLength }} left)
-
-
+
+
+ Skip ({{ moderationQueue.queueLength }} left)
+
-
-
-
- Stages
-
-
-
- {{ opt.text
- }}*
-
- {{
- opt.messages
- }}
- {{
- opt.fixes
- }}
-
-
-
+
+
+ Stages
+
+
+
+ {{ opt.text
+ }}*
+
+ {{
+ opt.messages
+ }}
+ {{ opt.fixes }}
+
+
-
-
-
-
- Next project ({{ moderationQueue.queueLength }} left)
-
-
-
- All done!
-
-
-
+
+
+
+ Next project ({{ moderationQueue.queueLength }} left)
+
+
+
+ All done!
+
+
-
-
-
- Edit
-
-
-
-
-
-
- Reject
-
-
-
-
-
-
- Withhold
-
-
-
-
-
-
- Approve
-
-
+
+
+ Edit
+
+
+
+
+ Reject
+
+
+
+
+ Withhold
+
+
+
+
+ Approve
+
-
-
- Previous
-
-
-
-
-
-
- {{ loadingMessage ? 'Generating...' : 'Generate Message' }}
-
- Next
-
-
+
+ Previous
+
+
+
+
+ {{ loadingMessage ? 'Generating...' : 'Generate Message' }}
+
+ Next
+
@@ -373,6 +411,7 @@ import {
LinkIcon,
ListBulletedIcon,
LockIcon,
+ MapPinIcon,
RightArrowIcon,
ScaleIcon,
SpinnerIcon,
@@ -381,62 +420,78 @@ import {
UndoIcon,
XIcon,
} from '@modrinth/assets'
+import type { Priority } from '@modrinth/moderation'
import {
- type IdentifiedNodeBuilder,
- moderationSettings,
- type NodeState,
- type Priority,
- type StageNodeBuilder,
- type ValueNodeBuilder,
-} from '@modrinth/moderation'
-import {
- createTrackedPatch,
- evalSegment,
expandVariables,
- getBooleanChildState,
- GLOBAL_STATE_KEY,
- isNodeActive,
kebabToTitleCase,
- NodeBuilder,
+ moderationSettings,
+ useStages,
+} from '@modrinth/moderation'
+import type { ActiveAction, NodeState, StageNode } from '@modrinth/moderation/src/types/node'
+import {
+ CHECKLIST_META_KEY,
+ collectActiveActions,
+ collectMessageNodes,
+ computeAttentionMap,
+ computeNodeMeta,
+ createTrackedPatch,
+ evalActiveAction,
+ evalSegment,
resolve,
resolveChildren,
setMessageProject,
setMissingMdHandler,
- useStages,
- walkNodes,
-} from '@modrinth/moderation'
+} from '@modrinth/moderation/src/types/node'
+import NodeRenderer from '@modrinth/moderation/src/types/node/components/NodeRenderer.vue'
+import type { FixBuilder } from '@modrinth/moderation/src/types/node/fix'
+import type { Writer } from '@modrinth/moderation/src/types/node/mutate'
import {
Avatar,
- ButtonStyled,
+ Button,
+ ButtonLink,
Collapsible,
ConfirmModal,
+ IconButton,
injectModrinthClient,
injectNotificationManager,
injectProjectPageContext,
MarkdownEditor,
StyledInput,
+ TeleportOverflowMenu,
useDebugLogger,
} from '@modrinth/ui'
-import TeleportOverflowMenu from '@modrinth/ui/src/components/base/TeleportOverflowMenu.vue'
import type { ProjectStatus } from '@modrinth/utils'
+import { renderHighlightedString } from '@modrinth/utils'
import { useQueryClient } from '@tanstack/vue-query'
import { useDebounceFn } from '@vueuse/core'
import type { Component } from 'vue'
-import { computed, nextTick, provide, ref, toRaw, watch } from 'vue'
+import { computed, nextTick, provide, ref, toRaw, watch, watchEffect } from 'vue'
+import LoaderPicker from '~/components/ui/create-project-version/components/LoaderPicker.vue'
+import McVersionPicker from '~/components/ui/create-project-version/components/McVersionPicker.vue'
import { useGeneratedState } from '~/composables/generated'
import { useImageUpload } from '~/composables/image-upload.ts'
import { getProjectTypeForUrlShorthand } from '~/helpers/projects.js'
+import {
+ clearSessionChecklistState,
+ getSessionChecklistState,
+ patchSessionChecklistState,
+} from '~/services/moderation/checklist-session-storage.ts'
import {
clearChecklistState,
loadChecklistState,
saveChecklistState,
-} from '~/services/moderation-checklist-storage.ts'
-import type { LockAcquireResponse } from '~/services/moderation-queue.ts'
-import { useModerationQueue } from '~/services/moderation-queue.ts'
+} from '~/services/moderation/checklist-storage.ts'
+import type { LockAcquireResponse } from '~/services/moderation/queue.ts'
+import { useModerationQueue } from '~/services/moderation/queue.ts'
+import {
+ batchCheckQueueCandidates,
+ findNextEligibleQueueProject,
+ isEligibleQueueCandidate,
+ type QueueCandidateCheck,
+} from '~/services/moderation/queue-eligibility.ts'
-import { type ActiveAction, type LiveNode, NODE_META_KEY, STATE_KEY } from './checklist-context'
-import NodeRenderer from './NodeRenderer.vue'
+import { type LiveNode, STATE_KEY } from './checklist-context'
const notifications = injectNotificationManager()
const { addNotification } = notifications
@@ -481,11 +536,10 @@ const alreadyReviewed = ref(false)
// Prefetch queue for parallel lock checking and instant navigation
interface PrefetchedProject {
- projectId: string
+ project: string
slug: string // For canonical URL navigation
projectType: string // For canonical URL navigation
validatedAt: number
- skippedIds: string[] // IDs that were locked when this was prefetched
}
const prefetchQueue = ref([])
@@ -606,7 +660,6 @@ function handleLockUnavailable() {
}
async function navigateToNextUnlockedProject(): Promise {
- // Remove stale entries first
const now = Date.now()
prefetchQueue.value = prefetchQueue.value.filter((p) => now - p.validatedAt < PREFETCH_STALE_MS)
@@ -616,29 +669,21 @@ async function navigateToNextUnlockedProject(): Promise {
// Quick re-check if close to expiry (last 5 seconds of TTL)
if (now - next.validatedAt > PREFETCH_STALE_MS - 5000) {
- const recheckResults = await batchCheckQueueCandidates([next.projectId])
- const recheck = recheckResults.get(next.projectId)
+ const recheckResults = await batchCheckQueueCandidates(client, moderationQueue, [next.project])
+ const recheck = recheckResults.get(next.project)
if (!isEligibleQueueCandidate(recheck)) {
prefetchQueue.value.shift()
return navigateToNextUnlockedProject()
}
}
- // Remove from queue after validation
prefetchQueue.value.shift()
- // Mark skipped projects as completed
- await Promise.all(
- next.skippedIds.map((id) => moderationQueue.completeCurrentProject(id, 'skipped')),
- )
-
- notifySkippedQueueProjects(next.skippedIds.length)
-
maintainPrefetchQueue()
navigateToQueueProject(
{ slug: next.slug, projectType: next.projectType, locked: false, isProcessing: true },
- next.projectId,
+ next.project,
)
return true
}
@@ -657,10 +702,27 @@ const persistedState = import.meta.client
? await loadChecklistState(checklistPersistenceProjectId)
: null
nodeStates.value = persistedState?.state ?? {}
+const activatedStages = ref>(new Set(persistedState?.activatedStages ?? []))
+const visitedStages = ref>(
+ new Set(
+ import.meta.client
+ ? (getSessionChecklistState(checklistPersistenceProjectId).visitedStages ?? [])
+ : [],
+ ),
+)
+
+function markStageVisited(stageId: string | undefined) {
+ if (!stageId || visitedStages.value.has(stageId)) return
+ visitedStages.value.add(stageId)
+ patchSessionChecklistState(checklistPersistenceProjectId, {
+ visitedStages: [...visitedStages.value],
+ })
+}
+
const reviewedAnyway = ref(persistedState?.reviewAnyway ?? false)
const message = ref(persistedState?.message ?? null)
const generatedActiveActions = ref(null)
-const resolvedMessageAvailability = ref>(new Map())
+const resolvedMessageAvailability = ref>(new Map())
const generatedMessage = computed(() => message.value !== null)
const loadingMessage = ref(false)
const moderationDecision = ref(null)
@@ -744,26 +806,9 @@ function reviewAnyway() {
alreadyReviewed.value = false
reviewedAnyway.value = true
persistState()
- // Start prefetching the next project in the background
maintainPrefetchQueue()
}
-// Batch check locks, processing status, and fetch project metadata in parallel
-interface QueueCandidateCheck {
- locked: boolean
- expired?: boolean
- isOwnLock?: boolean
- slug?: string
- projectType?: string
- status?: string
- isProcessing: boolean
-}
-
-function isEligibleQueueCandidate(result: QueueCandidateCheck | undefined): boolean {
- if (!result?.isProcessing) return false
- return !result.locked || !!result.expired || !!result.isOwnLock
-}
-
function notifySkippedQueueProjects(count: number) {
if (count <= 0) return
addNotification({
@@ -790,66 +835,6 @@ function navigateToQueueProject(result: QueueCandidateCheck, projectId: string)
}
}
-async function batchCheckQueueCandidates(
- projectIds: string[],
-): Promise> {
- const results = new Map()
-
- const checks = await Promise.allSettled(
- projectIds.map(async (id) => {
- const [lockResponse, projectData] = await Promise.all([
- moderationQueue.checkLock(id),
- useBaseFetch(`project/${id}`, { method: 'GET' }).catch(() => null),
- ])
-
- const status = (projectData as { status?: string } | null)?.status
-
- return {
- id,
- locked: lockResponse.locked,
- expired: lockResponse.expired,
- isOwnLock: lockResponse.is_own_lock,
- slug: (projectData as { slug?: string } | null)?.slug,
- projectType: (projectData as { project_type?: string } | null)?.project_type,
- status,
- isProcessing: projectData === null ? true : status === 'processing',
- }
- }),
- )
-
- checks.forEach((result, index) => {
- if (result.status === 'fulfilled') {
- results.set(result.value.id, result.value)
- } else {
- results.set(projectIds[index], { locked: false, isProcessing: true })
- }
- })
-
- return results
-}
-
-async function findNextEligibleQueueProject(candidateIds: string[]) {
- const skippedIds: string[] = []
- let checkedCount = 0
-
- while (checkedCount < candidateIds.length) {
- const batch = candidateIds.slice(checkedCount, checkedCount + PREFETCH_BATCH_SIZE)
- checkedCount += batch.length
-
- const results = await batchCheckQueueCandidates(batch)
-
- for (const id of batch) {
- const result = results.get(id)
- if (isEligibleQueueCandidate(result)) {
- return { projectId: id, result: result!, skippedIds: [...skippedIds] }
- }
- skippedIds.push(id)
- }
- }
-
- return null
-}
-
// Maintain a queue of prefetched unlocked projects for instant navigation
async function maintainPrefetchQueue() {
if (isPrefetching.value) return
@@ -860,22 +845,18 @@ async function maintainPrefetchQueue() {
isPrefetching.value = true
try {
- // 1. Remove stale entries (validated > 30s ago)
const now = Date.now()
prefetchQueue.value = prefetchQueue.value.filter((p) => now - p.validatedAt < PREFETCH_STALE_MS)
- // 2. Remove entries for current project
if (currentProjectId) {
- prefetchQueue.value = prefetchQueue.value.filter((p) => p.projectId !== currentProjectId)
+ prefetchQueue.value = prefetchQueue.value.filter((p) => p.project !== currentProjectId)
}
- // 3. If queue is full enough, exit early
if (prefetchQueue.value.length >= PREFETCH_TARGET_COUNT) {
return
}
- // 4. Get remaining queue items (excluding current and already prefetched)
- const prefetchedIds = new Set(prefetchQueue.value.map((p) => p.projectId))
+ const prefetchedIds = new Set(prefetchQueue.value.map((p) => p.project))
const queueItems = [...moderationQueue.currentQueue.items]
const currentIndex = currentProjectId ? queueItems.indexOf(currentProjectId) : -1
const remainingItems =
@@ -885,7 +866,6 @@ async function maintainPrefetchQueue() {
if (candidateIds.length === 0) return
- const skippedIds: string[] = []
let checkedCount = 0
while (
@@ -895,22 +875,21 @@ async function maintainPrefetchQueue() {
const batch = candidateIds.slice(checkedCount, checkedCount + PREFETCH_BATCH_SIZE)
checkedCount += batch.length
- const results = await batchCheckQueueCandidates(batch)
+ const results = await batchCheckQueueCandidates(client, moderationQueue, batch)
for (const id of batch) {
const result = results.get(id)
if (isEligibleQueueCandidate(result)) {
prefetchQueue.value.push({
- projectId: id,
+ project: id,
slug: result?.slug ?? '',
projectType: result?.projectType ?? '',
validatedAt: Date.now(),
- skippedIds: [...skippedIds],
})
if (prefetchQueue.value.length >= PREFETCH_TARGET_COUNT) break
} else {
- skippedIds.push(id)
+ void moderationQueue.excludeProject(id)
}
}
}
@@ -919,11 +898,25 @@ async function maintainPrefetchQueue() {
}
}
-// Debounced prefetch to prevent spam from rapid stage changes
const debouncedPrefetch = useDebounceFn(maintainPrefetchQueue, 300)
+async function goToNextEligibleProject(candidateIds: string[]): Promise {
+ if (candidateIds.length === 0) return false
+
+ const next = await findNextEligibleQueueProject(client, moderationQueue, candidateIds)
+
+ if (!next) {
+ await Promise.all(candidateIds.map((id) => moderationQueue.excludeProject(id)))
+ return false
+ }
+
+ await Promise.all(next.excluded.map((id) => moderationQueue.excludeProject(id)))
+ notifySkippedQueueProjects(next.excluded.length)
+ navigateToQueueProject(next.result, next.project)
+ return true
+}
+
async function skipToNextProject() {
- // Skip the current project
const currentProjectId = projectV2.value?.id
if (!currentProjectId) {
console.warn('[skipToNextProject] No current project ID, aborting')
@@ -932,12 +925,11 @@ async function skipToNextProject() {
debug('[skipToNextProject] Starting. Current project:', currentProjectId)
debug('[skipToNextProject] Queue before complete:', [...moderationQueue.currentQueue.items])
- await moderationQueue.completeCurrentProject(currentProjectId, 'skipped')
+ await moderationQueue.deferProject(currentProjectId)
debug('[skipToNextProject] Queue after complete:', [...moderationQueue.currentQueue.items])
debug('[skipToNextProject] hasItems:', moderationQueue.hasItems)
- // Use prefetched data if available
if (await navigateToNextUnlockedProject()) {
debug('[skipToNextProject] Used prefetch, returning')
return
@@ -948,25 +940,12 @@ async function skipToNextProject() {
const remainingIds = moderationQueue.currentQueue.items.filter((id) => id !== currentProjectId)
if (remainingIds.length > 0) {
- const next = await findNextEligibleQueueProject(remainingIds)
-
- if (next) {
- await Promise.all(
- next.skippedIds.map((id) => moderationQueue.completeCurrentProject(id, 'skipped')),
- )
- notifySkippedQueueProjects(next.skippedIds.length)
- navigateToQueueProject(next.result, next.projectId)
- return
- }
-
- await Promise.all(
- remainingIds.map((id) => moderationQueue.completeCurrentProject(id, 'skipped')),
- )
+ if (await goToNextEligibleProject(remainingIds)) return
debug('[skipToNextProject] No eligible projects in queue')
addNotification({
title: 'No projects available',
- text: 'All remaining projects are already moderated or locked by others.',
+ text: 'All remaining projects are already moderated, deleted, or locked by others.',
type: 'warning',
})
}
@@ -989,12 +968,14 @@ const checklistHasState = computed(() =>
function resetProgress() {
if (!isPseudoStage.value && currentStageHasState.value) {
Reflect.deleteProperty(nodeStates.value, currentStageObj.value.id!)
+ activatedStages.value.delete(currentStageObj.value.id!)
clearGeneratedMessageState()
return
}
currentStage.value = findFirstValidStage()
nodeStates.value = {}
+ activatedStages.value = new Set()
done.value = false
clearGeneratedMessageState()
@@ -1027,85 +1008,82 @@ const checklistTitleText = computed(() => {
return currentStageObj.value.label ?? kebabToTitleCase(currentStageObj.value.id)
})
-const checklistLive = computed>(() => {
- const map = new Map()
+function isStageLive(stage: StageNode): boolean {
+ return stage._shown === undefined || resolve(stage._shown)
+}
+
+function isStageEffectivelyShown(stage: StageNode): boolean {
+ if (isStageLive(stage)) return true
+ return stage._shownSticky === true && activatedStages.value.has(stage.id)
+}
+
+watchEffect(() => {
+ for (const stage of resolvedStages.value) {
+ if (stage._shownSticky && isStageLive(stage) && !activatedStages.value.has(stage.id)) {
+ activatedStages.value.add(stage.id)
+ }
+ }
+})
+
+function isFixActionable(fixes: FixBuilder[], state: Record): boolean {
+ return fixes.some((f) => {
+ if (f._projectFn) {
+ const { proxy, changes } = createTrackedPatch(projectV3.value as any)
+ f._projectFn(proxy as any, state)
+ return Object.keys(changes()).length > 0
+ }
+ if (f._versionFn) {
+ const version = versions.value?.[0]
+ if (!version) return true
+ const { proxy, changes } = createTrackedPatch(version as any)
+ f._versionFn(proxy as any, state)
+ return Object.keys(changes()).length > 0
+ }
+ return false
+ })
+}
+
+function computeStageLiveNode(stage: StageNode, stageState: Record): LiveNode {
+ if (!isStageEffectivelyShown(stage)) {
+ return {
+ isActive: true,
+ isVisible: false,
+ isFixActionable: false,
+ messageCount: 0,
+ fixCount: 0,
+ hasRequiredMissing: false,
+ activeActions: [],
+ }
+ }
+
+ const stageChildren = resolveChildren(stage, stageState)
+ const metaMap = computeNodeMeta(stageChildren, stageState, isFixActionable)
+ const attentionMap = computeAttentionMap(stageChildren, stageState, metaMap)
+ const actions = collectActiveActions(stageChildren, stageState, [stage.id])
+
+ if (stage._segments.length > 0) {
+ actions.unshift({ node: stage, state: stageState, statePath: [stage.id], active: true })
+ }
+
+ return {
+ isActive: true,
+ isVisible: metaMap.size > 0,
+ isFixActionable: false,
+ messageCount: actions.length,
+ fixCount: [...metaMap.values()].filter((m) => m.isFixActionable).length,
+ hasRequiredMissing: stageChildren.some(
+ (child) => typeof child === 'object' && child !== null && attentionMap.get(child) === true,
+ ),
+ activeActions: actions,
+ }
+}
+
+const checklistLive = computed>(() => {
+ const map = new Map()
for (const stage of resolvedStages.value) {
- const stageState = (nodeStates.value[stage.id!] ?? {}) as Record
-
- let isVisible = false
- let messageCount = 0
- let fixCount = 0
- let hasRequiredMissing = false
- const stageActiveActions: ActiveAction[] = []
-
- if (stage._shown === undefined || resolve(stage._shown)) {
- if (stage._segments.length > 0) {
- messageCount++
- stageActiveActions.push({
- node: stage,
- state: stageState,
- statePath: stage._statePath ?? [],
- })
- }
-
- walkNodes(resolveChildren(stage, stageState), stageState, (node, nodeState, localState) => {
- isVisible = true
- const active = isNodeActive(node, nodeState)
- const actionState =
- node.type === 'toggle' || node.type === 'check' || node.type === 'option'
- ? (getBooleanChildState(nodeState) as Record)
- : localState
- const isRequired = !!(node as ValueNodeBuilder)._required
- const nodeActiveActions: ActiveAction[] = []
-
- let isFixActionable = false
- if (active) {
- if (node._segments.length > 0) {
- messageCount++
- nodeActiveActions.push({ node, state: actionState, statePath: node._statePath ?? [] })
- stageActiveActions.push({ node, state: actionState, statePath: node._statePath ?? [] })
- }
- isFixActionable = node._fixes.some((f) => {
- if (f._projectFn) {
- const { proxy, changes } = createTrackedPatch(projectV3.value as any)
- f._projectFn(proxy as any, actionState)
- return Object.keys(changes()).length > 0
- }
- if (f._versionFn) {
- const version = versions.value?.[0]
- if (!version) return true
- const { proxy, changes } = createTrackedPatch(version as any)
- f._versionFn(proxy as any, actionState)
- return Object.keys(changes()).length > 0
- }
- return false
- })
- if (isFixActionable) fixCount++
- }
-
- if (isRequired && !active) hasRequiredMissing = true
- map.set(node, {
- isActive: active,
- isVisible: node._shown === undefined || resolve(node._shown),
- isFixActionable,
- messageCount: active && node._segments.some((s) => s.type !== 'collect') ? 1 : 0,
- fixCount: isFixActionable ? 1 : 0,
- hasRequiredMissing: isRequired && !active,
- activeActions: nodeActiveActions,
- })
- })
- }
-
- map.set(stage, {
- isActive: true,
- isVisible,
- isFixActionable: false,
- messageCount,
- fixCount,
- hasRequiredMissing,
- activeActions: stageActiveActions,
- })
+ const stageState = (nodeStates.value[stage.id] ?? {}) as Record
+ map.set(stage, computeStageLiveNode(stage, stageState))
}
return map
@@ -1116,6 +1094,8 @@ const restoredStage = persistedState
: -1
const currentStage = ref(restoredStage >= 0 ? restoredStage : findFirstValidStage())
const initialAutoStage = currentStage.value
+const needsInitialStageSettle = !persistedState && thread.value === undefined
+const hasSettledInitialStage = ref(!needsInitialStageSettle)
// Thread data may not be loaded when currentStage is first set, so stages that depend on it
// (like re-review) may be invisible initially. Re-evaluate once thread loads.
@@ -1126,16 +1106,78 @@ if (!persistedState) {
if (thread.value === undefined) return
if (currentStage.value === initialAutoStage) {
const firstValid = findFirstValidStage()
+ console.log('[DEBUG settle]', {
+ initialAutoStage,
+ currentStage: currentStage.value,
+ firstValid,
+ initialAutoStageId: resolvedStages.value[initialAutoStage]?.id,
+ firstValidId: resolvedStages.value[firstValid]?.id,
+ })
if (firstValid !== currentStage.value) {
currentStage.value = firstValid
+ } else if (needsInitialStageSettle) {
+ markStageVisited(currentStageObj.value.id)
}
+ } else {
+ console.log('[DEBUG settle] currentStage already changed before settle', {
+ initialAutoStage,
+ currentStage: currentStage.value,
+ })
}
+ hasSettledInitialStage.value = true
},
{ once: true },
)
}
const router = useRouter()
+const route = useRoute()
+
+const projectUrlType = computed(() =>
+ getProjectTypeForUrlShorthand(
+ projectV2.value.project_type,
+ projectV2.value.loaders ?? [],
+ tags.value,
+ ),
+)
+
+let lastSyncedStageTarget: string | null = null
+function syncStageUrl(stage: StageNode | undefined) {
+ const navigate = stage?._navigate
+ console.log('[DEBUG syncStageUrl]', { stageId: stage?.id, navigate, lastSyncedStageTarget })
+ if (navigate === undefined) return
+ const target = `/${projectUrlType.value}/${projectV2.value.slug}${navigate}`
+ if (target === lastSyncedStageTarget) return
+ lastSyncedStageTarget = target
+ setTimeout(() => router.replace(target), 0)
+}
+
+watch(
+ hasSettledInitialStage,
+ (settled) => {
+ if (settled) syncStageUrl(currentStageObj.value)
+ },
+ { immediate: true },
+)
+
+const stageNavigateTarget = computed(() => {
+ const navigate = currentStageObj.value?._navigate
+ if (navigate === undefined || !projectV2.value) return null
+ const base = `/${projectUrlType.value}/${projectV2.value.slug}`
+ return navigate === '' ? base : `${base}${navigate}`
+})
+
+const stageNavigateLabel = computed(() => {
+ const navigate = currentStageObj.value?._navigate
+ if (navigate === '') return 'Project Page'
+ const segment = navigate?.split('/').filter(Boolean).pop()
+ if (!segment) return ''
+ return segment.charAt(0).toUpperCase() + segment.slice(1)
+})
+
+function navigateToStagePage() {
+ if (stageNavigateTarget.value) router.push(stageNavigateTarget.value)
+}
let persistenceEnabled = true
let persistenceTimer: ReturnType | null = null
@@ -1154,7 +1196,15 @@ function savePersistedState(open: boolean, resetReviewAnyway = false) {
currentStage.value !== findFirstValidStage() ? currentStageObj.value.id : undefined
const messageVal = message.value ?? undefined
const stateVal = Object.keys(rawState).length > 0 ? rawState : undefined
- if (!openVal && !reviewAnywayVal && !stageVal && !messageVal && !stateVal) {
+ const activatedStagesVal = activatedStages.value.size > 0 ? [...activatedStages.value] : undefined
+ if (
+ !openVal &&
+ !reviewAnywayVal &&
+ !stageVal &&
+ !messageVal &&
+ !stateVal &&
+ !activatedStagesVal
+ ) {
return clearChecklistState(checklistPersistenceProjectId)
}
return saveChecklistState(checklistPersistenceProjectId, {
@@ -1163,6 +1213,7 @@ function savePersistedState(open: boolean, resetReviewAnyway = false) {
...(stageVal && { stage: stageVal }),
...(messageVal && { message: messageVal }),
...(stateVal && { state: stateVal }),
+ ...(activatedStagesVal && { activatedStages: activatedStagesVal }),
})
}
@@ -1183,20 +1234,24 @@ async function persistStateImmediately(open: boolean, resetReviewAnyway = false)
watch(currentStage, persistState)
watch(nodeStates, persistState, { deep: true })
+watch(activatedStages, persistState, { deep: true })
watch(message, persistState)
+watch(currentStageObj, (stage) => markStageVisited(stage.id), {
+ immediate: !needsInitialStageSettle,
+})
watch(
nodeStates,
async () => {
- const active = collectActiveActions()
- const newMap = new Map()
+ const active = collectAllActiveActions()
+ const newMap = new Map()
await Promise.all(
active
- .filter((a) => a.node._segments.some((s) => s.type !== 'collect'))
+ .filter((a) => (a.node as any)._segments.some((s: any) => s.type !== 'collect'))
.map(async ({ node, state, statePath }) => {
try {
let hasContent = false
- for (const seg of node._segments) {
+ for (const seg of (node as any)._segments) {
if (seg.type === 'collect') continue
const text = await evalSegment(seg, state, statePath)
if (text?.trim()) {
@@ -1215,11 +1270,6 @@ watch(
{ deep: true, immediate: true },
)
-interface MessagePart {
- priority?: Priority
- content: string
-}
-
function handleKeybinds(event: KeyboardEvent) {
keybinds.value.handle(event, {
project: projectV2.value,
@@ -1234,12 +1284,13 @@ function handleKeybinds(event: KeyboardEvent) {
isDone: done.value,
hasGeneratedMessage: generatedMessage.value,
isLoadingMessage: loadingMessage.value,
+ isModpackPermissionsStage: false,
futureProjectCount: moderationQueue.queueLength,
visibleActionsCount: resolveChildren(
currentStageObj.value,
- nodeStates.value[currentStageObj.value.id!] ?? {},
- ).filter((c) => c instanceof NodeBuilder).length,
+ nodeStates.value[currentStageObj.value.id] ?? {},
+ ).filter((c) => typeof c === 'object' && c !== null).length,
},
actions: {
tryGoNext: nextStage,
@@ -1259,11 +1310,10 @@ function handleKeybinds(event: KeyboardEvent) {
})
}
-// Trigger debounced prefetch when user progresses through stages
watch(currentStage, () => {
// Only prefetch if we're past the first stage (user is actively moderating)
if (currentStage.value > 0) {
- debouncedPrefetch() // Use debounced version to prevent spam
+ debouncedPrefetch()
}
})
@@ -1276,23 +1326,7 @@ onMounted(async () => {
notifications.setNotificationLocation('left')
}
- const finishedId = localStorage.getItem('moderation-checklist-finished')
- if (finishedId === projectV2.value.id) {
- localStorage.removeItem('moderation-checklist-finished')
- hasNextProject.value = moderationQueue.queueLength > 0
- done.value = true
- return
- }
-
- if (projectV2.value.status !== 'processing' && !reviewedAnyway.value) {
- alreadyReviewed.value = true
- return
- }
-
- const initialStage = resolvedStages.value[currentStage.value]
- if (initialStage?._navigate) {
- router.push(`/${projectV2.value.project_type}/${projectV2.value.slug}${initialStage._navigate}`)
- }
+ if (done.value || alreadyReviewed.value) return
const result = await moderationQueue.acquireLock(projectV2.value.id)
@@ -1309,7 +1343,6 @@ onMounted(async () => {
}
lockError.value = false
- // Start countdown timer
updateLockCountdown()
lockCountdownInterval.value = setInterval(updateLockCountdown, 1000)
} else {
@@ -1355,7 +1388,6 @@ onUnmounted(() => {
void moderationQueue.releaseLock(projectId)
}
- // Clear prefetch state to prevent memory leaks
prefetchQueue.value = []
isPrefetching.value = false
})
@@ -1363,111 +1395,131 @@ onUnmounted(() => {
watch(
currentStage,
(newIndex, oldIndex) => {
- const stage = resolvedStages.value[newIndex]
- // only navigate when the stage actually changes (not on initial mount/remount)
- if (oldIndex !== undefined && newIndex !== oldIndex && stage?._navigate) {
- router.push(`/${projectV2.value.project_type}/${projectV2.value.slug}${stage._navigate}`)
+ if (hasSettledInitialStage.value && oldIndex !== undefined && newIndex !== oldIndex) {
+ syncStageUrl(resolvedStages.value[newIndex])
}
},
{ immediate: true },
)
-watch(
- () => currentStageObj.value.id,
- (stageId) => {
- if (stageId === 'versions') {
- loadVersions()
- }
- },
- { immediate: true },
-)
+loadVersions()
-function countStageActions(stage: StageNodeBuilder): number {
+function countStageActions(stage: StageNode): number {
const actions = checklistLive.value.get(stage)?.activeActions ?? []
const resolved = resolvedMessageAvailability.value
return actions.filter((a) => {
- if (a.node._segments.every((s) => s.type === 'collect')) return false
+ if ((a.node as any)._segments.every((s: any) => s.type === 'collect')) return false
return resolved.get(a.node) ?? true
}).length
}
-function countStageFixes(stage: StageNodeBuilder): number {
+function countStageFixes(stage: StageNode): number {
return checklistLive.value.get(stage)?.fixCount ?? 0
}
-function hasRequiredMissing(stage: StageNodeBuilder): boolean {
+function hasRequiredMissing(stage: StageNode): boolean {
return checklistLive.value.get(stage)?.hasRequiredMissing ?? false
}
-function collectActiveActions(): ActiveAction[] {
+function collectAllActiveActions(): ActiveAction[] {
return resolvedStages.value.flatMap((s) => checklistLive.value.get(s)?.activeActions ?? [])
}
-function isDescendant(childPath: string[], ancestorPath: string[]): boolean {
- return (
- childPath.length > ancestorPath.length && ancestorPath.every((key, i) => childPath[i] === key)
- )
+function byPriority(a: ActiveAction, b: ActiveAction): number {
+ return ((a.node as any)._priority as Priority).compareTo((b.node as any)._priority as Priority)
}
async function assembleFullMessage() {
- const allEntries = collectActiveActions()
+ const allEntries = collectAllActiveActions()
generatedActiveActions.value = allEntries
- const consumed = new Set()
+ const consumed = new Set()
- async function evalEntry(entry: ActiveAction): Promise {
- let result = ''
- for (const seg of entry.node._segments) {
- if (seg.type === 'collect') {
- let collected = ''
- for (const childEntry of allEntries) {
- if (consumed.has(childEntry.node)) continue
- if (!isDescendant(childEntry.statePath, entry.statePath)) continue
- consumed.add(childEntry.node)
- collected += await evalEntry(childEntry)
- }
- if (!collected.trim() && seg.fallback) {
- collected = await evalSegment(seg.fallback, entry.state, entry.statePath)
- }
- result += collected
- } else {
- result += await evalSegment(seg, entry.state, entry.statePath)
- }
- }
- return result
- }
-
- const parts: MessagePart[] = []
+ const parts: { entry: ActiveAction; content: string }[] = []
for (const entry of allEntries) {
if (consumed.has(entry.node)) continue
- const content = await evalEntry(entry)
+ const content = await evalActiveAction(entry, allEntries, consumed)
if (content.trim()) {
- parts.push({ priority: entry.node._priority, content })
+ parts.push({ entry, content })
}
}
- parts.sort((a, b) => {
- if (!a.priority && !b.priority) return 0
- if (!a.priority) return 1
- if (!b.priority) return -1
- return a.priority.compareTo(b.priority)
- })
+ parts.sort((a, b) => byPriority(a.entry, b.entry))
return expandVariables(
parts
- .map((p) => p.content)
- .filter((c) => c.trim().length > 0)
+ .map((p) => p.content.trim())
+ .filter((c) => c.length > 0)
.join('\n\n'),
projectV2.value,
projectV3.value,
)
}
-provide(NODE_META_KEY, checklistLive)
-provide(STATE_KEY, nodeStates)
-provide(GLOBAL_STATE_KEY, nodeStates)
+const tooltipHtmlMap = ref(new Map())
-function shouldShowStage(stage: StageNodeBuilder): boolean {
+watchEffect(async () => {
+ const stage = currentStageObj.value
+ const stageState = (nodeStates.value[stage.id] ?? {}) as Record
+ const stageChildren = resolveChildren(stage, stageState)
+ const actions = collectMessageNodes(stageChildren, stageState, [stage.id])
+
+ const newMap = new Map()
+ await Promise.all(
+ actions.map(async (entry) => {
+ try {
+ const raw = await evalActiveAction(entry, actions, new Set())
+ const expanded = expandVariables(raw, projectV2.value, projectV3.value).trim()
+ newMap.set(
+ entry.node,
+ expanded
+ ? `${renderHighlightedString(expanded)}
`
+ : '',
+ )
+ } catch {
+ newMap.set(entry.node, '')
+ }
+ }),
+ )
+ tooltipHtmlMap.value = newMap
+})
+
+const stageMeta = computed(() => {
+ const stage = currentStageObj.value
+ const stageState = (nodeStates.value[stage.id] ?? {}) as Record
+ const stageChildren = resolveChildren(stage, stageState)
+ const metaMap = computeNodeMeta(stageChildren, stageState, isFixActionable)
+ const attentionMap = computeAttentionMap(stageChildren, stageState, metaMap)
+ return { metaMap, attentionMap, tooltipHtml: tooltipHtmlMap.value }
+})
+
+const appComponentsByKey: Record = {
+ 'loader-picker': LoaderPicker,
+ 'game-version-picker': McVersionPicker,
+}
+
+const stageState = computed(
+ () => (nodeStates.value[currentStageObj.value.id] ?? {}) as Record,
+)
+const stageNodes = computed(() => resolveChildren(currentStageObj.value, stageState.value))
+
+const stageWriter: Writer = (id, value) => {
+ const stageId = currentStageObj.value.id
+ const existing = nodeStates.value[stageId]
+ const next: Record = existing ? { ...existing } : {}
+ if (value === undefined) Reflect.deleteProperty(next, id)
+ else next[id] = value
+ if (Object.keys(next).length === 0) {
+ if (existing !== undefined) Reflect.deleteProperty(nodeStates.value, stageId)
+ } else {
+ nodeStates.value[stageId] = next
+ }
+}
+
+provide(CHECKLIST_META_KEY, stageMeta)
+provide(STATE_KEY, nodeStates)
+
+function shouldShowStage(stage: StageNode): boolean {
return checklistLive.value.get(stage)?.isVisible ?? false
}
@@ -1492,6 +1544,16 @@ function previousStage() {
}
function nextStage() {
+ if (done.value) {
+ endChecklist(undefined)
+ return
+ }
+
+ if (alreadyReviewed.value || isLockedByOther.value) {
+ if (moderationQueue.isQueueMode && moderationQueue.queueLength > 1) skipToNextProject()
+ return
+ }
+
if (generatedMessage.value) return
let targetStage = currentStage.value + 1
@@ -1523,8 +1585,9 @@ async function generateMessage() {
if (loadingMessage.value) return
loadingMessage.value = true
+ markStageVisited(currentStageObj.value.id)
- router.push(`/${projectV2.value.project_type}/${projectV2.value.slug}/moderation`)
+ router.push(`/${projectUrlType.value}/${projectV2.value.slug}/moderation`)
try {
missingMdPaths.clear()
@@ -1550,6 +1613,16 @@ async function generateMessage() {
}
const hasNextProject = ref(false)
+
+const finishedId = localStorage.getItem('moderation-checklist-finished')
+if (finishedId === projectV2.value.id) {
+ localStorage.removeItem('moderation-checklist-finished')
+ hasNextProject.value = moderationQueue.queueLength > 0
+ done.value = true
+} else if (projectV2.value.status !== 'processing' && !reviewedAnyway.value) {
+ alreadyReviewed.value = true
+}
+
async function refreshModerationCaches(threadId?: string) {
const refreshes: Promise[] = [
invalidate(),
@@ -1564,7 +1637,6 @@ async function refreshModerationCaches(threadId?: string) {
}
async function sendMessage(status: ProjectStatus) {
- // Capture project data upfront to avoid null issues during async operations
const projectId = projectV2.value?.id
const threadId = projectV2.value?.thread_id
@@ -1577,8 +1649,8 @@ async function sendMessage(status: ProjectStatus) {
return
}
- const active = generatedActiveActions.value ?? collectActiveActions()
- const shouldApplyFixes = active.some((a) => a.node._applyFixes)
+ const active = [...(generatedActiveActions.value ?? collectAllActiveActions())].sort(byPriority)
+ const shouldApplyFixes = active.some((a) => (a.node as any)._applyFixes)
moderationDecision.value = status
try {
@@ -1606,7 +1678,8 @@ async function sendMessage(status: ProjectStatus) {
projectV3.value as any,
)
for (const { node, state } of active) {
- for (const f of node._fixes) {
+ if (!('_fixes' in (node as object))) continue
+ for (const f of (node as any)._fixes) {
f._projectFn?.(projectProxy, state)
}
}
@@ -1617,7 +1690,11 @@ async function sendMessage(status: ProjectStatus) {
if (versions.value) {
const versionFixes = active.flatMap(({ node, state }) =>
- node._fixes.filter((f) => f._versionFn).map((f) => ({ fix: f, state })),
+ '_fixes' in (node as object)
+ ? (node as any)._fixes
+ .filter((f: FixBuilder) => f._versionFn)
+ .map((f: FixBuilder) => ({ fix: f, state }))
+ : [],
)
if (versionFixes.length > 0) {
await Promise.all(
@@ -1636,9 +1713,15 @@ async function sendMessage(status: ProjectStatus) {
}
}
- await refreshModerationCaches(threadId)
+ const willHaveNext = await moderationQueue.completeProject(projectId)
+ // Set both states together - hasNextProject MUST be set before done
+ // to avoid the race condition where done=true renders with hasNextProject=false
+ hasNextProject.value = willHaveNext
+ done.value = true
+ clearGeneratedMessageState()
+ await nextTick()
- const willHaveNext = await moderationQueue.completeCurrentProject(projectId, 'completed')
+ await refreshModerationCaches(threadId)
await Promise.race([
moderationQueue.releaseLock(projectId),
@@ -1648,16 +1731,9 @@ async function sendMessage(status: ProjectStatus) {
if (projectFixChanges?.slug) {
const urlType = getProjectTypeForUrlShorthand(projectV2.value.project_type, [], tags.value)
localStorage.setItem('moderation-checklist-finished', projectId)
- clearGeneratedMessageState()
await navigateTo(`/${urlType}/${projectFixChanges.slug}/moderation`, { replace: true })
return
}
-
- // Set both states together - hasNextProject MUST be set before done
- // to avoid the race condition where done=true renders with hasNextProject=false
- hasNextProject.value = willHaveNext
- done.value = true
- clearGeneratedMessageState()
} catch (error) {
console.error('Error submitting moderation:', error)
addNotification({
@@ -1674,22 +1750,23 @@ async function endChecklist(status?: string) {
await clearProjectLocalStorage()
if (!hasNextProject.value) {
+ const currentProjectId = projectV2.value?.id
+ const isRealQueue =
+ !!currentProjectId &&
+ (moderationQueue.currentQueue.completed.includes(currentProjectId) ||
+ moderationQueue.currentQueue.skipped.includes(currentProjectId))
+
await navigateTo({
name: 'moderation',
state: {
confetti: true,
+ queueSummary: isRealQueue,
},
})
await nextTick()
- if (moderationQueue.currentQueue.total > 1) {
- addNotification({
- title: 'Moderation completed',
- text: `You have completed the moderation queue.`,
- type: 'success',
- })
- } else {
+ if (!isRealQueue) {
addNotification({
title: 'Moderation submitted',
text: `Project ${status ?? 'completed successfully'}.`,
@@ -1703,30 +1780,15 @@ async function endChecklist(status?: string) {
(id) => id !== currentProjectId,
)
- let foundEligible = false
- if (remainingIds.length > 0) {
- const next = await findNextEligibleQueueProject(remainingIds)
-
- if (next) {
- await Promise.all(
- next.skippedIds.map((id) => moderationQueue.completeCurrentProject(id, 'skipped')),
- )
- notifySkippedQueueProjects(next.skippedIds.length)
- navigateToQueueProject(next.result, next.projectId)
- foundEligible = true
- } else {
- await Promise.all(
- remainingIds.map((id) => moderationQueue.completeCurrentProject(id, 'skipped')),
- )
+ if (!(await goToNextEligibleProject(remainingIds))) {
+ if (remainingIds.length > 0) {
addNotification({
title: 'No projects available',
- text: 'All remaining projects are already moderated or locked by others.',
+ text: 'All remaining projects are already moderated, deleted, or locked by others.',
type: 'warning',
})
}
- }
- if (!foundEligible) {
await navigateTo({
name: 'moderation',
})
@@ -1751,7 +1813,7 @@ async function skipCurrentProject() {
new Promise((r) => setTimeout(r, 2000)),
])
- hasNextProject.value = await moderationQueue.completeCurrentProject(projectId, 'skipped')
+ hasNextProject.value = await moderationQueue.deferProject(projectId)
await endChecklist('skipped')
}
@@ -1761,8 +1823,11 @@ async function clearProjectLocalStorage() {
cancelPendingPersistence()
nodeStates.value = {}
+ activatedStages.value = new Set()
+ visitedStages.value = new Set()
message.value = null
await clearChecklistState(checklistPersistenceProjectId)
+ clearSessionChecklistState(checklistPersistenceProjectId)
}
const isLastVisibleStage = computed(() => {
@@ -1785,13 +1850,15 @@ const hasValidPreviousStage = computed(() => {
interface StageOption {
id: string
+ label: string
action: () => void
text: string
- color?: 'green'
icon?: Component
messages?: number
fixes?: number
requiredMissing?: boolean
+ visited?: boolean
+ tone?: 'green'
}
const stageOptions = computed(() => {
@@ -1799,28 +1866,36 @@ const stageOptions = computed(() => {
.map((stage, index) => {
if (!shouldShowStage(stage)) return null
+ const label = stage.label ?? kebabToTitleCase(stage.id)
return {
id: String(index),
+ label,
action: () => {
clearGeneratedMessageState()
currentStage.value = index
},
- text: stage.label ?? kebabToTitleCase(stage.id),
- color: index === currentStage.value && !generatedMessage.value ? 'green' : undefined,
+ text: label,
icon: stage._icon ?? undefined,
messages: countStageActions(stage) || undefined,
fixes: countStageFixes(stage) || undefined,
requiredMissing: hasRequiredMissing(stage) || undefined,
+ visited:
+ ((index !== currentStage.value || generatedMessage.value) &&
+ stage.id &&
+ visitedStages.value.has(stage.id)) ||
+ undefined,
+ tone: index === currentStage.value && !generatedMessage.value ? 'green' : undefined,
}
})
.filter((opt): opt is StageOption => opt !== null)
options.push({
id: 'generate-message',
+ label: 'Generate Message',
action: () => generateMessage(),
text: 'Generate Message',
- color: generatedMessage.value ? 'green' : undefined,
icon: CheckIcon,
+ tone: generatedMessage.value ? 'green' : undefined,
})
return options
diff --git a/apps/frontend/src/components/ui/moderation/checklist/ModpackPermissionsFlow.vue b/apps/frontend/src/components/ui/moderation/checklist/ModpackPermissionsFlow.vue
index 6aec854a41..f99e3a2b12 100644
--- a/apps/frontend/src/components/ui/moderation/checklist/ModpackPermissionsFlow.vue
+++ b/apps/frontend/src/components/ui/moderation/checklist/ModpackPermissionsFlow.vue
@@ -19,16 +19,30 @@
What is the approval type of {{ modPackData[currentIndex].file_name }}?
-
-
- {{ option.name }}
-
-
+ {{ option.name }}
+
@@ -74,16 +88,30 @@
>)?
-
-
- {{ option.name }}
-
-
+ {{ option.name }}
+
@@ -110,40 +138,58 @@
>?
-
-
- {{ option.name }}
-
-
+ {{ option.name }}
+
-
-
-
- Previous
-
-
-
-
-
- {{ currentIndex + 1 >= modPackData.length ? 'Complete' : 'Next' }}
-
-
+
+
+ Previous
+
+
+
+ {{ currentIndex + 1 >= modPackData.length ? 'Complete' : 'Next' }}
+
-
-
-
-
-
-
- {{ item }}
-
-
-
-
-
-
- *
-
-
-
-
-
-
-
-
-
-
-
- {{ asLabeled(child).label }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ asLabeled(child).label }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- setNodeState(asIdentified(item), v || undefined)"
- />
-
-
-
-
-
-
-
-
-
-
- {{ asButton(item).label }}
-
-
-
-
-
-
-
-
-
- {{ asLabeled(item).label }}
-
-
-
-
-
-
-
-
-
-
-
- setTextState(asIdentified(item), v)"
- />
-
-
-
-
- setTextState(asIdentified(item), v)"
- />
-
-
-
-
-
-
-
-
-
-
-
diff --git a/apps/frontend/src/components/ui/moderation/checklist/checklist-context.ts b/apps/frontend/src/components/ui/moderation/checklist/checklist-context.ts
index e5271651d6..b3d40f8d62 100644
--- a/apps/frontend/src/components/ui/moderation/checklist/checklist-context.ts
+++ b/apps/frontend/src/components/ui/moderation/checklist/checklist-context.ts
@@ -1,11 +1,5 @@
-import type { IdentifiedNodeBuilder, NodeState } from '@modrinth/moderation'
-import type { ComputedRef, InjectionKey, Ref } from 'vue'
-
-export interface ActiveAction {
- node: IdentifiedNodeBuilder
- state: Record
- statePath: string[]
-}
+import type { ActiveAction, NodeState } from '@modrinth/moderation/src/types/node'
+import type { InjectionKey, Ref } from 'vue'
export interface LiveNode {
isActive: boolean
@@ -17,7 +11,5 @@ export interface LiveNode {
activeActions: ActiveAction[]
}
-export const NODE_META_KEY: InjectionKey>> =
- Symbol('nodeMeta')
export const STATE_KEY: InjectionKey[>>> =
Symbol('checklistState')
diff --git a/apps/frontend/src/components/ui/moderation/settings/ModerationKeybind.vue b/apps/frontend/src/components/ui/moderation/settings/ModerationKeybind.vue
index 3f13325e88..377c658252 100644
--- a/apps/frontend/src/components/ui/moderation/settings/ModerationKeybind.vue
+++ b/apps/frontend/src/components/ui/moderation/settings/ModerationKeybind.vue
@@ -2,15 +2,24 @@
]
+
{{ props.title }}
-
-
-
-
-
+
+
+
+
+
+
+
+ {{ formatMessage(messages.title) }}
+
+
+ {{ formatMessage(messages.uploadVersionFirst) }}
+
+
+
+
+
-
+
+
+
+ {{ formatMessage(messages.featuredTags) }}
+
+
+ {{ current.featuredTags.length }}/{{ MAX_FEATURED_TAGS }}
+
+
+
+ {{ formatMessage(messages.featuredTagsDescription) }}
+
+
+ {{ formatMessage(messages.selectAtLeastOneCategory) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/frontend/src/pages/[type]/[project]/settings/versions.vue b/apps/frontend/src/pages/[type]/[project]/settings/versions.vue
index a0f385a639..1343a79171 100644
--- a/apps/frontend/src/pages/[type]/[project]/settings/versions.vue
+++ b/apps/frontend/src/pages/[type]/[project]/settings/versions.vue
@@ -35,16 +35,16 @@
>
-
-
- {{ formatMessage(commonProjectSettingsMessages.withheldVersionsWarningResolve) }}
-
-
-
+
+ {{ formatMessage(commonProjectSettingsMessages.withheldVersionsWarningResolve) }}
+
+
@@ -67,180 +67,189 @@
:open-modal="currentMember ? () => handleOpenCreateVersionModal() : undefined"
>
-
-
+
+
+
+ {{ formatMessage(messages.editFilesOption) }}
+
+
+
+ {{ formatMessage(messages.editDetailsOption) }}
+
+
+
+ {{ formatMessage(messages.editMetadataOption) }}
+
+
+
-
-
-
- {{ formatMessage(messages.editFilesOption) }}
-
-
-
- {{ formatMessage(messages.editDetailsOption) }}
-
-
-
- {{ formatMessage(messages.editMetadataOption) }}
-
-
-
-
-
-
-
-
- {{ formatMessage(commonMessages.downloadButton) }}
-
-
-
- {{ formatMessage(messages.openInNewTabOption) }}
-
-
-
- {{ formatMessage(messages.copyLinkOption) }}
-
-
-
- {{ formatMessage(messages.shareOption) }}
-
-
-
- {{ formatMessage(commonMessages.reportButton) }}
-
-
-
- {{ formatMessage(messages.editFilesOption) }}
-
-
-
- {{ formatMessage(messages.editDetailsOption) }}
-
-
-
- {{ formatMessage(messages.editMetadataOption) }}
-
-
-
- {{ formatMessage(commonMessages.deleteLabel) }}
-
-
-
- {{ formatMessage(messages.copyIdOption) }}
-
-
-
- {{ formatMessage(messages.copyMavenCoordinatesOption) }}
-
-
-
+ shown: !!currentMember,
+ },
+ ]"
+ @select="$event.id === 'download' && emit('onDownload')"
+ >
+
+
+
+ {{ formatMessage(commonMessages.downloadButton) }}
+
+
+
+ {{ formatMessage(messages.openInNewTabOption) }}
+
+
+
+ {{ formatMessage(messages.copyLinkOption) }}
+
+
+
+ {{ formatMessage(messages.shareOption) }}
+
+
+
+ {{ formatMessage(commonMessages.reportButton) }}
+
+
+
+ {{ formatMessage(messages.editFilesOption) }}
+
+
+
+ {{ formatMessage(messages.editDetailsOption) }}
+
+
+
+ {{ formatMessage(messages.editMetadataOption) }}
+
+
+
+ {{ formatMessage(commonMessages.deleteLabel) }}
+
+
+
+ {{ formatMessage(messages.copyIdOption) }}
+
+
+
+ {{ formatMessage(messages.copyMavenCoordinatesOption) }}
+
+
@@ -304,11 +313,13 @@
No versions created
Create your first project version.
-
- createProjectVersionModal?.openCreateVersionModal()">
- Create version
-
-
+ createProjectVersionModal?.openCreateVersionModal()"
+ >
+ Create version
+
@@ -335,7 +346,8 @@ import {
} from '@modrinth/assets'
import {
Admonition,
- ButtonStyled,
+ Button,
+ ButtonLink,
commonMessages,
commonProjectSettingsMessages,
ConfirmModal,
@@ -343,8 +355,8 @@ import {
injectModrinthClient,
injectNotificationManager,
injectProjectPageContext,
- OverflowMenu,
ProjectPageVersions,
+ TeleportOverflowMenu,
useVIntl,
} from '@modrinth/ui'
import { useTemplateRef, watch } from 'vue'
diff --git a/apps/frontend/src/pages/[type]/[project]/version/[version].vue b/apps/frontend/src/pages/[type]/[project]/version/[version].vue
index 5facef220d..193aeb89f7 100644
--- a/apps/frontend/src/pages/[type]/[project]/version/[version].vue
+++ b/apps/frontend/src/pages/[type]/[project]/version/[version].vue
@@ -65,18 +65,19 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
- {{ formatMessage(messages.packageDataPack) }}
-
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+ {{ formatMessage(messages.packageDataPack) }}
+
+
@@ -104,16 +105,16 @@
>
-
-
- {{ formatMessage(commonProjectSettingsMessages.withheldVersionsWarningResolve) }}
-
-
-
+
+ {{ formatMessage(commonProjectSettingsMessages.withheldVersionsWarningResolve) }}
+
+
@@ -127,23 +128,39 @@
class="mb-4"
>
-
-
-
- {{ formatMessage(commonMessages.downloadButton) }}
-
-
-
+
+ {{ formatMessage(commonMessages.downloadButton) }}
+
+
+
+ Open
+
+
-
-
-
- {{ formatMessage(messages.requiredResourcePack) }}
-
-
- {{ formatMessage(messages.optionalResourcePack) }}
-
-
-
+
+
+ {{ formatMessage(messages.requiredResourcePack) }}
+
+
+ {{ formatMessage(messages.optionalResourcePack) }}
+
+
-
-
-
- {{ formatMessage(messages.packageAsMod) }}
-
-
-
-
- {{ formatMessage(messages.edit) }}
-
-
-
- {{ formatMessage(messages.editMetadata) }}
-
-
-
- {{ formatMessage(messages.editDetails) }}
-
-
-
- {{ formatMessage(messages.editFiles) }}
-
-
-
- {{ formatMessage(commonMessages.deleteLabel) }}
-
-
-
-
-
-
+ {{ formatMessage(messages.packageAsMod) }}
+
+
-
-
-
- {{ formatMessage(commonMessages.reportButton) }}
+
+
+
+ {{ formatMessage(messages.editMetadata) }}
-
-
- {{ formatMessage(commonMessages.reportButton) }}
+
+
+ {{ formatMessage(messages.editDetails) }}
-
-
- {{ formatMessage(commonMessages.copyIdButton) }}
+
+
+ {{ formatMessage(messages.editFiles) }}
-
-
- {{ formatMessage(commonMessages.copyPermalinkButton) }}
+
+
+ {{ formatMessage(commonMessages.deleteLabel) }}
-
-
+
+
+
+
+
+
+ {{ formatMessage(commonMessages.reportButton) }}
+
+
+
+ {{ formatMessage(commonMessages.reportButton) }}
+
+
+
+ {{ formatMessage(commonMessages.copyIdButton) }}
+
+
+
+ {{ formatMessage(commonMessages.copyPermalinkButton) }}
+
+
-
-
-
- {{ formatMessage(commonMessages.downloadButton) }}
-
-
-
-
-
-
-
- {{ formatMessage(messages.copySha1) }}
-
-
-
- {{ formatMessage(messages.copySha512) }}
-
-
-
+
+
+ {{ formatMessage(commonMessages.downloadButton) }}
+
+
+
+
+
+ {{ formatMessage(messages.copySha1) }}
+
+
+
+ {{ formatMessage(messages.copySha512) }}
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
getSignInRouteObj(route))
const versionRouteParam = computed(() => route.params.version as string)
diff --git a/apps/frontend/src/pages/[type]/[project]/versions.vue b/apps/frontend/src/pages/[type]/[project]/versions.vue
index 7770d541b6..adefb0711f 100644
--- a/apps/frontend/src/pages/[type]/[project]/versions.vue
+++ b/apps/frontend/src/pages/[type]/[project]/versions.vue
@@ -41,192 +41,217 @@
:open-modal="currentMember ? () => handleOpenCreateVersionModal() : undefined"
>
-
-
+
+
+
+
+
+
+
+
+
+
+ Edit files
+
+
+
+ Edit details
+
+
+
+ Edit metadata
+
+
+
+
+
-
-
-
-
-
-
-
- Edit files
-
-
-
- Edit details
-
-
-
- Edit metadata
-
-
-
-
-
-
-
-
- Download
-
-
-
- Open in new tab
-
-
-
- Copy link
-
-
-
- Share
-
-
-
- Report
-
-
-
- Edit files
-
-
-
- Edit details
-
-
-
- Edit metadata
-
-
-
- Delete
-
-
-
- Copy ID
-
-
-
- Copy Maven coordinates
-
-
-
+ Download
+
+
+
+ Open in new tab
+
+
+
+ Copy link
+
+
+
+ Share
+
+
+
+ Report
+
+
+
+ Edit files
+
+
+
+ Edit details
+
+
+
+ Edit metadata
+
+
+
+ Delete
+
+
+
+ Copy ID
+
+
+
+ Copy Maven coordinates
+
+
@@ -258,15 +283,17 @@ import {
SpinnerIcon,
TrashIcon,
} from '@modrinth/assets'
+import { moderationSettings } from '@modrinth/moderation'
import {
- ButtonStyled,
+ ButtonLink,
ConfirmModal,
injectModrinthClient,
injectNotificationManager,
injectProjectPageContext,
- OverflowMenu,
ProjectPageVersions,
+ TeleportOverflowMenu,
} from '@modrinth/ui'
+import { isStaff } from '@modrinth/utils'
import { onMounted, useTemplateRef, watch } from 'vue'
import CreateProjectVersionModal from '~/components/ui/create-project-version/CreateProjectVersionModal.vue'
@@ -279,6 +306,7 @@ const { createProjectDownloadUrl, updateVersionsFilterContext } = useCdnDownload
const tags = useGeneratedState()
const flags = useFeatureFlags()
+const modSettings = useModerationSettings()
const auth = await useAuth()
const client = injectModrinthClient()
diff --git a/apps/frontend/src/pages/admin/affiliates.vue b/apps/frontend/src/pages/admin/affiliates.vue
index 92925757ce..c67abeb81c 100644
--- a/apps/frontend/src/pages/admin/affiliates.vue
+++ b/apps/frontend/src/pages/admin/affiliates.vue
@@ -27,12 +27,10 @@
placeholder="Search affiliates..."
clearable
/>
-
-
-
- Create affiliate code
-
-
+
+
+ Create affiliate code
+
@@ -90,7 +88,7 @@ import {
AffiliateLinkCard,
AffiliateLinkCreateModal,
Avatar,
- ButtonStyled,
+ Button,
ConfirmModal,
injectModrinthClient,
injectNotificationManager,
diff --git a/apps/frontend/src/pages/admin/analytics/events.vue b/apps/frontend/src/pages/admin/analytics/events.vue
index bffebfaada..f3a9dddfb3 100644
--- a/apps/frontend/src/pages/admin/analytics/events.vue
+++ b/apps/frontend/src/pages/admin/analytics/events.vue
@@ -33,19 +33,20 @@
-
- Cancel
-
-
-
-
- {{ modalMode === 'create' ? 'Create event' : 'Save' }}
-
-
+ Cancel
+
+
+ {{ modalMode === 'create' ? 'Create event' : 'Save' }}
+
@@ -137,12 +139,10 @@
clearable
wrapper-class="w-full sm:w-72"
/>
-
-
-
- New event
-
-
+
+
+ New event
+
@@ -196,21 +196,23 @@
-
-
-
-
-
-
-
- Edit
-
-
-
+
+
+
+
+ Edit
+
+
@@ -239,8 +241,8 @@ import {
SpinnerIcon,
TrashIcon,
} from '@modrinth/assets'
+import { Button, ButtonLink, IconButton } from '@modrinth/ui'
import {
- ButtonStyled,
ConfirmModal,
DatePicker,
injectModrinthClient,
@@ -485,9 +487,9 @@ async function saveEvent() {
const payload = buildEventPayload()
if (modalMode.value === 'edit' && editingEventId.value !== null) {
- await client.labrinth.analytics_v3.editEvent(editingEventId.value, payload)
+ await client.labrinth.analytics_internal.editEvent(editingEventId.value, payload)
} else {
- await client.labrinth.analytics_v3.createEvent(payload)
+ await client.labrinth.analytics_internal.createEvent(payload)
}
await queryClient.invalidateQueries({ queryKey: analyticsEventsQueryKey })
@@ -528,7 +530,7 @@ async function deleteEvent(eventId: Labrinth.Analytics.v3.AnalyticsEventId) {
setDeletingEvent(eventId, true)
try {
- await client.labrinth.analytics_v3.deleteEvent(eventId)
+ await client.labrinth.analytics_internal.deleteEvent(eventId)
await queryClient.invalidateQueries({ queryKey: analyticsEventsQueryKey })
addNotification({
title: 'Analytics event deleted',
@@ -581,7 +583,7 @@ function commitAnnouncementUrl() {
committedAnnouncementUrl.value = form.value.announcementUrl
}
-function buildEventPayload(): Labrinth.Analytics.v3.AnalyticsEventUpsert {
+function buildEventPayload(): Labrinth.Analytics.Internal.AnalyticsEventUpsert {
const selectedRange = getEventFormDateRange()
if (!selectedRange) {
throw new Error('Select a valid start and end date')
diff --git a/apps/frontend/src/pages/admin/billing/[user].vue b/apps/frontend/src/pages/admin/billing/[user].vue
index 936ac39ca3..e8e9d75300 100644
--- a/apps/frontend/src/pages/admin/billing/[user].vue
+++ b/apps/frontend/src/pages/admin/billing/[user].vue
@@ -43,18 +43,14 @@
-
-
-
- Refund charge
-
-
-
-
-
- Cancel
-
-
+
+
+ Refund charge
+
+
+
+ Cancel
+
@@ -82,18 +78,14 @@
-
-
-
- Modify charge
-
-
-
-
-
- Cancel
-
-
+
+
+ Modify charge
+
+
+
+ Cancel
+
@@ -117,18 +109,14 @@
-
-
-
- Apply credit
-
-
-
-
-
- Cancel
-
-
+
+
+ Apply credit
+
+
+
+ Cancel
+
@@ -141,13 +129,11 @@
-
-
-
- User profile
-
-
-
+
+
+ User profile
+
+
@@ -176,25 +162,20 @@
-
-
- Server panel
-
-
-
-
-
- Credit
-
-
+ Server panel
+
+
+
+ Credit
+
@@ -226,7 +207,8 @@ import {
} from '@modrinth/assets'
import {
Avatar,
- ButtonStyled,
+ Button,
+ ButtonLink,
CopyCode,
defineMessages,
DropdownSelect,
diff --git a/apps/frontend/src/pages/admin/docs.vue b/apps/frontend/src/pages/admin/docs.vue
index 557caf30fd..59847b213a 100644
--- a/apps/frontend/src/pages/admin/docs.vue
+++ b/apps/frontend/src/pages/admin/docs.vue
@@ -1,6 +1,6 @@
-
+
{
+ const { dependencies, dependency_project_ids, compatible_dependency_project_ids, ...rendered } =
+ hit as Labrinth.Search.v3.ResultSearchProject & Record
+ return rendered as Labrinth.Search.v3.ResultSearchProject
+ })
+}
+
async function fetchSearch(requestParams: string) {
debug('search() called', {
requestParams: requestParams.substring(0, 100),
@@ -241,17 +254,19 @@ async function fetchSearch(requestParams: string) {
debug('search() response', { total_hits: raw.total_hits, hitCount: raw.hits?.length })
+ const hits = stripUnrenderedFields(raw.hits ?? [])
+
if (isServerType.value) {
return {
projectHits: [],
- serverHits: raw.hits,
+ serverHits: hits,
total_hits: raw.total_hits,
per_page: raw.hits_per_page,
}
}
return {
- projectHits: raw.hits,
+ projectHits: hits,
serverHits: [],
total_hits: raw.total_hits,
per_page: raw.hits_per_page,
diff --git a/apps/frontend/src/pages/hosting/index.vue b/apps/frontend/src/pages/hosting/index.vue
index dece65edec..827298042b 100644
--- a/apps/frontend/src/pages/hosting/index.vue
+++ b/apps/frontend/src/pages/hosting/index.vue
@@ -33,7 +33,7 @@
{{ formatMessage(commonMessages.betaRelease) }}
@@ -50,21 +50,23 @@
-
-
-
- {{
- hasServers
- ? formatMessage(messages.startANewServer)
- : formatMessage(messages.startYourServer)
- }}
-
-
-
-
- {{ formatMessage(messages.manageYourServers) }}
-
-
+
+
+ {{
+ hasServers
+ ? formatMessage(messages.startANewServer)
+ : formatMessage(messages.startYourServer)
+ }}
+
+
+ {{ formatMessage(messages.manageYourServers) }}
+
@@ -108,7 +110,7 @@
{{ formatMessage(messages.whyModrinthHosting) }}
@@ -152,7 +154,7 @@
-
+
{{ formatMessage(messages.yourFavoriteMods) }}
@@ -34,8 +38,10 @@
import type { Labrinth } from '@modrinth/api-client'
import { AffiliateIcon, XCircleIcon } from '@modrinth/assets'
+import { Button } from '#ui/components/base/buttons'
+
import { defineMessages, useVIntl } from '../../composables/i18n'
-import { AutoBrandIcon, ButtonStyled, CopyCode } from '../index'
+import { AutoBrandIcon, CopyCode } from '../index'
type AffiliateCode = Labrinth.Affiliate.Internal.AffiliateCode
diff --git a/packages/ui/src/components/affiliate/AffiliateLinkCreateModal.vue b/packages/ui/src/components/affiliate/AffiliateLinkCreateModal.vue
index 217102b74e..2773092034 100644
--- a/packages/ui/src/components/affiliate/AffiliateLinkCreateModal.vue
+++ b/packages/ui/src/components/affiliate/AffiliateLinkCreateModal.vue
@@ -46,13 +46,16 @@
input-class="pl-10"
/>
-
-
-
-
- {{ formatMessage(creatingLink ? messages.creatingButton : messages.createButton) }}
-
-
+
+
+
+ {{ formatMessage(creatingLink ? messages.creatingButton : messages.createButton) }}
+
@@ -62,9 +65,11 @@
import { AffiliateIcon, PlusIcon, SpinnerIcon, UserIcon } from '@modrinth/assets'
import { computed, ref, useTemplateRef } from 'vue'
+import { Button } from '#ui/components/base/buttons'
+
import { defineMessages, useVIntl } from '../../composables/i18n'
import { commonMessages } from '../../utils/common-messages'
-import { AutoBrandIcon, ButtonStyled, NewModal, StyledInput } from '../index'
+import { AutoBrandIcon, NewModal, StyledInput } from '../index'
export type CreateAffiliateProps = { sourceName: string; username?: string }
const props = withDefaults(
diff --git a/packages/ui/src/components/base/Admonition.vue b/packages/ui/src/components/base/Admonition.vue
index 26a3bfef62..73a6bd76a8 100644
--- a/packages/ui/src/components/base/Admonition.vue
+++ b/packages/ui/src/components/base/Admonition.vue
@@ -58,17 +58,22 @@
class="col-start-3 row-start-1 flex shrink-0 items-center gap-2 self-start"
>
-
-
-
-
-
+
+
-
-
-
-
-
+
+
+
-import { ExternalIcon, UnknownIcon } from '@modrinth/assets'
-import { computed } from 'vue'
-
-const props = defineProps({
- link: {
- type: String,
- default: null,
- },
- external: {
- type: Boolean,
- default: false,
- },
- download: {
- type: String,
- default: null,
- },
- action: {
- type: Function,
- default: null,
- },
- color: {
- type: String,
- default: 'default',
- },
- iconOnly: {
- type: Boolean,
- default: false,
- },
- large: {
- type: Boolean,
- default: false,
- },
- outline: {
- type: Boolean,
- default: false,
- },
- transparent: {
- type: Boolean,
- default: false,
- },
- hoverFilled: {
- type: Boolean,
- default: false,
- },
- hoverFilledOnly: {
- type: Boolean,
- default: false,
- },
- disabled: {
- type: Boolean,
- default: false,
- },
-})
-
-const accentedButton = computed(() =>
- ['danger', 'primary', 'red', 'orange', 'green', 'blue', 'purple', 'gray'].includes(props.color),
-)
-
-const classes = computed(() => {
- const color = props.color
- return {
- 'icon-only': props.iconOnly,
- 'btn-large': props.large,
- 'btn-danger': color === 'danger',
- 'btn-primary': color === 'primary',
- 'btn-secondary': color === 'secondary',
- 'btn-highlight': color === 'highlight',
- 'btn-red': color === 'red',
- 'btn-orange': color === 'orange',
- 'btn-green': color === 'green',
- 'btn-blue': color === 'blue',
- 'btn-purple': color === 'purple',
- 'btn-gray': color === 'gray',
- 'btn-transparent': props.transparent,
- 'btn-hover-filled': props.hoverFilled,
- 'btn-hover-filled-only': props.hoverFilledOnly,
- 'btn-outline': props.outline,
- 'color-accent-contrast': accentedButton,
- disabled: props.disabled,
- }
-})
-
-
-
- {
- if (disabled) {
- event.preventDefault()
- return
- }
- if (action) {
- action(event)
- }
- }
- "
- >
-
-
-
-
- {
- if (disabled) {
- event.preventDefault()
- return
- }
- if (action) {
- action(event)
- }
- }
- "
- >
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/ui/src/components/base/ButtonStyled.vue b/packages/ui/src/components/base/ButtonStyled.vue
deleted file mode 100644
index f546054c16..0000000000
--- a/packages/ui/src/components/base/ButtonStyled.vue
+++ /dev/null
@@ -1,397 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/packages/ui/src/components/base/Card.vue b/packages/ui/src/components/base/Card.vue
index f52f4533b0..c481f17eb0 100644
--- a/packages/ui/src/components/base/Card.vue
+++ b/packages/ui/src/components/base/Card.vue
@@ -2,7 +2,7 @@
import { DropdownIcon } from '@modrinth/assets'
import { reactive } from 'vue'
-import ButtonStyled from './ButtonStyled.vue'
+import { IconButton } from '#ui/components/base/buttons'
const props = defineProps({
collapsible: {
@@ -33,11 +33,9 @@ function toggleCollapsed() {
diff --git a/packages/ui/src/components/base/Chips.vue b/packages/ui/src/components/base/Chips.vue
index e1359c469e..e7daddc930 100644
--- a/packages/ui/src/components/base/Chips.vue
+++ b/packages/ui/src/components/base/Chips.vue
@@ -15,7 +15,11 @@
}"
@click="toggleItem(item)"
>
-
+
{{ formatLabel(item) }}
@@ -24,7 +28,7 @@
-
-
-
-
- {{ primaryAction.label }}
-
-
-
-
-
-
-
- {{ action.label }}
-
-
-
-
-
-
-
-
-
diff --git a/packages/ui/src/components/base/ManySelect.vue b/packages/ui/src/components/base/ManySelect.vue
index ed495af309..b3c927d039 100644
--- a/packages/ui/src/components/base/ManySelect.vue
+++ b/packages/ui/src/components/base/ManySelect.vue
@@ -1,23 +1,19 @@
-
- {
- searchQuery = ''
- }
- "
- >
+
+
-
+
+
+
{{ getOptionLabel(option) }}
{{ getOptionLabel(option) }}
-
-
-
+
+
+
-
-
diff --git a/packages/ui/src/components/base/Pagination.vue b/packages/ui/src/components/base/Pagination.vue
index ba1eae2cda..f7a6e08cb5 100644
--- a/packages/ui/src/components/base/Pagination.vue
+++ b/packages/ui/src/components/base/Pagination.vue
@@ -1,18 +1,20 @@
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/TimeFramePicker.vue b/packages/ui/src/components/base/TimeFramePicker.vue
index 0db65f9e14..2be4e72e73 100644
--- a/packages/ui/src/components/base/TimeFramePicker.vue
+++ b/packages/ui/src/components/base/TimeFramePicker.vue
@@ -5,6 +5,9 @@
:display-value="selectedTimeframeLabel"
:max-height="maxHeight"
:trigger-class="triggerClass"
+ :trigger-type="triggerType"
+ :trigger-size="triggerSize"
+ :trigger-interaction="triggerInteraction"
:dropdown-min-width="timeframeDropdownMinWidth"
:outside-click-ignore="timeframeDropdownOutsideClickIgnore"
:dropdown-class="
@@ -103,16 +106,18 @@
-
-
- {{ formatMessage(messages.cancel) }}
-
-
-
-
- {{ formatMessage(messages.apply) }}
-
-
+
+ {{ formatMessage(messages.cancel) }}
+
+
+ {{ formatMessage(messages.apply) }}
+
@@ -196,8 +201,14 @@
import { MinusIcon, PlusIcon } from '@modrinth/assets'
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
+import {
+ Button,
+ type ButtonInteraction,
+ type ButtonSize,
+ type ButtonType,
+} from '#ui/components/base/buttons'
+
import { defineMessages, useVIntl } from '../../composables/i18n'
-import ButtonStyled from './ButtonStyled.vue'
import Combobox, { type ComboboxOption } from './Combobox.vue'
import DatePicker from './DatePicker.vue'
@@ -391,11 +402,17 @@ const props = withDefaults(
nowTimestamp?: number
maxHeight?: number
triggerClass?: string
+ triggerType?: ButtonType
+ triggerSize?: ButtonSize
+ triggerInteraction?: ButtonInteraction
dropdownMinWidth?: string | number
customRangeDropdownMinWidth?: string | number
}>(),
{
maxHeight: TIMEFRAME_DROPDOWN_MAX_HEIGHT,
+ triggerType: 'base',
+ triggerSize: 'md',
+ triggerInteraction: 'surface',
dropdownMinWidth: TIMEFRAME_DROPDOWN_MIN_WIDTH,
customRangeDropdownMinWidth: CUSTOM_RANGE_DROPDOWN_MIN_WIDTH,
},
diff --git a/packages/ui/src/components/base/UnsavedChangesPopup.vue b/packages/ui/src/components/base/UnsavedChangesPopup.vue
index 4606042c86..5c3bab9260 100644
--- a/packages/ui/src/components/base/UnsavedChangesPopup.vue
+++ b/packages/ui/src/components/base/UnsavedChangesPopup.vue
@@ -3,9 +3,10 @@ import { HistoryIcon, SaveIcon, SpinnerIcon } from '@modrinth/assets'
import { isEqual } from 'es-toolkit'
import { type Component, computed, ref } from 'vue'
+import { Button } from '#ui/components/base/buttons'
+
import { defineMessage, type MessageDescriptor, useVIntl } from '../../composables/i18n'
import { commonMessages } from '../../utils'
-import ButtonStyled from './ButtonStyled.vue'
import FloatingActionBar from './FloatingActionBar.vue'
const { formatMessage } = useVIntl()
@@ -14,20 +15,25 @@ const emit = defineEmits<{
(e: 'reset' | 'save', event: MouseEvent): void
}>()
+type SaveDisabledReason = MessageDescriptor | string
+
const props = withDefaults(
defineProps<{
canReset?: boolean
+ canSave?: boolean
original: T
modified: Partial
saving?: boolean
text?: MessageDescriptor | string
saveLabel?: MessageDescriptor | string
savingLabel?: MessageDescriptor | string
+ saveDisabledReason?: SaveDisabledReason | SaveDisabledReason[]
saveIcon?: Component
inline?: boolean
}>(),
{
canReset: true,
+ canSave: true,
saving: false,
text: () =>
defineMessage({
@@ -36,6 +42,7 @@ const props = withDefaults(
}),
saveLabel: () => commonMessages.saveButton,
savingLabel: () => commonMessages.savingButton,
+ saveDisabledReason: undefined,
saveIcon: SaveIcon,
inline: false,
},
@@ -49,6 +56,22 @@ function localizeIfPossible(message: MessageDescriptor | string) {
return typeof message === 'string' ? message : formatMessage(message)
}
+const saveDisabled = computed(() => props.saving || !props.canSave)
+
+const saveDisabledTooltip = computed(() => {
+ if (!saveDisabled.value || props.saving || !props.saveDisabledReason) {
+ return undefined
+ }
+
+ const reasons = (
+ Array.isArray(props.saveDisabledReason) ? props.saveDisabledReason : [props.saveDisabledReason]
+ ).map(localizeIfPossible)
+
+ return reasons.length > 0
+ ? { content: reasons.join('\n'), popperClass: 'unsaved-changes-save-tooltip' }
+ : undefined
+})
+
const actionBar = ref | null>(null)
function nudge(): void {
@@ -62,18 +85,35 @@ defineExpose({ nudge })
{{ localizeIfPossible(text) }}
-
- emit('reset', e)">
- {{ formatMessage(commonMessages.resetButton) }}
-
-
-
- emit('save', e)">
+ emit('reset', e)">
+ {{ formatMessage(commonMessages.resetButton) }}
+
+
+ emit('save', e)"
+ >
{{ localizeIfPossible(saving ? savingLabel : saveLabel) }}
-
-
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/Button.vue b/packages/ui/src/components/base/buttons/Button.vue
new file mode 100644
index 0000000000..6d9f4e2b44
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/Button.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/ButtonFrame.vue b/packages/ui/src/components/base/buttons/ButtonFrame.vue
new file mode 100644
index 0000000000..81d0c09f8d
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/ButtonFrame.vue
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/ButtonGroup.vue b/packages/ui/src/components/base/buttons/ButtonGroup.vue
new file mode 100644
index 0000000000..04af5b1261
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/ButtonGroup.vue
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/ButtonLink.vue b/packages/ui/src/components/base/buttons/ButtonLink.vue
new file mode 100644
index 0000000000..cb11c7c6c6
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/ButtonLink.vue
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/FileButton.vue b/packages/ui/src/components/base/buttons/FileButton.vue
new file mode 100644
index 0000000000..0c6c09b2ee
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/FileButton.vue
@@ -0,0 +1,85 @@
+
+
+
+
+
+ {{ props.prompt }}
+
+
+
diff --git a/packages/ui/src/components/base/buttons/IconButton.vue b/packages/ui/src/components/base/buttons/IconButton.vue
new file mode 100644
index 0000000000..6fe601fb2b
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/IconButton.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/SplitButton.vue b/packages/ui/src/components/base/buttons/SplitButton.vue
new file mode 100644
index 0000000000..40badebad8
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/SplitButton.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/TeleportOverflowMenu.vue b/packages/ui/src/components/base/buttons/TeleportOverflowMenu.vue
new file mode 100644
index 0000000000..a9f638197d
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/TeleportOverflowMenu.vue
@@ -0,0 +1,484 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/TeleportPopoutMenu.vue b/packages/ui/src/components/base/buttons/TeleportPopoutMenu.vue
new file mode 100644
index 0000000000..d365b1673a
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/TeleportPopoutMenu.vue
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/base/buttons/index.ts b/packages/ui/src/components/base/buttons/index.ts
new file mode 100644
index 0000000000..cbfc192984
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/index.ts
@@ -0,0 +1,23 @@
+export { default as Button } from './Button.vue'
+export { default as ButtonGroup } from './ButtonGroup.vue'
+export { default as ButtonLink } from './ButtonLink.vue'
+export { default as FileButton } from './FileButton.vue'
+export { default as IconButton } from './IconButton.vue'
+export { default as SplitButton } from './SplitButton.vue'
+export { default as TeleportOverflowMenu } from './TeleportOverflowMenu.vue'
+export { default as TeleportPopoutMenu } from './TeleportPopoutMenu.vue'
+export type {
+ ButtonColor,
+ ButtonElementHandle,
+ ButtonInteraction,
+ ButtonLinkDestination,
+ ButtonNativeType,
+ ButtonSize,
+ ButtonType,
+ ButtonVisualProps,
+ OverflowMenuAction,
+ OverflowMenuDivider,
+ OverflowMenuLink,
+ OverflowMenuOption,
+ TeleportPlacement,
+} from './types'
diff --git a/packages/ui/src/components/base/buttons/types.ts b/packages/ui/src/components/base/buttons/types.ts
new file mode 100644
index 0000000000..f50eb35dcd
--- /dev/null
+++ b/packages/ui/src/components/base/buttons/types.ts
@@ -0,0 +1,105 @@
+import type { Component } from 'vue'
+import type { RouteLocationRaw } from 'vue-router'
+
+import type { AnchoredTeleportPlacement } from '../../../utils/use-anchored-teleport'
+
+export type ButtonType = 'base' | 'colored' | 'outlined' | 'quiet'
+
+export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
+
+export type ButtonInteraction = 'surface' | 'filled' | 'none'
+
+// TODO: Standardized color string enum props across @modrinth/ui
+export type ButtonColor =
+ | 'brand'
+ | 'red'
+ | 'orange'
+ | 'green'
+ | 'blue'
+ | 'purple'
+ | 'medal_promotion'
+
+export type ButtonVisualProps = {
+ size?: ButtonSize
+ interaction?: ButtonInteraction
+} & (
+ | {
+ type?: 'base'
+ color?: never
+ }
+ | {
+ type: 'outlined'
+ color?: ButtonColor
+ }
+ | {
+ type: 'colored'
+ color?: ButtonColor
+ }
+ | {
+ type: 'quiet'
+ color?: ButtonColor
+ }
+)
+
+export type ButtonNativeType = 'button' | 'submit' | 'reset'
+
+export interface ButtonProps {
+ type?: ButtonType
+ color?: ButtonColor
+ size?: ButtonSize
+ interaction?: ButtonInteraction
+ nativeType?: ButtonNativeType
+ disabled?: boolean
+ loading?: boolean
+}
+
+export type ButtonLinkDestination =
+ | {
+ to: RouteLocationRaw
+ href?: never
+ }
+ | {
+ href: string
+ to?: never
+ }
+
+export type TeleportPlacement = AnchoredTeleportPlacement
+
+export interface OverflowMenuItemBase {
+ id: string
+ label: string
+ icon?: Component
+ shown?: boolean
+ disabled?: boolean
+ tooltip?: string
+ remainOpen?: boolean
+ tone?: 'default' | ButtonColor
+ hoverFilled?: boolean
+ hoverFilledOnly?: boolean
+}
+
+export interface OverflowMenuAction extends OverflowMenuItemBase {
+ type?: 'action'
+ action: (event: MouseEvent) => void
+}
+
+export interface OverflowMenuLink extends OverflowMenuItemBase {
+ type: 'link'
+ to?: RouteLocationRaw
+ href?: string
+ target?: string
+ rel?: string
+ download?: string | boolean
+}
+
+export interface OverflowMenuDivider {
+ type: 'divider'
+ id?: string
+ shown?: boolean
+}
+
+export type OverflowMenuOption = OverflowMenuAction | OverflowMenuLink | OverflowMenuDivider
+
+export interface ButtonElementHandle {
+ element: HTMLElement | null
+}
diff --git a/packages/ui/src/components/base/index.ts b/packages/ui/src/components/base/index.ts
index 1373522c33..1f9405d81d 100644
--- a/packages/ui/src/components/base/index.ts
+++ b/packages/ui/src/components/base/index.ts
@@ -9,8 +9,27 @@ export { default as Badge } from './Badge.vue'
export { default as BaseTerminal } from './BaseTerminal.vue'
export { default as BigOptionButton } from './BigOptionButton.vue'
export { default as BulletDivider } from './BulletDivider.vue'
-export { default as Button } from './Button.vue'
-export { default as ButtonStyled } from './ButtonStyled.vue'
+export { default as Button } from './buttons/Button.vue'
+export { default as ButtonGroup } from './buttons/ButtonGroup.vue'
+export { default as ButtonLink } from './buttons/ButtonLink.vue'
+export { default as FileButton } from './buttons/FileButton.vue'
+export { default as IconButton } from './buttons/IconButton.vue'
+export { default as SplitButton } from './buttons/SplitButton.vue'
+export { default as TeleportOverflowMenu } from './buttons/TeleportOverflowMenu.vue'
+export { default as TeleportPopoutMenu } from './buttons/TeleportPopoutMenu.vue'
+export type {
+ ButtonColor,
+ ButtonInteraction,
+ ButtonNativeType,
+ ButtonSize,
+ ButtonType,
+ ButtonVisualProps,
+ OverflowMenuAction,
+ OverflowMenuDivider,
+ OverflowMenuLink,
+ OverflowMenuOption,
+ TeleportPlacement,
+} from './buttons/types'
export { default as Card } from './Card.vue'
export { default as Checkbox } from './Checkbox.vue'
export { default as Chips } from './Chips.vue'
@@ -46,8 +65,6 @@ export { default as HorizontalRule } from './HorizontalRule.vue'
export { default as I18nDebugPanel } from './I18nDebugPanel.vue'
export { default as IconSelect } from './IconSelect.vue'
export { default as IntlFormatted } from './IntlFormatted.vue'
-export type { JoinedButtonAction } from './JoinedButtons.vue'
-export { default as JoinedButtons } from './JoinedButtons.vue'
export { default as LoadingBar } from './LoadingBar.vue'
export { default as LoadingIndicator } from './LoadingIndicator.vue'
export { default as ManySelect } from './ManySelect.vue'
@@ -62,8 +79,6 @@ export type { MaybeCtxFn, StageButtonConfig, StageConfigInput } from './MultiSta
export { default as MultiStageModal, resolveCtxFn } from './MultiStageModal.vue'
export { default as NavTabs } from './NavTabs.vue'
export { default as OptionGroup } from './OptionGroup.vue'
-export type { Option as OverflowMenuOption } from './OverflowMenu.vue'
-export { default as OverflowMenu } from './OverflowMenu.vue'
export { default as Page } from './Page.vue'
export { default as PageHeader } from './page-header/index.vue'
export { default as PageHeaderMetadata } from './page-header/metadata/index.vue'
@@ -104,13 +119,9 @@ export type { SortDirection, TableColumn } from './Table.vue'
export { default as Table } from './Table.vue'
export type { TabsTab, TabsValue } from './Tabs.vue'
export { default as Tabs } from './Tabs.vue'
+export { default as TagIcon } from './TagIcon.vue'
export { default as TagItem } from './TagItem.vue'
export { default as TagTagItem } from './TagTagItem.vue'
-export type {
- Item as TeleportOverflowMenuItem,
- Option as TeleportOverflowMenuOption,
-} from './TeleportOverflowMenu.vue'
-export { default as TeleportOverflowMenu } from './TeleportOverflowMenu.vue'
export type {
TimeFrameLastUnit,
TimeFrameLastUnitOption,
diff --git a/packages/ui/src/components/billing/AddPaymentMethodModal.vue b/packages/ui/src/components/billing/AddPaymentMethodModal.vue
index 8e1361adb6..a05eaf4f20 100644
--- a/packages/ui/src/components/billing/AddPaymentMethodModal.vue
+++ b/packages/ui/src/components/billing/AddPaymentMethodModal.vue
@@ -3,9 +3,11 @@ import { PlusIcon, XIcon } from '@modrinth/assets'
import type Stripe from 'stripe'
import { nextTick, ref, useTemplateRef } from 'vue'
+import { Button } from '#ui/components/base/buttons'
+
import { defineMessages, useVIntl } from '../../composables/i18n'
import { commonMessages } from '../../utils'
-import { ButtonStyled, NewModal } from '../index'
+import { NewModal } from '../index'
import type { AddPaymentMethodProps } from './AddPaymentMethod.vue'
import AddPaymentMethod from './AddPaymentMethod.vue'
@@ -57,18 +59,14 @@ defineExpose({
@stop-loading="loading = false"
/>
diff --git a/packages/ui/src/components/billing/ModrinthServersPurchaseModal.vue b/packages/ui/src/components/billing/ModrinthServersPurchaseModal.vue
index bdae9d75ed..14c1eacd8a 100644
--- a/packages/ui/src/components/billing/ModrinthServersPurchaseModal.vue
+++ b/packages/ui/src/components/billing/ModrinthServersPurchaseModal.vue
@@ -12,12 +12,12 @@ import { useQueryClient } from '@tanstack/vue-query'
import type Stripe from 'stripe'
import { computed, nextTick, onBeforeUnmount, ref, toRef, useTemplateRef, watch } from 'vue'
+import { Button } from '#ui/components/base/buttons'
import { injectNotificationManager } from '#ui/providers/web-notifications.ts'
import { defineMessage, type MessageDescriptor, useVIntl } from '../../composables/i18n'
import { useStripe } from '../../composables/stripe'
import { commonMessages } from '../../utils'
-import { ButtonStyled } from '../index'
import ModalLoadingIndicator from '../modal/ModalLoadingIndicator.vue'
import NewModal from '../modal/NewModal.vue'
import PlanSelector from './ServersPurchase0Plan.vue'
@@ -555,51 +555,50 @@ function goToBreadcrumbStep(id: string) {
-
-
- {{ formatMessage(commonMessages.backButton) }}
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
- {
- if (props.onFinalizeNoPaymentChange) {
- try {
- await props.onFinalizeNoPaymentChange()
- } catch (e) {
- return
- }
+
+ {{ formatMessage(commonMessages.backButton) }}
+
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+ {
+ if (props.onFinalizeNoPaymentChange) {
+ try {
+ await props.onFinalizeNoPaymentChange()
+ } catch (e) {
+ return
}
- modal?.hide()
- })()
- : setStep(nextStep)
- "
- >
-
- Confirm Change
-
-
-
- Subscribe
-
-
+ }
+ modal?.hide()
+ })()
+ : setStep(nextStep)
+ "
+ >
+
+ Confirm Change
- {{ formatMessage(commonMessages.nextButton) }}
+
+
+ Subscribe
-
-
+
+
+ {{ formatMessage(commonMessages.nextButton) }}
+
+
diff --git a/packages/ui/src/components/billing/PurchaseModal.vue b/packages/ui/src/components/billing/PurchaseModal.vue
index d1753d10a0..5c291fb92a 100644
--- a/packages/ui/src/components/billing/PurchaseModal.vue
+++ b/packages/ui/src/components/billing/PurchaseModal.vue
@@ -86,7 +86,7 @@
}"
@click="serverLoader = loader"
>
-
+
{{ loader }}
@@ -478,9 +478,9 @@ import Checkbox from '../base/Checkbox.vue'
import Combobox from '../base/Combobox.vue'
import Slider from '../base/Slider.vue'
import StyledInput from '../base/StyledInput.vue'
+import TagIcon from '../base/TagIcon.vue'
import AnimatedLogo from '../brand/AnimatedLogo.vue'
import NewModal from '../modal/NewModal.vue'
-import LoaderIcon from '../servers/icons/LoaderIcon.vue'
const { formatMessage } = useVIntl()
const formatPrice = useFormatPrice()
diff --git a/packages/ui/src/components/billing/ResubscribeModal.vue b/packages/ui/src/components/billing/ResubscribeModal.vue
index 298416af3b..084f3a0a35 100644
--- a/packages/ui/src/components/billing/ResubscribeModal.vue
+++ b/packages/ui/src/components/billing/ResubscribeModal.vue
@@ -78,18 +78,14 @@
-
-
-
- {{ formatMessage(messages.cancelButton) }}
-
-
-
-
-
- {{ formatMessage(messages.resubscribeButton) }}
-
-
+
+
+ {{ formatMessage(messages.cancelButton) }}
+
+
+
+ {{ formatMessage(messages.resubscribeButton) }}
+
@@ -100,12 +96,13 @@ import type { Labrinth } from '@modrinth/api-client'
import { RotateCounterClockwiseIcon, XIcon } from '@modrinth/assets'
import { computed, ref, useTemplateRef } from 'vue'
+import { Button } from '#ui/components/base/buttons'
import { injectNotificationManager } from '#ui/providers/web-notifications.ts'
import { useFormatDateTime, useFormatPrice } from '../../composables'
import { defineMessages, useVIntl } from '../../composables/i18n'
import IntlFormatted from '../base/IntlFormatted.vue'
-import { ButtonStyled, NewModal } from '../index'
+import { NewModal } from '../index'
const { addNotification } = injectNotificationManager()
const { formatMessage } = useVIntl()
diff --git a/packages/ui/src/components/billing/ServersGuestPlanModal.vue b/packages/ui/src/components/billing/ServersGuestPlanModal.vue
index f99f2ecc52..f1322c88ac 100644
--- a/packages/ui/src/components/billing/ServersGuestPlanModal.vue
+++ b/packages/ui/src/components/billing/ServersGuestPlanModal.vue
@@ -3,7 +3,8 @@ import type { Labrinth } from '@modrinth/api-client'
import { ChevronRightIcon, ExternalIcon, XIcon } from '@modrinth/assets'
import { computed, ref, useTemplateRef } from 'vue'
-import ButtonStyled from '../base/ButtonStyled.vue'
+import { Button, IconButton } from '#ui/components/base/buttons'
+
import NewModal from '../modal/NewModal.vue'
import type { ServerBillingInterval } from './ModrinthServersPurchaseModal.vue'
import PlanSelector from './ServersPurchase0Plan.vue'
@@ -143,11 +144,9 @@ defineExpose({
class="absolute inset-x-0 bottom-0 -m-px z-30 rounded-2xl border border-solid border-surface-5 bg-bg-raised p-6 shadow-2xl"
>
-
-
-
-
-
+
+
+
@@ -155,12 +154,10 @@ defineExpose({
Sign in to continue your purchase
You need a Modrinth account to add your billing details.
-
-
- Sign in or create an account
-
-
-
+
+ Sign in or create an account
+
+
diff --git a/packages/ui/src/components/billing/ServersPurchase0Plan.vue b/packages/ui/src/components/billing/ServersPurchase0Plan.vue
index 456b324aea..16d85c9fbb 100644
--- a/packages/ui/src/components/billing/ServersPurchase0Plan.vue
+++ b/packages/ui/src/components/billing/ServersPurchase0Plan.vue
@@ -3,10 +3,11 @@ import type { Labrinth } from '@modrinth/api-client'
import { RightArrowIcon } from '@modrinth/assets'
import { computed } from 'vue'
+import { Button } from '#ui/components/base/buttons'
+
import { useFormatPrice } from '../../composables'
import { defineMessages, useVIntl } from '../../composables/i18n'
import { getPriceForInterval, monthsInInterval } from '../../utils/product-utils'
-import ButtonStyled from '../base/ButtonStyled.vue'
import OptionGroup from '../base/OptionGroup.vue'
import type { ServerBillingInterval } from './ModrinthServersPurchaseModal.vue'
import ServersSpecs from './ServersSpecs.vue'
@@ -218,19 +219,19 @@ function selectCustom() {
-
-
- {{
- existingPlan?.id === plansByRam.small.id
- ? formatMessage(messages.yourCurrentPlan)
- : formatMessage(messages.selectPlan)
- }}
-
-
+
+ {{
+ existingPlan?.id === plansByRam.small.id
+ ? formatMessage(messages.yourCurrentPlan)
+ : formatMessage(messages.selectPlan)
+ }}
+
-
+
{{ formatMessage(messages.mostPopular) }}
@@ -281,19 +280,19 @@ function selectCustom() {
-
-
- {{
- existingPlan?.id === plansByRam.medium.id
- ? formatMessage(messages.yourCurrentPlan)
- : formatMessage(messages.selectPlan)
- }}
-
-
+
+ {{
+ existingPlan?.id === plansByRam.medium.id
+ ? formatMessage(messages.yourCurrentPlan)
+ : formatMessage(messages.selectPlan)
+ }}
+
-
-
- {{
- existingPlan?.id === plansByRam.large.id
- ? formatMessage(messages.yourCurrentPlan)
- : formatMessage(messages.selectPlan)
- }}
-
-
+
+ {{
+ existingPlan?.id === plansByRam.large.id
+ ? formatMessage(messages.yourCurrentPlan)
+ : formatMessage(messages.selectPlan)
+ }}
+
-
-
- {{ formatMessage(messages.getStarted) }}
-
-
+
+ {{ formatMessage(messages.getStarted) }}
+
Starting at {{ formatPrice(customStartingPrice, currency, true) }}/mo
diff --git a/packages/ui/src/components/billing/ServersPurchase3Review.vue b/packages/ui/src/components/billing/ServersPurchase3Review.vue
index bfe6096c8d..ce76cbc1af 100644
--- a/packages/ui/src/components/billing/ServersPurchase3Review.vue
+++ b/packages/ui/src/components/billing/ServersPurchase3Review.vue
@@ -15,11 +15,12 @@ import dayjs from 'dayjs'
import type Stripe from 'stripe'
import { computed } from 'vue'
+import { Button } from '#ui/components/base/buttons'
+
import { useFormatPrice } from '../../composables'
import { useVIntl } from '../../composables/i18n'
import { getPriceForInterval, monthsInInterval } from '../../utils/product-utils'
import { regionOverrides } from '../../utils/regions'
-import ButtonStyled from '../base/ButtonStyled.vue'
import Checkbox from '../base/Checkbox.vue'
import TagItem from '../base/TagItem.vue'
import ModrinthServersIcon from '../servers/ModrinthServersIcon.vue'
@@ -323,12 +324,10 @@ function setInterval(newInterval: ServerBillingInterval) {
No payment method selected
-
-
- Change
- Select payment method
-
-
+
+ Change
+ Select payment method
+
diff --git a/packages/ui/src/components/chart/Chart.vue b/packages/ui/src/components/chart/Chart.vue
index 43c11e1fb5..72d42bc67a 100644
--- a/packages/ui/src/components/chart/Chart.vue
+++ b/packages/ui/src/components/chart/Chart.vue
@@ -4,7 +4,7 @@ import dayjs from 'dayjs'
import { defineAsyncComponent, onMounted, ref } from 'vue'
import { useFormatNumber } from '../../composables/index.ts'
-import Button from '../base/Button.vue'
+import { IconButton } from '../base/buttons'
import Checkbox from '../base/Checkbox.vue'
const VueApexCharts = defineAsyncComponent(() => import('vue3-apexcharts'))
@@ -231,12 +231,16 @@ defineExpose({
diff --git a/packages/ui/src/components/external_files/AddFilesToAttributionGroupModal.vue b/packages/ui/src/components/external_files/AddFilesToAttributionGroupModal.vue
index fc94cf5af1..effcec44fa 100644
--- a/packages/ui/src/components/external_files/AddFilesToAttributionGroupModal.vue
+++ b/packages/ui/src/components/external_files/AddFilesToAttributionGroupModal.vue
@@ -3,7 +3,8 @@ import type { Labrinth } from '@modrinth/api-client'
import { CheckIcon, PlusIcon, SearchIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
import { computed, nextTick, ref } from 'vue'
-import { ButtonStyled, NewModal, StyledInput } from '#ui/components'
+import { NewModal, StyledInput } from '#ui/components'
+import { Button } from '#ui/components/base/buttons'
import { commonMessages } from '#ui/utils'
import { defineMessages, useVIntl } from '../../composables/i18n'
@@ -263,23 +264,21 @@ defineExpose({ show, hide })
{{ formatMessage(messages.addFilesModalSelectedCount, { count: selectedFileCount }) }}
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
-
- {{ formatMessage(messages.addFilesModalConfirm, { count: selectedFileCount }) }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+
+ {{ formatMessage(messages.addFilesModalConfirm, { count: selectedFileCount }) }}
+
diff --git a/packages/ui/src/components/external_files/AddToExistingExternalProjectModal.vue b/packages/ui/src/components/external_files/AddToExistingExternalProjectModal.vue
index 9ad61e3b1a..85ccadcae4 100644
--- a/packages/ui/src/components/external_files/AddToExistingExternalProjectModal.vue
+++ b/packages/ui/src/components/external_files/AddToExistingExternalProjectModal.vue
@@ -4,7 +4,8 @@ import { PlusIcon, SearchIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
import { useMutation } from '@tanstack/vue-query'
import { computed, ref, useTemplateRef } from 'vue'
-import { Accordion, ButtonStyled, NewModal, StyledInput } from '#ui/components'
+import { Accordion, NewModal, StyledInput } from '#ui/components'
+import { Button } from '#ui/components/base/buttons'
import { injectModrinthClient, injectNotificationManager } from '../../providers'
import AttributionGroupFilePicker from './AttributionGroupFilePicker.vue'
@@ -228,12 +229,15 @@ defineExpose({ show, hide })
wrapper-class="flex-1 min-w-[12rem]"
:disabled="addFilesMutation.isPending.value"
/>
-
-
-
- Search
-
-
+
+
+ Search
+
-
-
- {{ selectedProjectId === project.id ? 'Selected' : 'Select' }}
-
-
+
+ {{ selectedProjectId === project.id ? 'Selected' : 'Select' }}
+
@@ -306,22 +308,29 @@ defineExpose({ show, hide })
/>
-
-
-
- Cancel
-
-
-
-
-
-
- Add files to entry
-
-
+
+
+ Cancel
+
+
+
+
+ Add files to entry
+
diff --git a/packages/ui/src/components/external_files/AddToGlobalPermissionsDatabaseModal.vue b/packages/ui/src/components/external_files/AddToGlobalPermissionsDatabaseModal.vue
index c3a55d80d0..e36d1785d9 100644
--- a/packages/ui/src/components/external_files/AddToGlobalPermissionsDatabaseModal.vue
+++ b/packages/ui/src/components/external_files/AddToGlobalPermissionsDatabaseModal.vue
@@ -4,14 +4,8 @@ import { PlusIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
import { useMutation } from '@tanstack/vue-query'
import { computed, ref, useTemplateRef } from 'vue'
-import {
- Accordion,
- ButtonStyled,
- Combobox,
- type ComboboxOption,
- NewModal,
- StyledInput,
-} from '#ui/components'
+import { Accordion, Combobox, type ComboboxOption, NewModal, StyledInput } from '#ui/components'
+import { Button } from '#ui/components/base/buttons'
import { injectModrinthClient, injectNotificationManager } from '../../providers'
import AttributionGroupFilePicker from './AttributionGroupFilePicker.vue'
@@ -223,22 +217,26 @@ defineExpose({ show, hide })
-
-
-
- Cancel
-
-
-
-
-
-
- Add to global database
-
-
+
+
+ Cancel
+
+
+
+
+ Add to global database
+
diff --git a/packages/ui/src/components/external_files/AttributionEditor.vue b/packages/ui/src/components/external_files/AttributionEditor.vue
index 3694793a02..82e99ad7cb 100644
--- a/packages/ui/src/components/external_files/AttributionEditor.vue
+++ b/packages/ui/src/components/external_files/AttributionEditor.vue
@@ -14,8 +14,9 @@ import { builtinLicenses } from '@modrinth/utils'
import { useMutation, useQueryClient } from '@tanstack/vue-query'
import { computed, ref, watch } from 'vue'
-import { ButtonStyled, Chips, Combobox, type ComboboxOption, StyledInput } from '#ui/components'
+import { Chips, Combobox, type ComboboxOption, StyledInput } from '#ui/components'
import { FileInput } from '#ui/components/base'
+import { Button, IconButton } from '#ui/components/base/buttons'
import { commonMessages } from '#ui/utils'
import { defineMessage, defineMessages, useVIntl } from '../../composables/i18n'
@@ -577,15 +578,14 @@ function cancelEditing() {
class="flex w-full object-contain bg-surface-3"
/>
-
-
-
-
-
+
+
+
@@ -633,29 +633,29 @@ function cancelEditing() {
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
-
- {{ formatMessage(commonMessages.savingButton) }}
-
-
- {{ formatMessage(messages.saveAttribution) }}
-
- {{ formatMessage(messages.addAttribution) }}
-
-
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+
+ {{ formatMessage(commonMessages.savingButton) }}
+
+
+ {{ formatMessage(messages.saveAttribution) }}
+
+ {{ formatMessage(messages.addAttribution) }}
+
diff --git a/packages/ui/src/components/external_files/ExternalProjectLookupCard.vue b/packages/ui/src/components/external_files/ExternalProjectLookupCard.vue
index 4bf6a34a92..2467b5d3cf 100644
--- a/packages/ui/src/components/external_files/ExternalProjectLookupCard.vue
+++ b/packages/ui/src/components/external_files/ExternalProjectLookupCard.vue
@@ -9,7 +9,8 @@ import {
import { Menu } from 'floating-vue'
import { computed } from 'vue'
-import { ButtonStyled, CopyCode } from '#ui/components'
+import { CopyCode } from '#ui/components'
+import { IconButton } from '#ui/components/base/buttons'
import ExternalProjectLicenseStateTag from './ExternalProjectLicenseStateTag.vue'
import type { ExternalLicenseStatus } from './types.ts'
@@ -58,11 +59,16 @@ async function copyProjectLink() {
Project link
-
-
-
-
-
+
+
+
diff --git a/packages/ui/src/components/external_files/ExternalProjectPermissionsCard.vue b/packages/ui/src/components/external_files/ExternalProjectPermissionsCard.vue
index bb26531235..9dc39af921 100644
--- a/packages/ui/src/components/external_files/ExternalProjectPermissionsCard.vue
+++ b/packages/ui/src/components/external_files/ExternalProjectPermissionsCard.vue
@@ -18,8 +18,9 @@ import { renderString } from '@modrinth/utils'
import { useMutation, useQueryClient } from '@tanstack/vue-query'
import { computed, ref, useTemplateRef, watch } from 'vue'
-import { ButtonStyled, Collapsible, ConfirmModal, OverflowMenu } from '#ui/components'
+import { Collapsible, ConfirmModal } from '#ui/components'
import type { OverflowMenuOption } from '#ui/components/base'
+import { Button, IconButton, TeleportOverflowMenu } from '#ui/components/base/buttons'
import { commonMessages } from '#ui/utils'
import { defineMessage, defineMessages, useVIntl } from '../../composables/i18n'
@@ -498,6 +499,7 @@ const visibleQuickReplies = computed(() => {
(reply) =>
({
id: reply.label,
+ label: reply.label,
action: () => handleQuickReply(reply),
}) as OverflowMenuOption,
)
@@ -577,28 +579,27 @@ const visibleQuickReplies = computed(() => {
-
-
-
-
-
-
+
+
+
+
-
-
- {{ formatMessage(messages.addFilesToGroup) }}
-
-
+
+ {{ formatMessage(messages.addFilesToGroup) }}
+
@@ -644,11 +645,9 @@ const visibleQuickReplies = computed(() => {
"
#actions
>
-
-
- {{ formatMessage(commonMessages.editButton) }}
-
-
+
+ {{ formatMessage(commonMessages.editButton) }}
+
-
-
- Reply presets
-
-
-
-
-
-
-
- Approve
-
-
-
-
-
-
- Reject: Insufficient proof
-
-
-
-
-
-
- Reject: Not allowed
-
-
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
+
+ Reply presets
+
+
+
+
+
+ Approve
+
+
+
+
+ Reject: Insufficient proof
+
+
+
+
+ Reject: Not allowed
+
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
-
-
- Add files to database...
-
-
-
-
- Add to existing entry...
-
-
+
+ Add files to database...
+
+
+ Add to existing entry...
+
@@ -808,12 +809,10 @@ const visibleQuickReplies = computed(() => {
"
class="ml-auto"
>
-
-
-
- {{ formatMessage(commonMessages.editButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.editButton) }}
+
@@ -835,16 +834,19 @@ const visibleQuickReplies = computed(() => {
/>
-
-
-
-
- {{ formatMessage(messages.removeGroup) }}
-
-
+
+
+
+ {{ formatMessage(messages.removeGroup) }}
+
diff --git a/packages/ui/src/components/flows/creation-flow-modal/components/CustomSetupStage.vue b/packages/ui/src/components/flows/creation-flow-modal/components/CustomSetupStage.vue
index 2d20d1a1a0..9899a8d370 100644
--- a/packages/ui/src/components/flows/creation-flow-modal/components/CustomSetupStage.vue
+++ b/packages/ui/src/components/flows/creation-flow-modal/components/CustomSetupStage.vue
@@ -4,18 +4,14 @@
-
-
-
- {{ formatMessage(messages.selectIcon) }}
-
-
-
-
-
- {{ formatMessage(messages.removeIcon) }}
-
-
+
+
+ {{ formatMessage(messages.selectIcon) }}
+
+
+
+ {{ formatMessage(messages.removeIcon) }}
+
@@ -153,11 +149,11 @@ import { EyeIcon, EyeOffIcon, UploadIcon, XIcon } from '@modrinth/assets'
import { commonMessages, defineMessages, useVIntl } from '@modrinth/ui'
import { computed, onMounted, ref, watch } from 'vue'
+import { Button } from '#ui/components/base/buttons'
import { useDebugLogger } from '#ui/composables/debug-logger'
import { injectFilePicker, injectModrinthClient, injectTags } from '../../../../providers'
import Avatar from '../../../base/Avatar.vue'
-import ButtonStyled from '../../../base/ButtonStyled.vue'
import Chips from '../../../base/Chips.vue'
import Collapsible from '../../../base/Collapsible.vue'
import Combobox, { type ComboboxOption } from '../../../base/Combobox.vue'
diff --git a/packages/ui/src/components/flows/creation-flow-modal/components/ImportInstanceStage.vue b/packages/ui/src/components/flows/creation-flow-modal/components/ImportInstanceStage.vue
index 6351399bd3..3102c9bf78 100644
--- a/packages/ui/src/components/flows/creation-flow-modal/components/ImportInstanceStage.vue
+++ b/packages/ui/src/components/flows/creation-flow-modal/components/ImportInstanceStage.vue
@@ -5,13 +5,14 @@
{{
formatMessage(messages.launcherInstancesTitle)
}}
- {{ formatMessage(messages.clearAll) }}
- {{ formatMessage(messages.clearAll) }}
-
@@ -76,28 +77,22 @@
-
-
- {{ formatMessage(messages.addLauncherPath) }}
-
-
+
+ {{ formatMessage(messages.addLauncherPath) }}
+
-
-
-
-
-
+
+
+
-
-
- {{ formatMessage(messages.add) }}
-
-
+
+ {{ formatMessage(messages.add) }}
+
@@ -108,9 +103,10 @@ import { ChevronRightIcon, FolderSearchIcon, SearchIcon } from '@modrinth/assets
import { defineMessages, useVIntl } from '@modrinth/ui'
import { computed, onMounted, ref, watch } from 'vue'
+import { Button, IconButton } from '#ui/components/base/buttons'
+
import { injectInstanceImport, injectNotificationManager } from '../../../../providers'
import type { ImportableLauncher } from '../../../../providers/instance-import'
-import ButtonStyled from '../../../base/ButtonStyled.vue'
import Checkbox from '../../../base/Checkbox.vue'
import Collapsible from '../../../base/Collapsible.vue'
import StyledInput from '../../../base/StyledInput.vue'
diff --git a/packages/ui/src/components/flows/creation-flow-modal/components/ModpackStage.vue b/packages/ui/src/components/flows/creation-flow-modal/components/ModpackStage.vue
index e0860dd303..8fc5605aa3 100644
--- a/packages/ui/src/components/flows/creation-flow-modal/components/ModpackStage.vue
+++ b/packages/ui/src/components/flows/creation-flow-modal/components/ModpackStage.vue
@@ -30,28 +30,27 @@
-
-
-
- {{ formatMessage(messages.importModpack) }}
-
-
-
-
-
- {{ formatMessage(messages.browseModpacks) }}
-
-
+
+
+ {{ formatMessage(messages.importModpack) }}
+
+
+
+ {{ formatMessage(messages.browseModpacks) }}
+
@@ -61,10 +60,10 @@ import { CompassIcon, ImportIcon, RightArrowIcon } from '@modrinth/assets'
import { commonMessages, defineMessages, useVIntl } from '@modrinth/ui'
import { defineAsyncComponent, h, onMounted, ref, watch } from 'vue'
+import { Button } from '#ui/components/base/buttons'
import { useDebugLogger } from '#ui/composables/debug-logger'
import { injectFilePicker } from '../../../../providers'
-import ButtonStyled from '../../../base/ButtonStyled.vue'
import Combobox from '../../../base/Combobox.vue'
import { injectCreationFlowContext } from '../creation-flow-context'
diff --git a/packages/ui/src/components/modal/ConfirmLeaveModal.vue b/packages/ui/src/components/modal/ConfirmLeaveModal.vue
index cba7b8468c..b49b7c0665 100644
--- a/packages/ui/src/components/modal/ConfirmLeaveModal.vue
+++ b/packages/ui/src/components/modal/ConfirmLeaveModal.vue
@@ -8,18 +8,14 @@
-
-
-
- {{ localizeIfPossible(stayLabel) }}
-
-
-
-
-
- {{ localizeIfPossible(leaveLabel) }}
-
-
+
+
+ {{ localizeIfPossible(stayLabel) }}
+
+
+
+ {{ localizeIfPossible(leaveLabel) }}
+
@@ -30,7 +26,7 @@ import { RightArrowIcon, XIcon } from '@modrinth/assets'
import { ref } from 'vue'
import Admonition from '#ui/components/base/Admonition.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import { defineMessage, type MessageDescriptor, useVIntl } from '#ui/composables/i18n'
import NewModal from './NewModal.vue'
diff --git a/packages/ui/src/components/modal/ConfirmModal.vue b/packages/ui/src/components/modal/ConfirmModal.vue
index 87a091324e..157b909d20 100644
--- a/packages/ui/src/components/modal/ConfirmModal.vue
+++ b/packages/ui/src/components/modal/ConfirmModal.vue
@@ -31,18 +31,19 @@
wrapper-class="max-w-[20rem]"
/>
-
-
-
- Cancel
-
-
-
-
-
- {{ proceedLabel }}
-
-
+
+
+ Cancel
+
+
+
+ {{ proceedLabel }}
+
@@ -53,7 +54,8 @@ import { TrashIcon, XIcon } from '@modrinth/assets'
import { renderString } from '@modrinth/utils'
import { computed, ref } from 'vue'
-import ButtonStyled from '../base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
+
import StyledInput from '../base/StyledInput.vue'
import NewModal from './NewModal.vue'
diff --git a/packages/ui/src/components/modal/NewModal.vue b/packages/ui/src/components/modal/NewModal.vue
index 803b831078..c5cb846bcd 100644
--- a/packages/ui/src/components/modal/NewModal.vue
+++ b/packages/ui/src/components/modal/NewModal.vue
@@ -43,33 +43,28 @@
-
-
-
-
-
+
+
+
-
-
-
-
-
+
+
@@ -116,8 +114,10 @@ import { CheckIcon, DownloadIcon, XIcon } from '@modrinth/assets'
import { commonMessages } from '@modrinth/ui'
import { computed, nextTick, onUnmounted, ref } from 'vue'
+import { Button, ButtonLink } from '#ui/components/base/buttons'
+
import { defineMessages, useVIntl } from '../../composables/i18n'
-import { Avatar, ButtonStyled } from '../base'
+import { Avatar } from '../base'
import ServerOnlinePlayers from '../project/server/ServerOnlinePlayers.vue'
import ServerRegion from '../project/server/ServerRegion.vue'
diff --git a/packages/ui/src/components/modal/ShareModal.vue b/packages/ui/src/components/modal/ShareModal.vue
index db9c485c1b..70cf15203c 100644
--- a/packages/ui/src/components/modal/ShareModal.vue
+++ b/packages/ui/src/components/modal/ShareModal.vue
@@ -12,9 +12,10 @@ import {
import QrcodeVue from 'qrcode.vue'
import { computed, nextTick, ref } from 'vue'
+import { ButtonLink, IconButton } from '#ui/components/base/buttons'
import { injectNotificationManager } from '#ui/providers'
-import { ButtonStyled, NewModal, StyledInput } from '../index'
+import { NewModal, StyledInput } from '../index'
const props = defineProps({
header: {
@@ -156,16 +157,15 @@ defineExpose({
-
-
-
-
-
+
+
+
-
-
-
-
-
+
+
+
-
-
- Open in new tab
-
-
-
+
+ Open in new tab
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/modal/UnknownFileWarningModal.vue b/packages/ui/src/components/modal/UnknownFileWarningModal.vue
index 247ff96c04..43284e5be7 100644
--- a/packages/ui/src/components/modal/UnknownFileWarningModal.vue
+++ b/packages/ui/src/components/modal/UnknownFileWarningModal.vue
@@ -86,17 +86,13 @@
/>
-
-
- {{ formatMessage(messages.installAnyway) }}
-
-
-
-
-
- {{ formatMessage(messages.dontInstall) }}
-
-
+
+ {{ formatMessage(messages.installAnyway) }}
+
+
+
+ {{ formatMessage(messages.dontInstall) }}
+
@@ -106,10 +102,11 @@
import { BanIcon } from '@modrinth/assets'
import { computed, nextTick, ref, useTemplateRef } from 'vue'
+import { Button } from '#ui/components/base/buttons'
+
import { defineMessages, useVIntl } from '../../composables/i18n'
import { useScrollIndicator } from '../../composables/scroll-indicator'
import Admonition from '../base/Admonition.vue'
-import ButtonStyled from '../base/ButtonStyled.vue'
import Checkbox from '../base/Checkbox.vue'
import Table, { type TableColumn } from '../base/Table.vue'
import NewModal from './NewModal.vue'
@@ -167,8 +164,7 @@ const messages = defineMessages({
},
reviewedFiles: {
id: 'unknown-file-warning-modal.reviewed-files',
- defaultMessage:
- 'A file is only reviewed if it’s published to Modrinth, regardless of its file format (including .mrpack).',
+ defaultMessage: "Files that aren't published to Modrinth aren't reviewed.",
},
unrecognizedFiles: {
id: 'unknown-file-warning-modal.unrecognized-files',
diff --git a/packages/ui/src/components/nav/NotificationPanel.vue b/packages/ui/src/components/nav/NotificationPanel.vue
index 95626d907e..0f0a592d53 100644
--- a/packages/ui/src/components/nav/NotificationPanel.vue
+++ b/packages/ui/src/components/nav/NotificationPanel.vue
@@ -59,22 +59,27 @@
x{{ item.count }}
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
- {{ button.label }}
-
-
+
+ {{ button.label }}
+
@@ -121,6 +132,7 @@ import {
} from '@modrinth/assets'
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
+import { Button, IconButton } from '#ui/components/base/buttons'
import { useModalStack } from '#ui/composables/modal-stack.ts'
import {
@@ -128,7 +140,6 @@ import {
type WebNotification,
type WebNotificationButton,
} from '../../providers'
-import ButtonStyled from '../base/ButtonStyled.vue'
const notificationManager = injectNotificationManager()
const notifications = computed(() => notificationManager.getNotifications())
diff --git a/packages/ui/src/components/nav/PopupNotificationPanel.vue b/packages/ui/src/components/nav/PopupNotificationPanel.vue
index 49c55ccd58..da57f93c20 100644
--- a/packages/ui/src/components/nav/PopupNotificationPanel.vue
+++ b/packages/ui/src/components/nav/PopupNotificationPanel.vue
@@ -95,11 +95,15 @@
-
-
-
-
-
+
+
+
{{ item.text }}
@@ -142,16 +146,28 @@
full-width
/>
-
-
-
- {{ btn.label }}
-
-
+
+ {{ btn.label }}
+
@@ -171,6 +187,8 @@ import {
} from '@modrinth/assets'
import { computed, ref } from 'vue'
+import { Button, IconButton } from '#ui/components/base/buttons'
+
import { useModalStack } from '../../composables/modal-stack'
import {
injectPopupNotificationManager,
@@ -178,7 +196,6 @@ import {
type PopupNotificationButton,
type PopupNotificationProgressItem,
} from '../../providers'
-import ButtonStyled from '../base/ButtonStyled.vue'
import ProgressBar from '../base/ProgressBar.vue'
import NotificationToast from '../notifications/NotificationToast.vue'
diff --git a/packages/ui/src/components/notifications/NotificationToast.vue b/packages/ui/src/components/notifications/NotificationToast.vue
index 185fee06d7..82169e0044 100644
--- a/packages/ui/src/components/notifications/NotificationToast.vue
+++ b/packages/ui/src/components/notifications/NotificationToast.vue
@@ -49,31 +49,33 @@
-
-
-
-
-
+
+
+
-
-
-
-
- Accept
-
-
-
-
-
- Decline
-
-
+
+
+
+ Accept
+
+
+
+ Decline
+
@@ -96,16 +98,17 @@
{{ entityLabel }}
-
-
-
-
-
+
+
+
-
- Launch game
-
-
- Instance
-
+ Launch game
+ Instance
{{ progressLabel }}
@@ -145,16 +144,28 @@
v-if="type === 'instance-download' && actions?.length"
class="col-start-1 col-end-3 row-start-3 mt-2 flex min-w-0 flex-wrap items-center gap-2"
>
-
-
-
- {{ action.label }}
-
-
+
+ {{ action.label }}
+
@@ -182,11 +193,12 @@
import { CheckIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
import { computed, ref } from 'vue'
+import { Button, IconButton } from '#ui/components/base/buttons'
+
import { useFormatBytes, useFormatNumber } from '../../composables'
import type { PopupNotificationButton, PopupNotificationProgressType } from '../../providers'
import { truncatedTooltip } from '../../utils/truncate'
import Avatar from '../base/Avatar.vue'
-import ButtonStyled from '../base/ButtonStyled.vue'
type NotificationToastType =
| 'friend-request'
diff --git a/packages/ui/src/components/page/NormalPage.vue b/packages/ui/src/components/page/NormalPage.vue
index ce3f0e1689..3acc18993e 100644
--- a/packages/ui/src/components/page/NormalPage.vue
+++ b/packages/ui/src/components/page/NormalPage.vue
@@ -3,6 +3,7 @@ import { injectPageContext } from '@modrinth/ui'
defineProps<{
sidebar?: 'right' | 'left'
+ fullWidth?: boolean
}>()
const { hierarchicalSidebarAvailable } = injectPageContext()
@@ -12,6 +13,7 @@ const { hierarchicalSidebarAvailable } = injectPageContext()
:class="{
'ui-normal-page--sidebar-left': sidebar === 'left' && !hierarchicalSidebarAvailable,
'ui-normal-page--sidebar-right': sidebar === 'right' && !hierarchicalSidebarAvailable,
+ 'ui-normal-page--full-width': fullWidth,
}"
>
-
-
-
- {{ addButtonLabel }}
-
-
+
+
+ {{ addButtonLabel }}
+
@@ -102,18 +102,17 @@
{{ inviteLinkHeading }}
-
-
-
- {{ link }}
-
-
-
-
+
+
+ {{ link }}
+
+
+
{{ linkExpiryDescription }}
props.addLabel ?? formatMessage(messages.addButton))
const inviteButtonLabel = computed(() => props.inviteLabel ?? formatMessage(messages.inviteButton))
const addedButtonLabel = computed(() => props.addedLabel ?? formatMessage(messages.addedButton))
-const cancelButtonLabel = computed(() => props.cancelLabel ?? formatMessage(messages.cancelButton))
+const cancelButtonLabel = computed(
+ () => props.cancelLabel ?? formatMessage(commonMessages.cancelButton),
+)
const requestedButtonLabel = computed(
() => props.requestedLabel ?? formatMessage(messages.requestedButton),
)
diff --git a/packages/ui/src/components/sharing/invite-players-modal/invite-players-modal-invite-link-editor.vue b/packages/ui/src/components/sharing/invite-players-modal/invite-players-modal-invite-link-editor.vue
index 433b42085e..c59177c2fd 100644
--- a/packages/ui/src/components/sharing/invite-players-modal/invite-players-modal-invite-link-editor.vue
+++ b/packages/ui/src/components/sharing/invite-players-modal/invite-players-modal-invite-link-editor.vue
@@ -31,20 +31,18 @@
calendar-class="!border-none"
/>
-
-
- {{ formatMessage(messages.cancel) }}
-
-
-
-
- {{ formatMessage(messages.apply) }}
-
-
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+ {{ formatMessage(messages.apply) }}
+
-
-
-
- {{ formatMessage(messages.cancel) }}
-
-
-
-
-
-
- {{ formatMessage(messages.save) }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+
+ {{ formatMessage(messages.save) }}
+
@@ -95,10 +89,12 @@
import { SaveIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
import { computed, ref, watch } from 'vue'
+import { Button } from '#ui/components/base/buttons'
+
import { useFormatDateTime } from '../../../composables'
import { defineMessages, useVIntl } from '../../../composables/i18n'
import { injectNotificationManager } from '../../../providers'
-import ButtonStyled from '../../base/ButtonStyled.vue'
+import { commonMessages } from '../../../utils/common-messages'
import Combobox, { type ComboboxOption } from '../../base/Combobox.vue'
import DatePicker from '../../base/DatePicker.vue'
import StyledInput from '../../base/StyledInput.vue'
@@ -191,10 +187,6 @@ const messages = defineMessages({
id: 'sharing.invite-players-modal.custom-expiry-value',
defaultMessage: 'Custom: {date}',
},
- cancel: {
- id: 'sharing.invite-players-modal.cancel-button',
- defaultMessage: 'Cancel',
- },
apply: {
id: 'sharing.invite-players-modal.apply-button',
defaultMessage: 'Apply',
diff --git a/packages/ui/src/components/sharing/invite-players-modal/invite-players-modal-user-row.vue b/packages/ui/src/components/sharing/invite-players-modal/invite-players-modal-user-row.vue
index d4bd297094..50d3a696ff 100644
--- a/packages/ui/src/components/sharing/invite-players-modal/invite-players-modal-user-row.vue
+++ b/packages/ui/src/components/sharing/invite-players-modal/invite-players-modal-user-row.vue
@@ -30,29 +30,26 @@
-
-
-
- {{ addedLabel }}
-
-
-
-
- {{ cancelLabel }}
-
-
+
+
+ {{ addedLabel }}
+
+
+ {{ cancelLabel }}
+
-
-
- {{ requestedLabel }}
-
-
+
+ {{ requestedLabel }}
+
-
-
- {{ inviteLabel }}
-
-
+
+ {{ inviteLabel }}
+
@@ -60,9 +57,10 @@
import { CheckIcon } from '@modrinth/assets'
import { computed } from 'vue'
+import { Button } from '#ui/components/base/buttons'
+
import AutoLink from '../../base/AutoLink.vue'
import Avatar from '../../base/Avatar.vue'
-import ButtonStyled from '../../base/ButtonStyled.vue'
import type { InvitePlayersUser, InvitePlayersUserProfileLink } from './types'
const props = withDefaults(
diff --git a/packages/ui/src/components/user/UserPageHeader.vue b/packages/ui/src/components/user/UserPageHeader.vue
index bac7c7db25..a99f3eadaf 100644
--- a/packages/ui/src/components/user/UserPageHeader.vue
+++ b/packages/ui/src/components/user/UserPageHeader.vue
@@ -57,21 +57,27 @@
-
-
-
- {{ formatMessage(commonMessages.editButton) }}
-
-
-
-
-
-
-
+
+
+ {{ formatMessage(commonMessages.editButton) }}
+
+
+
+ {{ formatMessage(commonMessages.editButton) }}
+
+
+
+
@@ -96,17 +102,15 @@ import {
} from '@modrinth/assets'
import { computed } from 'vue'
-import AutoLink from '#ui/components/base/AutoLink.vue'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import type { OverflowMenuOption } from '#ui/components/base/buttons'
+import { Button, ButtonLink, TeleportOverflowMenu } from '#ui/components/base/buttons'
import PageHeader from '#ui/components/base/page-header/index.vue'
import PageHeaderMetadata from '#ui/components/base/page-header/metadata/index.vue'
import PageHeaderMetadataNumberItem from '#ui/components/base/page-header/metadata/page-header-metadata-number-item.vue'
import PageHeaderMetadataTimeItem from '#ui/components/base/page-header/metadata/page-header-metadata-time-item.vue'
import PageHeaderActions from '#ui/components/base/page-header/page-header-actions.vue'
import PageHeaderBadgeItem from '#ui/components/base/page-header/page-header-badge-item.vue'
-import type { Item as TeleportOverflowMenuItem } from '#ui/components/base/TeleportOverflowMenu.vue'
-import TeleportOverflowMenu from '#ui/components/base/TeleportOverflowMenu.vue'
import { defineMessages, useFormatDateTime, useFormatNumber, useVIntl } from '#ui/composables'
import type { AuthUser } from '#ui/providers/auth'
import { commonMessages } from '#ui/utils'
@@ -132,10 +136,6 @@ const messages = defineMessages({
id: 'profile.button.unblock',
defaultMessage: 'Unblock',
},
- editRoleButton: {
- id: 'profile.button.edit-role',
- defaultMessage: 'Edit role',
- },
infoButton: {
id: 'profile.button.info',
defaultMessage: 'View user details',
@@ -216,7 +216,7 @@ const emit = defineEmits<{
toggleAffiliate: []
openInfo: []
openAnalytics: []
- editRole: []
+ editUser: []
}>()
const { formatMessage } = useVIntl()
@@ -228,7 +228,7 @@ const formatDateTime = useFormatDateTime({
const downloadsTooltip = computed(() => formatNumber(props.downloads))
const joinedTooltip = computed(() => formatDateTime(props.user.created))
-const moreActions = computed(() => [
+const moreActions = computed(() => [
{
id: 'manage-projects',
label: formatMessage(messages.profileManageProjectsButton),
@@ -236,16 +236,13 @@ const moreActions = computed(() => [
action: () => emit('manageProjects'),
shown: props.isSelf,
},
- {
- divider: true,
- shown: props.isSelf,
- },
+ { type: 'divider', shown: props.isSelf },
{
id: 'report',
label: formatMessage(commonMessages.reportButton),
icon: ReportIcon,
action: () => emit('report'),
- color: 'red',
+ tone: 'red',
shown: props.authUser?.id !== props.user.id,
},
{
@@ -253,7 +250,7 @@ const moreActions = computed(() => [
label: formatMessage(props.isBlocked ? messages.unblockButton : messages.blockButton),
icon: BanIcon,
action: () => emit('block'),
- color: 'red',
+ tone: 'red',
shown: props.authUser?.id !== props.user.id,
},
{
@@ -268,15 +265,13 @@ const moreActions = computed(() => [
icon: ClipboardCopyIcon,
action: () => emit('copyPermalink'),
},
- {
- divider: true,
- shown: props.showStaffActions && (props.isAdmin || props.isStaff),
- },
+ { type: 'divider', shown: props.showStaffActions && (props.isAdmin || props.isStaff) },
{
id: 'open-billing',
label: formatMessage(messages.billingButton),
icon: CurrencyIcon,
action: () => emit('openBilling'),
+ tone: 'orange',
shown: props.showStaffActions && props.isStaff,
},
{
@@ -287,14 +282,15 @@ const moreActions = computed(() => [
icon: AffiliateIcon,
action: () => emit('toggleAffiliate'),
shown: props.showStaffActions && props.isAdmin,
- remainOnClick: true,
- color: props.isAffiliate ? 'red' : 'orange',
+ remainOpen: true,
+ tone: props.isAffiliate ? 'red' : 'orange',
},
{
id: 'open-info',
label: formatMessage(messages.infoButton),
icon: InfoIcon,
action: () => emit('openInfo'),
+ tone: 'orange',
shown: props.showStaffActions && props.isStaff,
},
{
@@ -302,13 +298,15 @@ const moreActions = computed(() => [
label: formatMessage(messages.analyticsButton),
icon: ChartIcon,
action: () => emit('openAnalytics'),
+ tone: 'orange',
shown: props.showStaffActions && props.isAdmin,
},
{
- id: 'edit-role',
- label: formatMessage(messages.editRoleButton),
+ id: 'edit-user',
+ label: 'Edit user',
icon: EditIcon,
- action: () => emit('editRole'),
+ action: () => emit('editUser'),
+ tone: 'orange',
shown: props.showStaffActions && props.isAdmin,
},
])
diff --git a/packages/ui/src/components/version/VersionFilterControl.vue b/packages/ui/src/components/version/VersionFilterControl.vue
index 09a77a7bdd..0cc3f82a0e 100644
--- a/packages/ui/src/components/version/VersionFilterControl.vue
+++ b/packages/ui/src/components/version/VersionFilterControl.vue
@@ -7,13 +7,13 @@
:options="platformOptions"
fit-content
:dropdown-min-width="180"
- trigger-class="!min-h-9 !px-3 !py-0"
+ trigger-type="base"
@update:model-value="updateSelectedPlatforms"
>
-
Platforms
+
Platforms
-
Game versions
+
Game versions
- Channels
+ Channels
+import type { Labrinth } from '@modrinth/api-client'
import { ChevronLeftIcon, FilterIcon, XCircleIcon, XIcon } from '@modrinth/assets'
import type { MultiSelectOption } from '@modrinth/ui'
import { Checkbox, formatLoader, FormattedTag, MultiSelect, TagItem, useVIntl } from '@modrinth/ui'
-import type { GameVersionTag, Version } from '@modrinth/utils'
+import type { GameVersionTag } from '@modrinth/utils'
import { computed, ref } from 'vue'
import type { LocationQueryValue } from 'vue-router'
import { useRoute } from 'vue-router'
const props = defineProps<{
- versions: Version[]
+ versions: Labrinth.Versions.v3.Version[]
gameVersions: GameVersionTag[]
baseId?: string
}>()
@@ -243,31 +244,35 @@ if (selectedGameVersions.value.some((version) => !isReleaseGameVersion(version))
showSnapshots.value = true
}
-async function toggleFilters(type: FilterType, filters: Filter[]) {
- for (const filter of filters) {
- await toggleFilter(type, filter, true)
+function selectedFiltersOfType(type: FilterType) {
+ if (type === 'channel') {
+ return selectedChannels
+ } else if (type === 'gameVersion') {
+ return selectedGameVersions
+ } else {
+ return selectedPlatforms
}
+}
+
+function toggleFilters(type: FilterType, filters: Filter[]) {
+ const selected = selectedFiltersOfType(type)
+ const allSelected = filters.every((filter) => selected.value.includes(filter))
+
+ selected.value = allSelected
+ ? selected.value.filter((x) => !filters.includes(x))
+ : [...selected.value, ...filters.filter((filter) => !selected.value.includes(filter))]
updateFilters()
}
-async function toggleFilter(type: FilterType, filter: Filter, bulk = false) {
- if (type === 'channel') {
- selectedChannels.value = selectedChannels.value.includes(filter)
- ? selectedChannels.value.filter((x) => x !== filter)
- : [...selectedChannels.value, filter]
- } else if (type === 'gameVersion') {
- selectedGameVersions.value = selectedGameVersions.value.includes(filter)
- ? selectedGameVersions.value.filter((x) => x !== filter)
- : [...selectedGameVersions.value, filter]
- } else if (type === 'platform') {
- selectedPlatforms.value = selectedPlatforms.value.includes(filter)
- ? selectedPlatforms.value.filter((x) => x !== filter)
- : [...selectedPlatforms.value, filter]
- }
- if (!bulk) {
- updateFilters()
- }
+function toggleFilter(type: FilterType, filter: Filter) {
+ const selected = selectedFiltersOfType(type)
+
+ selected.value = selected.value.includes(filter)
+ ? selected.value.filter((x) => x !== filter)
+ : [...selected.value, filter]
+
+ updateFilters()
}
function updateSelectedGameVersions(versions: string[]) {
@@ -302,7 +307,7 @@ function updateShowSnapshots(value: boolean, _event?: MouseEvent) {
}
}
-async function clearFilters() {
+function clearFilters() {
selectedChannels.value = []
selectedGameVersions.value = []
selectedPlatforms.value = []
diff --git a/packages/ui/src/components/version/VersionSummary.vue b/packages/ui/src/components/version/VersionSummary.vue
index 8e26a8ea1c..db345933bd 100644
--- a/packages/ui/src/components/version/VersionSummary.vue
+++ b/packages/ui/src/components/version/VersionSummary.vue
@@ -11,27 +11,25 @@
{{ version.name }}
-
-
- Download
-
-
-
-
-
-
-
+
+ Download
+
+
+
+
@@ -40,7 +38,9 @@ import { DownloadIcon, ExternalIcon } from '@modrinth/assets'
import type { Version, VersionFile } from '@modrinth/utils'
import { computed } from 'vue'
-import { ButtonStyled, VersionChannelIndicator } from '../index'
+import { ButtonLink, IconButton } from '#ui/components/base/buttons'
+
+import { VersionChannelIndicator } from '../index'
const props = defineProps<{
version: Version
diff --git a/packages/ui/src/layouts/shared/browse-tab/components/SelectedProjectsFloatingBar.vue b/packages/ui/src/layouts/shared/browse-tab/components/SelectedProjectsFloatingBar.vue
index a97ac6ba2a..5fc1a98cb1 100644
--- a/packages/ui/src/layouts/shared/browse-tab/components/SelectedProjectsFloatingBar.vue
+++ b/packages/ui/src/layouts/shared/browse-tab/components/SelectedProjectsFloatingBar.vue
@@ -40,25 +40,28 @@
{{ selectedCountText }}
-
-
- {{ formatMessage(commonMessages.clearButton) }}
-
-
+
+ {{ formatMessage(commonMessages.clearButton) }}
+
-
-
-
- {{ installButtonText }}
-
-
+
+
+ {{ installButtonText }}
+
@@ -68,7 +71,7 @@ import { PlusIcon } from '@modrinth/assets'
import { computed } from 'vue'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import FloatingActionBar from '#ui/components/base/FloatingActionBar.vue'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
import { commonMessages } from '#ui/utils/common-messages'
diff --git a/packages/ui/src/layouts/shared/browse-tab/components/SelectedProjectsLeaveModal.vue b/packages/ui/src/layouts/shared/browse-tab/components/SelectedProjectsLeaveModal.vue
index c20bae50c8..450c70665b 100644
--- a/packages/ui/src/layouts/shared/browse-tab/components/SelectedProjectsLeaveModal.vue
+++ b/packages/ui/src/layouts/shared/browse-tab/components/SelectedProjectsLeaveModal.vue
@@ -6,24 +6,18 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
- {{ formatMessage(messages.discardButton) }}
-
-
-
-
-
- {{ formatMessage(commonMessages.installButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+ {{ formatMessage(messages.discardButton) }}
+
+
+
+ {{ formatMessage(commonMessages.installButton) }}
+
@@ -33,7 +27,7 @@
import { PlusIcon, TrashIcon, XIcon } from '@modrinth/assets'
import { ref } from 'vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import NewModal from '#ui/components/modal/NewModal.vue'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
import { commonMessages } from '#ui/utils/common-messages'
diff --git a/packages/ui/src/layouts/shared/browse-tab/header.vue b/packages/ui/src/layouts/shared/browse-tab/header.vue
index cda1745fb1..34ee71ef27 100644
--- a/packages/ui/src/layouts/shared/browse-tab/header.vue
+++ b/packages/ui/src/layouts/shared/browse-tab/header.vue
@@ -6,11 +6,11 @@ import { useRouter } from 'vue-router'
import Admonition from '#ui/components/base/Admonition.vue'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { IconButton } from '#ui/components/base/buttons'
import PageHeader from '#ui/components/base/page-header/index.vue'
import PageHeaderMetadata from '#ui/components/base/page-header/metadata/index.vue'
import PageHeaderMetadataItem from '#ui/components/base/page-header/metadata/page-header-metadata-item.vue'
-import LoaderIcon from '#ui/components/servers/icons/LoaderIcon.vue'
+import TagIcon from '#ui/components/base/TagIcon.vue'
import { useServerImage } from '#ui/composables/use-server-image'
import { formatLoaderLabel } from '#ui/utils/loaders'
@@ -77,8 +77,8 @@ const metadataItems = computed(() => {
items.push({
id: 'loader',
label: loaderLabel,
- icon: LoaderIcon,
- iconProps: { loader: loaderName },
+ icon: TagIcon,
+ iconProps: { tag: loaderName, enforceType: 'loader' },
class: '!text-primary',
})
}
@@ -146,16 +146,15 @@ async function handleSelectedProjectsLeaveResult(
truncate-title
>
-
-
-
-
-
+
+
+
svg]:!text-brand !shadow-[inset_0_0_0_1px_var(--color-brand)]',
+ red: '!text-red [&>svg]:!text-red !shadow-[inset_0_0_0_1px_var(--color-red)]',
+ green: '!text-green [&>svg]:!text-green !shadow-[inset_0_0_0_1px_var(--color-green)]',
+ }[action.color]
+}
+
function getLoaderFieldValues(
result: Labrinth.Search.v3.ResultSearchProject,
field: string,
@@ -133,6 +155,7 @@ function getProjectCardTags(result: Labrinth.Search.v3.ResultSearchProject, disp
-
-
- {{ formatMessage(messages.filterResults) }}
-
-
+
+ {{ formatMessage(messages.filterResults) }}
+
-
-
-
-
-
+
+
+
-
-
- {{ action.label }}
-
-
+
+
+
+ {{ action.label }}
+
+
@@ -315,22 +352,35 @@ function getProjectCardTags(result: Labrinth.Search.v3.ResultSearchProject, disp
>
-
-
- {{ action.label }}
-
-
+
+
+
+ {{ action.label }}
+
+
diff --git a/packages/ui/src/layouts/shared/browse-tab/sidebar.vue b/packages/ui/src/layouts/shared/browse-tab/sidebar.vue
index 29a78996ed..399d3153b2 100644
--- a/packages/ui/src/layouts/shared/browse-tab/sidebar.vue
+++ b/packages/ui/src/layouts/shared/browse-tab/sidebar.vue
@@ -2,7 +2,7 @@
import { InfoIcon, XIcon } from '@modrinth/assets'
import { computed, toValue } from 'vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { IconButton } from '#ui/components/base/buttons'
import Toggle from '#ui/components/base/Toggle.vue'
import SearchSidebarFilter from '#ui/components/search/SearchSidebarFilter.vue'
import { useVIntl } from '#ui/composables/i18n'
@@ -103,11 +103,9 @@ function getFilterOpenByDefault(filterId: string): boolean {
class="sticky top-0 z-10 mx-1 flex items-center justify-between gap-3 border-0 border-b-[1px] border-solid border-divider bg-bg-raised px-6 py-4"
>
{{ formatMessage(commonMessages.filtersLabel) }}
-
-
-
-
-
+
+
+
-
-
-
- Clear
-
-
-
-
-
- Delete
-
-
-
-
-
-
- Share
-
-
-
-
-
-
- {{ fullscreen ? 'Collapse' : 'Expand' }}
-
-
+
+
+ Clear
+
+
+
+ Delete
+
+
+
+
+ Share
+
+
+
+
+ {{ fullscreen ? 'Collapse' : 'Expand' }}
+
@@ -51,7 +51,7 @@ import {
XIcon,
} from '@modrinth/assets'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
defineProps<{
showClear?: boolean
diff --git a/packages/ui/src/layouts/shared/console/layout.vue b/packages/ui/src/layouts/shared/console/layout.vue
index 038f596fd4..a38881d351 100644
--- a/packages/ui/src/layouts/shared/console/layout.vue
+++ b/packages/ui/src/layouts/shared/console/layout.vue
@@ -27,6 +27,7 @@
(ctx.activeLogSourceIndex!.value = v)"
/>
@@ -79,18 +80,14 @@
-
-
-
- Cancel
-
-
-
-
-
- Delete
-
-
+
+
+ Cancel
+
+
+
+ Delete
+
@@ -103,7 +100,7 @@ import { computed, isRef, nextTick, onBeforeUnmount, ref, watch } from 'vue'
import Admonition from '#ui/components/base/Admonition.vue'
import BaseTerminal from '#ui/components/base/BaseTerminal.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import type { CollapsibleAdmonitionItem } from '#ui/components/base/CollapsibleAdmonition.vue'
import CollapsibleAdmonition from '#ui/components/base/CollapsibleAdmonition.vue'
import Combobox from '#ui/components/base/Combobox.vue'
diff --git a/packages/ui/src/layouts/shared/content-tab/components/ContentCardItem.vue b/packages/ui/src/layouts/shared/content-tab/components/ContentCardItem.vue
index 930615c2f5..1070c4fc84 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/ContentCardItem.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/ContentCardItem.vue
@@ -15,10 +15,9 @@ import type { RouteLocationRaw } from 'vue-router'
import AutoLink from '#ui/components/base/AutoLink.vue'
import Avatar from '#ui/components/base/Avatar.vue'
import BulletDivider from '#ui/components/base/BulletDivider.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import type { OverflowMenuOption } from '#ui/components/base/buttons'
+import { IconButton, TeleportOverflowMenu } from '#ui/components/base/buttons'
import Checkbox from '#ui/components/base/Checkbox.vue'
-import type { Option as OverflowMenuOption } from '#ui/components/base/OverflowMenu.vue'
-import TeleportOverflowMenu from '#ui/components/base/TeleportOverflowMenu.vue'
import Toggle from '#ui/components/base/Toggle.vue'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
import { commonMessages } from '#ui/utils/common-messages'
@@ -313,43 +312,44 @@ const deleteHovered = ref(false)
v-if="hasUpdateListener || hasSwitchVersionListener"
class="flex w-8 items-center justify-center"
>
-
-
-
-
-
-
+
+
-
-
-
-
+
+
emit('update:enabled', val as boolean)"
/>
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
diff --git a/packages/ui/src/layouts/shared/content-tab/components/ContentModpackCard.vue b/packages/ui/src/layouts/shared/content-tab/components/ContentModpackCard.vue
index e6898f8eae..fa36c4de7f 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/ContentModpackCard.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/ContentModpackCard.vue
@@ -14,12 +14,13 @@ import type { RouteLocationRaw } from 'vue-router'
import AutoLink from '#ui/components/base/AutoLink.vue'
import Avatar from '#ui/components/base/Avatar.vue'
import BulletDivider from '#ui/components/base/BulletDivider.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
-import OverflowMenu, {
- type Option as OverflowMenuOption,
-} from '#ui/components/base/OverflowMenu.vue'
+import {
+ Button,
+ IconButton,
+ type OverflowMenuOption,
+ TeleportOverflowMenu,
+} from '#ui/components/base/buttons'
import TagTagItem from '#ui/components/base/TagTagItem.vue'
-import TeleportOverflowMenu from '#ui/components/base/TeleportOverflowMenu.vue'
import { useRelativeTime } from '#ui/composables/how-ago'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
import { commonMessages } from '#ui/utils/common-messages'
@@ -83,21 +84,19 @@ const formatCompact = (n: number | undefined) => {
return new Intl.NumberFormat('en', { notation: 'compact', maximumFractionDigits: 2 }).format(n)
}
-const collapsedOptions = computed(() => {
- const options: {
- id: string
- action: () => void
- color?: 'standard' | 'red' | 'brand' | 'orange' | 'green' | 'blue' | 'purple'
- }[] = []
+const collapsedOptions = computed(() => {
+ const options: OverflowMenuOption[] = []
if (hasContentListener.value) {
options.push({
id: 'content',
+ label: formatMessage(commonMessages.contentLabel),
action: () => emit('content'),
})
}
if (hasSettingsListener.value) {
options.push({
id: 'settings',
+ label: formatMessage(messages.installationSettingsTooltip),
action: () => emit('settings'),
})
}
@@ -205,70 +204,72 @@ onUnmounted(() => {
-
-
-
- {{ formatMessage(commonMessages.updateButton) }}
-
-
+
+ {{ formatMessage(commonMessages.updateButton) }}
+
-
-
-
- {{ formatMessage(commonMessages.contentLabel) }}
-
-
+
+
+ {{ formatMessage(commonMessages.contentLabel) }}
+
-
-
-
-
-
+
+
+
-
-
-
-
-
+
+
+
-
-
-
-
-
- {{ formatMessage(commonMessages.contentLabel) }}
-
-
-
- {{ formatMessage(messages.installationSettingsTooltip) }}
-
-
-
-
-
-
-
-
-
+
+
+
+ {{ formatMessage(commonMessages.contentLabel) }}
+
+
+
+ {{ formatMessage(messages.installationSettingsTooltip) }}
+
+
+
+
+
+
diff --git a/packages/ui/src/layouts/shared/content-tab/components/ContentSelectionBar.vue b/packages/ui/src/layouts/shared/content-tab/components/ContentSelectionBar.vue
index d2693db24b..949f0c3e6b 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/ContentSelectionBar.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/ContentSelectionBar.vue
@@ -3,7 +3,7 @@ import { PowerIcon, PowerOffIcon, XIcon } from '@modrinth/assets'
import { computed } from 'vue'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import FloatingActionBar from '#ui/components/base/FloatingActionBar.vue'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
import { commonMessages, formatContentTypeSentence } from '#ui/utils/common-messages'
@@ -95,6 +95,7 @@ interface Props {
ariaLabel?: string
getItemId?: (item: ContentItem) => string
toggleItems?: ContentItem[]
+ hideWhenModalOpen?: boolean
}
const props = withDefaults(defineProps(), {
@@ -111,6 +112,7 @@ const props = withDefaults(defineProps(), {
ariaLabel: undefined,
getItemId: undefined,
toggleItems: undefined,
+ hideWhenModalOpen: true,
})
const emit = defineEmits<{
@@ -181,7 +183,11 @@ const bulkProgressMessage = computed(() => {
-
+
{
{{ selectedCountText }}
-
-
-
- {{ formatMessage(commonMessages.clearButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.clearButton) }}
+
-
-
-
- {{ formatMessage(commonMessages.enableButton) }}
-
-
-
-
-
- {{ formatMessage(commonMessages.disableButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.enableButton) }}
+
+
+
+ {{ formatMessage(commonMessages.disableButton) }}
+
@@ -290,7 +295,7 @@ const bulkProgressMessage = computed(() => {
:aria-valuenow="bulkWaiting ? undefined : bulkProgress"
:aria-valuemin="0"
:aria-valuemax="bulkTotal"
- style="box-shadow: 0px -2px 4px 0px rgba(27, 217, 106, 0.1)"
+ style="box-shadow: 0px -2px 4px 0px color-mix(in srgb, var(--color-brand) 10%, transparent)"
/>
diff --git a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmBulkUpdateModal.vue b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmBulkUpdateModal.vue
index 92c2863ff7..920d867b8f 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmBulkUpdateModal.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmBulkUpdateModal.vue
@@ -22,22 +22,20 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
- {{ formatMessage(messages.updateButton, { count: visibleCount }) }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+ {{ formatMessage(messages.updateButton, { count: visibleCount }) }}
+
@@ -48,7 +46,7 @@ import { DownloadIcon, XIcon } from '@modrinth/assets'
import { nextTick, ref } from 'vue'
import Admonition from '#ui/components/base/Admonition.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import NewModal from '#ui/components/modal/NewModal.vue'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
import { commonMessages } from '#ui/utils/common-messages'
diff --git a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmDeletionModal.vue b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmDeletionModal.vue
index 77317e4c8c..042caff48c 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmDeletionModal.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmDeletionModal.vue
@@ -23,22 +23,20 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
- {{ deleteButtonLabel }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+ {{ deleteButtonLabel }}
+
@@ -49,7 +47,7 @@ import { TrashIcon, XIcon } from '@modrinth/assets'
import { computed, nextTick, ref } from 'vue'
import Admonition from '#ui/components/base/Admonition.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import NewModal from '#ui/components/modal/NewModal.vue'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
import { commonMessages, formatContentTypeSentence } from '#ui/utils/common-messages'
diff --git a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmDisableModal.vue b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmDisableModal.vue
index dc1d76df7c..5a39f0d595 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmDisableModal.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmDisableModal.vue
@@ -17,22 +17,20 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
- {{ visibleWarning?.actionLabel }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+ {{ visibleWarning?.actionLabel }}
+
@@ -43,7 +41,7 @@ import { SlashIcon, XIcon } from '@modrinth/assets'
import { nextTick, ref } from 'vue'
import Admonition from '#ui/components/base/Admonition.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import NewModal from '#ui/components/modal/NewModal.vue'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
import { commonMessages, formatContentTypeSentence } from '#ui/utils/common-messages'
diff --git a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmModpackUpdateModal.vue b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmModpackUpdateModal.vue
index a0ab73badf..889045bf0c 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmModpackUpdateModal.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmModpackUpdateModal.vue
@@ -31,24 +31,22 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
- {{
- formatMessage(messages.confirmButton, { action: downgrade ? 'downgrade' : 'update' })
- }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+ {{
+ formatMessage(messages.confirmButton, { action: downgrade ? 'downgrade' : 'update' })
+ }}
+
@@ -59,7 +57,7 @@ import { DownloadIcon, XIcon } from '@modrinth/assets'
import { computed, ref } from 'vue'
import Admonition from '#ui/components/base/Admonition.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import NewModal from '#ui/components/modal/NewModal.vue'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
import { commonMessages } from '#ui/utils/common-messages'
diff --git a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmReinstallModal.vue b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmReinstallModal.vue
index d8946e3a5e..f51258d046 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmReinstallModal.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmReinstallModal.vue
@@ -19,18 +19,14 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
- {{ formatMessage(messages.reinstallButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+ {{ formatMessage(messages.reinstallButton) }}
+
@@ -41,7 +37,7 @@ import { DownloadIcon, XIcon } from '@modrinth/assets'
import { ref } from 'vue'
import Admonition from '#ui/components/base/Admonition.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import NewModal from '#ui/components/modal/NewModal.vue'
import { useDebugLogger } from '#ui/composables/debug-logger'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
diff --git a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmRepairModal.vue b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmRepairModal.vue
index a9dedf3c30..ed26509ec8 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmRepairModal.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmRepairModal.vue
@@ -14,18 +14,14 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
- {{ formatMessage(messages.repairButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+ {{ formatMessage(messages.repairButton) }}
+
@@ -35,7 +31,7 @@
import { HammerIcon, XIcon } from '@modrinth/assets'
import { ref } from 'vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import NewModal from '#ui/components/modal/NewModal.vue'
import { useDebugLogger } from '#ui/composables/debug-logger'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
diff --git a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmUnlinkModal.vue b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmUnlinkModal.vue
index 9497d880cc..331e9d95dd 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmUnlinkModal.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/modals/ConfirmUnlinkModal.vue
@@ -19,22 +19,20 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
- {{ formatMessage(actionMessage) }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+ {{ formatMessage(actionMessage) }}
+
@@ -45,7 +43,7 @@ import { UnlinkIcon, XIcon } from '@modrinth/assets'
import { computed, ref } from 'vue'
import Admonition from '#ui/components/base/Admonition.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import NewModal from '#ui/components/modal/NewModal.vue'
import { useDebugLogger } from '#ui/composables/debug-logger'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
diff --git a/packages/ui/src/layouts/shared/content-tab/components/modals/ContentDependencyWarningModal.vue b/packages/ui/src/layouts/shared/content-tab/components/modals/ContentDependencyWarningModal.vue
index eccfc87e16..9d1d50f10a 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/modals/ContentDependencyWarningModal.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/modals/ContentDependencyWarningModal.vue
@@ -168,22 +168,20 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
- {{ deleteButtonLabel }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+ {{ deleteButtonLabel }}
+
@@ -194,7 +192,7 @@ import { TrashIcon, XIcon } from '@modrinth/assets'
import { computed, nextTick, ref } from 'vue'
import Admonition from '#ui/components/base/Admonition.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import Checkbox from '#ui/components/base/Checkbox.vue'
import NewModal from '#ui/components/modal/NewModal.vue'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
diff --git a/packages/ui/src/layouts/shared/content-tab/components/modals/ContentInstallModal.vue b/packages/ui/src/layouts/shared/content-tab/components/modals/ContentInstallModal.vue
index b8df546ea5..96f1bb2d52 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/modals/ContentInstallModal.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/modals/ContentInstallModal.vue
@@ -73,15 +73,15 @@
:placeholder="formatMessage(messages.searchPlaceholder)"
class="flex-1"
/>
-
-
-
-
-
-
+
+
+
+
@@ -110,30 +110,29 @@
inst.name
}}
-
-
-
- {{ formatMessage(messages.installedBadge) }}
-
-
-
+
+ {{ formatMessage(messages.installedBadge) }}
+
+
-
-
- {{
- inst.installing
- ? formatMessage(commonMessages.installingLabel)
- : formatMessage(messages.installButton)
- }}
-
-
+
+ {{
+ inst.installing
+ ? formatMessage(commonMessages.installingLabel)
+ : formatMessage(messages.installButton)
+ }}
+
@@ -143,18 +142,14 @@
-
-
-
- {{ formatMessage(messages.selectIcon) }}
-
-
-
-
-
- {{ formatMessage(messages.removeIcon) }}
-
-
+
+
+ {{ formatMessage(messages.selectIcon) }}
+
+
+
+ {{ formatMessage(messages.removeIcon) }}
+
@@ -218,27 +213,26 @@
{{ formatMessage(messages.compatibleCount, { count: compatibleCount }) }}
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
- {{ formatMessage(messages.installButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+ {{ formatMessage(messages.installButton) }}
+
@@ -260,7 +254,7 @@ import { computed, ref, watch } from 'vue'
import AutoLink from '#ui/components/base/AutoLink.vue'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button, IconButton } from '#ui/components/base/buttons'
import Chips from '#ui/components/base/Chips.vue'
import Combobox, { type ComboboxOption } from '#ui/components/base/Combobox.vue'
import LoadingIndicator from '#ui/components/base/LoadingIndicator.vue'
diff --git a/packages/ui/src/layouts/shared/content-tab/components/modals/InlineBackupCreator.vue b/packages/ui/src/layouts/shared/content-tab/components/modals/InlineBackupCreator.vue
index f2cb95231f..313d8c8299 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/modals/InlineBackupCreator.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/modals/InlineBackupCreator.vue
@@ -10,26 +10,24 @@
-
-
-
-
- {{ formatMessage(backup.isBackingUp.value ? messages.backingUp : messages.createBackup) }}
-
-
+
+
+
+ {{ formatMessage(backup.isBackingUp.value ? messages.backingUp : messages.createBackup) }}
+
(() =>
...(props.switchVersion
? [
{
- id: formatMessage(commonMessages.switchVersionButton),
+ id: 'switch-version',
+ label: formatMessage(commonMessages.switchVersionButton),
icon: ArrowLeftRightIcon,
action: () => props.switchVersion!(item),
},
@@ -492,7 +493,7 @@ defineExpose({ show, showLoading, hide, getState, restore, updateItem, setItems
class="rounded-full border border-solid px-3 py-1.5 text-base font-semibold leading-5 transition-colors"
:class="
selectedFilters.length === 0
- ? 'border-green bg-brand-highlight text-brand'
+ ? 'border-brand bg-brand-highlight text-brand'
: 'border-surface-5 bg-surface-4 text-primary hover:bg-surface-5'
"
@click="selectedFilters = []"
@@ -506,7 +507,7 @@ defineExpose({ show, showLoading, hide, getState, restore, updateItem, setItems
class="rounded-full border border-solid px-3 py-1.5 text-base font-semibold leading-5 transition-colors"
:class="
selectedFilters.includes(option.id)
- ? 'border-green bg-brand-highlight text-brand'
+ ? 'border-brand bg-brand-highlight text-brand'
: 'border-surface-5 bg-surface-4 text-primary hover:bg-surface-5'
"
@click="toggleFilter(option.id)"
@@ -611,17 +612,18 @@ defineExpose({ show, showLoading, hide, getState, restore, updateItem, setItems
-
-
-
-
-
+
+
+
@@ -662,6 +664,7 @@ defineExpose({ show, showLoading, hide, getState, restore, updateItem, setItems
:selected-items="selectedItems"
:is-busy="props.actionDisabled"
:busy-tooltip="props.actionDisabledTooltip"
+ :hide-when-modal-open="false"
style="--left-bar-width: 0px; --right-bar-width: 0px"
@clear="selectedIds = []"
@enable="bulkEnable"
diff --git a/packages/ui/src/layouts/shared/content-tab/components/modals/content-updater-modal/index.vue b/packages/ui/src/layouts/shared/content-tab/components/modals/content-updater-modal/index.vue
index f7002f6ea4..a6d3c66943 100644
--- a/packages/ui/src/layouts/shared/content-tab/components/modals/content-updater-modal/index.vue
+++ b/packages/ui/src/layouts/shared/content-tab/components/modals/content-updater-modal/index.vue
@@ -95,25 +95,24 @@
class="absolute bottom-0 left-0 right-0 pointer-events-none flex flex-col items-center justify-end bg-gradient-to-b from-transparent to-bg-raised to-70% pb-3 h-24"
>
-
-
-
-
- {{
- hideIncompatibleState
- ? formatMessage(messages.showIncompatible)
- : formatMessage(messages.hideIncompatible)
- }}
-
-
+
+
+
+ {{
+ hideIncompatibleState
+ ? formatMessage(messages.showIncompatible)
+ : formatMessage(messages.hideIncompatible)
+ }}
+
@@ -214,43 +213,41 @@
}}
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
-
- {{
- actionLoading
- ? formatMessage(commonMessages.installingLabel)
- : incompatibilityWarningMode
- ? formatMessage(messages.installAnywayButton)
- : formatMessage(
- isDowngrade
- ? messages.downgradeToVersion
- : switchMode
- ? messages.switchToVersion
- : messages.updateToVersion,
- {
- version: selectedVersion?.version_number ?? '...',
- },
- )
- }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+
+ {{
+ actionLoading
+ ? formatMessage(commonMessages.installingLabel)
+ : incompatibilityWarningMode
+ ? formatMessage(messages.installAnywayButton)
+ : formatMessage(
+ isDowngrade
+ ? messages.downgradeToVersion
+ : switchMode
+ ? messages.switchToVersion
+ : messages.updateToVersion,
+ {
+ version: selectedVersion?.version_number ?? '...',
+ },
+ )
+ }}
+
@@ -294,7 +291,7 @@ import { useTimeoutFn } from '@vueuse/core'
import { computed, ref, toRef } from 'vue'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import StyledInput from '#ui/components/base/StyledInput.vue'
import ConfirmModal from '#ui/components/modal/ConfirmModal.vue'
import NewModal from '#ui/components/modal/NewModal.vue'
@@ -569,7 +566,7 @@ function getBadgeClasses(version: Labrinth.Versions.v2.Version): string {
// Version type badges
switch (version.version_type) {
case 'release':
- return 'bg-highlight-green border-brand text-brand'
+ return 'bg-highlight-green border-green text-green'
case 'beta':
return 'bg-highlight-blue border-brand-blue text-brand-blue'
case 'alpha':
@@ -582,7 +579,7 @@ function getBadgeClasses(version: Labrinth.Versions.v2.Version): string {
function getVersionTypeBadgeClasses(version: Labrinth.Versions.v2.Version): string {
switch (version.version_type) {
case 'release':
- return 'bg-highlight-green border-brand text-brand'
+ return 'bg-highlight-green border-green text-green'
case 'beta':
return 'bg-highlight-blue border-brand-blue text-brand-blue'
case 'alpha':
diff --git a/packages/ui/src/layouts/shared/content-tab/layout.vue b/packages/ui/src/layouts/shared/content-tab/layout.vue
index bdee7c24a8..2ec27bb643 100644
--- a/packages/ui/src/layouts/shared/content-tab/layout.vue
+++ b/packages/ui/src/layouts/shared/content-tab/layout.vue
@@ -20,9 +20,8 @@ import {
} from '@modrinth/assets'
import { computed, nextTick, ref, watch } from 'vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button, TeleportOverflowMenu } from '#ui/components/base/buttons'
import EmptyState from '#ui/components/base/EmptyState.vue'
-import OverflowMenu from '#ui/components/base/OverflowMenu.vue'
import StyledInput from '#ui/components/base/StyledInput.vue'
import { useDebugLogger } from '#ui/composables/debug-logger'
import { defineMessages, useVIntl } from '#ui/composables/i18n'
@@ -763,9 +762,9 @@ const confirmUnlinkModal = ref>()
{{ formatMessage(messages.failedToLoad) }}
{{ ctx.error.value.message }}
-
- {{ formatMessage(commonMessages.retryButton) }}
-
+
{{
+ formatMessage(commonMessages.retryButton)
+ }}
@@ -818,34 +817,33 @@ const confirmUnlinkModal = ref>()
/>
-
-
-
- {{ formatMessage(messages.uploadFiles) }}
-
-
-
-
-
- {{ formatMessage(messages.browseContent) }}
-
-
+
+
+ {{ formatMessage(messages.uploadFiles) }}
+
+
+
+ {{ formatMessage(messages.browseContent) }}
+
@@ -856,7 +854,7 @@ const confirmUnlinkModal = ref>()
class="cursor-pointer rounded-full border border-solid px-3 py-1.5 text-base font-semibold leading-5 transition-all duration-100 active:scale-[0.97]"
:class="
selectedFilters.length === 0
- ? 'border-green bg-brand-highlight text-brand'
+ ? 'border-brand bg-brand-highlight text-brand'
: 'border-surface-5 bg-surface-4 text-primary hover:bg-surface-5'
"
:aria-pressed="selectedFilters.length === 0"
@@ -870,7 +868,7 @@ const confirmUnlinkModal = ref>()
class="cursor-pointer rounded-full border border-solid px-3 py-1.5 text-base font-semibold leading-5 transition-all duration-100 active:scale-[0.97]"
:class="
selectedFilters.includes(option.id)
- ? 'border-green bg-brand-highlight text-brand'
+ ? 'border-brand bg-brand-highlight text-brand'
: 'border-surface-5 bg-surface-4 text-primary hover:bg-surface-5'
"
:aria-pressed="selectedFilters.includes(option.id)"
@@ -879,66 +877,58 @@ const confirmUnlinkModal = ref>()
{{ option.label }}
-
-
-
- {{ sortLabels[sortMode]() }}
-
-
+
+
+ {{ sortLabels[sortMode]() }}
+
-
-
-
- {{ sortLabels[sortMode]() }}
-
-
+
+
+ {{ sortLabels[sortMode]() }}
+
-
-
-
- {{ formatMessage(messages.updateAll) }}
-
-
+
+ {{ formatMessage(messages.updateAll) }}
+
-
-
-
- {{ formatMessage(commonMessages.refreshButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.refreshButton) }}
+
@@ -981,34 +971,33 @@ const confirmUnlinkModal = ref>()
}}
-
-
-
- {{ formatMessage(messages.uploadFiles) }}
-
-
-
-
-
- {{ formatMessage(messages.browseContent) }}
-
-
+
+
+ {{ formatMessage(messages.uploadFiles) }}
+
+
+
+ {{ formatMessage(messages.browseContent) }}
+
@@ -1034,84 +1023,82 @@ const confirmUnlinkModal = ref>()
@disable="bulkDisable"
>
-
-
-
- {{ formatMessage(commonMessages.updateButton) }}
-
-
+
+ {{ formatMessage(commonMessages.updateButton) }}
+
-
-
-
- {{ formatMessage(messages.share) }}
-
-
-
- {{ formatMessage(messages.shareProjectNames) }}
-
-
-
- {{ formatMessage(messages.shareFileNames) }}
-
-
-
- {{ formatMessage(messages.shareProjectLinks) }}
-
-
-
- {{ formatMessage(messages.shareMarkdownLinks) }}
-
-
-
+
+
+ {{ formatMessage(messages.share) }}
+
+
+
+ {{ formatMessage(messages.shareProjectNames) }}
+
+
+
+ {{ formatMessage(messages.shareFileNames) }}
+
+
+
+ {{ formatMessage(messages.shareProjectLinks) }}
+
+
+
+ {{ formatMessage(messages.shareMarkdownLinks) }}
+
+
-
-
-
- {{ formatMessage(commonMessages.deleteLabel) }}
-
-
+
+ {{ formatMessage(commonMessages.deleteLabel) }}
+
diff --git a/packages/ui/src/layouts/shared/content-tab/providers/content-manager.ts b/packages/ui/src/layouts/shared/content-tab/providers/content-manager.ts
index 8b8a88d24e..33224d73a5 100644
--- a/packages/ui/src/layouts/shared/content-tab/providers/content-manager.ts
+++ b/packages/ui/src/layouts/shared/content-tab/providers/content-manager.ts
@@ -1,7 +1,7 @@
import type { ComputedRef, Ref } from 'vue'
import type { RouteLocationRaw } from 'vue-router'
-import type { Option as OverflowMenuOption } from '#ui/components/base/OverflowMenu.vue'
+import type { OverflowMenuOption } from '#ui/components/base/buttons'
import { createContext } from '#ui/providers/create-context'
import type {
diff --git a/packages/ui/src/layouts/shared/content-tab/types.ts b/packages/ui/src/layouts/shared/content-tab/types.ts
index b643787f58..6a208ce4a3 100644
--- a/packages/ui/src/layouts/shared/content-tab/types.ts
+++ b/packages/ui/src/layouts/shared/content-tab/types.ts
@@ -1,7 +1,7 @@
import type { Labrinth } from '@modrinth/api-client'
import type { RouteLocationRaw } from 'vue-router'
-import type { Option as OverflowMenuOption } from '#ui/components/base/OverflowMenu.vue'
+import type { OverflowMenuOption } from '#ui/components/base/buttons'
export type ContentCardProject = Pick<
Labrinth.Projects.v2.Project,
diff --git a/packages/ui/src/layouts/shared/files-tab/components/FileContextMenu.vue b/packages/ui/src/layouts/shared/files-tab/components/FileContextMenu.vue
index cd8843d32a..340c136540 100644
--- a/packages/ui/src/layouts/shared/files-tab/components/FileContextMenu.vue
+++ b/packages/ui/src/layouts/shared/files-tab/components/FileContextMenu.vue
@@ -1,73 +1,67 @@
-
+
-
-
-
- {{ formatMessage(commonMessages.copyFilenameButton) }}
-
-
-
-
-
- {{ formatMessage(commonMessages.copyFullPathButton) }}
-
-
-
-
-
- {{ formatMessage(commonMessages.openInFolderButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.copyFilenameButton) }}
+
+
+
+ {{ formatMessage(commonMessages.copyFullPathButton) }}
+
+
+
+ {{ formatMessage(commonMessages.openInFolderButton) }}
+
-
-
-
-
-
+
+
@@ -78,7 +72,7 @@
import { ClipboardCopyIcon, FolderOpenIcon } from '@modrinth/assets'
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import { useVIntl } from '#ui/composables/i18n'
import { injectNotificationManager } from '#ui/providers/web-notifications'
import { commonMessages } from '#ui/utils/common-messages'
diff --git a/packages/ui/src/layouts/shared/files-tab/components/FileManagerError.vue b/packages/ui/src/layouts/shared/files-tab/components/FileManagerError.vue
index 361a3b0818..56772b206a 100644
--- a/packages/ui/src/layouts/shared/files-tab/components/FileManagerError.vue
+++ b/packages/ui/src/layouts/shared/files-tab/components/FileManagerError.vue
@@ -7,18 +7,14 @@
{{ message }}
-
-
-
- {{ formatMessage(messages.tryAgain) }}
-
-
-
-
-
- {{ formatMessage(messages.goToHome) }}
-
-
+
+
+ {{ formatMessage(messages.tryAgain) }}
+
+
+
+ {{ formatMessage(messages.goToHome) }}
+
@@ -27,7 +23,7 @@
-
-
diff --git a/packages/ui/src/layouts/shared/server-settings/pages/installation.vue b/packages/ui/src/layouts/shared/server-settings/pages/installation.vue
index 3d943bd823..21275870a7 100644
--- a/packages/ui/src/layouts/shared/server-settings/pages/installation.vue
+++ b/packages/ui/src/layouts/shared/server-settings/pages/installation.vue
@@ -22,17 +22,16 @@
formatMessage(messages.resetServerTitle)
}}
-
-
-
- {{ formatMessage(commonMessages.resetServerButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.resetServerButton) }}
+
{{ formatMessage(messages.resetServerDescription) }}
@@ -59,17 +58,16 @@
{{ formatMessage(messages.supportOptionsTitle) }}
-
-
-
- {{ formatMessage(messages.resetToOnboardingButton) }}
-
-
+
+
+ {{ formatMessage(messages.resetToOnboardingButton) }}
+
@@ -79,7 +77,6 @@
import type { Archon } from '@modrinth/api-client'
import { RotateCounterClockwiseIcon } from '@modrinth/assets'
import {
- ButtonStyled,
commonMessages,
ConfirmModal,
defineMessages,
@@ -103,6 +100,7 @@ import {
import { useQuery, useQueryClient } from '@tanstack/vue-query'
import { computed, ref, useTemplateRef, watch } from 'vue'
+import { Button } from '#ui/components/base/buttons'
import { injectFilePicker } from '#ui/providers/file-picker'
const debug = useDebugLogger('LoaderPage')
diff --git a/packages/ui/src/layouts/shared/server-settings/pages/network.vue b/packages/ui/src/layouts/shared/server-settings/pages/network.vue
index dd8091b289..9a91d08000 100644
--- a/packages/ui/src/layouts/shared/server-settings/pages/network.vue
+++ b/packages/ui/src/layouts/shared/server-settings/pages/network.vue
@@ -16,18 +16,16 @@
placeholder="e.g. Secondary allocation"
/>
-
- Cancel
-
-
-
- Update allocation
-
-
+ Cancel
+
+ Update allocation
+
@@ -61,9 +59,14 @@
allocationsError?.message ?? 'Unknown error'
}}
- refetchAllocations()">
- Retry
-
+ refetchAllocations()"
+ >Retry
@@ -83,16 +86,16 @@
placeholder="e.g. Secondary allocation"
/>
-
-
-
- Create allocation
-
-
+
+
+ Create allocation
+
@@ -105,30 +108,33 @@
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
@@ -153,16 +159,14 @@
:placeholder="exampleDomain"
/>
-
-
-
- Export
-
-
+
+
+ Export
+
@@ -223,8 +227,9 @@ import {
import { useQuery, useQueryClient } from '@tanstack/vue-query'
import { computed, nextTick, ref } from 'vue'
-import { ButtonStyled, ConfirmModal, NewModal, StyledInput, Table, TagItem } from '#ui/components'
+import { ConfirmModal, NewModal, StyledInput, Table, TagItem } from '#ui/components'
import type { TableColumn } from '#ui/components/base'
+import { Button, IconButton } from '#ui/components/base/buttons'
import { useServerPermissions } from '#ui/composables/server-permissions'
import {
injectModrinthClient,
diff --git a/packages/ui/src/layouts/shared/user-profile/components/edit-user-modal.vue b/packages/ui/src/layouts/shared/user-profile/components/edit-user-modal.vue
new file mode 100644
index 0000000000..64e3e27043
--- /dev/null
+++ b/packages/ui/src/layouts/shared/user-profile/components/edit-user-modal.vue
@@ -0,0 +1,310 @@
+
+
+
+
+
Profile picture
+
+
+
+
+
+
+
+
+ {{ formatMessage(commonMessages.removeImageButton) }}
+
+
+
+ {{ formatMessage(commonMessages.resetButton) }}
+
+
+
+
+
+
+
+ {{ formatMessage(commonMessages.usernameLabel) }}
+
+
+
+
+ {{ form.username.length }}/39
+
+
+
+
+
+
Bio
+
+
+ {{ form.bio.length }}/160
+
+
+
+
+ Role
+
+
+
+
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+
+ {{ formatMessage(commonMessages.savingButton) }}
+
+
+
+ {{ formatMessage(commonMessages.saveChangesButton) }}
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/layouts/shared/user-profile/layout.vue b/packages/ui/src/layouts/shared/user-profile/layout.vue
index be4f1644b9..8ffe648c35 100644
--- a/packages/ui/src/layouts/shared/user-profile/layout.vue
+++ b/packages/ui/src/layouts/shared/user-profile/layout.vue
@@ -13,60 +13,31 @@
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
-
- {{ formatMessage(messages.blockButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.cancelButton) }}
+
+
+
+
+ {{ formatMessage(messages.blockButton) }}
+
-
-
-
-
-
-
-
- {{ formatMessage(commonMessages.cancelButton) }}
-
-
-
-
-
-
- {{ formatMessage(messages.savingLabel) }}
-
-
-
- {{ formatMessage(commonMessages.saveChangesButton) }}
-
-
-
-
-
-
+
{{ formatMessage(messages.authProvidersLabel) }}
- {{ user.auth_providers?.join(', ') || '—' }}
+
+
+ {{ authProviderNames[provider] ?? provider }}
+
+ ({{ user.discord_id }})
+
+
+ (
+
+ {{
+ isLoadingGithubProfile
+ ? formatMessage(messages.loadingGithubProfileLabel)
+ : formatMessage(messages.viewGithubProfileLabel)
+ }}
+
+ )
+
+
+ ({{ user.steam_id }})
+
+
+
@@ -166,7 +163,7 @@
-
+
@@ -258,7 +255,11 @@
}"
:layout="displayMode === 'list' ? 'list' : 'grid'"
:status="project.status"
- />
+ >
+
+
+
+
-
-
- {{ formatMessage(messages.createProjectButton) }}
-
-
+
+ {{ formatMessage(messages.createProjectButton) }}
+
@@ -354,11 +353,9 @@
"
>
-
-
- {{ formatMessage(messages.createCollectionButton) }}
-
-
+
+ {{ formatMessage(messages.createCollectionButton) }}
+
@@ -411,11 +408,9 @@
:description="formatMessage(messages.userLoadErrorDescription)"
>
-
-
- {{ formatMessage(commonMessages.retryButton) }}
-
-
+
+ {{ formatMessage(commonMessages.retryButton) }}
+
@@ -431,7 +426,6 @@ import {
LibraryIcon,
LinkIcon,
LockIcon,
- SaveIcon,
SpinnerIcon,
XIcon,
} from '@modrinth/assets'
@@ -447,8 +441,7 @@ import { useRoute, useRouter } from 'vue-router'
import Admonition from '#ui/components/base/Admonition.vue'
import AutoLink from '#ui/components/base/AutoLink.vue'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
-import Combobox from '#ui/components/base/Combobox.vue'
+import { Button } from '#ui/components/base/buttons'
import EmptyState from '#ui/components/base/EmptyState.vue'
import IntlFormatted from '#ui/components/base/IntlFormatted.vue'
import NavTabs from '#ui/components/base/NavTabs.vue'
@@ -460,9 +453,16 @@ import ProjectCardList from '#ui/components/project/ProjectCardList.vue'
import UserBadges from '#ui/components/user/UserBadges.vue'
import UserPageHeader from '#ui/components/user/UserPageHeader.vue'
import { defineMessages, useVIntl } from '#ui/composables'
-import { injectAuth, injectNotificationManager, injectPageContext, injectTags } from '#ui/providers'
-import { commonMessages, getProjectTypeTitleMessage } from '#ui/utils'
+import {
+ injectAuth,
+ injectModrinthClient,
+ injectNotificationManager,
+ injectPageContext,
+ injectTags,
+} from '#ui/providers'
+import { commonMessages, getProjectTypeTitleMessage, sortProjectTypes } from '#ui/utils'
+import EditUserModal from './components/edit-user-modal.vue'
import { blockedUsersQueryKey, injectUserProfile } from './providers'
import {
hasActivePride26Midas,
@@ -520,6 +520,7 @@ const auth = injectAuth()
const tags = injectTags(null)
const pageContext = injectPageContext()
const notificationManager = injectNotificationManager()
+const client = injectModrinthClient()
const queryClient = useQueryClient()
const route = useRoute()
const router = useRouter()
@@ -535,18 +536,6 @@ const messages = defineMessages({
id: 'profile.collection.projects-count',
defaultMessage: '{count, plural, one {# project} other {# projects}}',
},
- savingLabel: {
- id: 'profile.label.saving',
- defaultMessage: 'Saving...',
- },
- editRoleButton: {
- id: 'profile.button.edit-role',
- defaultMessage: 'Edit role',
- },
- selectRolePlaceholder: {
- id: 'profile.role.select-placeholder',
- defaultMessage: 'Select a role',
- },
userDetailsTitle: {
id: 'profile.details.title',
defaultMessage: 'User details',
@@ -567,6 +556,26 @@ const messages = defineMessages({
id: 'profile.details.label.auth-providers',
defaultMessage: 'Auth providers',
},
+ viewGithubProfileLabel: {
+ id: 'profile.details.label.view-github-profile',
+ defaultMessage: 'View profile',
+ },
+ loadingGithubProfileLabel: {
+ id: 'profile.details.label.loading-github-profile',
+ defaultMessage: 'Loading...',
+ },
+ githubProfileErrorTitle: {
+ id: 'profile.details.error.github-profile-title',
+ defaultMessage: 'Unable to open GitHub profile',
+ },
+ githubProfileErrorMessage: {
+ id: 'profile.details.error.github-profile-message',
+ defaultMessage: 'The GitHub profile could not be retrieved. Please try again.',
+ },
+ githubPopupBlockedMessage: {
+ id: 'profile.details.error.github-popup-blocked',
+ defaultMessage: 'Allow pop-ups for Modrinth, then try again.',
+ },
paymentMethodsLabel: {
id: 'profile.details.label.payment-methods',
defaultMessage: 'Payment methods',
@@ -636,14 +645,6 @@ const messages = defineMessages({
defaultMessage:
'The official user account of Modrinth. Get support at or via email at ',
},
- roleUpdateErrorTitle: {
- id: 'profile.role.update-error-title',
- defaultMessage: 'Failed to update role',
- },
- roleUpdateErrorDescription: {
- id: 'profile.role.update-error-description',
- defaultMessage: 'An error occurred while updating the user role. Please try again.',
- },
blockButton: {
id: 'profile.button.block',
defaultMessage: 'Block',
@@ -784,7 +785,7 @@ const projectTypes = computed(() => {
const types = new Set(projects.value.map((project) => project.resolvedProjectType))
if (collections.value.length > 0) types.add('collection')
types.delete('project')
- return [...types]
+ return sortProjectTypes(types)
})
const navLinks = computed(() => {
@@ -795,15 +796,13 @@ const navLinks = computed(() => {
label: formatMessage(commonMessages.allProjectType),
href: profilePath,
},
- ...projectTypes.value
- .map((projectType) => ({
- label:
- projectType === 'collection'
- ? formatMessage(messages.collectionsLabel)
- : formatMessage(getProjectTypeTitleMessage(projectType), { count: 2 }),
- href: `${profilePath}/${projectType}s`,
- }))
- .sort((first, second) => first.label.localeCompare(second.label)),
+ ...projectTypes.value.map((projectType) => ({
+ label:
+ projectType === 'collection'
+ ? formatMessage(messages.collectionsLabel)
+ : formatMessage(getProjectTypeTitleMessage(projectType), { count: 2 }),
+ href: `${profilePath}/${projectType}s`,
+ })),
]
})
@@ -853,6 +852,17 @@ const showCollectionsEmptyState = computed(
const normalizedSiteUrl = computed(() => props.siteUrl.replace(/\/$/, ''))
const editProfileLink = computed(() => props.editProfileLink ?? linkTarget('/settings/profile'))
+const authProviderNames = {
+ github: 'GitHub',
+ discord: 'Discord',
+ microsoft: 'Microsoft',
+ gitlab: 'GitLab',
+ google: 'Google',
+ steam: 'Steam',
+ paypal: 'PayPal',
+}
+const isLoadingGithubProfile = ref(false)
+
function externalUrl(path: string): string {
return `${normalizedSiteUrl.value}${path.startsWith('/') ? path : `/${path}`}`
}
@@ -896,6 +906,50 @@ async function copyPermalink(): Promise {
}
}
+async function openGithubProfile() {
+ const githubId = user.value?.github_id
+ if (!githubId || isLoadingGithubProfile.value) return
+
+ const profileWindow = window.open('about:blank', '_blank')
+ if (!profileWindow) {
+ notificationManager.addNotification({
+ type: 'error',
+ title: formatMessage(messages.githubProfileErrorTitle),
+ text: formatMessage(messages.githubPopupBlockedMessage),
+ })
+ return
+ }
+
+ profileWindow.opener = null
+ isLoadingGithubProfile.value = true
+
+ try {
+ const githubUser = await client.request<{ login?: string }>(`/${githubId}`, {
+ api: 'https://api.github.com',
+ version: 'user',
+ method: 'GET',
+ headers: { 'Content-Type': '' },
+ skipAuth: true,
+ })
+
+ if (!githubUser?.login) {
+ throw new Error('GitHub user response did not include a login')
+ }
+
+ profileWindow.location.replace(`https://github.com/${encodeURIComponent(githubUser.login)}`)
+ } catch (error) {
+ profileWindow.close()
+ console.error('Failed to retrieve GitHub profile:', error)
+ notificationManager.addNotification({
+ type: 'error',
+ title: formatMessage(messages.githubProfileErrorTitle),
+ text: formatMessage(messages.githubProfileErrorMessage),
+ })
+ } finally {
+ isLoadingGithubProfile.value = false
+ }
+}
+
function reportProfile(): void {
if (!user.value) return
const reportPath = `/report?item=user&itemID=${encodeURIComponent(user.value.id)}`
@@ -934,35 +988,15 @@ async function retryQueries(): Promise {
}
const userDetailsModal = ref(null)
-const editRoleModal = ref(null)
+const editUserModal = ref | null>(null)
const blockUserModal = ref(null)
-const selectedRole = ref(null)
-const isSavingRole = ref(false)
const isBlockingUser = ref(false)
const isUnblockingUser = ref(false)
-const roleOptions = [
- { value: 'developer', label: 'Developer' },
- { value: 'moderator', label: 'Moderator' },
- { value: 'admin', label: 'Admin' },
-] satisfies { value: Labrinth.Users.v3.Role; label: string }[]
-
-watch(
- user,
- (currentUser) => {
- selectedRole.value = currentUser?.role ?? null
- },
- { immediate: true },
-)
function openUserDetails(): void {
userDetailsModal.value?.show()
}
-function openRoleEditModal(): void {
- selectedRole.value = user.value?.role ?? null
- editRoleModal.value?.show()
-}
-
async function handleBlockAction(): Promise {
if (!auth.user.value) {
await auth.requestSignIn(route.fullPath)
@@ -1039,11 +1073,6 @@ async function unblockCurrentUser(): Promise {
}
}
-function cancelRoleEdit(): void {
- selectedRole.value = user.value?.role ?? null
- editRoleModal.value?.hide()
-}
-
async function toggleAffiliate(): Promise {
if (!user.value) return
await userProfile.patchUser(user.value.id, {
@@ -1051,23 +1080,4 @@ async function toggleAffiliate(): Promise {
})
await queryClient.invalidateQueries({ queryKey: ['user', props.userId] })
}
-
-async function saveRoleEdit(): Promise {
- if (!user.value || !selectedRole.value || selectedRole.value === user.value.role) return
-
- isSavingRole.value = true
- try {
- await userProfile.patchUser(user.value.id, { role: selectedRole.value })
- await queryClient.invalidateQueries({ queryKey: ['user', props.userId] })
- editRoleModal.value?.hide()
- } catch {
- notificationManager.addNotification({
- type: 'error',
- title: formatMessage(messages.roleUpdateErrorTitle),
- text: formatMessage(messages.roleUpdateErrorDescription),
- })
- } finally {
- isSavingRole.value = false
- }
-}
diff --git a/packages/ui/src/layouts/shared/user-profile/providers/user-profile.ts b/packages/ui/src/layouts/shared/user-profile/providers/user-profile.ts
index 6314ece5c6..58270661bd 100644
--- a/packages/ui/src/layouts/shared/user-profile/providers/user-profile.ts
+++ b/packages/ui/src/layouts/shared/user-profile/providers/user-profile.ts
@@ -9,8 +9,10 @@ export interface UserProfileContext {
getCollections: (userId: string) => Promise
patchUser: (
userId: string,
- patch: Partial>,
+ patch: Partial>,
) => Promise
+ changeAvatar: (userId: string, file: Blob, extension: string) => Promise
+ deleteAvatar: (userId: string) => Promise
getBlockedUsers: () => Promise
blockUser: (userId: string) => Promise
unblockUser: (userId: string) => Promise
diff --git a/packages/ui/src/layouts/wrapped/AccountProfileSettings.vue b/packages/ui/src/layouts/wrapped/AccountProfileSettings.vue
index 1cd295cdcc..f38537a444 100644
--- a/packages/ui/src/layouts/wrapped/AccountProfileSettings.vue
+++ b/packages/ui/src/layouts/wrapped/AccountProfileSettings.vue
@@ -15,12 +15,10 @@
-
-
-
- {{ formatMessage(commonMessages.signInButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.signInButton) }}
+
@@ -56,30 +54,33 @@
-
-
-
-
-
-
-
-
- {{ formatMessage(commonMessages.removeImageButton) }}
-
-
-
-
-
- {{ formatMessage(commonMessages.resetButton) }}
-
-
+
+
+
+
+
+ {{ formatMessage(commonMessages.removeImageButton) }}
+
+
+
+ {{ formatMessage(commonMessages.resetButton) }}
+
@@ -135,9 +136,8 @@ import { computed, onBeforeUnmount, ref, shallowRef, watch } from 'vue'
import { RouterLink } from 'vue-router'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button, FileButton } from '#ui/components/base/buttons'
import EmptyState from '#ui/components/base/EmptyState.vue'
-import FileInput from '#ui/components/base/FileInput.vue'
import IntlFormatted from '#ui/components/base/IntlFormatted.vue'
import StyledInput from '#ui/components/base/StyledInput.vue'
import { defineMessages, useVIntl } from '#ui/composables'
diff --git a/packages/ui/src/layouts/wrapped/AccountSocialSettings.vue b/packages/ui/src/layouts/wrapped/AccountSocialSettings.vue
index 6d2f4f5d8c..240744fa31 100644
--- a/packages/ui/src/layouts/wrapped/AccountSocialSettings.vue
+++ b/packages/ui/src/layouts/wrapped/AccountSocialSettings.vue
@@ -15,12 +15,10 @@
-
-
-
- {{ formatMessage(commonMessages.signInButton) }}
-
-
+
+
+ {{ formatMessage(commonMessages.signInButton) }}
+
@@ -112,11 +110,9 @@
{{ formatMessage(messages.loadError) }}
-
-
- {{ formatMessage(commonMessages.retryButton) }}
-
-
+
+ {{ formatMessage(commonMessages.retryButton) }}
+
{{ formatMessage(messages.noBlockedUsers) }}
@@ -145,25 +141,24 @@
-
-
-
- {{ formatMessage(messages.unblockButton) }}
-
-
+
+
+ {{ formatMessage(messages.unblockButton) }}
+
@@ -195,7 +190,7 @@ import { useQuery, useQueryClient } from '@tanstack/vue-query'
import { computed, ref } from 'vue'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import Chips from '#ui/components/base/Chips.vue'
import EmptyState from '#ui/components/base/EmptyState.vue'
import Table, { type TableColumn } from '#ui/components/base/Table.vue'
diff --git a/packages/ui/src/layouts/wrapped/hosting/manage/[id]/access/access.vue b/packages/ui/src/layouts/wrapped/hosting/manage/[id]/access/access.vue
index 96cc63944a..b85f8d8fe3 100644
--- a/packages/ui/src/layouts/wrapped/hosting/manage/[id]/access/access.vue
+++ b/packages/ui/src/layouts/wrapped/hosting/manage/[id]/access/access.vue
@@ -14,23 +14,25 @@
v-model="roleFilter"
:options="roleFilterOptions"
:display-value="selectedRoleFilterLabel"
- trigger-class="min-w-[225px] !h-10 !min-h-10 !py-0"
+ trigger-size="lg"
+ trigger-class="min-w-[225px]"
>
-
-
-
- {{ formatMessage(messages.inviteFriends) }}
-
-
+
+
+ {{ formatMessage(messages.inviteFriends) }}
+
@@ -113,7 +115,7 @@ import { FilterIcon, SearchIcon, UserPlusIcon } from '@modrinth/assets'
import { useQuery, useQueryClient } from '@tanstack/vue-query'
import { computed, ref, watch } from 'vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import Combobox, { type ComboboxOption } from '#ui/components/base/Combobox.vue'
import DropdownFilterBar from '#ui/components/base/DropdownFilterBar.vue'
import StyledInput from '#ui/components/base/StyledInput.vue'
diff --git a/packages/ui/src/layouts/wrapped/hosting/manage/[id]/onboarding.vue b/packages/ui/src/layouts/wrapped/hosting/manage/[id]/onboarding.vue
index bcdebf6392..f231ba7956 100644
--- a/packages/ui/src/layouts/wrapped/hosting/manage/[id]/onboarding.vue
+++ b/packages/ui/src/layouts/wrapped/hosting/manage/[id]/onboarding.vue
@@ -42,22 +42,22 @@
-
-
-
- {{ formatMessage(messages.uploadingProgress, { percent: uploadPercent }) }}
-
-
-
-
- {{ formatMessage(messages.setupServerButton) }}
-
-
+
+
+ {{ formatMessage(messages.uploadingProgress, { percent: uploadPercent }) }}
+
+
+ {{ formatMessage(messages.setupServerButton) }}
+
{{ error.message }}
-
- Retry
-
+ Retry
@@ -71,16 +71,16 @@
{{ formatMessage(commonMessages.allProjectType) }}
-
-
-
- {{ formatMessage(messages.createBackup) }}
-
-
+
+
+ {{ formatMessage(messages.createBackup) }}
+
@@ -95,17 +95,17 @@
:description="formatMessage(messages.emptyDescription)"
>
-
-
-
- {{ formatMessage(messages.createBackup) }}
-
-
+
+
+ {{ formatMessage(messages.createBackup) }}
+
-
-
- {{ formatMessage(messages.clearFilters) }}
-
-
+
+ {{ formatMessage(messages.clearFilters) }}
+
@@ -198,30 +196,30 @@
}}
-
-
- {{ formatMessage(commonMessages.clearButton) }}
-
-
+
+ {{ formatMessage(commonMessages.clearButton) }}
+
-
-
-
- {{ formatMessage(commonMessages.deleteLabel) }}
-
-
+
+
+ {{ formatMessage(commonMessages.deleteLabel) }}
+
@@ -236,7 +234,9 @@
role="progressbar"
:aria-valuemin="0"
:aria-valuemax="bulkTotal"
- style="box-shadow: 0px -2px 4px 0px rgba(27, 217, 106, 0.1)"
+ style="
+ box-shadow: 0px -2px 4px 0px color-mix(in srgb, var(--color-brand) 10%, transparent);
+ "
/>
@@ -273,7 +273,7 @@ import type { Component } from 'vue'
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button } from '#ui/components/base/buttons'
import Checkbox from '#ui/components/base/Checkbox.vue'
import EmptyState from '#ui/components/base/EmptyState.vue'
import FilterPills, { type FilterPillOption } from '#ui/components/base/FilterPills.vue'
diff --git a/packages/ui/src/layouts/wrapped/hosting/manage/index.vue b/packages/ui/src/layouts/wrapped/hosting/manage/index.vue
index d22ac2dac4..f85d23337c 100644
--- a/packages/ui/src/layouts/wrapped/hosting/manage/index.vue
+++ b/packages/ui/src/layouts/wrapped/hosting/manage/index.vue
@@ -75,14 +75,17 @@
-
- {{
- formatMessage(messages.contactSupportButton)
- }}
-
- router.go(0)">
- {{ formatMessage(messages.reloadButton) }}
-
+ {{ formatMessage(messages.contactSupportButton) }}
+ router.go(0)">{{
+ formatMessage(messages.reloadButton)
+ }}
@@ -106,12 +109,10 @@
:placeholder="formatMessage(messages.searchPlaceholder, { count: filteredData.length })"
wrapper-class="w-full md:w-72"
/>
-
-
-
- {{ formatMessage(messages.newServerButton) }}
-
-
+
+
+ {{ formatMessage(messages.newServerButton) }}
+
@@ -231,8 +232,6 @@
import type { Archon, Labrinth } from '@modrinth/api-client'
import { HammerIcon, LoaderCircleIcon, PlusIcon, SearchIcon } from '@modrinth/assets'
import {
- AutoLink,
- ButtonStyled,
CopyCode,
defineMessages,
injectAuth,
@@ -255,6 +254,7 @@ import type Stripe from 'stripe'
import { type ComponentPublicInstance, computed, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
+import { Button, ButtonLink } from '#ui/components/base/buttons'
import ServersUpgradeModalWrapper from '#ui/components/billing/ServersUpgradeModalWrapper.vue'
import type { ServerListingOwner } from '#ui/components/servers/access'
import MedalServerListing from '#ui/components/servers/marketing/MedalServerListing.vue'
diff --git a/packages/ui/src/layouts/wrapped/hosting/manage/root.vue b/packages/ui/src/layouts/wrapped/hosting/manage/root.vue
index c781570242..978b6b6c49 100644
--- a/packages/ui/src/layouts/wrapped/hosting/manage/root.vue
+++ b/packages/ui/src/layouts/wrapped/hosting/manage/root.vue
@@ -142,8 +142,8 @@
{{ formatLoaderLabel(serverData.loader) }} {{ serverData.mc_version }}
@@ -181,31 +181,30 @@
:auto-hide="false"
placement="bottom-end"
>
-
-
-
-
-
+
+
+
{{ formatMessage(settingsHintMessages.title) }}
-
-
-
-
-
+
+
+
{{ formatMessage(settingsHintMessages.description) }}
@@ -213,15 +212,15 @@
-
-
-
-
-
+
+
+
@@ -284,13 +283,11 @@
If you're stuck, please contact Modrinth Support with the information below:
-
-
-
-
- Copy Debug Info
-
-
+
+
+
+ Copy Debug Info
+
An internal error occurred while installing your server. Don't fret — try
@@ -310,25 +307,23 @@
v-if="errorTitle === 'Installation error'"
class="mt-2 flex flex-col gap-4 sm:flex-row"
>
-
- Open Installation Log
-
-
-
-
-
- Copy Debug Info
-
-
-
-
-
- Change Loader
-
-
+ Open Installation Log
+
+
+
+ Copy Debug Info
+
+
+
+ Change Loader
+
@@ -430,7 +425,7 @@ import { computed, nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, watch
import { onBeforeRouteLeave, useRoute, useRouter } from 'vue-router'
import Avatar from '#ui/components/base/Avatar.vue'
-import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
+import { Button, IconButton, TeleportOverflowMenu } from '#ui/components/base/buttons'
import ErrorInformationCard from '#ui/components/base/ErrorInformationCard.vue'
import NavTabs from '#ui/components/base/NavTabs.vue'
import PageHeader from '#ui/components/base/page-header/index.vue'
@@ -438,10 +433,9 @@ import PageHeaderMetadata from '#ui/components/base/page-header/metadata/index.v
import PageHeaderMetadataItem from '#ui/components/base/page-header/metadata/page-header-metadata-item.vue'
import PageHeaderActions from '#ui/components/base/page-header/page-header-actions.vue'
import ServerNotice from '#ui/components/base/ServerNotice.vue'
-import TeleportOverflowMenu from '#ui/components/base/TeleportOverflowMenu.vue'
+import TagIcon from '#ui/components/base/TagIcon.vue'
import ConfirmLeaveModal from '#ui/components/modal/ConfirmLeaveModal.vue'
import ServerPanelAdmonitions from '#ui/components/servers/admonitions/ServerPanelAdmonitions.vue'
-import LoaderIcon from '#ui/components/servers/icons/LoaderIcon.vue'
import ServerIcon from '#ui/components/servers/icons/ServerIcon.vue'
import MedalServerCountdown from '#ui/components/servers/marketing/MedalServerCountdown.vue'
import { PanelServerActionButton } from '#ui/components/servers/server-header'
diff --git a/packages/ui/src/locales/cs-CZ/index.json b/packages/ui/src/locales/cs-CZ/index.json
index 3ca7ba4115..fbfe943185 100644
--- a/packages/ui/src/locales/cs-CZ/index.json
+++ b/packages/ui/src/locales/cs-CZ/index.json
@@ -1130,9 +1130,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Soubor uložen"
},
- "files.editor.find-close": {
- "defaultMessage": "Zavřít"
- },
"files.editor.find-in-file": {
"defaultMessage": "Najít"
},
@@ -4557,3 +4554,4 @@
"defaultMessage": "Typ"
}
}
+
diff --git a/packages/ui/src/locales/da-DK/index.json b/packages/ui/src/locales/da-DK/index.json
index 3277f89162..0a26f0a776 100644
--- a/packages/ui/src/locales/da-DK/index.json
+++ b/packages/ui/src/locales/da-DK/index.json
@@ -161,6 +161,9 @@
"button.enable": {
"defaultMessage": "Aktiver"
},
+ "button.extract": {
+ "defaultMessage": "Pak ud"
+ },
"button.follow": {
"defaultMessage": "Følg"
},
@@ -272,12 +275,24 @@
"changelog.product.hosting": {
"defaultMessage": "Hosting"
},
+ "changelog.product.web": {
+ "defaultMessage": "Platform"
+ },
"collection-widget.loading-projects": {
"defaultMessage": "Indlæser projekter..."
},
+ "collection-widget.search-placeholder": {
+ "defaultMessage": "Søg efter projekter"
+ },
"collections.label.private": {
"defaultMessage": "Privat"
},
+ "content-type.content.lowercase": {
+ "defaultMessage": "indhold"
+ },
+ "content-type.item.lowercase": {
+ "defaultMessage": "{count, plural, one {genstand} other {genstande}}"
+ },
"content.card.select-project": {
"defaultMessage": "Vælg {project}"
},
@@ -542,9 +557,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Fil gemt"
},
- "files.editor.find-close": {
- "defaultMessage": "Luk"
- },
"files.editor.find-in-file": {
"defaultMessage": "Find"
},
@@ -2238,3 +2250,4 @@
"defaultMessage": "Vanilla Shader"
}
}
+
diff --git a/packages/ui/src/locales/de-CH/index.json b/packages/ui/src/locales/de-CH/index.json
index bb3ed6010b..baf3a3c1dd 100644
--- a/packages/ui/src/locales/de-CH/index.json
+++ b/packages/ui/src/locales/de-CH/index.json
@@ -566,6 +566,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "Welt"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "Installationseinstellungen"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "Zusätzliche Inhalte"
},
@@ -1301,9 +1304,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Datei gespeichert"
},
- "files.editor.find-close": {
- "defaultMessage": "Schliessen"
- },
"files.editor.find-in-file": {
"defaultMessage": "Finden"
},
@@ -2240,6 +2240,9 @@
"label.details": {
"defaultMessage": "Details"
},
+ "label.discover-content": {
+ "defaultMessage": "Inhalte erkunden"
+ },
"label.done": {
"defaultMessage": "Fertig"
},
@@ -2318,6 +2321,9 @@
"label.password": {
"defaultMessage": "Passwort"
},
+ "label.permissions": {
+ "defaultMessage": "Berechtigungen"
+ },
"label.plan-custom": {
"defaultMessage": "Benutzerdefiniert"
},
@@ -2849,9 +2855,162 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Ein Modrinth-Ersteller."
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Ein Modrinth-Nutzer."
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} wird dir keine Freundschaftsanfragen mehr senden können, dich nicht zu geteilten Instanzen einladen können und dich nicht mehr zu Modrinth-Hosting Servern einladen können."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "Bist du dir sicher, dass du diesen Nutzer blockieren willst?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "Beim Blockieren dieses Nutzers ist ein Fehler aufgetreten. Bitte versuche es erneut."
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "Blockierung fehlgeschlagen"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} wurde blockiert."
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Nutzer blockiert"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "Blockiere {username}"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Benutzeranalysen anzeigen"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "Benutzerabrechnung verwalten"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Blockieren"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "Sammlung erstellen"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "Projekt erstellen"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Nutzerdetails anzeigen"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "Projekte verwalten"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "Als Partner entfernen"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "Als Partner festlegen"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Freigeben"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural, one {# Projekt} other {# Projekte}}"
+ },
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "Erlaube Pop-Ups für Modrinth und versuche es erneut."
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "Das GitHub-Profil konnte nicht abgerufen werden. Bitte versuche es erneut."
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "Das GitHub-Profil konnte nicht geöffnet werden"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "Authentifizierungsanbieter"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "E-Mail verifiziert"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "Hat Passwort"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "Hat TOTP"
+ },
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "Wird geladen..."
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "Zahlungsmethoden"
+ },
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "Profil anzeigen"
+ },
+ "profile.details.title": {
+ "defaultMessage": "Nutzerdetails"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "E-Mail nicht verifiziert"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "E-Mail verifiziert"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "Das Nutzerprofil konnte nicht geladen werden."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "Nutzer nicht gefunden"
+ },
+ "profile.label.affiliate": {
+ "defaultMessage": "Partner"
+ },
"profile.label.badges": {
"defaultMessage": "Abzeichen"
},
+ "profile.label.collection": {
+ "defaultMessage": "Kollektion"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, one {Download} other {Downloads}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "Beigetreten"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "Dieser Nutzer hat keine Kollektionen!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "Du hast noch keine Kollektionen."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "Dieser Nutzer hat keine Projekte!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "Du hast noch keine Projekte."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "Organisationen"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural, one {Projekt} other {Projekte}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Offizielles Modrinth-Konto"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "Das offizielle Benutzerkonto von Modrinth. Erhalte Hilfe unter oder per E-Mail unter "
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "Beim Freigeben dieses Nutzers ist ein Fehler aufgetreten. Bitte versuche es erneut."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "Nutzer konnte nicht freigegeben werden"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "{username} wurde freigegeben."
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "Benutzer freigegeben"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "Veröffentlicht {date}"
},
@@ -2879,6 +3038,9 @@
"project-type.all": {
"defaultMessage": "Alle"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "Kollektionen"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, one {Datenpaket} other {Datenpakete}}"
},
@@ -5105,9 +5267,120 @@
"settings.pats.title": {
"defaultMessage": "Persöhnlich Zugangstoken"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "Eine kurze Beschreibung um allen ein bisschen von dir zu erzählen."
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "Bio"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "Profil"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "Profilbild"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "Deine Profilinformationen sind öffentlich auf Modrinth und über die Modrinth-API sichtbar."
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "Profil konnte nicht aktualisiert werden"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "Beim Aktualisieren deines Profils ist ein Fehler aufgetreten. Bitte versuche es erneut."
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "Melde dich mit einem Modrinth-Konto an, um dein öffentliches Profil anzupassen."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Modrinth-Konto benötigt"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "Ein eindeutiger Name für dein Profil, bei dem Groß- und Kleinschreibung nicht unterschieden wird."
+ },
"settings.sessions.title": {
"defaultMessage": "Sitzungen"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "Aktionen"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Nutzer"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Dies sind die Benutzer, die du auf Modrinth blockiert hast. Diese können nicht:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "Du hast niemanden blockiert."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "Blockierte Nutzer konnten nicht geladen werden."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "Blockierte Nutzer werden geladen…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "Dir Freundschaftsanfragen senden"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "Dich zu einem Modrinth-Hosting Server einladen."
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "Dich zu geteilten Instanzen einladen"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "Blockierte Nutzer"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "Freigeben"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "Benutzer konnte nicht freigegeben werden"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "Beim Freigeben dieses Nutzers ist ein Fehler aufgetreten. Bitte versuche es erneut."
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "{username} freigeben"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "Avatar von {username}"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "Lege fest, wer dir auf Modrinth Freundschaftsanfragen senden kann."
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "Freundschaftsanfragen"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "Bald verfügbar!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "Jeder"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "Freunde"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "Freunde von Freunden"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "Niemand"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "Steuere, wer dir Einladungen zu geteilten Instanzen und Modrinth-Hosting-Panels senden kann."
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "Einladungen"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "Mit einem Modrinth-Konto kannst du festlegen, wer mit dir interagieren kann, und blockierte Nutzer verwalten"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Modrinth-Konto benötigt"
+ },
+ "settings.social.title": {
+ "defaultMessage": "Sozial"
+ },
"sharing.invite-players-modal.add": {
"defaultMessage": "Hinzufügen"
},
@@ -5117,14 +5390,17 @@
"sharing.invite-players-modal.already-invited": {
"defaultMessage": "Dieser Benutzer wurde bereits eingeladen."
},
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "Anwenden"
+ },
"sharing.invite-players-modal.avatar-alt": {
"defaultMessage": "Avatar von {username}"
},
- "sharing.invite-players-modal.cancel": {
- "defaultMessage": "Abbrechen"
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "Benutzerdefiniert..."
},
- "sharing.invite-players-modal.cancel-button": {
- "defaultMessage": "Abbrechen"
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "Benutzerdefiniert: {date}"
},
"sharing.invite-players-modal.edit-invite-link": {
"defaultMessage": "Einladungslink bearbeiten."
@@ -5132,6 +5408,24 @@
"sharing.invite-players-modal.edit-invite-link-title": {
"defaultMessage": "Einladungslink bearbeiten"
},
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "In 1 Tag"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "In 1 Stunde"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "In 7 Tagen"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "In 6 Stunden"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "In 3 Tagen"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "In 12 Stunden"
+ },
"sharing.invite-players-modal.expiry-label": {
"defaultMessage": "Ablaufdatum"
},
@@ -5937,3 +6231,4 @@
"defaultMessage": "Typ"
}
}
+
diff --git a/packages/ui/src/locales/de-DE/index.json b/packages/ui/src/locales/de-DE/index.json
index c6f62eb559..0f21ef03dc 100644
--- a/packages/ui/src/locales/de-DE/index.json
+++ b/packages/ui/src/locales/de-DE/index.json
@@ -291,7 +291,7 @@
"defaultMessage": "Registrieren"
},
"button.stop": {
- "defaultMessage": "Stopp"
+ "defaultMessage": "Stoppen"
},
"button.switch-to-version": {
"defaultMessage": "Zur Version wechseln"
@@ -566,6 +566,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "Welt"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "Installationseinstellungen"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "Zusätzliche Inhalte"
},
@@ -1301,9 +1304,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Datei gespeichert"
},
- "files.editor.find-close": {
- "defaultMessage": "Schließen"
- },
"files.editor.find-in-file": {
"defaultMessage": "Finden"
},
@@ -2240,6 +2240,9 @@
"label.details": {
"defaultMessage": "Details"
},
+ "label.discover-content": {
+ "defaultMessage": "Inhalte erkunden"
+ },
"label.done": {
"defaultMessage": "Fertig"
},
@@ -2292,7 +2295,7 @@
"defaultMessage": "Inhalt wird installiert"
},
"label.loading": {
- "defaultMessage": "Lädt..."
+ "defaultMessage": "Wird geladen..."
},
"label.moderation": {
"defaultMessage": "Moderation"
@@ -2318,6 +2321,9 @@
"label.password": {
"defaultMessage": "Passwort"
},
+ "label.permissions": {
+ "defaultMessage": "Berechtigungen"
+ },
"label.plan-custom": {
"defaultMessage": "Benutzerdefiniert"
},
@@ -2849,9 +2855,162 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Ein Modrinth-Ersteller."
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Ein Modrinth-Nutzer."
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} wird dir keine Freundschaftsanfragen mehr senden können, dich nicht zu geteilten Instanzen einladen können und dich nicht mehr zu Modrinth-Hosting Servern einladen können."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "Bist du dir sicher, dass du diesen Nutzer blockieren willst?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "Beim Blockieren dieses Nutzers ist ein Fehler aufgetreten. Bitte versuche es erneut."
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "Blockierung fehlgeschlagen"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} wurde blockiert."
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Nutzer blockiert"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "Blockiere {username}"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Benutzeranalysen anzeigen"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "Benutzerabrechnung verwalten"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Blockieren"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "Sammlung erstellen"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "Projekt erstellen"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Nutzerdetails anzeigen"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "Projekte verwalten"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "Als Partner entfernen"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "Als Partner festlegen"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Freigeben"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural, one {# Projekt} other {# Projekte}}"
+ },
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "Erlaube Pop-Ups für Modrinth und versuche es erneut."
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "Das GitHub-Profil konnte nicht abgerufen werden. Bitte versuche es erneut."
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "Das GitHub-Profil konnte nicht geöffnet werden"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "Authentifizierungsanbieter"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "E-Mail verifiziert"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "Hat Passwort"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "Hat TOTP"
+ },
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "Wird geladen..."
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "Zahlungsmethoden"
+ },
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "Profil anzeigen"
+ },
+ "profile.details.title": {
+ "defaultMessage": "Nutzerdetails"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "E-Mail nicht verifiziert"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "E-Mail verifiziert"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "Das Nutzerprofil konnte nicht geladen werden."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "Nutzer nicht gefunden"
+ },
+ "profile.label.affiliate": {
+ "defaultMessage": "Partner"
+ },
"profile.label.badges": {
"defaultMessage": "Abzeichen"
},
+ "profile.label.collection": {
+ "defaultMessage": "Kollektion"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, one {Download} other {Downloads}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "Beigetreten"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "Dieser Nutzer hat keine Kollektionen!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "Du hast noch keine Kollektionen."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "Dieser Nutzer hat keine Projekte!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "Du hast noch keine Projekte."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "Organisationen"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural, one {Projekt} other {Projekte}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Offizielles Modrinth-Konto"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "Das offizielle Benutzerkonto von Modrinth. Erhalte Hilfe unter oder per E-Mail unter "
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "Beim Freigeben dieses Nutzers ist ein Fehler aufgetreten. Bitte versuche es erneut."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "Nutzer konnte nicht freigegeben werden"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "{username} wurde freigegeben."
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "Benutzer freigegeben"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "Veröffentlicht am {date}"
},
@@ -2879,6 +3038,9 @@
"project-type.all": {
"defaultMessage": "Alle"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "Kollektionen"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, one {Datenpaket} other {Datenpakete}}"
},
@@ -5105,9 +5267,120 @@
"settings.pats.title": {
"defaultMessage": "Persönliche Zugangstoken"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "Eine kurze Beschreibung um allen ein bisschen von dir zu erzählen."
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "Bio"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "Profil"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "Profilbild"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "Deine Profilinformationen sind öffentlich auf Modrinth und über die Modrinth-API sichtbar."
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "Profil konnte nicht aktualisiert werden"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "Beim Aktualisieren deines Profils ist ein Fehler aufgetreten. Bitte versuche es erneut."
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "Melde dich mit einem Modrinth-Konto an, um dein öffentliches Profil anzupassen."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Modrinth-Konto benötigt"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "Ein eindeutiger Name für dein Profil, bei dem Groß- und Kleinschreibung nicht unterschieden wird."
+ },
"settings.sessions.title": {
"defaultMessage": "Sitzungen"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "Aktionen"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Nutzer"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Dies sind die Benutzer, die du auf Modrinth blockiert hast. Diese können nicht:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "Du hast niemanden blockiert."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "Blockierte Nutzer konnten nicht geladen werden."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "Blockierte Nutzer werden geladen…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "Dir Freundschaftsanfragen senden"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "Dich zu einem Modrinth-Hosting Server einladen."
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "Dich zu geteilten Instanzen einladen"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "Blockierte Nutzer"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "Freigeben"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "Benutzer konnte nicht freigegeben werden"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "Beim Freigeben dieses Nutzers ist ein Fehler aufgetreten. Bitte versuche es erneut."
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "{username} freigeben"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "Avatar von {username}"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "Lege fest, wer dir auf Modrinth Freundschaftsanfragen senden kann."
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "Freundschaftsanfragen"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "Bald verfügbar!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "Jeder"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "Freunde"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "Freunde von Freunden"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "Niemand"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "Steuere, wer dir Einladungen zu geteilten Instanzen und Modrinth-Hosting-Panels senden kann."
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "Einladungen"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "Mit einem Modrinth-Konto kannst du festlegen, wer mit dir interagieren kann, und blockierte Nutzer verwalten"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Modrinth-Konto benötigt"
+ },
+ "settings.social.title": {
+ "defaultMessage": "Sozial"
+ },
"sharing.invite-players-modal.add": {
"defaultMessage": "Hinzufügen"
},
@@ -5117,14 +5390,17 @@
"sharing.invite-players-modal.already-invited": {
"defaultMessage": "Dieser Benutzer wurde bereits eingeladen."
},
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "Anwenden"
+ },
"sharing.invite-players-modal.avatar-alt": {
"defaultMessage": "Avatar von {username}"
},
- "sharing.invite-players-modal.cancel": {
- "defaultMessage": "Abbrechen"
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "Benutzerdefiniert..."
},
- "sharing.invite-players-modal.cancel-button": {
- "defaultMessage": "Abbrechen"
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "Benutzerdefiniert: {date}"
},
"sharing.invite-players-modal.edit-invite-link": {
"defaultMessage": "Einladungslink bearbeiten."
@@ -5132,6 +5408,24 @@
"sharing.invite-players-modal.edit-invite-link-title": {
"defaultMessage": "Einladungslink bearbeiten"
},
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "In 1 Tag"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "In 1 Stunde"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "In 7 Tagen"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "In 6 Stunden"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "In 3 Tagen"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "In 12 Stunden"
+ },
"sharing.invite-players-modal.expiry-label": {
"defaultMessage": "Ablaufdatum"
},
@@ -5937,3 +6231,4 @@
"defaultMessage": "Typ"
}
}
+
diff --git a/packages/ui/src/locales/en-US/index.json b/packages/ui/src/locales/en-US/index.json
index e1c3941001..6e96468878 100644
--- a/packages/ui/src/locales/en-US/index.json
+++ b/packages/ui/src/locales/en-US/index.json
@@ -507,7 +507,7 @@
"defaultMessage": "{count} removed (disabled)"
},
"content.diff-modal.reviewed-files": {
- "defaultMessage": "A file is only reviewed if it’s published to Modrinth, regardless of its file format (including .mrpack)."
+ "defaultMessage": "Files that aren't published to Modrinth aren't reviewed."
},
"content.diff-modal.unknown-content-body": {
"defaultMessage": "Some content on your server could not be analyzed and may be affected by this change."
@@ -1304,9 +1304,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "File saved"
},
- "files.editor.find-close": {
- "defaultMessage": "Close"
- },
"files.editor.find-in-file": {
"defaultMessage": "Find"
},
@@ -2900,9 +2897,6 @@
"profile.button.create-project": {
"defaultMessage": "Create a project"
},
- "profile.button.edit-role": {
- "defaultMessage": "Edit role"
- },
"profile.button.info": {
"defaultMessage": "View user details"
},
@@ -2921,6 +2915,15 @@
"profile.collection.projects-count": {
"defaultMessage": "{count, plural, one {# project} other {# projects}}"
},
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "Allow pop-ups for Modrinth, then try again."
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "The GitHub profile could not be retrieved. Please try again."
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "Unable to open GitHub profile"
+ },
"profile.details.label.auth-providers": {
"defaultMessage": "Auth providers"
},
@@ -2933,9 +2936,15 @@
"profile.details.label.has-totp": {
"defaultMessage": "Has TOTP"
},
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "Loading..."
+ },
"profile.details.label.payment-methods": {
"defaultMessage": "Payment methods"
},
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "View profile"
+ },
"profile.details.title": {
"defaultMessage": "User details"
},
@@ -2984,24 +2993,12 @@
"profile.label.project-count": {
"defaultMessage": "{count, plural, one {project} other {projects}}"
},
- "profile.label.saving": {
- "defaultMessage": "Saving..."
- },
"profile.official-account": {
"defaultMessage": "Official Modrinth account"
},
"profile.official-account.bio": {
"defaultMessage": "The official user account of Modrinth. Get support at or via email at "
},
- "profile.role.select-placeholder": {
- "defaultMessage": "Select a role"
- },
- "profile.role.update-error-description": {
- "defaultMessage": "An error occurred while updating the user role. Please try again."
- },
- "profile.role.update-error-title": {
- "defaultMessage": "Failed to update role"
- },
"profile.unblock-user.error-description": {
"defaultMessage": "An error occurred while unblocking this user. Please try again."
},
@@ -5399,12 +5396,6 @@
"sharing.invite-players-modal.avatar-alt": {
"defaultMessage": "{username}'s avatar"
},
- "sharing.invite-players-modal.cancel": {
- "defaultMessage": "Cancel"
- },
- "sharing.invite-players-modal.cancel-button": {
- "defaultMessage": "Cancel"
- },
"sharing.invite-players-modal.custom-expiry": {
"defaultMessage": "Custom..."
},
@@ -6048,7 +6039,7 @@
"defaultMessage": "Unknown files warning"
},
"unknown-file-warning-modal.reviewed-files": {
- "defaultMessage": "A file is only reviewed if it’s published to Modrinth, regardless of its file format (including .mrpack)."
+ "defaultMessage": "Files that aren't published to Modrinth aren't reviewed."
},
"unknown-file-warning-modal.unrecognized-files": {
"defaultMessage": "Unrecognized files"
diff --git a/packages/ui/src/locales/es-419/index.json b/packages/ui/src/locales/es-419/index.json
index 700b0fd3dd..626f547ae2 100644
--- a/packages/ui/src/locales/es-419/index.json
+++ b/packages/ui/src/locales/es-419/index.json
@@ -39,7 +39,7 @@
"defaultMessage": "Error al cargar la configuración del servidor"
},
"badge.alpha": {
- "defaultMessage": "Alpha"
+ "defaultMessage": "Alfa"
},
"badge.beta": {
"defaultMessage": "Beta"
@@ -377,6 +377,9 @@
"content.confirm-deletion.header": {
"defaultMessage": "Eliminar {itemType}"
},
+ "content.confirm-disable.header": {
+ "defaultMessage": "Desactivar {itemType}"
+ },
"content.confirm-modpack-update.admonition-body": {
"defaultMessage": "{action, select, downgrade {Bajar de versión} other {Actualizar}} puede causar problemas de compatibilidad. Los mods o contenido que agregaste sobre el modpack se mantendrán, pero podrían no ser compatibles con la nueva versión."
},
@@ -446,33 +449,63 @@
"content.diff-modal.added-count": {
"defaultMessage": "{count} añadido"
},
+ "content.diff-modal.config-files-updated": {
+ "defaultMessage": "Archivos de configuración cambiados"
+ },
"content.diff-modal.diff-type.added": {
- "defaultMessage": "Añadido (dependencia)"
+ "defaultMessage": "Se añadió (dependencia)"
},
"content.diff-modal.diff-type.removed": {
- "defaultMessage": "Desactivado"
+ "defaultMessage": "Se desactivó"
+ },
+ "content.diff-modal.diff-type.removed-disabled": {
+ "defaultMessage": "Se eliminó (desactivado)"
},
"content.diff-modal.diff-type.updated": {
- "defaultMessage": "Actualizado"
+ "defaultMessage": "Se actualizó"
},
"content.diff-modal.dont-install": {
"defaultMessage": "No instalar"
},
"content.diff-modal.external-diff-type.added": {
- "defaultMessage": "Agregado"
+ "defaultMessage": "Se añadió"
},
"content.diff-modal.external-diff-type.removed": {
- "defaultMessage": "Eliminado"
+ "defaultMessage": "Se eliminó"
},
"content.diff-modal.external-diff-type.updated": {
- "defaultMessage": "Actualizado"
+ "defaultMessage": "Se actualizó"
+ },
+ "content.diff-modal.file-count": {
+ "defaultMessage": "{count, plural, one {# archivo} other {# archivos}}"
+ },
+ "content.diff-modal.game-version-updated": {
+ "defaultMessage": "Versión del juego"
},
"content.diff-modal.install-anyway": {
"defaultMessage": "Instalar de todos modos"
},
+ "content.diff-modal.loader-updated": {
+ "defaultMessage": "Loader"
+ },
+ "content.diff-modal.modpack-linked": {
+ "defaultMessage": "Modpack vinculado"
+ },
+ "content.diff-modal.modpack-unlinked": {
+ "defaultMessage": "Modpack desvinculado"
+ },
+ "content.diff-modal.modpack-updated": {
+ "defaultMessage": "Modpack actualizado"
+ },
+ "content.diff-modal.no-content-changes": {
+ "defaultMessage": "Sin cambios al contenido"
+ },
"content.diff-modal.removed-count": {
"defaultMessage": "{count} eliminados"
},
+ "content.diff-modal.removed-disabled-count": {
+ "defaultMessage": "{count} eliminados (desactivados)"
+ },
"content.diff-modal.reviewed-files": {
"defaultMessage": "Un archivo solo se revisa si se publica en Modrinth, sin importar su formato (incluido el .mrpack)."
},
@@ -533,6 +566,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "mundo"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "Ajustes de instalación"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "Contenido adicional"
},
@@ -585,7 +621,7 @@
"defaultMessage": "Nombres de los proyectos"
},
"content.page-layout.sort.alphabetical": {
- "defaultMessage": "Allfabético"
+ "defaultMessage": "Alfabético"
},
"content.page-layout.sort.date-added-newest": {
"defaultMessage": "Más recientes primero"
@@ -921,7 +957,7 @@
"defaultMessage": "Configurar servidor"
},
"external-files.permissions-card.add-files-modal.confirm": {
- "defaultMessage": "{count, plural, one {Agregar archivo} other {Agregar archivos}}"
+ "defaultMessage": "{count, plural, one {Añadir archivo} other {Añadir archivos}}"
},
"external-files.permissions-card.add-files-modal.description": {
"defaultMessage": "Selecciona cualquier archivo que deba ser movido a este grupo."
@@ -930,7 +966,7 @@
"defaultMessage": "No hay archivos en otros grupos que se puedan mover aquí."
},
"external-files.permissions-card.add-files-modal.load-error.title": {
- "defaultMessage": "No se pudieron cargar los archivos."
+ "defaultMessage": "No se pudieron cargar los archivos"
},
"external-files.permissions-card.add-files-modal.no-search-results": {
"defaultMessage": "No hay archivos que coincidan con tu búsqueda."
@@ -945,10 +981,10 @@
"defaultMessage": "Añadir archivos a este grupo"
},
"external-files.permissions-card.add-files-to-group": {
- "defaultMessage": "Agregar archivos..."
+ "defaultMessage": "Añadir archivos..."
},
"external-files.permissions-card.assign-files-error.title": {
- "defaultMessage": "No se pudieron agregar los archivos"
+ "defaultMessage": "No se pudieron añadir los archivos"
},
"external-files.permissions-card.attribution.moderation-status.content-not-allowed": {
"defaultMessage": "Contenido no permitido"
@@ -1077,7 +1113,7 @@
"defaultMessage": "Grupo de atribución {id}"
},
"external-files.permissions-card.file-count": {
- "defaultMessage": "{count, plural, one {Agregar archivo} other {Agregar archivos}}"
+ "defaultMessage": "{count, plural, one {Añadir archivo} other {Añadir archivos}}"
},
"external-files.permissions-card.included-files": {
"defaultMessage": "Archivos incluidos:"
@@ -1101,7 +1137,7 @@
"defaultMessage": "Motivo"
},
"external-files.permissions-card.moderation.error.title": {
- "defaultMessage": "No se pudo guardar la revisión de moderación."
+ "defaultMessage": "No se pudo guardar la revisión de moderación"
},
"external-files.permissions-card.not-used-in-versions": {
"defaultMessage": "Estos archivos no están siendo utilizados actualmente por ninguna versión."
@@ -1160,6 +1196,21 @@
"external-files.permissions-card.reason.special-permission.description": {
"defaultMessage": "Has obtenido permiso especial para redistribuir este trabajo en tu modpack."
},
+ "external-files.permissions-card.remove-group": {
+ "defaultMessage": "Borrar grupo"
+ },
+ "external-files.permissions-card.remove-group-confirmation.description": {
+ "defaultMessage": "Esto eliminará permanentemente este grupo de atribución y todos los archivos dentro. Esta acción no se puede deshacer."
+ },
+ "external-files.permissions-card.remove-group-confirmation.title": {
+ "defaultMessage": "¿Borrar {title}?"
+ },
+ "external-files.permissions-card.remove-group-error.title": {
+ "defaultMessage": "No se pudo borrar el grupo"
+ },
+ "external-files.permissions-card.remove-group-shift-hint": {
+ "defaultMessage": "Mantén Shift al hacer clic para saltar la confirmación."
+ },
"external-files.permissions-card.split-file": {
"defaultMessage": "Eliminar del grupo"
},
@@ -1253,9 +1304,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Archivo guardado"
},
- "files.editor.find-close": {
- "defaultMessage": "Cerrar"
- },
"files.editor.find-in-file": {
"defaultMessage": "Buscar"
},
@@ -1899,7 +1947,7 @@
"defaultMessage": "Reinstalando modpack"
},
"installation-settings.removed-incompatible": {
- "defaultMessage": "Eliminado (incompatible)"
+ "defaultMessage": "Se eliminó (incompatible)"
},
"installation-settings.repair.instance-description": {
"defaultMessage": "Reinstala las dependencias de Minecraft y verifica si hay archivos corruptos. Esto puede solucionar problemas si tu juego no se inicia debido a errores relacionados con el launcher."
@@ -2039,6 +2087,12 @@
"instances.modpack-content-modal.empty-title": {
"defaultMessage": "No se encontró contenido"
},
+ "instances.modpack-content-modal.external-content": {
+ "defaultMessage": "Externo"
+ },
+ "instances.modpack-content-modal.external-content-description": {
+ "defaultMessage": "Este archivo no está publicado en Modrinth."
+ },
"instances.modpack-content-modal.header": {
"defaultMessage": "Contenido del modpack"
},
@@ -2048,6 +2102,9 @@
"instances.modpack-content-modal.no-results": {
"defaultMessage": "Ningún proyecto coincide con tu búsqueda."
},
+ "instances.modpack-content-modal.open-in-slicer": {
+ "defaultMessage": "Abrir en Slicer"
+ },
"instances.modpack-content-modal.search-placeholder": {
"defaultMessage": "Buscar en {count, number} {count, plural, one {proyecto} other {proyectos}}"
},
@@ -2183,6 +2240,9 @@
"label.details": {
"defaultMessage": "Detalles"
},
+ "label.discover-content": {
+ "defaultMessage": "Descubrir contenido"
+ },
"label.done": {
"defaultMessage": "Listo"
},
@@ -2261,6 +2321,9 @@
"label.password": {
"defaultMessage": "Contraseña"
},
+ "label.permissions": {
+ "defaultMessage": "Permisos"
+ },
"label.plan-custom": {
"defaultMessage": "Personalizado"
},
@@ -2616,7 +2679,7 @@
"defaultMessage": "URL del video de YouTube"
},
"modal.add-payment-method.action": {
- "defaultMessage": "Agregar método de pago"
+ "defaultMessage": "Añadir método de pago"
},
"modal.add-payment-method.title": {
"defaultMessage": "Añadiendo método de pago"
@@ -2792,9 +2855,162 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Un creador de Modrinth."
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Un usuario de Modrinth."
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} no podrá enviarte solicitudes de amistad, invitarte a instancias compartidas o invitarte a servidores de Modrinth Hosting."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "¿Estás seguro de que quieres bloquear a este usuario?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "Ocurrió un error al bloquear a este usuario. Por favor inténtalo otra vez."
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "Error al bloquear usuario"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "Bloqueaste a {username}."
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Usuario bloqueado"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "Bloquear a {username}"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Ver analíticas del usuario"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "Gestionar facturación del usuario"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Bloquear"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "Crear una colección"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "Crear un proyecto"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Ver detalles del usuario"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "Gestionar proyectos"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "Remover como afiliado"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "Configurar como afiliado"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Desbloquear"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural, one {# proyecto} other {# proyectos}}"
+ },
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "Permite las ventanas emergentes para Modrinth, y luego vuelve a intentarlo."
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "Este perfil de GitHub no pudo ser cargado. Por favor inténtalo otra vez."
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "Error al abrir el perfil de GitHub"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "Proveedores de autenticación"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "Correo verificado"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "Tiene contraseña"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "Tiene TOTP"
+ },
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "Cargando..."
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "Métodos de pago"
+ },
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "Ver perfil"
+ },
+ "profile.details.title": {
+ "defaultMessage": "Detalles de usuario"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "Correo sin verificar"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "Correo verificado"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "Este perfil de usuario no se pudo cargar."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "Usuario no encontrado"
+ },
+ "profile.label.affiliate": {
+ "defaultMessage": "Afiliado"
+ },
"profile.label.badges": {
"defaultMessage": "Insignias"
},
+ "profile.label.collection": {
+ "defaultMessage": "Colección"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, one {descarga} other {descargas}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "Se unió"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "¡Este usuario no tiene colecciones!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "Todavía no tienes ninguna colección."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "¡Este usuario no tiene proyectos!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "Todavía no tienes ningún proyecto."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "Organizaciones"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural, one {proyecto} other {proyectos}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Cuenta oficial de Modrinth"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "La cuenta oficial de Modrinth. Consigue ayuda en o escríbenos por correo electrónico: "
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "Ocurrió un error al desbloquear a este usuario. Por favor inténtalo otra vez."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "Error al desbloquear usuario"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "Desbloqueaste a {username}."
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "Usuario desbloqueado"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "Publicado el {date}"
},
@@ -2810,12 +3026,21 @@
"project-card.environment.client-or-server": {
"defaultMessage": "Cliente o servidor"
},
+ "project-card.environment.dedicated-server": {
+ "defaultMessage": "Servidor dedicado"
+ },
"project-card.environment.server": {
"defaultMessage": "Servidor"
},
+ "project-card.environment.singleplayer": {
+ "defaultMessage": "Un solo jugador"
+ },
"project-type.all": {
"defaultMessage": "Todo"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "Colecciones"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, one {Data Pack} other {Data Packs}}"
},
@@ -2943,7 +3168,7 @@
"defaultMessage": "Enviado {date}"
},
"project.about.details.updated": {
- "defaultMessage": "Actualizado {date}"
+ "defaultMessage": "Actualizado el {date}"
},
"project.about.links.discord": {
"defaultMessage": "Únete al servidor de Discord"
@@ -3086,6 +3311,15 @@
"project.follower-count-tooltip": {
"defaultMessage": "{count, number} {count, plural, one {seguidor} other {seguidores}}"
},
+ "project.license.error": {
+ "defaultMessage": "No se pudo conseguir el texto de la licencia."
+ },
+ "project.license.loading": {
+ "defaultMessage": "Cargando el texto de la licencia..."
+ },
+ "project.license.title": {
+ "defaultMessage": "Licencia"
+ },
"project.online-player-count": {
"defaultMessage": "{count, number} en línea"
},
@@ -3491,6 +3725,12 @@
"project.settings.view.title": {
"defaultMessage": "Ver"
},
+ "project.stats.downloads-label": {
+ "defaultMessage": "{count, plural, one {descarga} other {descargas}}"
+ },
+ "project.stats.followers-label": {
+ "defaultMessage": "{count, plural, one {seguidor} other {seguidores}}"
+ },
"project.versions.channel.alpha.symbol": {
"defaultMessage": "A"
},
@@ -5022,14 +5262,221 @@
"defaultMessage": "Idioma"
},
"settings.language.warning": {
- "defaultMessage": "Cambiar el idioma de {platform} podría provocar que parte del contenido aparezca en inglés si no hay una traducción disponible. {platform} Aún no está completamente traducida, por lo que parte del contenido podría permanecer en inglés en ciertos idiomas."
+ "defaultMessage": "Cambiar el idioma de la {platform} podría provocar que parte del contenido aparezca en inglés si no hay una traducción disponible. La {platform} aún no está completamente traducida, por lo que parte del contenido podría permanecer en inglés en ciertos idiomas."
},
"settings.pats.title": {
"defaultMessage": "Tokens de acceso personal"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "Una descripción corta que le cuente a todos un poquito sobre tí."
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "Biografía"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "Perfil"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "Foto de perfil"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "La información de tu perfil es visible públicamente en Modrinth y también a través de la Modrinth API ."
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "Error al actualizar perfil"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "Ocurrió un error al actualizar tu perfil. Por favor inténtalo otra vez."
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "Regístrate con una cuenta Modrinth para personalizar tu perfil."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Cuenta Modrinth requerida"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "Un nombre único, sin distinción de mayúsculas y minúsculas, para identificar tu perfil."
+ },
"settings.sessions.title": {
"defaultMessage": "Sesiones"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "Acciones"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Usuario"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Estos son los usuarios que has bloqueado en Modrinth. Ellos no pueden:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "No has bloqueado a nadie."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "No se pudo cargar los usuarios bloqueados."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "Cargando usuarios bloqueados…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "Enviarte solicitudes de amistad"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "Invitarte a gestionar un servidor de Modrinth Hosting."
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "Invitarte a instancias compartidas"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "Usuarios bloqueados"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "Desbloquear"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "Error al desbloquear usuario"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "Ocurrió un error al desbloquear a este usuario. Por favor inténtalo otra vez."
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "Desbloquear a {username}"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "Avatar de {username}"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "Controla quién puede enviarte solicitudes de amistad en Modrinth."
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "Solicitudes de amistad"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "¡Próximamente!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "Todos"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "Amigos"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "Amigos de amigos"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "Nadie"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "Controla quién te puede enviar invitaciones a instancias compartidas y paneles de Modrinth Hosting."
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "Invitaciones"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "Puedes controlar quién puede interactuar contigo, y gestionar los usuarios bloqueados con una Cuenta Modrinth"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Cuenta Modrinth requerida"
+ },
+ "settings.social.title": {
+ "defaultMessage": "Social"
+ },
+ "sharing.invite-players-modal.add": {
+ "defaultMessage": "Añadir"
+ },
+ "sharing.invite-players-modal.added": {
+ "defaultMessage": "Añadido"
+ },
+ "sharing.invite-players-modal.already-invited": {
+ "defaultMessage": "Este usuario ya fue invitado."
+ },
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "Aplicar"
+ },
+ "sharing.invite-players-modal.avatar-alt": {
+ "defaultMessage": "Avatar de {username}"
+ },
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "Otro..."
+ },
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "Otro: {date}"
+ },
+ "sharing.invite-players-modal.edit-invite-link": {
+ "defaultMessage": "Editar link de invitación."
+ },
+ "sharing.invite-players-modal.edit-invite-link-title": {
+ "defaultMessage": "Editar link de invitación"
+ },
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "En 1 día"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "En 1 hora"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "En 7 días"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "En 6 horas"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "En 3 días"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "En 12 horas"
+ },
+ "sharing.invite-players-modal.expiry-label": {
+ "defaultMessage": "Fecha de expiración"
+ },
+ "sharing.invite-players-modal.friends-heading": {
+ "defaultMessage": "Tus amigos - {count}"
+ },
+ "sharing.invite-players-modal.invite": {
+ "defaultMessage": "Invitar"
+ },
+ "sharing.invite-players-modal.invite-expiry-description": {
+ "defaultMessage": "Tu link de invitación expira en {duration}."
+ },
+ "sharing.invite-players-modal.invite-link-heading": {
+ "defaultMessage": "O usa un link de invitación"
+ },
+ "sharing.invite-players-modal.link-copied-text": {
+ "defaultMessage": "El link de invitación fue copiado a tu portapapeles."
+ },
+ "sharing.invite-players-modal.link-copied-title": {
+ "defaultMessage": "Link copiado"
+ },
+ "sharing.invite-players-modal.link-copy-failed-title": {
+ "defaultMessage": "Error al copiar link"
+ },
+ "sharing.invite-players-modal.max-uses-label": {
+ "defaultMessage": "Usos máximos"
+ },
+ "sharing.invite-players-modal.no-friends": {
+ "defaultMessage": "No tienes amigos."
+ },
+ "sharing.invite-players-modal.no-search-results": {
+ "defaultMessage": "No se encontró ningún usuario coincidente."
+ },
+ "sharing.invite-players-modal.requested": {
+ "defaultMessage": "Solicitud enviada"
+ },
+ "sharing.invite-players-modal.requested-tooltip": {
+ "defaultMessage": "{username} debe aceptar tu solicitud de amistad primero"
+ },
+ "sharing.invite-players-modal.save-button": {
+ "defaultMessage": "Guardar"
+ },
+ "sharing.invite-players-modal.search-placeholder": {
+ "defaultMessage": "Introduce el nombre de usuario de Modrinth"
+ },
+ "sharing.invite-players-modal.searching": {
+ "defaultMessage": "Buscando..."
+ },
+ "sharing.invite-players-modal.update-invite-link-failed-title": {
+ "defaultMessage": "Error al actualizar link de invitación"
+ },
"tag.category.128x": {
"defaultMessage": "128x"
},
@@ -5181,7 +5628,7 @@
"defaultMessage": "Kit PvP"
},
"tag.category.library": {
- "defaultMessage": "Librería"
+ "defaultMessage": "Biblioteca"
},
"tag.category.lifesteal": {
"defaultMessage": "Lifesteal"
@@ -5445,7 +5892,7 @@
"defaultMessage": "Sponge"
},
"tag.loader.vanilla": {
- "defaultMessage": "Shader vanilla"
+ "defaultMessage": "Shader Vanilla"
},
"tag.loader.velocity": {
"defaultMessage": "Velocity"
@@ -5784,3 +6231,4 @@
"defaultMessage": "Tipo"
}
}
+
diff --git a/packages/ui/src/locales/es-ES/index.json b/packages/ui/src/locales/es-ES/index.json
index bfeabbbb50..fab7c1f684 100644
--- a/packages/ui/src/locales/es-ES/index.json
+++ b/packages/ui/src/locales/es-ES/index.json
@@ -221,6 +221,9 @@
"button.open-folder": {
"defaultMessage": "Abrir carpeta"
},
+ "button.open-in-browser": {
+ "defaultMessage": "Abrir en el navegador"
+ },
"button.open-in-folder": {
"defaultMessage": "Abrir en carpeta"
},
@@ -236,6 +239,9 @@
"button.reinstall-modpack": {
"defaultMessage": "Reinstalar modpack"
},
+ "button.remove": {
+ "defaultMessage": "Eliminar"
+ },
"button.remove-image": {
"defaultMessage": "Eliminar imagen"
},
@@ -287,6 +293,9 @@
"button.stop": {
"defaultMessage": "Detener"
},
+ "button.switch-to-version": {
+ "defaultMessage": "Cambiar a la versión"
+ },
"button.switch-version": {
"defaultMessage": "Cambiar versión"
},
@@ -314,6 +323,21 @@
"changelog.product.web": {
"defaultMessage": "Plataforma"
},
+ "collection-widget.empty-collection": {
+ "defaultMessage": "Esta colección está vacía."
+ },
+ "collection-widget.loading-projects": {
+ "defaultMessage": "Cargando proyectos..."
+ },
+ "collection-widget.no-search-results": {
+ "defaultMessage": "No proyectos coinciden con tu búsqueda."
+ },
+ "collection-widget.project-count": {
+ "defaultMessage": "{count, plural, one {# proyecto} other {# proyectos}}"
+ },
+ "collection-widget.search-placeholder": {
+ "defaultMessage": "Buscar proyectos"
+ },
"collections.label.private": {
"defaultMessage": "Privado"
},
@@ -353,6 +377,9 @@
"content.confirm-deletion.header": {
"defaultMessage": "Borrar {itemType}"
},
+ "content.confirm-disable.header": {
+ "defaultMessage": "Desactivar {itemType}"
+ },
"content.confirm-modpack-update.admonition-body": {
"defaultMessage": "{action, select,downgrade {Bajar de versión} other {Actualizar}} puede causar problemas de compatibilidad. Mods o contenido que tu has añandido encima del modpack se quedara, pero no podria ser compatible con la nueva version."
},
@@ -422,21 +449,78 @@
"content.diff-modal.added-count": {
"defaultMessage": "{count} añadido/s"
},
+ "content.diff-modal.config-files-updated": {
+ "defaultMessage": "Archivos de configuración modificados"
+ },
"content.diff-modal.diff-type.added": {
"defaultMessage": "Añadido (dependencia)"
},
"content.diff-modal.diff-type.removed": {
"defaultMessage": "Desactivado"
},
+ "content.diff-modal.diff-type.removed-disabled": {
+ "defaultMessage": "Removido (desactivado)"
+ },
"content.diff-modal.diff-type.updated": {
"defaultMessage": "Actualizado"
},
+ "content.diff-modal.dont-install": {
+ "defaultMessage": "No instalar"
+ },
+ "content.diff-modal.external-diff-type.added": {
+ "defaultMessage": "Añadido"
+ },
+ "content.diff-modal.external-diff-type.removed": {
+ "defaultMessage": "Eliminado"
+ },
+ "content.diff-modal.external-diff-type.updated": {
+ "defaultMessage": "Actualizado"
+ },
+ "content.diff-modal.file-count": {
+ "defaultMessage": "{count, plural, one {# archivo} other {# archivos}}"
+ },
+ "content.diff-modal.game-version-updated": {
+ "defaultMessage": "Versión del juego"
+ },
+ "content.diff-modal.install-anyway": {
+ "defaultMessage": "Instalar de todas formas"
+ },
+ "content.diff-modal.loader-updated": {
+ "defaultMessage": "Cargador"
+ },
+ "content.diff-modal.modpack-linked": {
+ "defaultMessage": "Modpack vinculado"
+ },
+ "content.diff-modal.modpack-unlinked": {
+ "defaultMessage": "Modpack desvinculado"
+ },
+ "content.diff-modal.modpack-updated": {
+ "defaultMessage": "Modpack actualizado"
+ },
+ "content.diff-modal.no-content-changes": {
+ "defaultMessage": "No hay cambios en el contenido"
+ },
"content.diff-modal.removed-count": {
"defaultMessage": "{count} eliminado"
},
+ "content.diff-modal.removed-disabled-count": {
+ "defaultMessage": "{count} removido (desactivado)"
+ },
+ "content.diff-modal.reviewed-files": {
+ "defaultMessage": "Un archivo es revisado si es que está publicado en Modrinth, sin imputar su formato de archivo (Incluyendo .mrpack)."
+ },
"content.diff-modal.unknown-content-body": {
"defaultMessage": "No se ha podido analizar parte del contenido de su servidor, por lo que podría verse afectado por este cambio."
},
+ "content.diff-modal.unknown-files-description": {
+ "defaultMessage": "Esta actualización contiene archivos que no están publicados en Modrinth. Te recomendamos instalar archivos de fuentes de confianza."
+ },
+ "content.diff-modal.unknown-files-warning": {
+ "defaultMessage": "Advertencia de archivos desconocidos"
+ },
+ "content.diff-modal.unknown-project": {
+ "defaultMessage": "Desconocido"
+ },
"content.diff-modal.updated-count": {
"defaultMessage": "{count} actualizado/s"
},
@@ -482,6 +566,9 @@
"content.inline-backup.world-label": {
"defaultMessage": " mundo"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "Configuración de la instalación"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "Contenido adicional"
},
@@ -560,24 +647,36 @@
"content.selection-bar.bulk.deleting": {
"defaultMessage": "Eliminando {progress}/{total} {contentType}..."
},
+ "content.selection-bar.bulk.deleting-count": {
+ "defaultMessage": "Eliminando {count, number} {contentType}"
+ },
"content.selection-bar.bulk.deleting-waiting": {
"defaultMessage": "Eliminando {contentType}..."
},
"content.selection-bar.bulk.disabling": {
"defaultMessage": "Desactivando {progress}/{total} {contentType}..."
},
+ "content.selection-bar.bulk.disabling-count": {
+ "defaultMessage": "Desactivando {count, number} {contentType}"
+ },
"content.selection-bar.bulk.disabling-waiting": {
"defaultMessage": "Desactivando {contentType}..."
},
"content.selection-bar.bulk.enabling": {
"defaultMessage": "Activando {progress}/{total} {contentType}..."
},
+ "content.selection-bar.bulk.enabling-count": {
+ "defaultMessage": "Activando {count, number} {contentType}"
+ },
"content.selection-bar.bulk.enabling-waiting": {
"defaultMessage": "Activando {contentType}..."
},
"content.selection-bar.bulk.updating": {
"defaultMessage": "Actualizando {progress}/{total} {contentType}..."
},
+ "content.selection-bar.bulk.updating-count": {
+ "defaultMessage": "Actualizando {count, number} {contentType}"
+ },
"content.selection-bar.bulk.updating-waiting": {
"defaultMessage": "Actualizando {contentType}..."
},
@@ -872,6 +971,9 @@
"external-files.permissions-card.add-files-modal.no-search-results": {
"defaultMessage": "No hay archivos que coincidan con tu búsqueda."
},
+ "external-files.permissions-card.add-files-modal.search-placeholder": {
+ "defaultMessage": "Buscar archivos..."
+ },
"external-files.permissions-card.add-files-modal.selected-count": {
"defaultMessage": "{count, plural, one {# archivo seleccionado} other {# archivos seleccionados}}"
},
@@ -1094,6 +1196,21 @@
"external-files.permissions-card.reason.special-permission.description": {
"defaultMessage": "Has obtenido permiso especial para redistribuir este trabajo en tu modpack."
},
+ "external-files.permissions-card.remove-group": {
+ "defaultMessage": "Eliminar grupo"
+ },
+ "external-files.permissions-card.remove-group-confirmation.description": {
+ "defaultMessage": "Esto elimina permanentemente el grupo de atribución y todos los archivos dentro de ellos. Esta ación no se puede deshacer."
+ },
+ "external-files.permissions-card.remove-group-confirmation.title": {
+ "defaultMessage": "¿Borrar {title}?"
+ },
+ "external-files.permissions-card.remove-group-error.title": {
+ "defaultMessage": "No se pudo eliminar el grupo"
+ },
+ "external-files.permissions-card.remove-group-shift-hint": {
+ "defaultMessage": "Mantén pulsada el Shift mientras haces clic para omitir la confirmación."
+ },
"external-files.permissions-card.split-file": {
"defaultMessage": "Eliminar del grupo"
},
@@ -1187,9 +1304,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Archivo guardado"
},
- "files.editor.find-close": {
- "defaultMessage": "Cerrar"
- },
"files.editor.find-in-file": {
"defaultMessage": "Encontrar"
},
@@ -1379,6 +1493,9 @@
"files.row.item-count": {
"defaultMessage": "{count, plural, one {# elemento} other {# elementos}}"
},
+ "files.row.parent-folder": {
+ "defaultMessage": "Carpeta principal"
+ },
"files.table-header.created": {
"defaultMessage": "Creado"
},
@@ -1970,6 +2087,12 @@
"instances.modpack-content-modal.empty-title": {
"defaultMessage": "No se ha encontrado contenido"
},
+ "instances.modpack-content-modal.external-content": {
+ "defaultMessage": "Externo"
+ },
+ "instances.modpack-content-modal.external-content-description": {
+ "defaultMessage": "Este archivo no está publicado en Modrinth."
+ },
"instances.modpack-content-modal.header": {
"defaultMessage": "Contenido del modpack"
},
@@ -1979,6 +2102,9 @@
"instances.modpack-content-modal.no-results": {
"defaultMessage": "No hay proyectos que coincidan con tu búsqueda."
},
+ "instances.modpack-content-modal.open-in-slicer": {
+ "defaultMessage": "Abrir en Slicer"
+ },
"instances.modpack-content-modal.search-placeholder": {
"defaultMessage": "Buscar {count, number} {count, plural, one {proyecto} other {proyectos}}"
},
@@ -2111,6 +2237,9 @@
"label.details": {
"defaultMessage": "Detalles"
},
+ "label.discover-content": {
+ "defaultMessage": "Descubrir contenido"
+ },
"label.done": {
"defaultMessage": "Hecho"
},
@@ -2141,6 +2270,9 @@
"label.game-version": {
"defaultMessage": "Versión del juego"
},
+ "label.hide-installed-content": {
+ "defaultMessage": "Esconder contenido ya instalado"
+ },
"label.hide-selected-content": {
"defaultMessage": "Ocultar contenido seleccionado"
},
@@ -2186,6 +2318,9 @@
"label.password": {
"defaultMessage": "Contraseña"
},
+ "label.permissions": {
+ "defaultMessage": "Permisos"
+ },
"label.plan-custom": {
"defaultMessage": "Personalizado"
},
@@ -2243,6 +2378,9 @@
"label.server": {
"defaultMessage": "Servidor"
},
+ "label.server-only": {
+ "defaultMessage": "Solo servidor"
+ },
"label.servers": {
"defaultMessage": "Servidores"
},
@@ -2714,9 +2852,162 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Creador en Modrinth."
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Usuario de Modrinth."
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} no podrá enviarte solicitudes de amistad, invitarte a instancias compartidas o invítate a Servers en Modrinth."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "¿Estás seguro de que deseas bloquear este usuario?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "Ocurrió un error al bloquear este usuario: Por favor intenta de nuevo."
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "No se pudo bloquear el usuario"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} fue bloqueado."
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Usuario bloqueado"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "Bloquear {username}"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Ver analíticas del usuario"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "Gestionar la facturación de los usuarios"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Bloquear"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "Crear una colección"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "Crear un proyecto"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Ver detalles del usuario"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "Gestionar proyectos"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "Borrar como afiliado"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "Poner como afiliado"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Desbloquear"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural, one {# proyecto} other {# proyectos}}"
+ },
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "Permite las ventanas emergentes para Modrinth e inténtalo de nuevo."
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "No se pudo mostrar el perfil de GitHub. Por favor intenta de nuevo."
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "No se pudo abrir el perfil de GitHub"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "Proveedores de autenticación"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "Correo verificado"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "Tiene contraseña"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "Tiene TOTP"
+ },
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "Cargando..."
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "Métodos de pago"
+ },
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "Ver perfil"
+ },
+ "profile.details.title": {
+ "defaultMessage": "Detalles de usuario"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "Correo no verificado"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "Correo verificado"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "El perfil del usuario no pudo cargar."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "Usuario no encontrado"
+ },
+ "profile.label.affiliate": {
+ "defaultMessage": "Afiliado"
+ },
"profile.label.badges": {
"defaultMessage": "Medallas"
},
+ "profile.label.collection": {
+ "defaultMessage": "Colección"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, one {descarga} other {descargas}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "Se unió hace"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "¡Este usuario no tiene colecciones!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "No tienes una colección aun."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "¡Este usuario no tiene proyectos!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "No tienes ningún proyecto aun."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "Organizaciones"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural, one {proyecto} other {proyectos}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Cuenta oficial de Modrinth"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "Cuenta oficial de Modrinth. Obtén soporte en o vía correo a "
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "Ocurrió un error al desbloquear este usuario. Por favor intenta de nuevo."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "No se pudo desbloquear el usuario"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "{username} fue desbloqueado."
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "Usuario desbloqueado"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "Publicado el {date}"
},
@@ -2732,12 +3023,21 @@
"project-card.environment.client-or-server": {
"defaultMessage": "Cliente o servidor"
},
+ "project-card.environment.dedicated-server": {
+ "defaultMessage": "Servidor dedicado"
+ },
"project-card.environment.server": {
"defaultMessage": "Servidor"
},
+ "project-card.environment.singleplayer": {
+ "defaultMessage": "Un jugador"
+ },
"project-type.all": {
"defaultMessage": "Todos"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "Colecciones"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, one {Paquete de Datos} other {Paquetes de Datos}}"
},
@@ -3008,6 +3308,15 @@
"project.follower-count-tooltip": {
"defaultMessage": "{count, number} {count, plural, one {seguidor} other {seguidores}}"
},
+ "project.license.error": {
+ "defaultMessage": "No se pudo coger el texto de la Licencia."
+ },
+ "project.license.loading": {
+ "defaultMessage": "Cargando texto de la licencia..."
+ },
+ "project.license.title": {
+ "defaultMessage": "Licencia"
+ },
"project.online-player-count": {
"defaultMessage": "{count, number} en línea"
},
@@ -3413,6 +3722,12 @@
"project.settings.view.title": {
"defaultMessage": "Vista"
},
+ "project.stats.downloads-label": {
+ "defaultMessage": "{count, plural, one {descarga} other {descargas}}"
+ },
+ "project.stats.followers-label": {
+ "defaultMessage": "{count, plural, one {seguidor} other {seguidores}}"
+ },
"project.versions.channel.alpha.symbol": {
"defaultMessage": "A"
},
@@ -3422,6 +3737,12 @@
"project.versions.channel.release.symbol": {
"defaultMessage": "R"
},
+ "project.versions.filter.toggle-tooltip": {
+ "defaultMessage": "Alternar filtro para {filter}"
+ },
+ "project.versions.platform.modloader.short": {
+ "defaultMessage": "Cargador de mod"
+ },
"project.versions.version.withheld": {
"defaultMessage": "Retenido"
},
@@ -3506,6 +3827,18 @@
"search.filter.option.show_more": {
"defaultMessage": "Mostrar más"
},
+ "search.filter_type.advanced": {
+ "defaultMessage": "Avanzado"
+ },
+ "search.filter_type.advanced.exclude_datapack": {
+ "defaultMessage": "Excluir paquetes de datos"
+ },
+ "search.filter_type.advanced.exclude_mod": {
+ "defaultMessage": "Excluir mods"
+ },
+ "search.filter_type.advanced.exclude_plugin": {
+ "defaultMessage": "Excluir plugins"
+ },
"search.filter_type.environment": {
"defaultMessage": "Entorno"
},
@@ -4931,9 +5264,216 @@
"settings.pats.title": {
"defaultMessage": "Tokens de acceso personal"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "Una breve descripción para contar a todos sobre ti."
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "Biografía"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "Perfil"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "Foto de perfil"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "La información de tu perfil está visible públicamente en Modrinth y a la Modrinth API ."
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "No se pudo actualizar el perfil"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "Ocurrió un error al actualizar tu perfil. Por favor intenta de nuevo."
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "Inicia sesión con una cuenta de Modrinth para editar tu perfil público."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Cuenta de Modrinth requerida"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "Un nombre que no distingue de mayúsculas o minúsculas para identificar tu perfil."
+ },
"settings.sessions.title": {
"defaultMessage": "Sesiones"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "Acciones"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Usuario"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Estos son los usuarios que bloqueaste en Modrinth. Ellos no pueden:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "No bloqueaste a nadie."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "No se pudo cargar los usuarios bloqueados."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "Cargando usuarios bloqueados…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "Enviar solicitudes de amistad"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "Invitarte a administrar un Servidor en Modrinth."
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "Invitarte a instancias compartidas"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "Usuarios bloqueados"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "Desbloquear"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "No se pudo desbloquear el usuario"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "Ocurrió un error al desbloquear este usuario. por favor intenta de nuevo."
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "Desbloquear {username}"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "Avatar de {username}"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "Controla quien puede enviarte solicitudes de amistad en Modrinth."
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "Solicitudes de amistad"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "¡Próximamente!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "Todos"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "Amigos"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "Amigos de amigos"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "Ninguno"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "Controla quien puede enviarte invitaciones a instancias compartidas y servidores en Modrinth."
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "Invitaciones"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "Puedes controlar quien puede interactuar contigo, y gestionar los usuarios bloqueados con una cuenta de Modrinth"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Cuenta de Modrinth requerida"
+ },
+ "settings.social.title": {
+ "defaultMessage": "Social"
+ },
+ "sharing.invite-players-modal.add": {
+ "defaultMessage": "Añadir"
+ },
+ "sharing.invite-players-modal.added": {
+ "defaultMessage": "Añadido"
+ },
+ "sharing.invite-players-modal.already-invited": {
+ "defaultMessage": "Este usuario ya fue invitado."
+ },
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "Aplicar"
+ },
+ "sharing.invite-players-modal.avatar-alt": {
+ "defaultMessage": "Avatar de {username}"
+ },
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "Personalizado..."
+ },
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "Personalizado: {date}"
+ },
+ "sharing.invite-players-modal.edit-invite-link": {
+ "defaultMessage": "Editar enlace de invitación."
+ },
+ "sharing.invite-players-modal.edit-invite-link-title": {
+ "defaultMessage": "Editar enlace de invitación"
+ },
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "En 1 día"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "En 1 hora"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "En 7 días"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "En 6 horas"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "En 3 días"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "En 12 horas"
+ },
+ "sharing.invite-players-modal.expiry-label": {
+ "defaultMessage": "Día de caducidad"
+ },
+ "sharing.invite-players-modal.friends-heading": {
+ "defaultMessage": "Tus amigos - {count}"
+ },
+ "sharing.invite-players-modal.invite": {
+ "defaultMessage": "Invitar"
+ },
+ "sharing.invite-players-modal.invite-expiry-description": {
+ "defaultMessage": "Tu link de invitación expira en {duration}."
+ },
+ "sharing.invite-players-modal.invite-link-heading": {
+ "defaultMessage": "O usa un link de invitación"
+ },
+ "sharing.invite-players-modal.link-copied-text": {
+ "defaultMessage": "La URL del link de invitación fue copiado al portapapeles."
+ },
+ "sharing.invite-players-modal.link-copied-title": {
+ "defaultMessage": "Link Copiado"
+ },
+ "sharing.invite-players-modal.link-copy-failed-title": {
+ "defaultMessage": "No se pudo copiar el link"
+ },
+ "sharing.invite-players-modal.max-uses-label": {
+ "defaultMessage": "Usos máximos"
+ },
+ "sharing.invite-players-modal.no-friends": {
+ "defaultMessage": "No tienes amigos."
+ },
+ "sharing.invite-players-modal.no-search-results": {
+ "defaultMessage": "No se encontraron usuarios coincidentes."
+ },
+ "sharing.invite-players-modal.requested": {
+ "defaultMessage": "Solicitud enviada"
+ },
+ "sharing.invite-players-modal.requested-tooltip": {
+ "defaultMessage": "{username} debe de aceptar tu solicitud de amistad primero"
+ },
+ "sharing.invite-players-modal.save-button": {
+ "defaultMessage": "Guardar"
+ },
+ "sharing.invite-players-modal.search-placeholder": {
+ "defaultMessage": "Introduce el nombre de usuario de Modrinth"
+ },
+ "sharing.invite-players-modal.searching": {
+ "defaultMessage": "Buscando..."
+ },
+ "sharing.invite-players-modal.update-invite-link-failed-title": {
+ "defaultMessage": "No se pudo actualizar el enlace de invitación"
+ },
"tag.category.128x": {
"defaultMessage": "128x"
},
@@ -5468,6 +6008,39 @@
"ui.stacked-admonitions.dismiss-all": {
"defaultMessage": "Descartar todas"
},
+ "unknown-file-warning-modal.dont-install": {
+ "defaultMessage": "No instalar"
+ },
+ "unknown-file-warning-modal.dont-show-again": {
+ "defaultMessage": "No mostar esta advertencia de nuevo"
+ },
+ "unknown-file-warning-modal.header": {
+ "defaultMessage": "Confirmar Instalación"
+ },
+ "unknown-file-warning-modal.install-anyway": {
+ "defaultMessage": "Instalar de todas formas"
+ },
+ "unknown-file-warning-modal.malware-warning": {
+ "defaultMessage": "Malware suele distribuir a través de archivos de mods compartidos en plataformas como Discord."
+ },
+ "unknown-file-warning-modal.mod-warning-body": {
+ "defaultMessage": " no está publicado en Modrinth. Te recomendamos instalar archivos de fuentes de confianza."
+ },
+ "unknown-file-warning-modal.mod-warning-title": {
+ "defaultMessage": "Advertencia de archivo desconocido"
+ },
+ "unknown-file-warning-modal.modpack-warning-body": {
+ "defaultMessage": " contiene archivos que no están publicados en Modrinth. Te recomendamos instalar archivos de fuentes de confianza."
+ },
+ "unknown-file-warning-modal.modpack-warning-title": {
+ "defaultMessage": "Advertencia de archivos desconocidos"
+ },
+ "unknown-file-warning-modal.reviewed-files": {
+ "defaultMessage": "Un archivo es revisado si es que está publicado en Modrinth, sin importar su formato de archivo (Incluyendo .mrpack)."
+ },
+ "unknown-file-warning-modal.unrecognized-files": {
+ "defaultMessage": "Archivos sin reconocer"
+ },
"user.profile.badge.alpha.about.1": {
"defaultMessage": "Este usuario ha estado presente desde la Alpha de Modrinth, la cuál terminó en noviembre de 2020."
},
diff --git a/packages/ui/src/locales/fi-FI/index.json b/packages/ui/src/locales/fi-FI/index.json
index 0f53d3fe32..f7213394cc 100644
--- a/packages/ui/src/locales/fi-FI/index.json
+++ b/packages/ui/src/locales/fi-FI/index.json
@@ -567,3 +567,4 @@
"defaultMessage": "Sinulla on tallentamattomia muutoksia."
}
}
+
diff --git a/packages/ui/src/locales/fil-PH/index.json b/packages/ui/src/locales/fil-PH/index.json
index 554ae942b3..6ea0d596fb 100644
--- a/packages/ui/src/locales/fil-PH/index.json
+++ b/packages/ui/src/locales/fil-PH/index.json
@@ -341,9 +341,6 @@
"external-project-license-status.yes": {
"defaultMessage": "Oo"
},
- "files.editor.find-close": {
- "defaultMessage": "Isara"
- },
"files.editor.find-in-file": {
"defaultMessage": "Hahanapin"
},
@@ -2766,3 +2763,4 @@
"defaultMessage": "Uri"
}
}
+
diff --git a/packages/ui/src/locales/fr-FR/index.json b/packages/ui/src/locales/fr-FR/index.json
index 4d7ec28f42..4f224d92bc 100644
--- a/packages/ui/src/locales/fr-FR/index.json
+++ b/packages/ui/src/locales/fr-FR/index.json
@@ -138,7 +138,7 @@
"defaultMessage": "Liens affiliés"
},
"button.analytics": {
- "defaultMessage": "Analyses"
+ "defaultMessage": "Statistiques"
},
"button.back": {
"defaultMessage": "Retour"
@@ -566,6 +566,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "monde"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "Paramètres d'installation"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "Contenu supplémentaire"
},
@@ -1298,9 +1301,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Fichier sauvegardé"
},
- "files.editor.find-close": {
- "defaultMessage": "Fermer"
- },
"files.editor.find-in-file": {
"defaultMessage": "Trouver"
},
@@ -2234,6 +2234,9 @@
"label.details": {
"defaultMessage": "Détails"
},
+ "label.discover-content": {
+ "defaultMessage": "Découvrir du contenu"
+ },
"label.done": {
"defaultMessage": "Terminé"
},
@@ -2312,6 +2315,9 @@
"label.password": {
"defaultMessage": "Mot de passe"
},
+ "label.permissions": {
+ "defaultMessage": "Permissions"
+ },
"label.plan-custom": {
"defaultMessage": "Personnalisé"
},
@@ -2682,16 +2688,16 @@
"defaultMessage": "Garder les fichiers à jour quand le serveur change"
},
"modal.open-in-app.get-app": {
- "defaultMessage": "Obtenir l'application Modrinth"
+ "defaultMessage": "Obtenir Modrinth App"
},
"modal.open-in-app.opening-automatically": {
- "defaultMessage": "L'application Modrinth s'ouvrira automatiquement..."
+ "defaultMessage": "Modrinth App s'ouvrira automatiquement..."
},
"modal.open-in-app.title": {
"defaultMessage": "L'application Modrinth est en cours d'ouverture"
},
"modal.open-in-app.why-use": {
- "defaultMessage": "Pourquoi utiliser l'application Modrinth"
+ "defaultMessage": "Pourquoi utiliser Modrinth App"
},
"notification.error.title": {
"defaultMessage": "Une erreur est survenue"
@@ -2843,9 +2849,162 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Un créateur Modrinth."
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Un utilisateur Modrinth."
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} ne va pas pouvoir vous envoyer de demande d'ami, vous inviter aux instances partagées ni à des serveurs Modrinth Hosting."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "Êtes-vous sûr de vouloir bloquer cet utilisateur ?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "Une erreur s'est produite pendant le blocage de cet utilisateur. Veuillez réessayer."
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "Impossible de bloquer l'utilisateur"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} a été bloqué."
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Utilisateur bloqué"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "Bloquer {username}"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Voir les statistiques de l'utilisateur"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "Gérer la facturation de l’utilisateur"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Bloquer"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "Créer une collection"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "Créer un projet"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Voir les détails de l'utilisateur"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "Gérer les projets"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "Retirer l'affiliation"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "Se mettre comme affilié"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Débloquer"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural,one {# projet} other {# projets}}"
+ },
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "Autorisez les pop-ups pour Modrinth, puis réessayez."
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "Le profil GitHub n'a pas pu être récupéré. Veuillez réessayer."
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "Impossible d'ouvrir le profil GitHub"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "Fournisseurs d’authentification"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "Adresse e-mail vérifiée"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "Dispose d'un mot de passe"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "Dispose d'un TOTP"
+ },
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "Chargement..."
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "Moyens de paiements"
+ },
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "Voir le profil"
+ },
+ "profile.details.title": {
+ "defaultMessage": "Détails de l'utilisateur"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "Adresse e-mail non vérifiée"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "Adresse e-mail vérifiée"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "Impossible de charger le profil."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "Utilisateur introuvable"
+ },
+ "profile.label.affiliate": {
+ "defaultMessage": "Affilié"
+ },
"profile.label.badges": {
"defaultMessage": "Badges"
},
+ "profile.label.collection": {
+ "defaultMessage": "Collection"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, one {téléchargement} other {téléchargements}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "Rejoint"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "Cet utilisateur n'a pas de collection !"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "Vous n'avez pas encore de collection."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "Cet utilisateur n'a pas de projet !"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "Vous n'avez pas encore de projet."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "Organisations"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural,one {projet}other {projets}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Compte Modrinth officiel"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "Le compte utilisateur officiel de Modrinth. Obtenez de l’aide via ou par e-mail à "
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "Une erreur s'est produite pendant le déblocage de cet utilisateur. Veuillez réessayer."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "Impossible de débloquer l'utilisateur"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "{username} a été débloqué."
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "Utilisateur débloqué"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "Publié {date}"
},
@@ -2873,6 +3032,9 @@
"project-type.all": {
"defaultMessage": "Tout"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "Collections"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, one {Data Pack} other {Data Packs}}"
},
@@ -4680,7 +4842,7 @@
"defaultMessage": "Détails de l'erreur :"
},
"servers.manage.error.queue-notice": {
- "defaultMessage": "Si vous avez acheté votre serveur Modrinth Hosting récemment, alors il fait actuellement la queue et apparaîtra ici dès qu'il est près. N'essayez pas d'acheter un nouveau serveur. "
+ "defaultMessage": "Si vous avez acheté votre serveur Modrinth Hosting récemment, alors il fait actuellement la queue et apparaîtra ici dès qu'il est prêt. N'essayez pas d'acheter un nouveau serveur. "
},
"servers.manage.error.support-notice": {
"defaultMessage": "Si vous avez besoin de soutien personnalisé à propos du status de votre serveur, veuillez contacter Modrinth Support."
@@ -5099,9 +5261,117 @@
"settings.pats.title": {
"defaultMessage": "Jetons d'accès personnel"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "Une courte description pour permettre à tout le monde d'en savoir un peu plus sur vous."
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "Biographie"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "Profil"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "Photo de profil"
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "Impossible de mettre à jour le profil"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "Une erreur s'est produite en essayant de mettre à jour votre profil. Veuillez réessayer."
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "Connectez-vous avec votre compte Modrinth pour personnaliser votre profil public."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Compte Modrinth requis"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "Un nom unique, insensible à la casse, permettant d'identifier votre profil."
+ },
"settings.sessions.title": {
"defaultMessage": "Sessions"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "Actions"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Utilisateur"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Voici les utilisateurs que vous avez bloqués sur Modrinth. Ils ne peuvent pas :"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "Vous n'avez bloqué personne."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "Impossible de charger les utilisateurs bloqués."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "Chargement des utilisateurs bloqués…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "Vous envoyer des demandes d'ami"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "Vous inviter à gérer un serveur Modrinth Hosting."
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "Vous inviter à des instances partagées"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "Utilisateurs bloqués"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "Débloquer"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "Impossible de débloquer l'utilisateur"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "Une erreur s'est produite en essayant de débloquer cet utilisateur. Veuillez réessayer."
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "Débloquer {username}"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "avatar de {username}"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "Contrôlez qui peut vous envoyer des demandes d'ami sur Modrinth."
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "Demandes d'ami"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "À venir !"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "Tout le monde"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "Amis"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "Amis d'amis"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "Personne"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "Contrôlez qui peut vous inviter à des instances partagées et à des panneaux Modrinth Hosting."
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "Invitations"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "Vous pouvez contrôler qui peut interagir avec vous, et gérer les utilisateurs bloqués avec un compte Modrinth"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Compte Modrinth requis"
+ },
+ "settings.social.title": {
+ "defaultMessage": "Social"
+ },
"sharing.invite-players-modal.add": {
"defaultMessage": "Ajouter"
},
@@ -5111,14 +5381,17 @@
"sharing.invite-players-modal.already-invited": {
"defaultMessage": "Cet utilisateur a déjà été invité."
},
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "Appliquer"
+ },
"sharing.invite-players-modal.avatar-alt": {
"defaultMessage": "Avatar de {username}"
},
- "sharing.invite-players-modal.cancel": {
- "defaultMessage": "Annuler"
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "Personnaliser..."
},
- "sharing.invite-players-modal.cancel-button": {
- "defaultMessage": "Annuler"
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "Personnalisé : {date}"
},
"sharing.invite-players-modal.edit-invite-link": {
"defaultMessage": "Modifier le lien d'invitation."
@@ -5126,6 +5399,24 @@
"sharing.invite-players-modal.edit-invite-link-title": {
"defaultMessage": "Modifier le lien d'invitation"
},
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "Dans 1 jour"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "Dans 1 heure"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "Dans 7 jours"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "Dans 6 heures"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "Dans 3 jours"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "Dans 12 jours"
+ },
"sharing.invite-players-modal.expiry-label": {
"defaultMessage": "Date d'expiration"
},
diff --git a/packages/ui/src/locales/fr-FR/meta.json b/packages/ui/src/locales/fr-FR/meta.json
index 0d64aef5ba..29f12c6283 100644
--- a/packages/ui/src/locales/fr-FR/meta.json
+++ b/packages/ui/src/locales/fr-FR/meta.json
@@ -1,7 +1,7 @@
{
"displayName": {
"description": "Please enter the name of the language in its specific variant or regional form (e.g., English (US) for American English, not just English). If the language does not have any specific variant, simply enter the name of the language (e.g., Français, Deutsch).",
- "message": "Français (France)"
+ "message": "Français"
},
"searchTerms": {
"description": "Please provide additional search terms associated with the language, if needed, to enhance the search functionality (e.g., American English, Deutschland). Each search term should be entered on a separate line. Translate as a hyphen (-) if no additional terms are needed.",
diff --git a/packages/ui/src/locales/hu-HU/index.json b/packages/ui/src/locales/hu-HU/index.json
index faa51d7f32..429f6a088d 100644
--- a/packages/ui/src/locales/hu-HU/index.json
+++ b/packages/ui/src/locales/hu-HU/index.json
@@ -54,7 +54,7 @@
"defaultMessage": "Mégse"
},
"billing.resubscribe-modal.cpus": {
- "defaultMessage": "{sharedCpus} Megosztott CPU-k"
+ "defaultMessage": "{sharedCpus} megosztott CPU"
},
"billing.resubscribe-modal.description": {
"defaultMessage": "Ön újra elő fog fizetni {serverName} szerverre. Az előfizetése újra fog aktiválódni és a szervere kimaradás nélkül tovább fog működni."
@@ -123,7 +123,7 @@
"defaultMessage": "Elfogadás"
},
"button.add-server-to-instance": {
- "defaultMessage": "Szerver hozzáadása a játékpéldányhoz"
+ "defaultMessage": "Szerver hozzáadása a játékprofilhoz"
},
"button.affiliate-links": {
"defaultMessage": "Társulati linkek"
@@ -212,6 +212,9 @@
"button.open-folder": {
"defaultMessage": "Mappa megnyitása"
},
+ "button.open-in-browser": {
+ "defaultMessage": "Megnyitás a böngészőben"
+ },
"button.open-in-folder": {
"defaultMessage": "Megnyitás mappában"
},
@@ -305,6 +308,9 @@
"changelog.product.web": {
"defaultMessage": "Platform"
},
+ "collection-widget.loading-projects": {
+ "defaultMessage": "Projektek betöltése..."
+ },
"collection-widget.project-count": {
"defaultMessage": "{count} projekt"
},
@@ -378,7 +384,7 @@
"defaultMessage": "Néhány kijelölt projekt függőségként van telepítve. Ha törlöd őket, a {context} hibásan működhet, vagy a tőlük függő tartalmak nem fognak megfelelően betöltődni."
},
"content.dependency-warning.context.instance": {
- "defaultMessage": "játékpéldány"
+ "defaultMessage": "játékprofil"
},
"content.dependency-warning.context.server": {
"defaultMessage": "szerver"
@@ -440,6 +446,9 @@
"content.diff-modal.unknown-files-warning": {
"defaultMessage": "Ismeretlen fájlok"
},
+ "content.diff-modal.unknown-project": {
+ "defaultMessage": "Ismeretlen"
+ },
"content.diff-modal.updated-count": {
"defaultMessage": "{count} frissítve"
},
@@ -474,7 +483,7 @@
"defaultMessage": "Biztonsági mentés létrehozása"
},
"content.inline-backup.instance-label": {
- "defaultMessage": "játékpéldány"
+ "defaultMessage": "játékprofil"
},
"content.inline-backup.shift-click-hint": {
"defaultMessage": "A megerősítés kihagyásához tartsd lenyomva a Shift billentyűt a kattintás közben."
@@ -485,6 +494,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "világ"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "Telepítési beállítások"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "További tartalom"
},
@@ -588,7 +600,7 @@
"defaultMessage": "{count, number} kiválasztva"
},
"creation-flow.button.create-instance": {
- "defaultMessage": "Játékpéldány létrehozása"
+ "defaultMessage": "Játékprofil létrehozása"
},
"creation-flow.button.create-world": {
"defaultMessage": "Világ létrehozása"
@@ -600,7 +612,7 @@
"defaultMessage": "Importálás"
},
"creation-flow.button.import-instances": {
- "defaultMessage": "{count} játékpéldány importálása"
+ "defaultMessage": "{count} játékprofil importálása"
},
"creation-flow.button.setup-server": {
"defaultMessage": "Szerver beállítása"
@@ -654,7 +666,7 @@
"defaultMessage": "Név"
},
"creation-flow.modal.custom-setup.name.placeholder": {
- "defaultMessage": "Add meg a játékpéldány nevét"
+ "defaultMessage": "Add meg a játékprofil nevét"
},
"creation-flow.modal.custom-setup.options.no-versions-available": {
"defaultMessage": "Nincsenek elérhető verziók"
@@ -698,6 +710,9 @@
"creation-flow.modal.final-config.generate-structures.label": {
"defaultMessage": "Struktúrák generálása"
},
+ "creation-flow.modal.final-config.generator-settings-json.placeholder": {
+ "defaultMessage": "Add meg a generátor beállításait JSON formátumban"
+ },
"creation-flow.modal.final-config.generator-settings.custom": {
"defaultMessage": "Egyéni"
},
@@ -758,20 +773,26 @@
"creation-flow.modal.import-instance.custom-launcher.name": {
"defaultMessage": "Egyéni ({pathName})"
},
+ "creation-flow.modal.import-instance.detecting-launcher-instances": {
+ "defaultMessage": "Indító-játékprofilok észlelése..."
+ },
"creation-flow.modal.import-instance.launcher-instances.title": {
- "defaultMessage": "Más indítók játékpéldányai"
+ "defaultMessage": "Más indítók játékprofiljai"
+ },
+ "creation-flow.modal.import-instance.launcher-path.add": {
+ "defaultMessage": "Add meg az elérési utat az indítóhoz"
},
"creation-flow.modal.import-instance.launcher-path.placeholder": {
"defaultMessage": "Elérési útvonal az indítóhoz..."
},
"creation-flow.modal.import-instance.notification.no-instances-found.text": {
- "defaultMessage": "Nem találtunk importálható játékpéldányokat a megadott útvonalon."
+ "defaultMessage": "Nem találtunk importálható játékprofilokat a megadott útvonalon."
},
"creation-flow.modal.import-instance.notification.no-instances-found.title": {
- "defaultMessage": "Nem található játékpéldány"
+ "defaultMessage": "Nem található játékprofil"
},
"creation-flow.modal.import-instance.search.placeholder": {
- "defaultMessage": "Játékpéldánynév keresése..."
+ "defaultMessage": "Játékprofilnév keresése..."
},
"creation-flow.modal.import-instance.selection.clear-all": {
"defaultMessage": "Összes törlése"
@@ -792,7 +813,7 @@
"defaultMessage": "Modcsomag keresése"
},
"creation-flow.modal.setup-type.instance.description": {
- "defaultMessage": "A játékpéldány egy külön Minecraft-környezet egy adott modbetöltővel, verzióval és modokkal."
+ "defaultMessage": "A játékprofil egy külön Minecraft-környezet egy adott modbetöltővel, verzióval és modokkal."
},
"creation-flow.modal.setup-type.option.custom-setup.description": {
"defaultMessage": "Kezdés alapoktól: válassz betöltőt és játékverziót."
@@ -801,10 +822,10 @@
"defaultMessage": "Egyedi beállítás"
},
"creation-flow.modal.setup-type.option.import-instance.description": {
- "defaultMessage": "Importálj egy játékpéldányt a Prismből, CurseForge-ból, vagy hasonló forrásból."
+ "defaultMessage": "Importálj egy játékprofilt a Prismből, CurseForge-ból, vagy hasonló forrásból."
},
"creation-flow.modal.setup-type.option.import-instance.title": {
- "defaultMessage": "Játékpéldány importálása"
+ "defaultMessage": "Játékprofil importálása"
},
"creation-flow.modal.setup-type.option.modpack-base.description": {
"defaultMessage": "Böngéssz modcsomagokat a Modrinthon, vagy tölts be egyet fájlból."
@@ -822,7 +843,7 @@
"defaultMessage": "Telepítés típusa"
},
"creation-flow.modal.setup-type.title.instance": {
- "defaultMessage": "Játékpéldány típusa"
+ "defaultMessage": "Játékprofil típusa"
},
"creation-flow.modal.setup-type.title.world": {
"defaultMessage": "Világ típusa"
@@ -831,13 +852,13 @@
"defaultMessage": "Modcsomag kiválasztása"
},
"creation-flow.title.create-instance": {
- "defaultMessage": "Játékpéldány létrehozása"
+ "defaultMessage": "Játékprofil létrehozása"
},
"creation-flow.title.create-world": {
"defaultMessage": "Világ létrehozása"
},
"creation-flow.title.import-instance": {
- "defaultMessage": "Játékpéldány importálása"
+ "defaultMessage": "Játékprofil importálása"
},
"creation-flow.title.reset-server": {
"defaultMessage": "Szerver visszaállítása"
@@ -875,6 +896,9 @@
"external-files.permissions-card.custom-license-option": {
"defaultMessage": "Egyéb"
},
+ "external-files.permissions-card.editor.add": {
+ "defaultMessage": "Hozzárendelés hozzáadása"
+ },
"external-files.permissions-card.editor.custom-license-label": {
"defaultMessage": "Hivatkozás a lincenszhez"
},
@@ -905,9 +929,15 @@
"external-files.permissions-card.editor.notes-placeholder": {
"defaultMessage": "Írj valamit ide..."
},
+ "external-files.permissions-card.editor.save": {
+ "defaultMessage": "Hossárendelés mentése"
+ },
"external-files.permissions-card.editor.select-license-label": {
"defaultMessage": "Válassz egy licenszt..."
},
+ "external-files.permissions-card.fallback-group-title": {
+ "defaultMessage": "A(z) {id} hozzárendelési csoport"
+ },
"external-files.permissions-card.file-count": {
"defaultMessage": "{count} fájl"
},
@@ -932,6 +962,9 @@
"external-files.permissions-card.reason.my-project": {
"defaultMessage": "Az én projektem"
},
+ "external-files.permissions-card.remove-group-confirmation.title": {
+ "defaultMessage": "{title} törlése?"
+ },
"external-files.permissions-card.updated-by-moderator": {
"defaultMessage": "Moderátor"
},
@@ -995,9 +1028,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "A fájl mentve"
},
- "files.editor.find-close": {
- "defaultMessage": "Bezárás"
- },
"files.editor.find-in-file": {
"defaultMessage": "Keresés"
},
@@ -1467,7 +1497,7 @@
"defaultMessage": "{storage} GB Tárhely"
},
"hosting.specs.shared-cpus": {
- "defaultMessage": "{cpus} Megosztott CPU-k"
+ "defaultMessage": "{cpus} megosztott CPU"
},
"icon-select.edit": {
"defaultMessage": "Ikon szerkesztése"
@@ -1569,13 +1599,13 @@
"defaultMessage": "Modcsomag újratelepítése..."
},
"installation-settings.removed-incompatible": {
- "defaultMessage": "Eltávolítva (inkompatibilis)"
+ "defaultMessage": "Eltávolítva: (inkompatibilis)"
},
"installation-settings.repair.instance-description": {
"defaultMessage": "Újratelepíti a Minecraft függőségeit, és ellenőrzi, hogy nincsenek-e sérült fájlok. Ez megoldhatja azokat a problémákat, ha a játék az indítóval kapcsolatos hibák miatt nem indul el."
},
"installation-settings.repair.instance-title": {
- "defaultMessage": "Játékpéldány javítása"
+ "defaultMessage": "Játékprofil javítása"
},
"installation-settings.repair.server-description": {
"defaultMessage": "Újratelepíti a betöltőt és a Minecraft függőségeit anélkül, hogy törölné a tartalmaidat. Ez megoldhatja a problémákat, ha a szervered nem indul el megfelelően."
@@ -1590,10 +1620,10 @@
"defaultMessage": "Játékverzió keresése..."
},
"installation-settings.type.instance": {
- "defaultMessage": "játékpéldány"
+ "defaultMessage": "játékprofil"
},
"installation-settings.type.instance-possessive": {
- "defaultMessage": "játékpéldány"
+ "defaultMessage": "játékprofil"
},
"installation-settings.type.server": {
"defaultMessage": "szerver"
@@ -1632,7 +1662,7 @@
"defaultMessage": "{type} javítása"
},
"instance.confirm-repair.instance-label": {
- "defaultMessage": "Játékpéldány"
+ "defaultMessage": "Példány"
},
"instance.confirm-repair.repair-button": {
"defaultMessage": "Javítás"
@@ -1656,10 +1686,10 @@
"defaultMessage": "Ismeretlen játékmód"
},
"instances.content-install.compatible-count": {
- "defaultMessage": "{count} kompatiblis játékpéldány"
+ "defaultMessage": "{count} kompatiblis játékprofil"
},
"instances.content-install.existing-tab": {
- "defaultMessage": "Meglévő játékpéldány"
+ "defaultMessage": "Meglévő játékprofil"
},
"instances.content-install.game-version-placeholder": {
"defaultMessage": "Játékverzió kiválasztása"
@@ -1668,7 +1698,7 @@
"defaultMessage": "Projekt letöltése"
},
"instances.content-install.incompatible-tooltip": {
- "defaultMessage": "Ez a játékpéldány olyan betöltőt vagy játékverziót használ, amelyet ez a projekt nem támogat."
+ "defaultMessage": "Ez a játékprofil olyan betöltőt vagy játékverziót használ, amelyet ez a projekt nem támogat."
},
"instances.content-install.install-button": {
"defaultMessage": "Letöltés"
@@ -1689,7 +1719,7 @@
"defaultMessage": "Add meg a profil nevét"
},
"instances.content-install.new-tab": {
- "defaultMessage": "Új profil"
+ "defaultMessage": "Új játékprofil"
},
"instances.content-install.no-instances": {
"defaultMessage": "Nem található kompatibilis profil"
@@ -1709,6 +1739,12 @@
"instances.modpack-content-modal.empty-title": {
"defaultMessage": "Nincsen tartalom"
},
+ "instances.modpack-content-modal.external-content": {
+ "defaultMessage": "Külső"
+ },
+ "instances.modpack-content-modal.external-content-description": {
+ "defaultMessage": "Ez a fájl nem szerepel a Modrinthon."
+ },
"instances.modpack-content-modal.header": {
"defaultMessage": "Modcsomag tartalma"
},
@@ -1718,6 +1754,9 @@
"instances.modpack-content-modal.no-results": {
"defaultMessage": "Nincsen olyan projekt ami keresnél."
},
+ "instances.modpack-content-modal.open-in-slicer": {
+ "defaultMessage": "Megnyitás a Slicer-ben"
+ },
"instances.modpack-content-modal.search-placeholder": {
"defaultMessage": "Keresés {count, number} projekt között"
},
@@ -1788,7 +1827,7 @@
"defaultMessage": "Frissítés a(z) {version} verzióra"
},
"instances.updater-modal.warning-app": {
- "defaultMessage": "A frissítés meghibásodást okozhat a játékpéldányban. Először nézd át a változásnaplót, és készíts biztonsági mentést."
+ "defaultMessage": "A frissítés meghibásodást okozhat a játékprofilban. Először nézd át a változásnaplót, és készíts biztonsági mentést."
},
"instances.updater-modal.warning-web": {
"defaultMessage": "A frissítés meghibásodást okozhat a világban. Először nézd át a változásnaplót, és készíts biztonsági mentést."
@@ -1853,6 +1892,9 @@
"label.details": {
"defaultMessage": "Részletek"
},
+ "label.discover-content": {
+ "defaultMessage": "Tartalom felfedezése"
+ },
"label.done": {
"defaultMessage": "Kész"
},
@@ -2298,7 +2340,7 @@
"defaultMessage": "Szerezd meg a Modrinth Appot"
},
"modal.open-in-app.opening-automatically": {
- "defaultMessage": "A Modrinth alkalmazás automatikusan megnyílik..."
+ "defaultMessage": "A Modrinth App automatikusan megnyílik..."
},
"modal.open-in-app.title": {
"defaultMessage": "A Modrinth App megnyitása"
@@ -2453,9 +2495,135 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Egy Modrinth fejlesztő."
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Egy Modrinth felhasználó."
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} nem fog tudni neked barátkérelmet küldeni, meghívni téged megosztott játékprofilokba, illetve meghívni téged a Modrinth Hosting szervereire."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "Biztosan le szeretnéd tiltani ezt a felhasználót?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "Hiba történt a felhasználó letiltása közben. Kérlek próbáld meg újra."
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "A felhasználó letiltása nem sikerült"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} le lett tiltva"
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Felhasználó letiltva"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "{username} letiltása"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Felhasználói statisztikák megtekintése"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Letiltás"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "Gyűjtemény létrehozása"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "Projekt létrehozása"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Felhasználói adatok megtekintése"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "Projektek kezelése"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Letiltás feloldása"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count} projekt"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "Hitelesítési szolgáltatók"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "E-mail cím hitelesítve"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "Van jelszava"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "Kétlépcsős hitelesítést használ"
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "Fizetési módok"
+ },
+ "profile.details.title": {
+ "defaultMessage": "Felhasználó adatai"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "Nem hitelesített e-mail cím"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "Hitelesített e-mail cím"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "A felhasználói profil betöltése nem sikerült."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "Felhasználó nem található"
+ },
"profile.label.badges": {
"defaultMessage": "Jelvények"
},
+ "profile.label.collection": {
+ "defaultMessage": "Gyűjtemény"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "letöltés"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "Csatlakozott"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "Ennek a felhasználónak nincsenek gyűjteményei!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "Még nincs gyűjteményed."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "Ennek a felhasználónak nincsenek projektjei!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "Még nincsenek projektjeid."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "Szervezetek"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "projekt"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Hivatalos Modrinth-fiók"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "A Modrinth hivatalos felhasználói fiókja. Támogatás a oldalon kaphatsz vagy e-mailben a címen."
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "Hiba történt a felhasználó letiltásának feloldása közben. Kérlek próbáld meg újra."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "A felhasználó letiltásának feloldása nem sikerült"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "{username} letiltása fel lett oldva"
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "Felhasználó letiltása feloldva"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "Közzététel: {date}"
},
@@ -2477,8 +2645,11 @@
"project-type.all": {
"defaultMessage": "Összes"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "Gyűjtemények"
+ },
"project-type.datapack.capital": {
- "defaultMessage": "{count, plural, one {Adatcsomag} other {Adatcsomagok}}"
+ "defaultMessage": "adatcsomag"
},
"project-type.datapack.category": {
"defaultMessage": "Adatcsomagok"
@@ -2487,7 +2658,7 @@
"defaultMessage": "adatcsomag"
},
"project-type.mod.capital": {
- "defaultMessage": "{count, plural,one {Mod} other {Modok}}"
+ "defaultMessage": "mod"
},
"project-type.mod.category": {
"defaultMessage": "Modok"
@@ -2505,7 +2676,7 @@
"defaultMessage": "modcsomag"
},
"project-type.plugin.capital": {
- "defaultMessage": "{count, plural,one {Bővítmény} other {Bővítmények}}"
+ "defaultMessage": "bővítmény"
},
"project-type.plugin.category": {
"defaultMessage": "Bővítmények"
@@ -2523,7 +2694,7 @@
"defaultMessage": "projekt"
},
"project-type.resourcepack.capital": {
- "defaultMessage": "{count, plural,one {Forráscsomag} other {Forráscsomagok}}"
+ "defaultMessage": "forráscsomag"
},
"project-type.resourcepack.category": {
"defaultMessage": "Forráscsomagok"
@@ -2541,7 +2712,7 @@
"defaultMessage": "szerver"
},
"project-type.shader.capital": {
- "defaultMessage": "{count, plural,one {Shader} other {Shaderek}}"
+ "defaultMessage": "shader"
},
"project-type.shader.category": {
"defaultMessage": "Shaderek"
@@ -2735,6 +2906,9 @@
"project.follower-count-tooltip": {
"defaultMessage": "{count, number} követő"
},
+ "project.license.title": {
+ "defaultMessage": "Licensz"
+ },
"project.online-player-count": {
"defaultMessage": "{count, number} online"
},
@@ -3053,6 +3227,9 @@
"project.settings.environment.notice.review-options.description": {
"defaultMessage": "Nemrégiben átalakítottuk a Modrinth környezetrendszerét, és mostantól új beállítási lehetőségek állnak rendelkezésre. Kérjük, győződj meg arról, hogy az alábbiak közül a megfelelő opciót választottad ki, majd ha kész vagy, kattints az „Ellenőrzés” gombra!"
},
+ "project.settings.environment.notice.review-options.title": {
+ "defaultMessage": "Kérjük, tekintsd át az alábbi lehetőségeket"
+ },
"project.settings.environment.notice.wrong-project-type.description": {
"defaultMessage": "Csak a mod- vagy modcsomag-projektek rendelkezhetnek környezeti metaadatokkal."
},
@@ -3132,7 +3309,7 @@
"defaultMessage": "letöltés"
},
"project.stats.followers-label": {
- "defaultMessage": "{count} követő"
+ "defaultMessage": "követő"
},
"project.versions.channel.alpha.symbol": {
"defaultMessage": "A"
@@ -3143,6 +3320,9 @@
"project.versions.channel.release.symbol": {
"defaultMessage": "K"
},
+ "project.versions.platform.modloader.short": {
+ "defaultMessage": "ModLoader"
+ },
"project.visibility.archived": {
"defaultMessage": "Archiválva"
},
@@ -3354,7 +3534,7 @@
"defaultMessage": "Újraindított szerver"
},
"servers.access-page.activity-log-filter.instances": {
- "defaultMessage": "Játékpéldányok"
+ "defaultMessage": "Játékprofilok"
},
"servers.access-page.activity-log-filter.server-scoped-instance": {
"defaultMessage": "Szerver"
@@ -3420,7 +3600,7 @@
"defaultMessage": "Szerkesztő"
},
"servers.access-page.role.editor-description": {
- "defaultMessage": "A játékpéldány tartalmának, fájljainak, biztonsági mentéseinek és egyéb beállításainak kezelése."
+ "defaultMessage": "A játékprofil tartalmának, fájljainak, biztonsági mentéseinek és egyéb beállításainak kezelése."
},
"servers.access-page.role.owner": {
"defaultMessage": "Tulajdonos"
@@ -3498,7 +3678,7 @@
"defaultMessage": "Felhasználó"
},
"servers.audit-log.column.world": {
- "defaultMessage": "Játékpéldány"
+ "defaultMessage": "Játékprofil"
},
"servers.audit-log.column.world.tooltip-title": {
"defaultMessage": "Hamarosan érkezik!"
@@ -3519,7 +3699,7 @@
"defaultMessage": "Leválasztott modcsomag-verzió "
},
"servers.audit-log.event.server-plan.ram-mb": {
- "defaultMessage": "{amount, number} MB RAM"
+ "defaultMessage": "{amount, number} MB memória"
},
"servers.audit-log.event.server-plan.storage-gb": {
"defaultMessage": "{amount, number} GB tárhely"
@@ -3723,7 +3903,7 @@
"defaultMessage": "Szerkesztő"
},
"servers.grant-access-modal.role.editor-description": {
- "defaultMessage": "A játékpéldány tartalmának, fájljainak, biztonsági mentéseinek és egyéb beállításainak kezelése."
+ "defaultMessage": "A játékprofil tartalmának, fájljainak, biztonsági mentéseinek és egyéb beállításainak kezelése."
},
"servers.grant-access-modal.role.label": {
"defaultMessage": "Rang kiválasztása"
@@ -3806,6 +3986,9 @@
"servers.list-empty.no-servers-title": {
"defaultMessage": "Még nincsenek szerverek"
},
+ "servers.list-empty.one-click-mod-installs-description": {
+ "defaultMessage": "Válaszd ki a kedvenc modjaidat, a többit bízd ránk!"
+ },
"servers.list-empty.one-click-mod-installs-title": {
"defaultMessage": "Modok telepítése egy kattintással"
},
@@ -3899,6 +4082,9 @@
"servers.manage.no-servers-found": {
"defaultMessage": "Nem található szerver."
},
+ "servers.manage.no-shared-servers-found": {
+ "defaultMessage": "Egy megosztott szerver sem egyezik a kereséssel."
+ },
"servers.manage.reload-button": {
"defaultMessage": "Újra"
},
@@ -3920,6 +4106,9 @@
"servers.manage.settings-hint.title": {
"defaultMessage": "A szerver beállításait áthelyeztük"
},
+ "servers.manage.shared-servers-title": {
+ "defaultMessage": "Megosztott szerverek"
+ },
"servers.medal-listing.countdown.remaining": {
"defaultMessage": "{days} nap {hours} óra {minutes} perc és {seconds} másodperc van hátra..."
},
@@ -4017,7 +4206,7 @@
"defaultMessage": "Legnépszerűbb"
},
"servers.purchase.step.plan.select": {
- "defaultMessage": "Válasz előfizetést"
+ "defaultMessage": "Csomag kiválasztása"
},
"servers.purchase.step.plan.small": {
"defaultMessage": "Kicsi"
@@ -4026,7 +4215,7 @@
"defaultMessage": "Tökéletes 1–5 barát számára, néhány kisebb moddal."
},
"servers.purchase.step.plan.title": {
- "defaultMessage": "Előfizetés"
+ "defaultMessage": "Csomag"
},
"servers.purchase.step.plan.your-current-plan": {
"defaultMessage": "Jelenlegi csomag"
@@ -4046,6 +4235,15 @@
"servers.region.custom.prompt-ram-only": {
"defaultMessage": "memória"
},
+ "servers.region.north-america-central": {
+ "defaultMessage": "Észak-Amerika középső része"
+ },
+ "servers.region.north-america-east": {
+ "defaultMessage": "Észak-Amerika keleti része"
+ },
+ "servers.region.north-america-west": {
+ "defaultMessage": "Észak-Amerika nyugati része"
+ },
"servers.region.prompt": {
"defaultMessage": "Hol szeretnéd elhelyezni a szerveredet?"
},
@@ -4166,6 +4364,9 @@
"settings.display.theme.title": {
"defaultMessage": "Téma"
},
+ "settings.feature-flags.title": {
+ "defaultMessage": "Funkciójelzők"
+ },
"settings.language.categories.default": {
"defaultMessage": "Alapértelmezett nyelvek"
},
@@ -4199,9 +4400,120 @@
"settings.pats.title": {
"defaultMessage": "Személyes hozzáférési tokenek"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "Egy rövid leírás, hogy mindenki megismerjen téged."
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "Bemutatkozás"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "Profil"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "Profilkép"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "A profiladataid nyilvánosan megtekinthetők a Modrinthon és a Modrinth API -n keresztül."
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "A profil frissítése nem sikerült"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "Hiba történt a profilod frissítése közben. Kérlek, próbáld meg újra."
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "Jelentkezz be egy Modrinth-fiókkal, hogy személyre szabhasd a nyilvános profilodat."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Modrinth-fiók szükséges"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "Egyedi, kis- és nagybetűktől független név a profilod azonosításához."
+ },
"settings.sessions.title": {
"defaultMessage": "Munkamenetek"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "Műveletek"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Felhasználó"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Ezek azok a felhasználók, akiket a Modrinthon letiltottál. Ők nem tudnak:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "Nem tiltottál le senkit."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "A letiltott felhasználók betöltése nem sikerült."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "A letiltott felhasználók betöltése…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "Barátkérelmeket küldeni neked"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "Meghívni téged, hogy kezelj egy Modrinth Hosting szervert."
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "Meghívni téged megosztott játékprofilokba"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "Letiltott felhasználók"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "Letiltás feloldása"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "A felhasználó letiltásának feloldása nem sikerült"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "Hiba történt a felhasználó letiltásának feloldása közben. Kérlek próbáld meg újra."
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "{username} letiltásának feloldása"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "{username} avatárja"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "Állítsd be, hogy ki küldhet neked barátkérelmeket a Modrinthon."
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "Barátkérelmek"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "Hamarosan érkezik!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "Bárki"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "Barátok"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "A barátok barátai"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "Senki"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "Állítsd be, hogy kik küldhetnek neked meghívókat a megosztott játékprofilokhoz és a Modrinth Hosting vezérlőpultjaihoz."
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "Meghívók"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "A Modrinth-fiókod segítségével beállíthatod, hogy kik léphetnek veled kapcsolatba, és kezelheted a letiltott felhasználókat"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Modrinth-fiók szükséges"
+ },
+ "settings.social.title": {
+ "defaultMessage": "Közösségi"
+ },
"sharing.invite-players-modal.add": {
"defaultMessage": "Hozzáadás"
},
@@ -4214,12 +4526,6 @@
"sharing.invite-players-modal.avatar-alt": {
"defaultMessage": "{username} avatárja"
},
- "sharing.invite-players-modal.cancel": {
- "defaultMessage": "Mégse"
- },
- "sharing.invite-players-modal.cancel-button": {
- "defaultMessage": "Mégse"
- },
"sharing.invite-players-modal.edit-invite-link": {
"defaultMessage": "Meghívólink szerkesztése."
},
@@ -4247,6 +4553,15 @@
"sharing.invite-players-modal.link-copied-title": {
"defaultMessage": "Link kimásolva"
},
+ "sharing.invite-players-modal.link-copy-failed-title": {
+ "defaultMessage": "A link másolása nem sikerült"
+ },
+ "sharing.invite-players-modal.max-uses-label": {
+ "defaultMessage": "Maximális felhasználások száma"
+ },
+ "sharing.invite-players-modal.no-friends": {
+ "defaultMessage": "Nem találhatók barátok."
+ },
"sharing.invite-players-modal.no-search-results": {
"defaultMessage": "Nem található a keresésnek megfelelő felhasználó."
},
@@ -4775,6 +5090,9 @@
"ui.stacked-admonitions.alert-count": {
"defaultMessage": "{count} figyelmeztetés"
},
+ "unknown-file-warning-modal.malware-warning": {
+ "defaultMessage": "A rosszindulatú programokat gyakran modfájlokon keresztül terjesztik, például a Discordhoz hasonló platformokon történő megosztás révén."
+ },
"unknown-file-warning-modal.modpack-warning-title": {
"defaultMessage": "Ismeretlen fájlok"
},
@@ -4873,5 +5191,14 @@
},
"user.profile.badge.staff.name": {
"defaultMessage": "A Modrinth-csapat"
+ },
+ "version.section.content": {
+ "defaultMessage": "Tartalom"
+ },
+ "version.section.content.search-placeholder": {
+ "defaultMessage": "Tartalom keresése..."
+ },
+ "version.section.required-content": {
+ "defaultMessage": "Kötelező tartalom"
}
}
diff --git a/packages/ui/src/locales/id-ID/index.json b/packages/ui/src/locales/id-ID/index.json
index 8ad53fed3f..e2044d9b8e 100644
--- a/packages/ui/src/locales/id-ID/index.json
+++ b/packages/ui/src/locales/id-ID/index.json
@@ -824,9 +824,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Berkas disimpan"
},
- "files.editor.find-close": {
- "defaultMessage": "Tutup"
- },
"files.editor.find-in-file": {
"defaultMessage": "Cari"
},
@@ -2985,3 +2982,4 @@
"defaultMessage": "Anda memiliki perubahan yang belum tersimpan."
}
}
+
diff --git a/packages/ui/src/locales/it-IT/index.json b/packages/ui/src/locales/it-IT/index.json
index 8ff9e91298..02ebe7b976 100644
--- a/packages/ui/src/locales/it-IT/index.json
+++ b/packages/ui/src/locales/it-IT/index.json
@@ -545,6 +545,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "mondo"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "Impostazioni installazione"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "Contenuto aggiuntivo"
},
@@ -732,7 +735,7 @@
"defaultMessage": "Nessuna versione trovata"
},
"creation-flow.modal.final-config.additional-settings.title": {
- "defaultMessage": "Opzioni aggiuntive"
+ "defaultMessage": "Impostazioni aggiuntive"
},
"creation-flow.modal.final-config.backup.before-reset-server.name": {
"defaultMessage": "Prima della reimpostazione"
@@ -1173,7 +1176,7 @@
"defaultMessage": "Elimina gruppo"
},
"external-files.permissions-card.remove-group-confirmation.description": {
- "defaultMessage": "Questo gruppo di attribuzione sarà rimosso per sempre. Quest'azione non può essere annullata."
+ "defaultMessage": "Il gruppo di attribuzione e i suoi contenuti saranno eliminati per sempre. Questa azione è irreversibile."
},
"external-files.permissions-card.remove-group-confirmation.title": {
"defaultMessage": "Eliminare {title}?"
@@ -1248,10 +1251,10 @@
"defaultMessage": "Elimina file"
},
"files.delete-modal.warning.file": {
- "defaultMessage": "Questo file verrà eliminato permanentemente. Questa azione non può essere annullata."
+ "defaultMessage": "Il file sarà eliminato per sempre. Questa azione è irreversibile."
},
"files.delete-modal.warning.folder": {
- "defaultMessage": "Questa cartella e tutti i suoi contenuti verranno eliminati permanentemente. Questa azione non può essere annullata."
+ "defaultMessage": "La cartella e i suoi contenuti saranno eliminati per sempre. Questa azione è irreversibile."
},
"files.editor.failed-to-open-text": {
"defaultMessage": "Impossibile caricare i contenuti del file."
@@ -1271,9 +1274,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "File salvato"
},
- "files.editor.find-close": {
- "defaultMessage": "Chiudi"
- },
"files.editor.find-in-file": {
"defaultMessage": "Trova"
},
@@ -2198,6 +2198,9 @@
"label.details": {
"defaultMessage": "Dettagli"
},
+ "label.discover-content": {
+ "defaultMessage": "Sfoglia i contenuti"
+ },
"label.done": {
"defaultMessage": "Fatto"
},
@@ -2276,6 +2279,9 @@
"label.password": {
"defaultMessage": "Password"
},
+ "label.permissions": {
+ "defaultMessage": "Permessi"
+ },
"label.plan-custom": {
"defaultMessage": "Ad hoc"
},
@@ -2807,9 +2813,162 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Creatore su Modrinth."
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Utente di Modrinth."
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} non potrà inviarti richieste di amicizia, invitarti alle istanze condivise o invitarti ai server Modrinth Hosting."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "Vuoi davvero bloccare quest'utente?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "Sì è verificato un errore nel bloccare l'utente. Riprova più tardi."
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "Impossibile bloccare l'utente"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "Utente {username} bloccato."
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Utente bloccato"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "Blocca {username}"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Mostra analitiche utente"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "Gestisci fatturato utente"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Blocca"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "Crea una raccolta"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "Crea un progetto"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Mostra info utente"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "Gestisci progetti"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "Rimuovi da affiliato"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "Imposta come affiliato"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Sblocca"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural, one {# progetto} other {# progetti}}"
+ },
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "Consentì i pop-up per Modrinth, poi riprova."
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "Impossibile recuperare il profilo GitHub. Riprova più tardi."
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "Errore nell'apertura del profilo GitHub"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "Fornitori d'autenticazione"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "Email verificata"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "Usa una password"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "Usa un TOTP"
+ },
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "Caricamento..."
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "Metodi di pagamento"
+ },
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "Visita profilo"
+ },
+ "profile.details.title": {
+ "defaultMessage": "Informazioni"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "Email non verificata"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "Email verificata"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "Non è stato possibile caricare il profilo."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "Utente non trovato"
+ },
+ "profile.label.affiliate": {
+ "defaultMessage": "Affiliato"
+ },
"profile.label.badges": {
"defaultMessage": "Distintivi"
},
+ "profile.label.collection": {
+ "defaultMessage": "Raccolta"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "download"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "Iscrizione"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "Nessuna raccolta qui!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "Ancora nessuna raccolta."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "Nessun progetto qui!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "Ancora nessun progetto."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "Organizzazioni"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural, one {progetto} other {progetti}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Account Modrinth ufficiale"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "L'account ufficiale di Modrinth. Ricevi assistenza presso o tramite mail presso "
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "Sì è verificato un errore nello sbloccare l'utente. Riprova più tardi."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "Impossibile sbloccare l'utente"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "Utente {username} sbloccato."
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "Utente sbloccato"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "Pubblicato {date}"
},
@@ -2837,6 +2996,9 @@
"project-type.all": {
"defaultMessage": "Tutto"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "Raccolte"
+ },
"project-type.datapack.capital": {
"defaultMessage": "Pacchett{count, plural, one {o} other {i}} di dati"
},
@@ -4464,7 +4626,7 @@
"defaultMessage": "Installazione fallita"
},
"servers.installing-banner.error.internal-platform": {
- "defaultMessage": "Si è verificato un errore nell'installazione della piattaforma. Riprova più tardi."
+ "defaultMessage": "Si è verificato un errore durante l'installazione della piattaforma. Riprova più tardi."
},
"servers.installing-banner.error.invalid-loader-version": {
"defaultMessage": "Questa versione di Minecraft o del loader non è potuta essere installata. Potrebbe essere non valida o non supportata."
@@ -5063,9 +5225,120 @@
"settings.pats.title": {
"defaultMessage": "Token di accesso (PAT)"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "Una breve descrizione per raccontare a tutti qualcosa su di te."
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "Bio"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "Profilo"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "Foto profilo"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "Le informazioni del tuo profilo sono visibili pubblicamente su Modrinth e tramite l''API di Modrinth ."
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "Impossibile salvare il profilo"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "Si è verificato un errore nel salvataggio del profilo. Riprova più tardi."
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "Accedi con un account Modrinth per personalizzare il tuo profilo pubblico."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Account Modrinth richiesto"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "Un nome univoco per identificare il tuo profilo (maiuscole irrilevanti)."
+ },
"settings.sessions.title": {
"defaultMessage": "Sessioni"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "Azioni"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Utente"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Questi sono gli utenti che hai bloccato su Modrinth. Non potranno:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "Non hai bloccato nessuno."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "Impossibile caricare gli utenti bloccati."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "Caricamento utenti bloccati…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "Inviarti richieste di amicizia"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "Invitarti a gestire un server Modrinth Hosting."
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "Invitarti nelle istanze condivise"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "Utenti bloccati"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "Sblocca"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "Impossibile sbloccare l'utente"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "Sì è verificato un errore nello sbloccare l'utente. Riprova più tardi."
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "Sblocca {username}"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "Foto profilo di {username}"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "Controlla chi può inviarti richieste d'amicizia su Modrinth."
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "Richieste di amicizia"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "In arrivo!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "Tutti"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "Amici"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "Amici di amici"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "Nessuno"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "Controlla chi può invitarti alle istanze condivise e pannelli di Modrinth Hosting."
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "Inviti"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "Puoi controllare chi può interagire con te e gestire gli utenti bloccati con un account Modrinth"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Account Modrinth richiesto"
+ },
+ "settings.social.title": {
+ "defaultMessage": "Interazioni"
+ },
"sharing.invite-players-modal.add": {
"defaultMessage": "Aggiungi"
},
@@ -5075,14 +5348,17 @@
"sharing.invite-players-modal.already-invited": {
"defaultMessage": "Quest'utente ha già ricevuto un invito."
},
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "Applica"
+ },
"sharing.invite-players-modal.avatar-alt": {
"defaultMessage": "Foto profilo di {username}"
},
- "sharing.invite-players-modal.cancel": {
- "defaultMessage": "Annulla"
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "Personalizzata..."
},
- "sharing.invite-players-modal.cancel-button": {
- "defaultMessage": "Annulla"
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "Personalizzata: {date}"
},
"sharing.invite-players-modal.edit-invite-link": {
"defaultMessage": "Modifica link d'invito."
@@ -5090,6 +5366,24 @@
"sharing.invite-players-modal.edit-invite-link-title": {
"defaultMessage": "Modifica link di invito"
},
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "In 1 giorno"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "In 1 ora"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "In 7 giorni"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "In 6 ore"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "In 3 giorni"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "In 12 ore"
+ },
"sharing.invite-players-modal.expiry-label": {
"defaultMessage": "Scadenza"
},
@@ -5430,7 +5724,7 @@
"defaultMessage": "SMP"
},
"tag.category.social": {
- "defaultMessage": "Società"
+ "defaultMessage": "Interazione"
},
"tag.category.storage": {
"defaultMessage": "Immagazzinamento"
diff --git a/packages/ui/src/locales/ja-JP/index.json b/packages/ui/src/locales/ja-JP/index.json
index 10ed45ffbf..f80815d161 100644
--- a/packages/ui/src/locales/ja-JP/index.json
+++ b/packages/ui/src/locales/ja-JP/index.json
@@ -1,6 +1,6 @@
{
"action.no-permission": {
- "defaultMessage": "権限がありません"
+ "defaultMessage": "権限がありません。"
},
"affiliate.create.button": {
"defaultMessage": "アフィリエイトリンクを作成"
@@ -449,12 +449,18 @@
"content.diff-modal.added-count": {
"defaultMessage": "{count} 件追加されました"
},
+ "content.diff-modal.config-files-updated": {
+ "defaultMessage": "設定変更"
+ },
"content.diff-modal.diff-type.added": {
"defaultMessage": "追加 (依存関係)"
},
"content.diff-modal.diff-type.removed": {
"defaultMessage": "無効化済み"
},
+ "content.diff-modal.diff-type.removed-disabled": {
+ "defaultMessage": "削除済み(無効)"
+ },
"content.diff-modal.diff-type.updated": {
"defaultMessage": "アップデート済み"
},
@@ -470,12 +476,33 @@
"content.diff-modal.external-diff-type.updated": {
"defaultMessage": "更新されました"
},
+ "content.diff-modal.game-version-updated": {
+ "defaultMessage": "ゲームバージョン変更"
+ },
"content.diff-modal.install-anyway": {
"defaultMessage": "それでもインストールする"
},
+ "content.diff-modal.loader-updated": {
+ "defaultMessage": "Modローダー変更"
+ },
+ "content.diff-modal.modpack-linked": {
+ "defaultMessage": "リンク済みモッドパック"
+ },
+ "content.diff-modal.modpack-unlinked": {
+ "defaultMessage": "未リンクのモッドパック"
+ },
+ "content.diff-modal.modpack-updated": {
+ "defaultMessage": "Modパックのアップデート"
+ },
+ "content.diff-modal.no-content-changes": {
+ "defaultMessage": "変更点なし"
+ },
"content.diff-modal.removed-count": {
"defaultMessage": "{count} 件削除されました"
},
+ "content.diff-modal.removed-disabled-count": {
+ "defaultMessage": "{count}件 削除済み(無効)"
+ },
"content.diff-modal.reviewed-files": {
"defaultMessage": "ファイルは、(.mrpackなどのファイル形式に関係なく)Modrinthに公開されたもののみ審査されます。"
},
@@ -536,6 +563,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "ワールド"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "インストール設定"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "追加のコンテンツ"
},
@@ -959,6 +989,9 @@
"external-files.permissions-card.attribution.moderation-status.passed": {
"defaultMessage": "審査を通りました"
},
+ "external-files.permissions-card.attribution.moderation-status.rejected-proof": {
+ "defaultMessage": "証明が拒否されました"
+ },
"external-files.permissions-card.badge.attributed": {
"defaultMessage": "完了しました"
},
@@ -983,6 +1016,9 @@
"external-files.permissions-card.editor.all-rights-reserved": {
"defaultMessage": "無断転載禁止/ライセンスなし"
},
+ "external-files.permissions-card.editor.custom-license-label": {
+ "defaultMessage": "ライセンスへのリンク"
+ },
"external-files.permissions-card.editor.custom-license-my-project-label": {
"defaultMessage": "ライセンス名はSPDX識別子であることが望ましい"
},
@@ -1019,9 +1055,36 @@
"external-files.permissions-card.editor.notes-placeholder": {
"defaultMessage": "何かここに書いてください..."
},
+ "external-files.permissions-card.editor.proof-image-alt": {
+ "defaultMessage": "証明のスクリーンショット {n}"
+ },
+ "external-files.permissions-card.editor.proof-image-remove": {
+ "defaultMessage": "画像を削除"
+ },
+ "external-files.permissions-card.editor.proof-images-label": {
+ "defaultMessage": "証明画像"
+ },
+ "external-files.permissions-card.editor.proof-images-upload-prompt": {
+ "defaultMessage": "ドラッグ&ドロップしてアップロード、またはクリックして画像を選択"
+ },
+ "external-files.permissions-card.editor.proof-warning.body": {
+ "defaultMessage": "虚偽の申告や画像の改ざんが発覚した場合、プロジェクトの削除およびアカウントの停止措置が取られる可能性があります。"
+ },
+ "external-files.permissions-card.editor.proof-warning.title": {
+ "defaultMessage": "Modrinthスタッフが提出された証明を確認・検証する場合があります"
+ },
+ "external-files.permissions-card.editor.save": {
+ "defaultMessage": "帰属情報を保存"
+ },
"external-files.permissions-card.editor.select-license-label": {
"defaultMessage": "ライセンスを選んでください…"
},
+ "external-files.permissions-card.editor.type-label": {
+ "defaultMessage": "パーミッションの理由"
+ },
+ "external-files.permissions-card.error.custom-license-required": {
+ "defaultMessage": "ライセンスへのリンクを含めてください。ライセンスがない場合は、「All Rights Reserved / ライセンスなし」を選択することをお勧めします。"
+ },
"external-files.permissions-card.error.explanation-or-images-required": {
"defaultMessage": "説明や根拠となる画像を少なくとも一枚提示してください。"
},
@@ -1130,12 +1193,30 @@
"external-files.permissions-card.reason.special-permission.description": {
"defaultMessage": "あなたは、自身のModパックでこの作品を再配布するための特別な許可を得ています。"
},
+ "external-files.permissions-card.remove-group": {
+ "defaultMessage": "グループを削除"
+ },
+ "external-files.permissions-card.remove-group-confirmation.description": {
+ "defaultMessage": "この操作により、この帰属グループとグループ内のすべてのファイルが完全に削除されます。この操作を取り消すことはできません。"
+ },
+ "external-files.permissions-card.remove-group-confirmation.title": {
+ "defaultMessage": "「{title}」を削除しますか?"
+ },
+ "external-files.permissions-card.remove-group-error.title": {
+ "defaultMessage": "グループを削除できませんでした"
+ },
+ "external-files.permissions-card.remove-group-shift-hint": {
+ "defaultMessage": "Shiftキーを押しながらクリックすると確認をスキップします"
+ },
"external-files.permissions-card.split-file": {
"defaultMessage": "グループから削除する"
},
"external-files.permissions-card.split-file-error.title": {
"defaultMessage": "ファイルの分割に失敗"
},
+ "external-files.permissions-card.unnamed-multi-group-title": {
+ "defaultMessage": "{filename} ほか{count}件"
+ },
"external-files.permissions-card.updated-by-moderator": {
"defaultMessage": "モデレーター"
},
@@ -1220,9 +1301,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "保存済み"
},
- "files.editor.find-close": {
- "defaultMessage": "閉じる"
- },
"files.editor.find-in-file": {
"defaultMessage": "検索"
},
@@ -2006,6 +2084,12 @@
"instances.modpack-content-modal.empty-title": {
"defaultMessage": "コンテンツが見つかりません"
},
+ "instances.modpack-content-modal.external-content": {
+ "defaultMessage": "外部"
+ },
+ "instances.modpack-content-modal.external-content-description": {
+ "defaultMessage": "このファイルは Modrinth 上で公開されていません"
+ },
"instances.modpack-content-modal.header": {
"defaultMessage": "Modpackコンテンツ"
},
@@ -2015,6 +2099,9 @@
"instances.modpack-content-modal.no-results": {
"defaultMessage": "該当するプロジェクトがありません。"
},
+ "instances.modpack-content-modal.open-in-slicer": {
+ "defaultMessage": "Slicer で開く"
+ },
"instances.modpack-content-modal.search-placeholder": {
"defaultMessage": "{count, number}件のプロジェクトを検索"
},
@@ -2150,6 +2237,9 @@
"label.details": {
"defaultMessage": "詳細"
},
+ "label.discover-content": {
+ "defaultMessage": "コンテンツを探す"
+ },
"label.done": {
"defaultMessage": "完了"
},
@@ -2228,6 +2318,9 @@
"label.password": {
"defaultMessage": "パスワード"
},
+ "label.permissions": {
+ "defaultMessage": "権限"
+ },
"label.plan-custom": {
"defaultMessage": "カスタム"
},
@@ -2759,9 +2852,90 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Modrinth クリエイター"
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Modrinth ユーザー"
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} はあなたにフレンドリクエストの送信、共有インスタンスへの招待、および Modrinth Hosting サーバーへの招待ができなくなります。"
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "このユーザーをブロックしてもよろしいですか?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "このユーザーのブロック中にエラーが発生しました。もう一度お試しください。"
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "ユーザーのブロックに失敗しました"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} をブロックしました"
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "ユーザーをブロックしました"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "{username} をブロック"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "ユーザーアナリティクスを表示"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "ユーザーの請求情報を管理"
+ },
+ "profile.button.block": {
+ "defaultMessage": "ブロック"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "コレクションを作成"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "プロジェクトを作成"
+ },
+ "profile.button.info": {
+ "defaultMessage": "ユーザーの詳細を表示"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "プロジェクトを管理"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "アフィリエイトから削除"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "アフィリエイトに設定"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "ブロック解除"
+ },
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "Modrinth でのポップアップを許可してから、もう一度お試しください。"
+ },
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "読み込み中…"
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "ユーザーが見つかりません"
+ },
"profile.label.badges": {
"defaultMessage": "バッジ"
},
+ "profile.label.no-projects": {
+ "defaultMessage": "このユーザーはまだプロジェクトがありません!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "まだプロジェクトを何も持っていないようです。"
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "組織"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Modrinth 公式アカウント"
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "ユーザーのブロックを解除しました"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "{date}に公開済み"
},
@@ -2780,9 +2954,15 @@
"project-card.environment.server": {
"defaultMessage": "サーバー"
},
+ "project-card.environment.singleplayer": {
+ "defaultMessage": "シングルプレイヤー"
+ },
"project-type.all": {
"defaultMessage": "すべて"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "コレクション"
+ },
"project-type.datapack.capital": {
"defaultMessage": "データパック"
},
@@ -3641,9 +3821,54 @@
"servers.access-page.activity-log-filter.action-types": {
"defaultMessage": "アクション"
},
+ "servers.access-page.activity-log-filter.action.addon-disabled": {
+ "defaultMessage": "無効化されたコンテンツ"
+ },
+ "servers.access-page.activity-log-filter.action.addon-enabled": {
+ "defaultMessage": "有効化されたコンテンツ"
+ },
+ "servers.access-page.activity-log-filter.action.addon-updated": {
+ "defaultMessage": "更新されたコンテンツ"
+ },
+ "servers.access-page.activity-log-filter.action.addon-uploaded": {
+ "defaultMessage": "アップロードされたコンテンツ"
+ },
+ "servers.access-page.activity-log-filter.action.backup-created": {
+ "defaultMessage": "バックアップを作成しました"
+ },
"servers.access-page.activity-log-filter.action.backup-deleted": {
"defaultMessage": "削除されたバックアップ"
},
+ "servers.access-page.activity-log-filter.action.backup-renamed": {
+ "defaultMessage": "バックアップの名前を変更しました"
+ },
+ "servers.access-page.activity-log-filter.action.backup-restored": {
+ "defaultMessage": "バックアップを復元しました"
+ },
+ "servers.access-page.activity-log-filter.action.changed-server-name": {
+ "defaultMessage": "サーバー名を変更しました"
+ },
+ "servers.access-page.activity-log-filter.action.changed-server-subdomain": {
+ "defaultMessage": "サーバーのサブドメインを変更しました"
+ },
+ "servers.access-page.activity-log-filter.action.console-cleared": {
+ "defaultMessage": "コンソールをクリアしました"
+ },
+ "servers.access-page.activity-log-filter.action.console-command-executed": {
+ "defaultMessage": "コンソールコマンドを実行しました"
+ },
+ "servers.access-page.activity-log-filter.action.file-deleted": {
+ "defaultMessage": "ファイルを削除しました"
+ },
+ "servers.access-page.activity-log-filter.action.file-edited": {
+ "defaultMessage": "ファイルを編集しました"
+ },
+ "servers.access-page.activity-log-filter.action.file-renamed": {
+ "defaultMessage": "ファイル名を変更しました"
+ },
+ "servers.access-page.activity-log-filter.action.file-uploaded": {
+ "defaultMessage": "ファイルをアップロードしました"
+ },
"servers.access-page.activity-log-filter.action.game-version-edited": {
"defaultMessage": "Minecraftのバージョンを変更しました"
},
@@ -3950,6 +4175,93 @@
"servers.audit-log.event.config-changed": {
"defaultMessage": "サーバーの設定が変更されました"
},
+ "servers.audit-log.event.console-cleared": {
+ "defaultMessage": "コンソールをクリアしました"
+ },
+ "servers.audit-log.event.console-command-executed": {
+ "defaultMessage": "コンソールコマンド「 」を実行しました"
+ },
+ "servers.audit-log.event.entity-list.hidden-count": {
+ "defaultMessage": "+{count, number}"
+ },
+ "servers.audit-log.event.file-changed": {
+ "defaultMessage": "ファイル「 」を変更しました"
+ },
+ "servers.audit-log.event.file-deleted": {
+ "defaultMessage": "ファイル「 」を削除しました"
+ },
+ "servers.audit-log.event.file-edited": {
+ "defaultMessage": "ファイル「 」を編集しました"
+ },
+ "servers.audit-log.event.file-renamed": {
+ "defaultMessage": "「 」の名前を「 」に変更しました"
+ },
+ "servers.audit-log.event.file-uploaded": {
+ "defaultMessage": " をアップロードしました"
+ },
+ "servers.audit-log.event.game-version-changed": {
+ "defaultMessage": "Minecraftのバージョンを に変更しました"
+ },
+ "servers.audit-log.event.java-runtime-modified": {
+ "defaultMessage": "Javaの実行環境を に変更しました"
+ },
+ "servers.audit-log.event.java-version-modified": {
+ "defaultMessage": "Javaのバージョンを に変更しました"
+ },
+ "servers.audit-log.event.loader-and-version-changed": {
+ "defaultMessage": "ローダーを に変更しました"
+ },
+ "servers.audit-log.event.loader-changed": {
+ "defaultMessage": "ローダーを に変更しました"
+ },
+ "servers.audit-log.event.loader-version-changed": {
+ "defaultMessage": "ローダーのバージョンを に変更しました"
+ },
+ "servers.audit-log.event.loader-version-cleared": {
+ "defaultMessage": "ローダーのバージョン設定を消去しました"
+ },
+ "servers.audit-log.event.modpack-changed": {
+ "defaultMessage": "モッドパックを変更しました"
+ },
+ "servers.audit-log.event.modpack-changed-to-modpack": {
+ "defaultMessage": "モッドパックを に変更しました"
+ },
+ "servers.audit-log.event.modpack-changed-to-version": {
+ "defaultMessage": "モッドパックのバージョンを に変更しました"
+ },
+ "servers.audit-log.event.modpack-unlinked": {
+ "defaultMessage": "モッドパックの連携を解除しました"
+ },
+ "servers.audit-log.event.modpack-unlinked-modpack": {
+ "defaultMessage": "モッドパック の連携を解除しました"
+ },
+ "servers.audit-log.event.modpack-unlinked-version": {
+ "defaultMessage": "モッドパックのバージョン の連携を解除しました"
+ },
+ "servers.audit-log.event.port-allocation-added": {
+ "defaultMessage": "ポート割り当て を追加しました"
+ },
+ "servers.audit-log.event.port-allocation-removed": {
+ "defaultMessage": "ポート割り当て を削除しました"
+ },
+ "servers.audit-log.event.server-created": {
+ "defaultMessage": "サーバーを作成しました"
+ },
+ "servers.audit-log.event.server-killed": {
+ "defaultMessage": "サーバーを強制終了しました"
+ },
+ "servers.audit-log.event.server-metadata-changed": {
+ "defaultMessage": "サーバーのメタデータを変更しました"
+ },
+ "servers.audit-log.event.server-name-changed": {
+ "defaultMessage": "サーバー名を に変更しました"
+ },
+ "servers.audit-log.event.server-plan-changed": {
+ "defaultMessage": "プランを に変更しました"
+ },
+ "servers.audit-log.event.server-plan.new-plan": {
+ "defaultMessage": "新しいプラン"
+ },
"servers.audit-log.event.server-plan.ram-gb": {
"defaultMessage": "メモリ {amount, number} GB"
},
@@ -3962,6 +4274,21 @@
"servers.audit-log.event.server-plan.storage-mb": {
"defaultMessage": "ストレージ {amount, number} MB"
},
+ "servers.audit-log.event.server-properties-modified": {
+ "defaultMessage": "サーバープロパティ を変更しました"
+ },
+ "servers.audit-log.event.server-properties-modified-label": {
+ "defaultMessage": "サーバープロパティを変更しました"
+ },
+ "servers.audit-log.event.server-reallocated": {
+ "defaultMessage": "サーバーの割り当てを変更しました"
+ },
+ "servers.audit-log.event.server-repaired": {
+ "defaultMessage": "サーバーを修復しました"
+ },
+ "servers.audit-log.event.server-reset": {
+ "defaultMessage": "サーバーをリセットしました"
+ },
"servers.audit-log.scope.server": {
"defaultMessage": "サーバー"
},
@@ -4292,15 +4619,66 @@
"servers.listing.notice.pending-change": {
"defaultMessage": "あなたのサーバーは {formattedDate} に {planSize} へと {verb, select, downgrade {ダウングレード} other {アップグレード}} されます。"
},
+ "servers.listing.support-label": {
+ "defaultMessage": "サポート"
+ },
+ "servers.manage.new-server-button": {
+ "defaultMessage": "新しいサーバー"
+ },
+ "servers.manage.no-servers-found": {
+ "defaultMessage": "サーバーは見つかりませんでした。"
+ },
"servers.manage.reload-button": {
"defaultMessage": "再読み込み"
},
+ "servers.manage.resubscribe-submitted.text": {
+ "defaultMessage": "現在サーバーがキャンセルされている場合、再課金の試行までに最大10分ほどかかることがあります。"
+ },
+ "servers.manage.resubscribe-submitted.title": {
+ "defaultMessage": "再購読のリクエストを送信しました"
+ },
+ "servers.manage.resubscribe-success.text": {
+ "defaultMessage": "サーバーのサブスクリプションが完了しました"
+ },
+ "servers.manage.resubscribe-success.title": {
+ "defaultMessage": "成功"
+ },
+ "servers.manage.servers-title": {
+ "defaultMessage": "Modrinth ホスティング"
+ },
+ "servers.manage.settings-hint.description": {
+ "defaultMessage": "こちらに移動しました!"
+ },
+ "servers.manage.settings-hint.dismiss": {
+ "defaultMessage": "次回から表示しない"
+ },
+ "servers.manage.settings-hint.title": {
+ "defaultMessage": "サーバー設定の場所が移動しました"
+ },
+ "servers.manage.shared-servers-title": {
+ "defaultMessage": "共有サーバー"
+ },
"servers.manage.your-servers-title": {
"defaultMessage": "あなたのサーバー"
},
"servers.medal-listing.new-server-label": {
"defaultMessage": "新しいサーバー"
},
+ "servers.medal-listing.notice.medal-trial-ended": {
+ "defaultMessage": "Medalサーバーの試用期間が終了し、サーバーがサスペンド(停止)されました。サーバーを引き続き利用するにはアップグレードしてください。"
+ },
+ "servers.medal-listing.notice.suspended": {
+ "defaultMessage": "サーバーがサスペンド(停止)されました。請求情報を更新するか、詳細は Modrinth サポートにお問い合わせください。"
+ },
+ "servers.medal-listing.notice.suspended-with-reason": {
+ "defaultMessage": "サーバーがサスペンド(停止)されました: {reason}。請求情報を更新するか、詳細は Modrinth サポートにお問い合わせください。"
+ },
+ "servers.medal-listing.notice.upgrading": {
+ "defaultMessage": "サーバーのハードウェアをアップグレード中です。まもなくオンラインに戻ります。"
+ },
+ "servers.medal-listing.owner-avatar-alt": {
+ "defaultMessage": "{username} のアバター"
+ },
"servers.medal-listing.owner-tooltip": {
"defaultMessage": "{username}によって所有されています"
},
@@ -4355,9 +4733,15 @@
"servers.purchase.step.payment.title": {
"defaultMessage": "支払い方法"
},
+ "servers.purchase.step.plan.billing-subtitle": {
+ "defaultMessage": "北米、ヨーロッパ、東南アジアでご利用いただけます。"
+ },
"servers.purchase.step.plan.custom.desc": {
"defaultMessage": "必要な仕様だけのカスタマイズされたプランを選択。"
},
+ "servers.purchase.step.plan.custom.heading": {
+ "defaultMessage": "必要なものがお決まりですか?"
+ },
"servers.purchase.step.plan.get-started": {
"defaultMessage": "始めましょう"
},
@@ -4388,6 +4772,9 @@
"servers.purchase.step.plan.title": {
"defaultMessage": "プラン"
},
+ "servers.purchase.step.plan.your-current-plan": {
+ "defaultMessage": "現在のプラン"
+ },
"servers.purchase.step.region.title": {
"defaultMessage": "地域"
},
@@ -4427,12 +4814,99 @@
"servers.region.western-europe": {
"defaultMessage": "西ヨーロッパ"
},
+ "servers.remove-access-modal.added-label": {
+ "defaultMessage": "{time} に追加済み"
+ },
+ "servers.remove-access-modal.cancel-button": {
+ "defaultMessage": "招待を取り消す"
+ },
+ "servers.remove-access-modal.cancel-effect-access": {
+ "defaultMessage": "このサーバーには追加されません"
+ },
+ "servers.remove-access-modal.cancel-effect-invite": {
+ "defaultMessage": "あとから再度招待を送ることもできます"
+ },
+ "servers.remove-access-modal.cancel-header": {
+ "defaultMessage": "招待を取り消す"
+ },
+ "servers.remove-access-modal.cancel-warning-body": {
+ "defaultMessage": "この招待を取り消すと、{username} がこのサーバーに参加するには新しい招待が必要になります。"
+ },
+ "servers.remove-access-modal.header": {
+ "defaultMessage": "アクセス権を取り消す"
+ },
+ "servers.remove-access-modal.invited-label": {
+ "defaultMessage": "{time} に招待済み"
+ },
+ "servers.remove-access-modal.pending-invite-label": {
+ "defaultMessage": "保留中の招待"
+ },
+ "servers.remove-access-modal.remove-button": {
+ "defaultMessage": "アクセス権を取り消す"
+ },
+ "servers.remove-access-modal.remove-effect-access": {
+ "defaultMessage": "サーバーパネルへのアクセス権が即座に無効化され、コンテンツの編集ができなくなります"
+ },
+ "servers.remove-access-modal.remove-effect-join": {
+ "defaultMessage": "個別に設定を変更しない限り、ユーザーは引き続きサーバーに参加してプレイすることができます"
+ },
+ "servers.remove-access-modal.unknown-added-label": {
+ "defaultMessage": "追加日不明"
+ },
+ "servers.remove-access-modal.user-avatar-alt": {
+ "defaultMessage": "{username} のアバター"
+ },
+ "servers.remove-access-modal.warning-body": {
+ "defaultMessage": "ユーザーのサーバーアクセス権を取り消した場合、アクセスを復元するには再度招待し直す必要があります。"
+ },
+ "servers.remove-access-modal.what-happens-label": {
+ "defaultMessage": "どうなるの?"
+ },
+ "servers.setup.onboarding.installation-failed.text": {
+ "defaultMessage": "インストール中に予期しないエラーが発生しました。時間をおいて再度お試しください。"
+ },
+ "servers.setup.onboarding.installation-failed.title": {
+ "defaultMessage": "インストールの失敗"
+ },
+ "servers.setup.onboarding.modpack-upload-failed.text": {
+ "defaultMessage": "アップロード中に予期しないエラーが発生しました。時間をおいて再度お試しください。"
+ },
+ "servers.setup.onboarding.modpack-upload-failed.title": {
+ "defaultMessage": "モッドパックのアップロード失敗"
+ },
"servers.setup.onboarding.setup-server.button": {
"defaultMessage": "サーバーをセットアップ"
},
+ "servers.setup.onboarding.step.choose.description": {
+ "defaultMessage": "Modrinthからお気に入りのモッドパックを選ぶか、ローダーを選択して好きなModを追加してください"
+ },
+ "servers.setup.onboarding.step.choose.title": {
+ "defaultMessage": "プレイするものを選ぶ"
+ },
+ "servers.setup.onboarding.step.configure-world.description": {
+ "defaultMessage": "シングルプレイと同じようにワールドを設定できます。ゲームモードとワールドシード値を選択してください"
+ },
+ "servers.setup.onboarding.step.configure-world.title": {
+ "defaultMessage": "ワールドを設定する"
+ },
+ "servers.setup.onboarding.step.invite-friends.description": {
+ "defaultMessage": "アドレスをコピーして友達に共有し、参加に必要なModを教えてあげましょう"
+ },
"servers.setup.onboarding.step.invite-friends.title": {
"defaultMessage": "フレンドを招待"
},
+ "servers.setup.onboarding.steps.heading": {
+ "defaultMessage": "サーバーをセットアップする(約2分)"
+ },
+ "servers.setup.onboarding.uploading.progress": {
+ "defaultMessage": "アップロード中 ({percent, number}%)"
+ },
+ "servers.setup.onboarding.welcome.description": {
+ "defaultMessage": "サーバーの準備が完了しました。プレイを開始する手順は以下の通りです!"
+ },
+ "servers.setup.onboarding.welcome.title": {
+ "defaultMessage": "Modrinth ホスティングへようこそ"
+ },
"servers.setup.rate-limit.text": {
"defaultMessage": "レート制限に達しました。時間をおいて再試行してください。"
},
@@ -4493,6 +4967,9 @@
"settings.display.theme.title": {
"defaultMessage": "カラーテーマ"
},
+ "settings.feature-flags.title": {
+ "defaultMessage": "機能フラグ"
+ },
"settings.language.categories.default": {
"defaultMessage": "一般的な言語"
},
@@ -4526,9 +5003,57 @@
"settings.pats.title": {
"defaultMessage": "個人用アクセストークン"
},
+ "settings.profile.bio.title": {
+ "defaultMessage": "自己紹介"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "プロファイル"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "プロファイルアイコン"
+ },
"settings.sessions.title": {
"defaultMessage": "セッション"
},
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "ブロックを解除"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "近日公開!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "全員"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "フレンド"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "フレンドのフレンド"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "なし"
+ },
+ "sharing.invite-players-modal.add": {
+ "defaultMessage": "追加"
+ },
+ "sharing.invite-players-modal.added": {
+ "defaultMessage": "追加済み"
+ },
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "適用"
+ },
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "カスタム…"
+ },
+ "sharing.invite-players-modal.friends-heading": {
+ "defaultMessage": "あなたのフレンド - {count} 人"
+ },
+ "sharing.invite-players-modal.invite": {
+ "defaultMessage": "招待"
+ },
+ "sharing.invite-players-modal.save-button": {
+ "defaultMessage": "保存"
+ },
"tag.category.128x": {
"defaultMessage": "128x"
},
@@ -4998,16 +5523,16 @@
"defaultMessage": "一般的にマルウェアは、Discord等のプラットフォーム上でModファイルを配布して拡散されます"
},
"user.profile.badge.alpha.about.1": {
- "defaultMessage": "2020年11月までのModrinthがAlpha版だった頃から活動しています"
+ "defaultMessage": "2020年11月までのModrinthがAlpha版の頃から活動しています"
},
"user.profile.badge.alpha.name": {
"defaultMessage": "Alpha Tester"
},
"user.profile.badge.beta.about.1": {
- "defaultMessage": "2022年2月までのModrinthがBeta版だった頃から活動しています"
+ "defaultMessage": "2022年2月までのModrinthがBeta版の頃から活動しています"
},
"user.profile.badge.beta.link": {
- "defaultMessage": "クリックすると、ModrinthのBeta版のリリース記事を読むことができます。"
+ "defaultMessage": "クリックするとModrinthのBeta版リリース記事を読むことができます"
},
"user.profile.badge.beta.name": {
"defaultMessage": "Beta Tester"
@@ -5021,6 +5546,12 @@
"user.profile.badge.moderator.name": {
"defaultMessage": "コンテンツモデレーター"
},
+ "user.profile.badge.plus.about.1": {
+ "defaultMessage": "Modrinthとクリエイターに特別なサポートを贈っています!"
+ },
+ "user.profile.badge.plus.link": {
+ "defaultMessage": "クリックしてModrinth+のメンバーになる方法を知る"
+ },
"user.profile.badge.plus.name": {
"defaultMessage": "Modrinth+ Member"
},
@@ -5045,6 +5576,9 @@
"version.section.content.search-placeholder": {
"defaultMessage": "コンテンツを検索…"
},
+ "version.section.dependencies.any-version": {
+ "defaultMessage": "すべてのバージョン"
+ },
"version.section.files": {
"defaultMessage": "ファイル"
},
diff --git a/packages/ui/src/locales/ko-KR/index.json b/packages/ui/src/locales/ko-KR/index.json
index 33db6fadd9..7ce577da9e 100644
--- a/packages/ui/src/locales/ko-KR/index.json
+++ b/packages/ui/src/locales/ko-KR/index.json
@@ -377,6 +377,9 @@
"content.confirm-deletion.header": {
"defaultMessage": "{itemType} 삭제"
},
+ "content.confirm-disable.header": {
+ "defaultMessage": "{itemType} 비활성화"
+ },
"content.confirm-modpack-update.admonition-body": {
"defaultMessage": "{action, select, downgrade {다운그레이드 진행 중} other {업데이트 진행 중}}에는 호환성 문제가 발생할 수 있습니다. 모드팩에 추가한 모드나 콘텐츠는 유지되지만, 새 버전과 호환되지 않을 수 있습니다."
},
@@ -446,12 +449,18 @@
"content.diff-modal.added-count": {
"defaultMessage": "{count}개 추가됨"
},
+ "content.diff-modal.config-files-updated": {
+ "defaultMessage": "변경된 설정 파일"
+ },
"content.diff-modal.diff-type.added": {
"defaultMessage": "추가됨 (종속성)"
},
"content.diff-modal.diff-type.removed": {
"defaultMessage": "비활성화"
},
+ "content.diff-modal.diff-type.removed-disabled": {
+ "defaultMessage": "제거됨 (비활성화됨)"
+ },
"content.diff-modal.diff-type.updated": {
"defaultMessage": "업데이트됨"
},
@@ -467,12 +476,36 @@
"content.diff-modal.external-diff-type.updated": {
"defaultMessage": "업데이트됨"
},
+ "content.diff-modal.file-count": {
+ "defaultMessage": "{count, plural, one {#개 파일} other {#개 파일}}"
+ },
+ "content.diff-modal.game-version-updated": {
+ "defaultMessage": "게임 버전"
+ },
"content.diff-modal.install-anyway": {
"defaultMessage": "무시하고 설치"
},
+ "content.diff-modal.loader-updated": {
+ "defaultMessage": "로더"
+ },
+ "content.diff-modal.modpack-linked": {
+ "defaultMessage": "연동된 모드팩"
+ },
+ "content.diff-modal.modpack-unlinked": {
+ "defaultMessage": "연동 해제된 모드팩"
+ },
+ "content.diff-modal.modpack-updated": {
+ "defaultMessage": "업데이트된 모드팩"
+ },
+ "content.diff-modal.no-content-changes": {
+ "defaultMessage": "콘텐츠 변경 사항 없음"
+ },
"content.diff-modal.removed-count": {
"defaultMessage": "{count}개 제거됨"
},
+ "content.diff-modal.removed-disabled-count": {
+ "defaultMessage": "{count} 제거됨 (비활성화됨)"
+ },
"content.diff-modal.reviewed-files": {
"defaultMessage": "모든 파일은 형식(.mrpack 포함)에 무관하게 Modrinth에 게시되어야만 검수를 거칩니다."
},
@@ -533,6 +566,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "세계"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "설치 설정"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "추가 콘텐츠"
},
@@ -1160,6 +1196,21 @@
"external-files.permissions-card.reason.special-permission.description": {
"defaultMessage": "이 작업물을 모드팩에 재배포할 수 있는 특별 허가를 받았습니다."
},
+ "external-files.permissions-card.remove-group": {
+ "defaultMessage": "그룹 삭제"
+ },
+ "external-files.permissions-card.remove-group-confirmation.description": {
+ "defaultMessage": "이 작업은 해당 출처 표시 그룹 및 내부의 모든 파일을 영구 삭제합니다. 이 작업은 되돌릴 수 없습니다."
+ },
+ "external-files.permissions-card.remove-group-confirmation.title": {
+ "defaultMessage": "{title}를 삭제하시겠습니까?"
+ },
+ "external-files.permissions-card.remove-group-error.title": {
+ "defaultMessage": "그룹을 삭제할 수 없습니다"
+ },
+ "external-files.permissions-card.remove-group-shift-hint": {
+ "defaultMessage": "Shift 키를 누른 채 클릭하면 확인 절차를 생략합니다."
+ },
"external-files.permissions-card.split-file": {
"defaultMessage": "그룹에서 제거"
},
@@ -1253,9 +1304,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "파일 저장됨"
},
- "files.editor.find-close": {
- "defaultMessage": "닫다"
- },
"files.editor.find-in-file": {
"defaultMessage": "찾다"
},
@@ -2039,6 +2087,12 @@
"instances.modpack-content-modal.empty-title": {
"defaultMessage": "콘텐츠를 찾을 수 없습니다"
},
+ "instances.modpack-content-modal.external-content": {
+ "defaultMessage": "외부"
+ },
+ "instances.modpack-content-modal.external-content-description": {
+ "defaultMessage": "이 파일은 Modrinth에 게시되지 않았습니다."
+ },
"instances.modpack-content-modal.header": {
"defaultMessage": "모드팩 콘텐츠"
},
@@ -2048,6 +2102,9 @@
"instances.modpack-content-modal.no-results": {
"defaultMessage": "검색 결과와 일치하는 프로젝트가 없습니다."
},
+ "instances.modpack-content-modal.open-in-slicer": {
+ "defaultMessage": "Slicer에서 열기"
+ },
"instances.modpack-content-modal.search-placeholder": {
"defaultMessage": "{count, number}개의 프로젝트 검색"
},
@@ -2183,6 +2240,9 @@
"label.details": {
"defaultMessage": "세부 사항"
},
+ "label.discover-content": {
+ "defaultMessage": "콘텐츠 둘러보기"
+ },
"label.done": {
"defaultMessage": "완료"
},
@@ -2261,6 +2321,9 @@
"label.password": {
"defaultMessage": "비밀번호"
},
+ "label.permissions": {
+ "defaultMessage": "권한"
+ },
"label.plan-custom": {
"defaultMessage": "사용자 지정"
},
@@ -2792,9 +2855,147 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Modrinth 크리에이터입니다."
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Modrinth 사용자입니다."
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} 님은 친구 요청을 보내거나, 공유 인스턴스 초대 및 Modrinth Hosting 서버 초대를 할 수 없게 됩니다."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "이 사용자를 차단하시겠습니까?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "이 사용자를 차단하는 중 오류가 발생했습니다. 다시 시도해 주세요."
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "사용자 차단 실패"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} 님을 차단했습니다."
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "사용자 차단됨"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "{username} 차단"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "사용자 분석 보기"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "사용자 결제 관리"
+ },
+ "profile.button.block": {
+ "defaultMessage": "차단"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "컬렉션 만들기"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "프로젝트 만들기"
+ },
+ "profile.button.info": {
+ "defaultMessage": "사용자 상세 정보 보기"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "프로젝트 관리"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "제휴 자격 해제"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "제휴 자격 부여"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "차단 해제"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural, one {프로젝트 #개} other {프로젝트 #개}}"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "인증 제공자"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "이메일 인증됨"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "비밀번호 설정됨"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "TOTP 설정됨"
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "결제 수단"
+ },
+ "profile.details.title": {
+ "defaultMessage": "사용자 상세 정보"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "이메일 미인증"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "이메일 인증됨"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "사용자 프로필을 불러올 수 없습니다."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "사용자를 찾을 수 없음"
+ },
+ "profile.label.affiliate": {
+ "defaultMessage": "제휴 파트너"
+ },
"profile.label.badges": {
"defaultMessage": "배지"
},
+ "profile.label.collection": {
+ "defaultMessage": "컬렉션"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, other {다운로드}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "가입일"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "이 사용자는 컬렉션이 없습니다!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "아직 컬렉션이 없습니다."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "이 사용자는 프로젝트가 없습니다!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "아직 프로젝트가 없습니다."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "조직"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural, other {프로젝트}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "공식 Modrinth 계정"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "Modrinth의 공식 사용자 계정입니다. 또는 을 통해 문의해 주세요"
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "이 사용자의 차단을 해제하는 동안 오류가 발생했습니다. 다시 시도해 주세요."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "사용자 차단 해제 실패"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "{username}님의 차단이 해제되었습니다."
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "사용자 차단 해제됨"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "{date}에 게시됨"
},
@@ -2810,12 +3011,21 @@
"project-card.environment.client-or-server": {
"defaultMessage": "클라이언트 또는 서버"
},
+ "project-card.environment.dedicated-server": {
+ "defaultMessage": "전용 서버"
+ },
"project-card.environment.server": {
"defaultMessage": "서버"
},
+ "project-card.environment.singleplayer": {
+ "defaultMessage": "싱글플레이어"
+ },
"project-type.all": {
"defaultMessage": "모두"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "컬렉션"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, other {데이터 팩}}"
},
@@ -5039,9 +5249,216 @@
"settings.pats.title": {
"defaultMessage": "개인 액세스 토큰"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "자신을 알릴 수 있는 간단한 소개글입니다."
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "자기소개"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "프로필"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "프로필 사진"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "프로필 정보는 Modrinth에서 누구나 볼 수 있게 공개 되며, Modrinth API 를 통해서도 확인할 수 있습니다."
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "프로필 업데이트 실패"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "프로필을 업데이트하는 동안 오류가 발생했습니다. 다시 시도해 주세요."
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "공개 프로필을 맞춤 설정하려면 Modrinth 계정에 로그인하세요."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Modrinth 계정 필요"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "프로필을 식별하기 위한 대소문자 구분 없는 고유한 이름입니다."
+ },
"settings.sessions.title": {
"defaultMessage": "세션"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "작업"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "사용자"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Modrinth에서 차단한 사용자 목록입니다. 해당 사용자는 다음 행위를 할 수 없습니다:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "차단한 사용자가 없습니다."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "차단된 사용자 목록을 불러올 수 없습니다."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "차단된 사용자 목록 불러오는 중…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "나에게 친구 요청 전송"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "Modrinth 호스팅 서버 관리 초대."
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "공유 인스턴스에 초대"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "차단된 사용자"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "차단 해제"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "사용자 차단 해제 실패"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "이 사용자의 차단을 해제하는 중 오류가 발생했습니다. 다시 시도해 주세요."
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "{username} 차단 해제"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "{username} 님의 아바타"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "Modrinth에서 본인에게 친구 요청을 보낼 수 있는 사람을 설정합니다."
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "친구 요청"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "곧 제공할 예정입니다!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "모든 사람"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "친구"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "친구의 친구"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "아무도 없음"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "공유 인스턴스 및 Modrinth Hosting 패널 초대를 보낼 수 있는 사람을 설정합니다."
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "초대"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "Modrinth 계정이 있으면 본인과 소통 가능한 사람을 설정하고 차단된 사용자를 관리할 수 있습니다"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Modrinth 계정이 필요합니다"
+ },
+ "settings.social.title": {
+ "defaultMessage": "소셜"
+ },
+ "sharing.invite-players-modal.add": {
+ "defaultMessage": "추가"
+ },
+ "sharing.invite-players-modal.added": {
+ "defaultMessage": "추가됨"
+ },
+ "sharing.invite-players-modal.already-invited": {
+ "defaultMessage": "이 사용자는 이미 초대되었습니다."
+ },
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "선택"
+ },
+ "sharing.invite-players-modal.avatar-alt": {
+ "defaultMessage": "{username} 님의 아바타"
+ },
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "커스텀..."
+ },
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "커스텀: {date}"
+ },
+ "sharing.invite-players-modal.edit-invite-link": {
+ "defaultMessage": "초대 링크 수정."
+ },
+ "sharing.invite-players-modal.edit-invite-link-title": {
+ "defaultMessage": "초대 링크 수정"
+ },
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "1일 후"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "1시간 후"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "7일 후"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "6시간 후"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "3일 후"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "12시간 후"
+ },
+ "sharing.invite-players-modal.expiry-label": {
+ "defaultMessage": "만료일"
+ },
+ "sharing.invite-players-modal.friends-heading": {
+ "defaultMessage": "당신의 친구 - {count}"
+ },
+ "sharing.invite-players-modal.invite": {
+ "defaultMessage": "초대"
+ },
+ "sharing.invite-players-modal.invite-expiry-description": {
+ "defaultMessage": "초대 링크는 {duration} 후 만료됩니다."
+ },
+ "sharing.invite-players-modal.invite-link-heading": {
+ "defaultMessage": "또는 초대 링크 사용"
+ },
+ "sharing.invite-players-modal.link-copied-text": {
+ "defaultMessage": "초대 링크가 클립보드에 복사되었습니다."
+ },
+ "sharing.invite-players-modal.link-copied-title": {
+ "defaultMessage": "링크 복사됨"
+ },
+ "sharing.invite-players-modal.link-copy-failed-title": {
+ "defaultMessage": "링크 복사 실패"
+ },
+ "sharing.invite-players-modal.max-uses-label": {
+ "defaultMessage": "최대 사용 횟수"
+ },
+ "sharing.invite-players-modal.no-friends": {
+ "defaultMessage": "친구가 없습니다."
+ },
+ "sharing.invite-players-modal.no-search-results": {
+ "defaultMessage": "일치하는 사용자를 찾을 수 없습니다."
+ },
+ "sharing.invite-players-modal.requested": {
+ "defaultMessage": "요청 전송됨"
+ },
+ "sharing.invite-players-modal.requested-tooltip": {
+ "defaultMessage": "{username}님이 먼저 친구 요청을 수락해야 합니다"
+ },
+ "sharing.invite-players-modal.save-button": {
+ "defaultMessage": "저장"
+ },
+ "sharing.invite-players-modal.search-placeholder": {
+ "defaultMessage": "Modrinth 사용자 이름 입력"
+ },
+ "sharing.invite-players-modal.searching": {
+ "defaultMessage": "검색 중..."
+ },
+ "sharing.invite-players-modal.update-invite-link-failed-title": {
+ "defaultMessage": "초대 링크 업데이트 실패"
+ },
"tag.category.128x": {
"defaultMessage": "128x"
},
diff --git a/packages/ui/src/locales/ms-MY/index.json b/packages/ui/src/locales/ms-MY/index.json
index 26c129ef81..225cb67d6c 100644
--- a/packages/ui/src/locales/ms-MY/index.json
+++ b/packages/ui/src/locales/ms-MY/index.json
@@ -386,6 +386,9 @@
"content.diff-modal.diff-type.updated": {
"defaultMessage": "Dikemas Kini"
},
+ "content.diff-modal.external-diff-type.added": {
+ "defaultMessage": "Ditambah"
+ },
"content.diff-modal.removed-count": {
"defaultMessage": "{count} dialih keluar"
},
@@ -911,9 +914,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Fail disimpan"
},
- "files.editor.find-close": {
- "defaultMessage": "Tutup"
- },
"files.editor.find-in-file": {
"defaultMessage": "Cari"
},
@@ -2402,6 +2402,9 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.button.block": {
+ "defaultMessage": "Sekat"
+ },
"profile.label.badges": {
"defaultMessage": "Lencana"
},
@@ -4442,9 +4445,27 @@
"settings.pats.title": {
"defaultMessage": "Token akses peribadi"
},
+ "settings.profile.bio.title": {
+ "defaultMessage": "Bio"
+ },
"settings.sessions.title": {
"defaultMessage": "Sesi"
},
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Pengguna"
+ },
+ "sharing.invite-players-modal.add": {
+ "defaultMessage": "Tambah"
+ },
+ "sharing.invite-players-modal.added": {
+ "defaultMessage": "Ditambah"
+ },
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "Terapkan"
+ },
+ "sharing.invite-players-modal.save-button": {
+ "defaultMessage": "Simpan"
+ },
"tag.category.128x": {
"defaultMessage": "128x"
},
@@ -5034,3 +5055,4 @@
"defaultMessage": "Jenis"
}
}
+
diff --git a/packages/ui/src/locales/nl-NL/index.json b/packages/ui/src/locales/nl-NL/index.json
index 12973c623a..44ed5407ee 100644
--- a/packages/ui/src/locales/nl-NL/index.json
+++ b/packages/ui/src/locales/nl-NL/index.json
@@ -3,22 +3,22 @@
"defaultMessage": "Je hebt geen toestemming."
},
"affiliate.create.button": {
- "defaultMessage": "Maak een affiliatelink"
+ "defaultMessage": "Partnerlink aanmaken"
},
"affiliate.create.header": {
- "defaultMessage": "Nieuwe affiliate aanmaken"
+ "defaultMessage": "Nieuwe partnercode aanmaken"
},
"affiliate.create.title.description": {
- "defaultMessage": "Geef je affiliate-link een naam, zodat je weet waar mensen vandaan komen!"
+ "defaultMessage": "Geef je partnerlink een naam, zodat je weet waar mensen vandaan komen!"
},
"affiliate.create.title.label": {
- "defaultMessage": "Titel van affiliate-link"
+ "defaultMessage": "Titel van de partnerlink"
},
"affiliate.create.title.placeholder": {
- "defaultMessage": "bijvoorbeeld YouTube"
+ "defaultMessage": "bijv. YouTube"
},
"affiliate.create.user.description": {
- "defaultMessage": "De gebruikersnaam van de gebruiker voor wie de affiliatecode moet worden aangemaakt"
+ "defaultMessage": "De gebruikersnaam van de gebruiker voor wie de partnercode moet worden aangemaakt"
},
"affiliate.create.user.placeholder": {
"defaultMessage": "Voer gebruikersnaam in..."
@@ -27,13 +27,13 @@
"defaultMessage": "Gemaakt door {user}"
},
"affiliate.creating.button": {
- "defaultMessage": "Affiliate-link maken..."
+ "defaultMessage": "Partnerlink maken..."
},
"affiliate.revoke": {
- "defaultMessage": "Affiliatie-link intrekken"
+ "defaultMessage": "Partnerlink intrekken"
},
"affiliate.viewAnalytics": {
- "defaultMessage": "Bekijk analyses"
+ "defaultMessage": "Statistieken bekijken"
},
"app.server-settings.failed-to-load-server": {
"defaultMessage": "Serverinstellingen konden niet worden geladen"
@@ -135,7 +135,7 @@
"defaultMessage": "Voeg server toevoegen aan instantie"
},
"button.affiliate-links": {
- "defaultMessage": "Affiliatelinks"
+ "defaultMessage": "Partnerlinks"
},
"button.analytics": {
"defaultMessage": "Analytica"
@@ -566,6 +566,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "wereld"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "Installatie-instellingen"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "Extra inhoud"
},
@@ -1301,9 +1304,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Bestand opgeslagen"
},
- "files.editor.find-close": {
- "defaultMessage": "Sluiten"
- },
"files.editor.find-in-file": {
"defaultMessage": "Vind"
},
@@ -2231,6 +2231,9 @@
"label.details": {
"defaultMessage": "Details"
},
+ "label.discover-content": {
+ "defaultMessage": "Ontdek inhoud"
+ },
"label.done": {
"defaultMessage": "Klaar"
},
@@ -2309,6 +2312,9 @@
"label.password": {
"defaultMessage": "Wachtwoord"
},
+ "label.permissions": {
+ "defaultMessage": "Machtigingen"
+ },
"label.plan-custom": {
"defaultMessage": "Op maat"
},
@@ -2840,9 +2846,162 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Een maker op Modrinth."
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Een gebruiker van Modrinth."
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} zal je geen vriendschapsverzoeken kunnen sturen, je niet kunnen uitnodigen voor gedeelde instanties en je ook niet kunnen uitnodigen voor Modrinth Hosting-servers."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "Weet je zeker dat je deze gebruiker wilt blokkeren?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "Er is een fout opgetreden bij het blokkeren van deze gebruiker. Probeer het nog eens."
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "Gebruiker blokkeren mislukt"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} is geblokkeerd."
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Gebruiker geblokkeerd"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "{username} blokkeren"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Gebruikersstatistieken bekijken"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "Gebruikersfacturering beheren"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Blokkeren"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "Een collectie aanmaken"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "Een project aanmaken"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Gebruikersgegevens bekijken"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "Projecten beheren"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "Als partner verwijderen"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "Als partner instellen"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Deblokkeren"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural, one {# project} other {# projecten}}"
+ },
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "Schakel pop-ups voor Modrinth in en probeer het vervolgens opnieuw."
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "Het GitHub-profiel kon niet worden opgehaald. Probeer het nog eens."
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "Kan GitHub-profiel niet openen"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "Authenticatieproviders"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "E-mailadres geverifieerd"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "Heeft wachtwoord"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "Heeft TOTP"
+ },
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "Laden..."
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "Betaalmethoden"
+ },
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "Profiel bekijken"
+ },
+ "profile.details.title": {
+ "defaultMessage": "Gebruikersgegevens"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "E-mailadres niet geverifieerd"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "E-mailadres geverifieerd"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "Het profiel kon niet worden geladen."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "Gebruiker niet gevonden"
+ },
+ "profile.label.affiliate": {
+ "defaultMessage": "Partner"
+ },
"profile.label.badges": {
"defaultMessage": "Badges"
},
+ "profile.label.collection": {
+ "defaultMessage": "Collectie"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, one {download} other {downloads}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "Lid sinds"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "Deze gebruiker heeft geen collecties!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "Je hebt nog geen collecties."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "Deze gebruiker heeft geen projecten!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "Je hebt nog geen projecten."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "Organisaties"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural, one {project} other {projecten}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Officieel Modrinth-account"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "Het officiële gebruikersaccount van Modrinth. Neem contact op met het Helpcentrum via of per e-mail via "
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "Er is een fout opgetreden bij het deblokkeren van deze gebruiker. Probeer het nog eens."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "Kan gebruiker niet deblokkeren"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "{username} is gedeblokkeerd."
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "Gebruiker gedeblokkeerd"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "Gepubliceerd op {date}"
},
@@ -2870,6 +3029,9 @@
"project-type.all": {
"defaultMessage": "Alles"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "Collecties"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, one {Gegevenspakket} other {Gegevenspakketten}}"
},
@@ -3546,7 +3708,7 @@
"defaultMessage": "Upload"
},
"project.settings.versions.permissions": {
- "defaultMessage": "Toestemmingen"
+ "defaultMessage": "Machtigingen"
},
"project.settings.versions.title": {
"defaultMessage": "Versies"
@@ -4632,7 +4794,7 @@
"defaultMessage": "Je abonnement wordt op {formattedDate} opgezegd. "
},
"servers.listing.notice.suspended": {
- "defaultMessage": "Je server is opgeschort. Neem contact op met de klantenservice van Modrinth voor meer informatie."
+ "defaultMessage": "Je server is opgeschort. Neem contact op met Modrinth-ondersteuning voor meer informatie."
},
"servers.listing.notice.upgrading": {
"defaultMessage": "De hardware van uw server wordt momenteel geüpgraded en zal binnenkort weer online zijn."
@@ -4665,7 +4827,7 @@
"defaultMessage": "Bezig met uploaden"
},
"servers.manage.contact-support-button": {
- "defaultMessage": "Neem contact op met de klantenservice van Modrinth"
+ "defaultMessage": "Contact opnemen met Modrinth-ondersteuning"
},
"servers.manage.error.alert-notice": {
"defaultMessage": "Onze systemen waarschuwen ons team automatisch wanneer er een probleem is. We zijn al bezig om ze weer online te krijgen."
@@ -4680,7 +4842,7 @@
"defaultMessage": "Als je kort geleden een Modrinth Hosting-server hebt gekocht, staat deze momenteel in de wachtrij en zal hij hier verschijnen zodra hij klaar is. Probeer geen nieuwe server aan te schaffen. "
},
"servers.manage.error.support-notice": {
- "defaultMessage": "Als je persoonlijke ondersteuning nodig hebt met betrekking tot de status van uw server, neem dan contact op met Modrinth Support."
+ "defaultMessage": "Als je persoonlijke ondersteuning nodig hebt met de status van je server, neem dan contact op met Modrinth-ondersteuning."
},
"servers.manage.error.title": {
"defaultMessage": "De servers konden niet worden geladen"
@@ -4758,10 +4920,10 @@
"defaultMessage": "De proefperiode van je Medal-server is afgelopen en je server is opgeschort. Voer een upgrade uit om je server te kunnen blijven gebruiken."
},
"servers.medal-listing.notice.suspended": {
- "defaultMessage": "Je server is opgeschort. Werk je factuurgegevens bij of neem contact op met de klantenservice van Modrinth voor meer informatie."
+ "defaultMessage": "Je server is opgeschort. Werk je factuurgegevens bij of neem contact op met Modrinth-ondersteuning voor meer informatie."
},
"servers.medal-listing.notice.suspended-with-reason": {
- "defaultMessage": "Je server is opgeschort met de reden: {reason}. Werk je factuurgegevens bij of neem contact op met de klantenservice van Modrinth voor meer informatie."
+ "defaultMessage": "Je server is opgeschort met de reden: {reason}. Werk je factuurgegevens bij of neem contact op met Modrinth-ondersteuning voor meer informatie."
},
"servers.medal-listing.notice.upgrading": {
"defaultMessage": "De hardware van je server wordt momenteel geüpgraded en zal binnenkort weer online zijn."
@@ -5096,9 +5258,120 @@
"settings.pats.title": {
"defaultMessage": "Persoonlijke toegangstokens"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "Een korte beschrijving om iedereen iets over jezelf te vertellen."
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "Bio"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "Profiel"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "Profielfoto"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "Je profielgegevens zijn openbaar te bekijken op Modrinth en via de Modrinth API ."
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "Het bijwerken van het profiel is mislukt"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "Er is een fout opgetreden bij het bijwerken van je profiel. Probeer het nog eens."
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "Log in met een Modrinth-account om je openbare profiel aan te passen."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Modrinth-account vereist"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "Een unieke, hoofdletterongevoelige naam waarmee je profiel wordt geïdentificeerd."
+ },
"settings.sessions.title": {
"defaultMessage": "Sessies"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "Acties"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Gebruiker"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Dit zijn de gebruikers die je op Modrinth hebt geblokkeerd. Zij kunnen jou niet:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "Je hebt niemand geblokkeerd."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "De geblokkeerde gebruikers konden niet worden geladen."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "Geblokkeerde gebruikers laden…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "Een vriendschapsverzoek sturen"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "Uitnodigen om een Modrinth Hosting-server te beheren."
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "Uitnodigen voor gedeelde instanties"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "Geblokkeerde gebruikers"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "Deblokkeren"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "Kan gebruiker niet deblokkeren"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "Er is een fout opgetreden bij het deblokkeren van deze gebruiker. Probeer het nog eens."
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "{username} deblokkeren"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "Avatar van {username}"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "Bepaal zelf wie je vriendschapsverzoeken kan sturen op Modrinth."
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "Vriendschapsverzoeken"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "Binnenkort beschikbaar!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "Iedereen"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "Vrienden"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "Vrienden van vrienden"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "Niemand"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "Bepaal zelf wie je uitnodigingen kan sturen voor gedeelde instanties en Modrinth Hosting-panelen."
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "Uitnodigingen"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "Met een Modrinth-account kun je bepalen wie er contact met je kan opnemen en kun je geblokkeerde gebruikers beheren"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Modrinth-account vereist"
+ },
+ "settings.social.title": {
+ "defaultMessage": "Sociaal"
+ },
"sharing.invite-players-modal.add": {
"defaultMessage": "Toevoegen"
},
@@ -5108,14 +5381,17 @@
"sharing.invite-players-modal.already-invited": {
"defaultMessage": "Deze gebruiker is al uitgenodigd."
},
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "Toepassen"
+ },
"sharing.invite-players-modal.avatar-alt": {
"defaultMessage": "Avatar van {username}"
},
- "sharing.invite-players-modal.cancel": {
- "defaultMessage": "Annuleren"
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "Aangepast..."
},
- "sharing.invite-players-modal.cancel-button": {
- "defaultMessage": "Annuleren"
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "Aangepast: {date}"
},
"sharing.invite-players-modal.edit-invite-link": {
"defaultMessage": "Uitnodigingslink bewerken."
@@ -5123,6 +5399,24 @@
"sharing.invite-players-modal.edit-invite-link-title": {
"defaultMessage": "Uitnodigingslink bewerken"
},
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "Over 1 dag"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "Over 1 uur"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "Over 7 dagen"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "Over 6 uur"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "Over 3 dagen"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "Over 12 uur"
+ },
"sharing.invite-players-modal.expiry-label": {
"defaultMessage": "Vervaldatum"
},
diff --git a/packages/ui/src/locales/no-NO/index.json b/packages/ui/src/locales/no-NO/index.json
index 0d28108348..5167d41191 100644
--- a/packages/ui/src/locales/no-NO/index.json
+++ b/packages/ui/src/locales/no-NO/index.json
@@ -2778,3 +2778,4 @@
"defaultMessage": "Du har ulagrede endringer."
}
}
+
diff --git a/packages/ui/src/locales/pl-PL/index.json b/packages/ui/src/locales/pl-PL/index.json
index 6b58310342..579d0fdf09 100644
--- a/packages/ui/src/locales/pl-PL/index.json
+++ b/packages/ui/src/locales/pl-PL/index.json
@@ -566,6 +566,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "Twój świat"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "Ustawienia instalacji"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "Dodatkowa zawartość"
},
@@ -1196,6 +1199,9 @@
"external-files.permissions-card.remove-group": {
"defaultMessage": "Usuń grupę"
},
+ "external-files.permissions-card.remove-group-confirmation.description": {
+ "defaultMessage": "Trwale usunie to grupę atrybucji i wszystkie zawarte w niej pliki. Tej akcji nie można cofnąć."
+ },
"external-files.permissions-card.remove-group-confirmation.title": {
"defaultMessage": "Usuń {title}?"
},
@@ -1269,10 +1275,10 @@
"defaultMessage": "Usuń plik"
},
"files.delete-modal.warning.file": {
- "defaultMessage": "Ten plik zostanie trwale usunięty. Tej akcji nie będzie można cofnąć."
+ "defaultMessage": "Ten plik zostanie trwale usunięty. Tej akcji nie można cofnąć."
},
"files.delete-modal.warning.folder": {
- "defaultMessage": "Ten folder wraz z całą jego zawartością zostanie trwale usunięty. Tej akcji nie będzie można cofnąć."
+ "defaultMessage": "Ten folder wraz z całą jego zawartością zostanie trwale usunięty. Tej akcji nie można cofnąć."
},
"files.editor.failed-to-open-text": {
"defaultMessage": "Nie udało się odczytać danych z pliku."
@@ -1292,9 +1298,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Plik zapisany"
},
- "files.editor.find-close": {
- "defaultMessage": "Zamknij"
- },
"files.editor.find-in-file": {
"defaultMessage": "Znajdź"
},
@@ -2225,6 +2228,9 @@
"label.details": {
"defaultMessage": "Szczegóły"
},
+ "label.discover-content": {
+ "defaultMessage": "Odkrywaj zawartość"
+ },
"label.done": {
"defaultMessage": "Gotowe"
},
@@ -2303,6 +2309,9 @@
"label.password": {
"defaultMessage": "Hasło"
},
+ "label.permissions": {
+ "defaultMessage": "Uprawnienia"
+ },
"label.plan-custom": {
"defaultMessage": "Niestandardowy"
},
@@ -2834,9 +2843,138 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Twórca na Modrinth."
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Użytkownik Modrinth."
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "Użytkownik {username} nie będzie mógł wysyłać ci zaproszeń do znajomych, zapraszać się do udostępnionych instancji lub zapraszać się do serwerów Modrinth Hosting."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "Czy na pewno chcesz zablokować tego użytkownika?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "Wystąpił błąd podczas blokowania tego użytkownika. Spróbuj ponownie później."
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "Nie udało się zablokować użytkownika"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "Użytkownik {username} został zablokowany."
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Zablokowano użytkownika"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "Zablokuj {username}"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Pokaż dane analityczne użytkownika"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "Zarządzaj rozliczaniem użytkownika"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Zablokuj"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "Utwórz kolekcję"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "Utwórz projekt"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Otwórz szczegóły użytkownika"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "Zarządzaj projektami"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Odblokuj"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural, one {# projekt} few {# projekty} other {# projektów}}"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "Dostawcy uwierzytelniania"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "Zweryfikowano e-mail"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "Ma hasło"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "Ma TOTP"
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "Metody płatności"
+ },
+ "profile.details.title": {
+ "defaultMessage": "Szczegóły użytkownika"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "E-mail nie jest zweryfikowany"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "E-mail jest zweryfikowany"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "Nie udało się załadować profilu tego użytkownika."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "Nie znaleziono użytkownika"
+ },
"profile.label.badges": {
"defaultMessage": "Odznaki"
},
+ "profile.label.collection": {
+ "defaultMessage": "Kolekcja"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, one {pobranie} few {pobrania} other {pobrań}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "Dołączył(-a)"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "Ten użytkownik nie ma żadnych kolekcji!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "Nie masz jeszcze żadnych kolekcji."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "Ten użytkownik nie ma żadnych projektów!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "Nie masz jeszcze żadnych projektów."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "Organizacje"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural, one {projekt} few {projekty} other {projektów}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Oficjalne konto Modrinth"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "Oficjalne konto Modrinth. Otrzymaj wsparcie na stronie lub poprzez e-mail "
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "Wystąpił błąd podczas odblokowywania tego użytkownika. Spróbuj ponownie później."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "Nie udało się odblokować użytkownika"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "Użytkownik {username} został odblokowany."
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "Użytkownik odblokowany"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "Opublikowany {date}"
},
@@ -2864,6 +3002,9 @@
"project-type.all": {
"defaultMessage": "Wszystko"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "Kolekcje"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, one {Paczka danych} few {Paczki danych} other {Paczek danych}}"
},
@@ -3134,6 +3275,9 @@
"project.follower-count-tooltip": {
"defaultMessage": "{count, number} {count, plural, one {obserwujący} other {obserwujących}}"
},
+ "project.license.error": {
+ "defaultMessage": "Nie można pobrać tekstu licencji."
+ },
"project.license.loading": {
"defaultMessage": "Ładowanie treści licencji..."
},
@@ -5087,9 +5231,111 @@
"settings.pats.title": {
"defaultMessage": "Klucze dostępu osobistego"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "Krótki opis, aby powiedzieć wszystkim trochę o Tobie."
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "O mnie"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "Profil"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "Zdjęcie profilowe"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "Twoje informacje profilowe są publicznie dostępne na Modrinth i poprzez Modrinth API ."
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "Nie udało się zaktualizować profilu"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "Wystąpił błąd podczas aktualizowania profilu. Spróbuj ponownie później."
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "Zaloguj się na konto Modrinth, by dostosować swój publiczny profil."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Wymagane jest konto Modrinth"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "Unikatowa bez uwzględniania wielkości liter nazwa identyfikująca Twój profil."
+ },
"settings.sessions.title": {
"defaultMessage": "Sesje"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "Akcje"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Użytkownik"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Lista użytkowników zablokowanych na Modrinth. Nie mogą oni:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "Brak zablokowanych użytkowników."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "Nie udała się załadować zablokowanych użytkowników."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "Ładowanie zablokowanych użytkowników…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "Wysyłać ci zaproszeń do znajomych"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "Zapraszać cię do zarządzania serwerem Modrinth Hosting."
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "Zapraszać cię do udostępnionych instancji"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "Zablokowani użytkownicy"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "Odblokuj"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "Nie udało się odblokować użytkownika"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "Wystąpił błąd podczas odblokowywania tego użytkownika. Spróbuj ponownie później."
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "Odblokuj {username}"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "Awatar użytkownika {username}"
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "Zaproszenia do znajomych"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "Już wkrótce!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "Wszyscy"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "Znajomi"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "Znajomi znajomych"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "Nikt"
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "Zaproszenia"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Wymagane jest konto Modrinth"
+ },
+ "settings.social.title": {
+ "defaultMessage": "Społeczne"
+ },
"sharing.invite-players-modal.add": {
"defaultMessage": "Dodaj"
},
@@ -5099,15 +5345,12 @@
"sharing.invite-players-modal.already-invited": {
"defaultMessage": "Ten użytkownik został już zaproszony."
},
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "Zastosuj"
+ },
"sharing.invite-players-modal.avatar-alt": {
"defaultMessage": "Awatar użytkownika {username}"
},
- "sharing.invite-players-modal.cancel": {
- "defaultMessage": "Anuluj"
- },
- "sharing.invite-players-modal.cancel-button": {
- "defaultMessage": "Anuluj"
- },
"sharing.invite-players-modal.expiry-label": {
"defaultMessage": "Data wygaśnięcia"
},
diff --git a/packages/ui/src/locales/pt-BR/index.json b/packages/ui/src/locales/pt-BR/index.json
index 27fb435faf..2467fbbb69 100644
--- a/packages/ui/src/locales/pt-BR/index.json
+++ b/packages/ui/src/locales/pt-BR/index.json
@@ -566,6 +566,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "mundo"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "Configurações de instalação"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "Conteúdo adicional"
},
@@ -1301,9 +1304,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Arquivo salvo"
},
- "files.editor.find-close": {
- "defaultMessage": "Fechar"
- },
"files.editor.find-in-file": {
"defaultMessage": "Localizar"
},
@@ -2240,6 +2240,9 @@
"label.details": {
"defaultMessage": "Detalhes"
},
+ "label.discover-content": {
+ "defaultMessage": "Descobrir conteúdo"
+ },
"label.done": {
"defaultMessage": "Feito"
},
@@ -2318,6 +2321,9 @@
"label.password": {
"defaultMessage": "Senha"
},
+ "label.permissions": {
+ "defaultMessage": "Permissões"
+ },
"label.plan-custom": {
"defaultMessage": "Personalizado"
},
@@ -2849,9 +2855,162 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Um criador Modrinth."
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Um usuário do Modrinth."
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} não poderá enviar solicitações de amizade para você, convidar você para instâncias compartilhadas ou convidar você para servidores do Modrinth Hosting."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "Deseja mesmo bloquear este usuário?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "Ocorreu um erro ao bloquear este usuário. Tente novamente."
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "Falha ao bloquear usuário"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} bloqueado."
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Usuário bloqueado"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "Bloquear {username}"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Ver estatísticas do usuário"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "Gerenciar cobrança do usuário"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Bloquear"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "Criar coleção"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "Criar projeto"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Ver detalhes do usuário"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "Gerenciar projetos"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "Remover como afiliado"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "Definir como afiliado"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Desbloquear"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural, one {# projeto} other {# projetos}}"
+ },
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "Permita pop-ups para o Modrinth e tente novamente."
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "O perfil do GitHub não pode ser recuperado. Tente novamente."
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "Não foi possível abrir o perfil do GitHub"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "Provedores de autenticação"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "E-mail verificado"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "Possui senha"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "Possui TOTP"
+ },
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "Carregando..."
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "Métodos de pagamento"
+ },
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "Ver perfil"
+ },
+ "profile.details.title": {
+ "defaultMessage": "Detalhes do usuário"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "E-mail não verificado"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "E-mail verificado"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "O perfil do usuário não pôde ser carregado."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "Usuário não encontrado"
+ },
+ "profile.label.affiliate": {
+ "defaultMessage": "Afiliado"
+ },
"profile.label.badges": {
"defaultMessage": "Emblemas"
},
+ "profile.label.collection": {
+ "defaultMessage": "Coleção"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, one {download} other {downloads}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "Entrou"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "Este usuário não tem coleções!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "Você ainda não tem nenhuma coleção."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "Este usuário não tem projetos!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "Você ainda não tem projetos."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "Organizações"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural, one {projeto} other {projetos}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Conta oficial do Modrinth"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "Conta oficial do Modrinth. Obtenha suporte em ou por e-mail via "
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "Ocorreu um erro ao desbloquear este usuário. Tente novamente."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "Falha ao desbloquear usuário"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "{username} desbloqueado."
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "Usuário desbloqueado"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "Publicado {date}"
},
@@ -2879,6 +3038,9 @@
"project-type.all": {
"defaultMessage": "Todos"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "Coleções"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, one {Pacote de dados} other {Pacotes de dados}}"
},
@@ -3159,7 +3321,10 @@
"defaultMessage": "Licença"
},
"project.online-player-count": {
- "defaultMessage": "{count, plural, =0 {Ninguém online} other {{count} online}}"
+ "defaultMessage": "{count, number} online"
+ },
+ "project.online-player-count.tooltip": {
+ "defaultMessage": "{count} {countPlural, plural, one {jogador} other {jogadores}} online"
},
"project.recent-plays": {
"defaultMessage": "{countPlural, plural, =0 {Nenhuma entrada recente} one {{count} entrada recente} other {{count} entradas recentes}}"
@@ -5102,9 +5267,120 @@
"settings.pats.title": {
"defaultMessage": "Token de acesso pessoal"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "Uma breve descrição para falar um pouco sobre você para todos."
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "Sobre"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "Perfil"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "Foto de perfil"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "As informações do seu perfil são visíveis publicamente no Modrinth e através da API do Modrinth ."
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "Falha ao atualizar o perfil"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "Ocorreu um erro ao atualizar seu perfil. Tente novamente."
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "Inicie sessão com uma conta Modrinth para personalizar seu perfil público."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Conta Modrinth necessária"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "Um nome único sem distinção de maiúsculas e minúsculas para identificar o seu perfil."
+ },
"settings.sessions.title": {
"defaultMessage": "Sessões"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "Ações"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Usuário"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Estes são os usuários que você bloqueou no Modrinth. Eles não poderão:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "Você não bloqueou ninguém."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "Os usuários bloqueados não puderam ser carregados."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "Carregando usuários bloqueados…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "Enviar solicitações de amizade"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "Convidar você para gerenciar um servidor Modrinth Hosting."
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "Convidar você para instâncias compartilhadas"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "Usuários bloqueados"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "Desbloquear"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "Falha ao desbloquear usuário"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "Ocorreu um erro ao desbloquear este usuário. Tente novamente."
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "Desbloquear {username}"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "Foto de perfil de {username}"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "Controle quem pode enviá-lo solicitações de amizade no Modrinth."
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "Solicitações de amizade"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "Em breve!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "Todos"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "Amigos"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "Amigos de amigos"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "Ninguém"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "Controle quem pode enviá-lo convites a instâncias compartilhadas e painéis do Modrinth Hosting."
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "Convites"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "Você pode controlar quem interagir com você e gerenciar usuários bloqueados com uma conta Modrinth"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Conta Modrinth necessária"
+ },
+ "settings.social.title": {
+ "defaultMessage": "Social"
+ },
"sharing.invite-players-modal.add": {
"defaultMessage": "Adicionar"
},
@@ -5114,14 +5390,17 @@
"sharing.invite-players-modal.already-invited": {
"defaultMessage": "Este usuário já foi convidado."
},
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "Aplicar"
+ },
"sharing.invite-players-modal.avatar-alt": {
"defaultMessage": "Avatar de {username}"
},
- "sharing.invite-players-modal.cancel": {
- "defaultMessage": "Cancelar"
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "Personalizado..."
},
- "sharing.invite-players-modal.cancel-button": {
- "defaultMessage": "Cancelar"
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "Personalizado: {date}"
},
"sharing.invite-players-modal.edit-invite-link": {
"defaultMessage": "Editar link de convite."
@@ -5129,6 +5408,24 @@
"sharing.invite-players-modal.edit-invite-link-title": {
"defaultMessage": "Editar link de convite"
},
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "Em 1 dia"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "Em 1 hora"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "Em 7 dias"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "Em 6 horas"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "Em 3 dias"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "Em 12 horas"
+ },
"sharing.invite-players-modal.expiry-label": {
"defaultMessage": "Data de expiração"
},
@@ -5934,3 +6231,4 @@
"defaultMessage": "Tipo"
}
}
+
diff --git a/packages/ui/src/locales/pt-PT/index.json b/packages/ui/src/locales/pt-PT/index.json
index f27ed83e44..6a5706345e 100644
--- a/packages/ui/src/locales/pt-PT/index.json
+++ b/packages/ui/src/locales/pt-PT/index.json
@@ -497,9 +497,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Ficheiro salvo"
},
- "files.editor.find-close": {
- "defaultMessage": "Fechar"
- },
"files.editor.find-in-file": {
"defaultMessage": "Encontrar"
},
@@ -2526,3 +2523,4 @@
"defaultMessage": "Tens alterações por guardar."
}
}
+
diff --git a/packages/ui/src/locales/ro-RO/index.json b/packages/ui/src/locales/ro-RO/index.json
index 689a414b43..3fe8371574 100644
--- a/packages/ui/src/locales/ro-RO/index.json
+++ b/packages/ui/src/locales/ro-RO/index.json
@@ -551,9 +551,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Fișier salvat"
},
- "files.editor.find-close": {
- "defaultMessage": "Închide"
- },
"files.editor.find-in-file": {
"defaultMessage": "Caută"
},
diff --git a/packages/ui/src/locales/ru-RU/index.json b/packages/ui/src/locales/ru-RU/index.json
index 072d67b335..31701a083b 100644
--- a/packages/ui/src/locales/ru-RU/index.json
+++ b/packages/ui/src/locales/ru-RU/index.json
@@ -348,10 +348,10 @@
"defaultMessage": "Выбрать {project}"
},
"content.confirm-bulk-update.admonition-body": {
- "defaultMessage": "Вы уверены, что хотите обновить {count, plural, one {# проект} few {# проекта} other {# проектов}} до их последней совместимой версии? Рекомендуется обновлять контент по отдельности."
+ "defaultMessage": "Вы точно хотите обновить {count, plural, one {# проект} few {# проекта} other {# проектов}} до {count, plural, =1 {последней совместимой версии} other {последних совместимых версий}}? Рекомендуется обновлять контент по очереди."
},
"content.confirm-bulk-update.admonition-header": {
- "defaultMessage": "Предупреждение об обновлении"
+ "defaultMessage": "Предупреждение об обновлении"
},
"content.confirm-bulk-update.header": {
"defaultMessage": "Обновление проектов"
@@ -363,10 +363,10 @@
"defaultMessage": "Обновить {count, plural, one {# проект} few {# проекта} other {# проектов}}"
},
"content.confirm-deletion.admonition-body": {
- "defaultMessage": "Удаление мода может необратимо повлиять на ваш мир, что приведет к потере контента или непредвиденным ошибкам при следующей загрузке."
+ "defaultMessage": "Удаление модов может повлиять на миры и привести к необратимой пропаже контента или ошибкам при следующей загрузке."
},
"content.confirm-deletion.admonition-header": {
- "defaultMessage": "Предупреждение об удалении"
+ "defaultMessage": "Предупреждение об удалении"
},
"content.confirm-deletion.header": {
"defaultMessage": "Удалить {itemType}"
@@ -375,10 +375,10 @@
"defaultMessage": "Отключить {itemType}"
},
"content.confirm-modpack-update.admonition-body": {
- "defaultMessage": "{action, select, downgrade {Понижение версии} other {Обновление}} может привести к проблемам с совместимостью. Моды или другой контент, который вы установили в сборку, сохранятся, но могут быть несовместимы с новой версией."
+ "defaultMessage": "{action, select, downgrade {Откат} other {Обновление}} может нарушить совместимость. Добавленные вами моды и контент останутся, но могут перестать работать в новой версии."
},
"content.confirm-modpack-update.admonition-header": {
- "defaultMessage": "Предупреждение: {action, select, downgrade {откат} other {обновление}} версии"
+ "defaultMessage": "Предупреждение об {action, select, downgrade {откате} other {обновлении}}"
},
"content.confirm-modpack-update.confirm-button": {
"defaultMessage": "{action, select, downgrade {Откатить} other {Обновить}} сборку"
@@ -387,7 +387,7 @@
"defaultMessage": "{action, select, downgrade {Откат} other {Обновление}} сборки"
},
"content.confirm-unlink.admonition-body": {
- "defaultMessage": "Моды и контент будут объединены с тем, что вы добавили в сборку. После этого сборка перестанет получать обновления."
+ "defaultMessage": "Моды и контент объединятся с вашими добавлениями, но сборка перестанет получать обновления."
},
"content.confirm-unlink.admonition-header": {
"defaultMessage": "Отвязка сборки"
@@ -471,13 +471,13 @@
"defaultMessage": "Загрузчик"
},
"content.diff-modal.modpack-linked": {
- "defaultMessage": "Связанная сборка"
+ "defaultMessage": "Привязана сборка"
},
"content.diff-modal.modpack-unlinked": {
- "defaultMessage": "Несвязанная сборка"
+ "defaultMessage": "Отвязана сборка"
},
"content.diff-modal.modpack-updated": {
- "defaultMessage": "Обновлённая сборка"
+ "defaultMessage": "Обновлена сборка"
},
"content.diff-modal.no-content-changes": {
"defaultMessage": "Без изменений"
@@ -536,6 +536,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "мир"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "Настройки установки"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "Дополнительный контент"
},
@@ -846,7 +849,7 @@
"defaultMessage": "Начать с нуля, выбрав загрузчик и версию игры."
},
"creation-flow.modal.setup-type.option.custom-setup.title": {
- "defaultMessage": "Пользовательская настройка"
+ "defaultMessage": "Собственная настройка"
},
"creation-flow.modal.setup-type.option.import-instance.description": {
"defaultMessage": "Импортировать сборку из Prism, CurseForge, или похожего лаунчера."
@@ -1229,9 +1232,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Файл сохранён"
},
- "files.editor.find-close": {
- "defaultMessage": "Закрыть"
- },
"files.editor.find-in-file": {
"defaultMessage": "Найти"
},
@@ -1809,52 +1809,52 @@
"defaultMessage": "Настройка установки"
},
"installation-settings.edit.warning-instance": {
- "defaultMessage": "Мы не рекомендуем изменять настройки сборки после установки контента. Если вы всё же хотите их изменить, будьте осторожны, так как это может вызвать проблемы."
+ "defaultMessage": "Не рекомендуется изменять установку после добавления контента. Это может привести к ошибкам."
},
"installation-settings.edit.warning-server": {
- "defaultMessage": "Не рекомендуется менять настройки инсталляции после установки контента. Если вы всё же хотите изменить их, перезагрузите сервер."
+ "defaultMessage": "Не рекомендуется изменять установку после добавления контента. Лучше сразу переустановить сервер."
},
"installation-settings.incompatible-content.auto-fix-button": {
- "defaultMessage": "Авто-исправление"
+ "defaultMessage": "Исправить"
},
"installation-settings.incompatible-content.change-loader-button": {
"defaultMessage": "Сменить загрузчик"
},
"installation-settings.incompatible-content.disable-conflicts-button": {
- "defaultMessage": "Отключить конфликты"
+ "defaultMessage": "Отключить"
},
"installation-settings.incompatible-content.game-version-warning-body": {
- "defaultMessage": "При изменении версии игры вы можете либо отключить несовместимый контент, либо попытаться устранить несовместимости."
+ "defaultMessage": "При смене версии игры можно отключить несовместимый контент или попытаться исправить несовместимости автоматически."
},
"installation-settings.incompatible-content.game-version-warning-title": {
- "defaultMessage": "Предупреждение о несовместимости"
+ "defaultMessage": "Предупреждение о несовместимости"
},
"installation-settings.incompatible-content.header": {
- "defaultMessage": "Установлены несовместимые проекты"
+ "defaultMessage": "Нарушение совместимости"
},
"installation-settings.incompatible-content.loader-change-body": {
- "defaultMessage": "При смене загрузчика модов, все установленные проекты будут отключены. Вместо этого рекомендуется сбросить сервер."
+ "defaultMessage": "Смена загрузчика отключит установленный контент. Лучше сразу переустановить сервер."
},
"installation-settings.incompatible-content.loader-change-title": {
"defaultMessage": "Смена загрузчика небезопасна"
},
"installation-settings.linked-instance.title": {
- "defaultMessage": "Связанный {projectType}"
+ "defaultMessage": "Отвязка {projectType}"
},
"installation-settings.linked.modpack": {
- "defaultMessage": "сборка"
+ "defaultMessage": "сборки"
},
"installation-settings.linked.server-project": {
- "defaultMessage": "серверный проект"
+ "defaultMessage": "серверного проекта"
},
"installation-settings.loader-version": {
"defaultMessage": "Версия {loader}"
},
"installation-settings.platform-lock-tooltip": {
- "defaultMessage": "Необходимо сбросить сервер для изменения загрузчика."
+ "defaultMessage": "Для смены загрузчика необходимо переустановить сервер."
},
"installation-settings.reinstall-modpack.description": {
- "defaultMessage": "Переустановка сборки сбросит контент, который использует {type}, до исходного состояния, удалив все добавленные вами моды и файлы."
+ "defaultMessage": "Переустановка сбросит {type} к исходному состоянию, удалив все добавленные вами моды и контент."
},
"installation-settings.reinstall-modpack.title": {
"defaultMessage": "Переустановка сборки"
@@ -1884,31 +1884,31 @@
"defaultMessage": "Поиск версии игры..."
},
"installation-settings.type.instance": {
- "defaultMessage": "сборка"
+ "defaultMessage": "сборку"
},
"installation-settings.type.instance-possessive": {
- "defaultMessage": "сборки"
+ "defaultMessage": "сборку"
},
"installation-settings.type.server": {
"defaultMessage": "сервер"
},
"installation-settings.type.server-possessive": {
- "defaultMessage": "серверы"
+ "defaultMessage": "сервер"
},
"installation-settings.unlink": {
"defaultMessage": "Отвязать"
},
"installation-settings.unlink.description": {
- "defaultMessage": "Отвязка навсегда отключит этот {type} от проекта {projectType}, что позволит вам изменить загрузчик и версию Minecraft, но вы больше не сможете получать обновления."
+ "defaultMessage": "Отвязка навсегда отключит {type} от исходного проекта. Это откроет доступ к смене версии игры и загрузчика, но получение обновлений прекратится."
},
"installation-settings.verifying": {
"defaultMessage": "Проверка..."
},
"instance.confirm-reinstall.admonition-body": {
- "defaultMessage": "Переустановка сбросит весь установленный или изменённый контент к начальному состоянию, удалив моды и контент, добавленные поверх исходной установки."
+ "defaultMessage": "Переустановка сбросит установленное содержимое к исходному состоянию, удалив добавленные вами моды и контент."
},
"instance.confirm-reinstall.admonition-header": {
- "defaultMessage": "Предупреждение переустановки"
+ "defaultMessage": "Предупреждение о переустановке"
},
"instance.confirm-reinstall.header": {
"defaultMessage": "Переустановка сборки"
@@ -2156,6 +2156,9 @@
"label.details": {
"defaultMessage": "Сведения"
},
+ "label.discover-content": {
+ "defaultMessage": "Найти проекты"
+ },
"label.done": {
"defaultMessage": "Готово"
},
@@ -2234,6 +2237,9 @@
"label.password": {
"defaultMessage": "Пароль"
},
+ "label.permissions": {
+ "defaultMessage": "Разрешения"
+ },
"label.plan-custom": {
"defaultMessage": "Свой"
},
@@ -2762,9 +2768,162 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Автор на Modrinth."
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Пользователь Modrinth."
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} не сможет отправлять вам запросы в друзья, приглашать вас в сборки или приглашать вас управлять сервером Modrinth Hosting."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "Вы действительно хотите заблокировать этого пользователя?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "Произошла ошибка при блокировке пользователя. Попробуйте снова."
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "Не удалось заблокировать"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} заблокирован."
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Пользователь заблокирован"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "Заблокировать {username}"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Посмотреть аналитику"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "Управление платежами"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Заблокировать"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "Создать коллекцию"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "Создать проект"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Посмотреть подробности"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "Управление проектами"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "Убрать из партнёров"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "Сделать партнёром"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Разблокировать"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural, one {# проект} few {# проекта} other {# проектов}}"
+ },
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "Разрешите всплывающие окна для Modrinth и повторите попытку."
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "Не удалось получить профиль GitHub. Повторите попытку."
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "Не удалось открыть профиль GitHub"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "Сервисы входа"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "Почта подтверждена"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "Есть пароль"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "Есть TOTP"
+ },
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "Загрузка..."
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "Способы оплаты"
+ },
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "Посмотреть профиль"
+ },
+ "profile.details.title": {
+ "defaultMessage": "О пользователе"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "Почта не подтверждена"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "Почта подтверждена"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "Не удалось загрузить профиль."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "Пользователь не найден"
+ },
+ "profile.label.affiliate": {
+ "defaultMessage": "Партнёр"
+ },
"profile.label.badges": {
"defaultMessage": "Значки"
},
+ "profile.label.collection": {
+ "defaultMessage": "Коллекция"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, one {скачивание} few {скачивания} other {скачиваний}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "Регистрация:"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "У этого пользователя нет коллекций!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "Коллекций пока нет."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "У этого пользователя нет проектов!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "Проектов пока нет."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "Организации"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural, one {проект} few {проекта} other {проектов}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Официальный аккаунт Modrinth"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "Официальный аккаунт Modrinth. Связь с поддержкой: или по почте "
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "Произошла ошибка при разблокировке пользователя. Попробуйте снова."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "Не удалось разблокировать"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "{username} разблокирован."
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "Пользователь разблокирован"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "Опубликован {date}"
},
@@ -2792,6 +2951,9 @@
"project-type.all": {
"defaultMessage": "Всё"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "Коллекции"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, one {набор данных} few {набора данных} other {наборов данных}}"
},
@@ -4290,7 +4452,7 @@
"defaultMessage": "После удаления {count, plural, one {эта резервная копия не может быть восстановлена} other {эти резервные копии не могут быть восстановлены}}. Удаление необратимо."
},
"servers.backups.delete-modal.admonition-header": {
- "defaultMessage": "Предупреждение об удалении"
+ "defaultMessage": "Предупреждение об удалении"
},
"servers.backups.delete-modal.backups-label": {
"defaultMessage": "{count, plural, one {Резервная копия} other {Резервные копии ({count})}}"
@@ -4746,7 +4908,7 @@
"defaultMessage": "Способ оплаты"
},
"servers.purchase.step.plan.billed": {
- "defaultMessage": "оплата {interval, select, monthly {ежемесячно} quarterly {ежеквартально} yearly {ежегодно} other {{interval}}}"
+ "defaultMessage": "{interval, select, monthly {за месяц} quarterly {за 3 месяца} yearly {за год} other {billed {interval}}}"
},
"servers.purchase.step.plan.billing-subtitle": {
"defaultMessage": "Доступно в Северной Америке, Европе и Юго‑Восточной Азии."
@@ -5018,9 +5180,120 @@
"settings.pats.title": {
"defaultMessage": "Личные токены доступа"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "Возможность кратко рассказать всем о себе."
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "О себе"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "Профиль"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "Изображение профиля"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "Информация в вашем профиле доступна публично на Modrinth и через API Modrinth ."
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "Не удалось обновить профиль"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "Произошла ошибка при обновлении профиля. Попробуйте снова."
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "Войдите в аккаунт Modrinth для кастомизации вашего публичного профиля."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Требуется аккаунт Modrinth"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "Уникальное имя для идентификации профиля."
+ },
"settings.sessions.title": {
"defaultMessage": "Сеансы"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "Действия"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Пользователь"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Это пользователи, которых вы заблокировали на Modrinth. Они не могут:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "Вы никого не заблокировали."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "Заблокированные пользователи не загрузились."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "Загрузка заблокированных пользователей..."
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "Отправлять вам запросы в друзья"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "Приглашать вас управлять сервером Modrinth Hosting."
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "Приглашать вас в сборки"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "Заблокированные пользователи"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "Разблокировать"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "Не удалось разблокировать"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "Произошла ошибка при разблокировке пользователя. Попробуйте снова."
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "Разблокировать {username}"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "Аватар {username}"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "Настройте, кто может отправить вам заявку в друзья на Modrinth."
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "Запросы в друзья"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "Скоро будет!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "Все"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "Друзья"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "Друзья друзей"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "Никто"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "Настройте, кто вам может отправить заявку на общие сборки и панели Modrinth Hosting."
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "Приглашения"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "С помощью аккаунта Modrinth, вы можете настраивать кто может взаимодействовать с вами, а также управлять заблокированными пользователями"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Требуется аккаунт Modrinth"
+ },
+ "settings.social.title": {
+ "defaultMessage": "Общение"
+ },
"sharing.invite-players-modal.add": {
"defaultMessage": "Добавить"
},
@@ -5030,14 +5303,17 @@
"sharing.invite-players-modal.already-invited": {
"defaultMessage": "Этот пользователь уже приглашён."
},
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "Применить"
+ },
"sharing.invite-players-modal.avatar-alt": {
"defaultMessage": "Аватар {username}"
},
- "sharing.invite-players-modal.cancel": {
- "defaultMessage": "Отозвать"
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "Другое..."
},
- "sharing.invite-players-modal.cancel-button": {
- "defaultMessage": "Отмена"
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "Другое: {date}"
},
"sharing.invite-players-modal.edit-invite-link": {
"defaultMessage": "Настроить ссылку."
@@ -5045,6 +5321,24 @@
"sharing.invite-players-modal.edit-invite-link-title": {
"defaultMessage": "Настройка ссылки"
},
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "1 день"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "1 час"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "7 дней"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "6 часов"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "3 дня"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "12 часов"
+ },
"sharing.invite-players-modal.expiry-label": {
"defaultMessage": "Срок действия"
},
diff --git a/packages/ui/src/locales/sr-CS/index.json b/packages/ui/src/locales/sr-CS/index.json
index 6117939c7d..ad1b71e4ae 100644
--- a/packages/ui/src/locales/sr-CS/index.json
+++ b/packages/ui/src/locales/sr-CS/index.json
@@ -1253,9 +1253,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Datoteka sačuvana"
},
- "files.editor.find-close": {
- "defaultMessage": "Zatvori"
- },
"files.editor.find-in-file": {
"defaultMessage": "Pronađi"
},
@@ -5784,3 +5781,4 @@
"defaultMessage": "Tip"
}
}
+
diff --git a/packages/ui/src/locales/sv-SE/index.json b/packages/ui/src/locales/sv-SE/index.json
index fa83bc14dd..a8bd5ccf7f 100644
--- a/packages/ui/src/locales/sv-SE/index.json
+++ b/packages/ui/src/locales/sv-SE/index.json
@@ -117,7 +117,7 @@
"defaultMessage": "Du har valt {count, number} projekt att installera. Installera dem nu eller gå tillbaka utan att installera dem."
},
"browse.selected-projects-leave-modal.admonition-header": {
- "defaultMessage": "Valda projekt är inte installerade än"
+ "defaultMessage": "De valda projekten är inte installerade än"
},
"browse.selected-projects-leave-modal.discard": {
"defaultMessage": "Kasta"
@@ -377,6 +377,9 @@
"content.confirm-deletion.header": {
"defaultMessage": "Radera {itemType}"
},
+ "content.confirm-disable.header": {
+ "defaultMessage": "Inaktivera {itemType}"
+ },
"content.confirm-modpack-update.admonition-body": {
"defaultMessage": "Att {action, select, downgrade {nedgradera} other {uppdatera}} kan orsaka kompatibilitetsproblem. Moddar eller innehåller du själv lagt till kommer behållas, men är kanske inte kompatibel med den nya versionen."
},
@@ -455,6 +458,9 @@
"content.diff-modal.diff-type.removed": {
"defaultMessage": "Inaktiverade"
},
+ "content.diff-modal.diff-type.removed-disabled": {
+ "defaultMessage": "Tog bort (inaktiverad)"
+ },
"content.diff-modal.diff-type.updated": {
"defaultMessage": "Uppdaterade"
},
@@ -470,18 +476,33 @@
"content.diff-modal.external-diff-type.updated": {
"defaultMessage": "Uppdaterad"
},
+ "content.diff-modal.file-count": {
+ "defaultMessage": "{count, plural, one {# fil} other {# filer}}"
+ },
"content.diff-modal.game-version-updated": {
"defaultMessage": "Spelversion"
},
"content.diff-modal.install-anyway": {
"defaultMessage": "Installera ändå"
},
+ "content.diff-modal.modpack-linked": {
+ "defaultMessage": "Länkat modpaket"
+ },
+ "content.diff-modal.modpack-unlinked": {
+ "defaultMessage": "Avlänkat modpaket"
+ },
+ "content.diff-modal.modpack-updated": {
+ "defaultMessage": "Uppdaterat modpaket"
+ },
"content.diff-modal.no-content-changes": {
"defaultMessage": "Inga innehållsändringar"
},
"content.diff-modal.removed-count": {
"defaultMessage": "{count} borttagna"
},
+ "content.diff-modal.reviewed-files": {
+ "defaultMessage": "En fil granskas bara om den publiceras på Modrinth, oavsett dess filformat (däribland .mrpack)."
+ },
"content.diff-modal.unknown-content-body": {
"defaultMessage": "Något innehåll på din server kunde inte analyseras och kommer kanske påverkas av denna ändring."
},
@@ -539,6 +560,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "värld"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "Installationsinställningar"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "Ytterligare innehåll"
},
@@ -774,7 +798,7 @@
"defaultMessage": "Ange världnamn"
},
"creation-flow.modal.final-config.world-seed.description": {
- "defaultMessage": "Lämna tom för slumpmässig utsäde."
+ "defaultMessage": "Lämna tom för slumpmässig frö."
},
"creation-flow.modal.final-config.world-seed.placeholder": {
"defaultMessage": "Ange världsfrö"
@@ -842,12 +866,21 @@
"creation-flow.modal.setup-type.option.import-instance.title": {
"defaultMessage": "Importera instans"
},
+ "creation-flow.modal.setup-type.option.modpack-base.description": {
+ "defaultMessage": "Bläddra bland modpaket på Modrinth eller importera ett från en fil."
+ },
"creation-flow.modal.setup-type.option.modpack-base.title": {
"defaultMessage": "Installera modpaket"
},
"creation-flow.modal.setup-type.option.vanilla-minecraft.description": {
"defaultMessage": "Klassiska Minecraft, utan moddar eller plugin."
},
+ "creation-flow.modal.setup-type.option.vanilla-minecraft.title": {
+ "defaultMessage": "Vanilla Minecraft"
+ },
+ "creation-flow.modal.setup-type.title.installation": {
+ "defaultMessage": "Välj installationstyp"
+ },
"creation-flow.modal.setup-type.title.instance": {
"defaultMessage": "Välj instanstyp"
},
@@ -869,9 +902,15 @@
"creation-flow.title.reset-server": {
"defaultMessage": "Starta om server"
},
+ "creation-flow.title.set-up-server": {
+ "defaultMessage": "Ställ in server"
+ },
"external-files.permissions-card.add-files-modal.confirm": {
"defaultMessage": "Lägg till {count, plural, one {# fil} other {# filer}}"
},
+ "external-files.permissions-card.add-files-modal.load-error.title": {
+ "defaultMessage": "Kunde inte ladda filer"
+ },
"external-files.permissions-card.add-files-modal.no-search-results": {
"defaultMessage": "Inga filer matchade din sökning."
},
@@ -896,9 +935,15 @@
"external-files.permissions-card.attribution.moderation-status.passed": {
"defaultMessage": "Godkänd"
},
+ "external-files.permissions-card.badge.no-permission": {
+ "defaultMessage": "Ingen tillåtelse"
+ },
"external-files.permissions-card.badge.not-allowed": {
"defaultMessage": "Inte tillåten"
},
+ "external-files.permissions-card.badge.pending": {
+ "defaultMessage": "Väntar"
+ },
"external-files.permissions-card.custom-license-option": {
"defaultMessage": "Annan"
},
@@ -962,6 +1007,12 @@
"external-files.permissions-card.file-count": {
"defaultMessage": "{count, plural, one {# fil} other {# filer}}"
},
+ "external-files.permissions-card.included-files": {
+ "defaultMessage": "Inkluderade filer:"
+ },
+ "external-files.permissions-card.included-in-versions": {
+ "defaultMessage": "Inkuderad i {count, plural, one {# verion} other {# versioner}}:"
+ },
"external-files.permissions-card.last-updated": {
"defaultMessage": "Senast uppdaterad den {date} av {user}"
},
@@ -1010,6 +1061,18 @@
"external-files.permissions-card.reason.special-permission.description": {
"defaultMessage": "Du har erhållit speciell tillåtelse för att distribuera detta verk i ditt modpaket."
},
+ "external-files.permissions-card.remove-group": {
+ "defaultMessage": "Radera grupp"
+ },
+ "external-files.permissions-card.remove-group-confirmation.title": {
+ "defaultMessage": "Radera {title}?"
+ },
+ "external-files.permissions-card.remove-group-error.title": {
+ "defaultMessage": "Kunde inte radera grupp"
+ },
+ "external-files.permissions-card.remove-group-shift-hint": {
+ "defaultMessage": "Håll skift medan du klickar för att hoppa över bekräftelsen."
+ },
"external-files.permissions-card.split-file": {
"defaultMessage": "Ta bort från grupp"
},
@@ -1094,9 +1157,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Filen sparades"
},
- "files.editor.find-close": {
- "defaultMessage": "Stäng"
- },
"files.editor.find-in-file": {
"defaultMessage": "Hitta"
},
@@ -1145,12 +1205,18 @@
"files.image_viewer.image_too_large": {
"defaultMessage": "Bilden är för stor för att se (högst {maxDimension}x{maxDimension} pixlar)"
},
+ "files.image_viewer.invalid_image": {
+ "defaultMessage": "Ogiltig eller tom bildfil."
+ },
"files.image_viewer.load_failed": {
"defaultMessage": "Kunde inte ladda bilden"
},
"files.image_viewer.reset_zoom": {
"defaultMessage": "Återställ zoom"
},
+ "files.image_viewer.viewed_image_alt": {
+ "defaultMessage": "Visad bild"
+ },
"files.image_viewer.zoom_in": {
"defaultMessage": "Zooma in"
},
@@ -1190,6 +1256,9 @@
"files.move-modal.header": {
"defaultMessage": "Flytta {type}"
},
+ "files.navbar.back-to-home": {
+ "defaultMessage": "Tillbaka hem"
+ },
"files.navbar.breadcrumb-navigation": {
"defaultMessage": "Länkstigsnavigering"
},
@@ -1220,9 +1289,24 @@
"files.navbar.upload-from-zip": {
"defaultMessage": "Ladda upp .zip-fil"
},
+ "files.navbar.upload-from-zip-url": {
+ "defaultMessage": "Uppladdad från .zip-URL"
+ },
"files.operations.current-file": {
"defaultMessage": "Nuvarande fil: {file}"
},
+ "files.operations.extracted": {
+ "defaultMessage": "{size} packas upp"
+ },
+ "files.operations.extracting": {
+ "defaultMessage": "Packar upp {source}"
+ },
+ "files.operations.extracting-completed": {
+ "defaultMessage": "Uppackning {source} slutförd"
+ },
+ "files.operations.extracting-failed": {
+ "defaultMessage": "Uppackning {source} misslyckad"
+ },
"files.operations.modpack-from-url": {
"defaultMessage": "modpaket från en webbadress"
},
@@ -1437,7 +1521,7 @@
"defaultMessage": "Prestandapåverkan"
},
"header.category.resolutions": {
- "defaultMessage": "Kvalitet"
+ "defaultMessage": "Upplösning"
},
"hosting.content.failed-to-bulk-delete": {
"defaultMessage": "Kunde inte radera innehållet"
@@ -1496,6 +1580,9 @@
"hosting.loader.loader-version": {
"defaultMessage": "{loader, select, null {Loader} other {{loader}}} version"
},
+ "hosting.loader.reset-server": {
+ "defaultMessage": "Återställ server"
+ },
"hosting.specs.burst": {
"defaultMessage": "Ökar upp till {cpus} CPU:er"
},
@@ -1571,9 +1658,15 @@
"installation-settings.incompatible-content.auto-fix-button": {
"defaultMessage": "Auto-fix"
},
+ "installation-settings.linked-instance.title": {
+ "defaultMessage": "Länkat {projectType}"
+ },
"installation-settings.linked.modpack": {
"defaultMessage": "modpaket"
},
+ "installation-settings.linked.server-project": {
+ "defaultMessage": "serverprojekt"
+ },
"installation-settings.loader-version": {
"defaultMessage": "{loader} version"
},
@@ -1581,7 +1674,7 @@
"defaultMessage": "Du kommer att behöva ställa om din server för att ändra loader."
},
"installation-settings.reinstall-modpack.description": {
- "defaultMessage": "Ominstallering av modpaketet återställer {type} innehåll till dess ursprungliga skick, vilket tar bort moddar eller innehåll du lagt till."
+ "defaultMessage": "Ominstallering av modpaketet återställer {type}innehållet till dess ursprungliga skick, vilket tar bort moddar eller innehåll du lagt till."
},
"installation-settings.reinstall-modpack.title": {
"defaultMessage": "Ominstallera modpaket"
@@ -1715,6 +1808,9 @@
"instances.modpack-content-modal.empty-title": {
"defaultMessage": "Inget innehåll hittades"
},
+ "instances.modpack-content-modal.external-content-description": {
+ "defaultMessage": "Den här filen är inte publiserad på Modrinth."
+ },
"instances.modpack-content-modal.header": {
"defaultMessage": "Modpaketets innehåll"
},
@@ -1724,6 +1820,9 @@
"instances.modpack-content-modal.no-results": {
"defaultMessage": "Inga projekt matchar din sökning."
},
+ "instances.modpack-content-modal.open-in-slicer": {
+ "defaultMessage": "Öppna i Slicer"
+ },
"instances.modpack-content-modal.search-placeholder": {
"defaultMessage": "Sök genom {count, number} projekt"
},
@@ -1823,6 +1922,9 @@
"label.copied-path": {
"defaultMessage": "Kopiera sökväg"
},
+ "label.create-failed": {
+ "defaultMessage": "Skapning misslyckades"
+ },
"label.created-ago": {
"defaultMessage": "Skapad {ago}"
},
@@ -1844,6 +1946,9 @@
"label.details": {
"defaultMessage": "Detaljer"
},
+ "label.discover-content": {
+ "defaultMessage": "Upptäck innehåll"
+ },
"label.done": {
"defaultMessage": "Klart"
},
@@ -1859,6 +1964,9 @@
"label.error": {
"defaultMessage": "Fel"
},
+ "label.extract-failed": {
+ "defaultMessage": "Uppackning misslyckades"
+ },
"label.filter-by": {
"defaultMessage": "Filtrera efter"
},
@@ -1874,6 +1982,9 @@
"label.hide-installed-content": {
"defaultMessage": "Göm redan installerat innehåll"
},
+ "label.hide-selected-content": {
+ "defaultMessage": "Göm valt innehåll"
+ },
"label.installation-info": {
"defaultMessage": "Installationsinfo"
},
@@ -1898,6 +2009,9 @@
"label.modpack": {
"defaultMessage": "Modpaket"
},
+ "label.move-failed": {
+ "defaultMessage": "Flytt misslyckades"
+ },
"label.no": {
"defaultMessage": "Nej"
},
@@ -1913,6 +2027,9 @@
"label.password": {
"defaultMessage": "Lösenord"
},
+ "label.permissions": {
+ "defaultMessage": "Behörigheter"
+ },
"label.plan-custom": {
"defaultMessage": "Anpassad"
},
@@ -1943,6 +2060,9 @@
"label.rejected": {
"defaultMessage": "Nekad"
},
+ "label.rename-failed": {
+ "defaultMessage": "Namnbyte misslyckades"
+ },
"label.rewards-program-terms-agreement": {
"defaultMessage": "Jag godkänner Belöningsprogrammets Villkor "
},
@@ -1958,12 +2078,18 @@
"label.select-all": {
"defaultMessage": "Välj alla"
},
+ "label.selected": {
+ "defaultMessage": "Vald"
+ },
"label.selection-actions": {
"defaultMessage": "Valåtgärder"
},
"label.server": {
"defaultMessage": "Server"
},
+ "label.server-only": {
+ "defaultMessage": "Endast server"
+ },
"label.servers": {
"defaultMessage": "Servrar"
},
@@ -1994,6 +2120,9 @@
"label.updating": {
"defaultMessage": "Uppdaterar..."
},
+ "label.upload-failed": {
+ "defaultMessage": "Uppladdning misslyckades"
+ },
"label.username": {
"defaultMessage": "Användarnamn"
},
@@ -2162,6 +2291,9 @@
"markdown-editor.markdown-formatting-support": {
"defaultMessage": "Denna redigerare stödjer markdown formatering ."
},
+ "markdown-editor.max-length.label": {
+ "defaultMessage": "Max längd:"
+ },
"markdown-editor.max-length.unlimited": {
"defaultMessage": "Obegränsad"
},
@@ -2420,6 +2552,108 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.user": {
+ "defaultMessage": "En Modrinth-användare."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "Är du säker på att du vill blocka den här användaren?"
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Användare blockerad"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "Blocka {username}"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Visa användarstatistik"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Blockera"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "Skapa ett projekt"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Visa användardetaljer"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "Hantera projekt"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Avblockera"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "projekt"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "E-post verifierad"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "Har lösenord"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "Har TOTP"
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "Betalningsmetoder"
+ },
+ "profile.details.title": {
+ "defaultMessage": "Användardetaljer"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "E-post ej verifierad"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "E-post verifierad"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "Användarprofilen kunde inte laddas in."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "Användare hittades inte"
+ },
+ "profile.label.collection": {
+ "defaultMessage": "Sammling"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, one {nedladdning} other {nedladdningar}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "Gick med"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "Den här användaren har inga samlingar!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "Du har inga samlingar än."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "Den här användaren har inga projekt!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "Du har inga projekt än."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "Organisationer"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "Projekt"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Officiellt Modrinth-konto"
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "Ett fel inträffade under avblockeringen av den här användaren. Vänligen försök igen."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "Misslyckades att avblockera användare"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "{username} har avblockerats."
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "Användare avblockerad"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "Skapades {date}"
},
@@ -2438,9 +2672,15 @@
"project-card.environment.server": {
"defaultMessage": "Server"
},
+ "project-card.environment.singleplayer": {
+ "defaultMessage": "Enspelarläge"
+ },
"project-type.all": {
"defaultMessage": "Alla"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "Samlingar"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, one {Datapaket} other {Datapaket}}"
},
@@ -2540,6 +2780,9 @@
"project.about.compatibility.platforms": {
"defaultMessage": "Plattformar"
},
+ "project.about.compatibility.platforms-plural": {
+ "defaultMessage": "Platform{count, plural, one {} other {ar}}"
+ },
"project.about.compatibility.title": {
"defaultMessage": "Kompatibilitet"
},
@@ -2708,6 +2951,9 @@
"project.follower-count-tooltip": {
"defaultMessage": "{count, number} följare"
},
+ "project.license.title": {
+ "defaultMessage": "Licens"
+ },
"project.online-player-count": {
"defaultMessage": "{count, number} online"
},
@@ -3113,6 +3359,12 @@
"project.settings.view.title": {
"defaultMessage": "Visa"
},
+ "project.stats.downloads-label": {
+ "defaultMessage": "nedladdning{count, plural, one {} other {ar}}"
+ },
+ "project.stats.followers-label": {
+ "defaultMessage": "följare"
+ },
"project.versions.channel.alpha.symbol": {
"defaultMessage": "A"
},
@@ -3122,6 +3374,9 @@
"project.versions.channel.release.symbol": {
"defaultMessage": "R"
},
+ "project.versions.platform.modloader.short": {
+ "defaultMessage": "ModLoader"
+ },
"project.visibility.archived": {
"defaultMessage": "Arkiverad"
},
@@ -3338,6 +3593,9 @@
"servers.access-page.activity-log-filter.action.java-version-modified": {
"defaultMessage": "Ändrade Java-version"
},
+ "servers.access-page.activity-log-filter.action.loader-version-edited": {
+ "defaultMessage": "Ändrade loaderversion"
+ },
"servers.access-page.activity-log-filter.action.modpack-changed": {
"defaultMessage": "Ändrade modpaket"
},
@@ -3638,6 +3896,18 @@
"servers.audit-log.event.java-version-modified": {
"defaultMessage": "Ändrade Java-version till "
},
+ "servers.audit-log.event.loader-and-version-changed": {
+ "defaultMessage": "Ändrade loader till "
+ },
+ "servers.audit-log.event.loader-changed": {
+ "defaultMessage": "Ändrade loader till "
+ },
+ "servers.audit-log.event.loader-version-changed": {
+ "defaultMessage": "Ändrare loaderversion till "
+ },
+ "servers.audit-log.event.loader-version-cleared": {
+ "defaultMessage": "Rensade laoaderversion"
+ },
"servers.audit-log.event.modpack-changed": {
"defaultMessage": "Ändrade modpaket"
},
@@ -3695,6 +3965,9 @@
"servers.audit-log.event.server-properties-modified-label": {
"defaultMessage": "Modifierade serveregenskaper"
},
+ "servers.audit-log.event.server-reset": {
+ "defaultMessage": "Återställ server"
+ },
"servers.audit-log.event.server-restarted": {
"defaultMessage": "Startade om server"
},
@@ -3767,30 +4040,75 @@
"servers.backups.admonition.fallback-name": {
"defaultMessage": "Din säkerhetskopia"
},
+ "servers.backups.admonition.restore-cancelled.title": {
+ "defaultMessage": "Återställning avbröts"
+ },
"servers.backups.admonition.restore-failed.description": {
"defaultMessage": "Något gick fel när vi försökte återställa från säkerhetskopian {backupName}. Vänligen försök igen eller kontakta support om felet återkommer."
},
+ "servers.backups.admonition.restore-failed.title": {
+ "defaultMessage": "Återställning misslyckades"
+ },
"servers.backups.admonition.restore-queued.description": {
"defaultMessage": "Återställning från {backupName} är köad och kommer att börja strax."
},
"servers.backups.admonition.restore-successful.description": {
"defaultMessage": "Din server har återställts till {backupName} och är redo för att startas."
},
+ "servers.backups.admonition.restore-successful.title": {
+ "defaultMessage": "Återställning slutförd"
+ },
"servers.backups.admonition.restoring-backup.description": {
"defaultMessage": "Återställer din server från {backupName}. Detta kan ta några minuter."
},
"servers.backups.admonition.restoring-backup.title": {
"defaultMessage": "Återställer från säkerhetskopia"
},
+ "servers.backups.bulk-bar.deleting": {
+ "defaultMessage": "Raderar {total, plural, one {# säkerhetskopia} other {# säkerhetskopior}}..."
+ },
+ "servers.backups.bulk-bar.selected-count": {
+ "defaultMessage": "{count, plural, one {# säkerhetskopia vald} other {# säkerhetskopior valda}}"
+ },
"servers.backups.delete-modal.admonition-body": {
"defaultMessage": "När {count, plural, one {denna säkerhetskopia raderas kan den} other {dessa säkerhetskopior raderas kan de}} inte återställas. Radering är permanent."
},
+ "servers.backups.delete-modal.admonition-header": {
+ "defaultMessage": "Raderingsvarning"
+ },
+ "servers.backups.delete-modal.backups-label": {
+ "defaultMessage": "{count, plural, one {Säkerhetskopia} other {Säkerhetskopior ({count})}}"
+ },
+ "servers.backups.delete-modal.confirm": {
+ "defaultMessage": "Radera {count, plural, one {säkerhetskopia} other {# säkerhetskopior}}"
+ },
+ "servers.backups.delete-modal.header": {
+ "defaultMessage": "Radera {count, plural, one {säkerhetskopia} other {säkerhetskopior}}"
+ },
+ "servers.backups.empty.description": {
+ "defaultMessage": "Skapa din första säkerhetskopia"
+ },
+ "servers.backups.empty.heading": {
+ "defaultMessage": "Inga säkerhetskopior än"
+ },
+ "servers.backups.filtered-empty.clear-filters": {
+ "defaultMessage": "Töm filter"
+ },
+ "servers.backups.filtered-empty.description": {
+ "defaultMessage": "Prova ett annat filer eller töm filtren för att se alla säkerhetskopior."
+ },
+ "servers.backups.filtered-empty.heading": {
+ "defaultMessage": "Inga säkerhetskopior matchar"
+ },
"servers.backups.item.auto": {
"defaultMessage": "Auto"
},
"servers.backups.item.backup-schedule": {
"defaultMessage": "Säkerhetskopieringschema"
},
+ "servers.backups.item.creator-avatar-alt": {
+ "defaultMessage": "{username}s avatar"
+ },
"servers.backups.item.manual-backup": {
"defaultMessage": "Manuel säkerhetskopiering"
},
@@ -3800,6 +4118,9 @@
"servers.backups.item.restore": {
"defaultMessage": "Återställ"
},
+ "servers.backups.select-backup-aria": {
+ "defaultMessage": "Välj säkerhetskopia {name}"
+ },
"servers.backups.toolbar.create-backup": {
"defaultMessage": "Skapa säkerhetskopia"
},
@@ -3872,12 +4193,18 @@
"servers.installing-banner.error.internal-platform": {
"defaultMessage": "Ett internt fel inträffade när plattformen installerades. Vänligen försök igen."
},
+ "servers.installing-banner.error.invalid-loader-version": {
+ "defaultMessage": "Den angivna loader eller Minecraft-versionen kunde inte installeras. Den kan vara ogiltig eller stöds inte."
+ },
"servers.installing-banner.error.modpack-install-failed": {
"defaultMessage": "Modpaketet kunde inte installeras. Det kanske är korrumperad eller inkompatibel."
},
"servers.installing-banner.error.unknown": {
"defaultMessage": "Ett oväntat fel inträffade under installeringen."
},
+ "servers.installing-banner.error.unsupported-loader-version": {
+ "defaultMessage": "Denna version av Minecraft eller loader stöds ännu inte av Modrinth Hosting."
+ },
"servers.installing-banner.phase.installing-addons": {
"defaultMessage": "Installerar tillägg..."
},
@@ -3906,7 +4233,7 @@
"defaultMessage": "Ny server"
},
"servers.list-empty.no-servers-description": {
- "defaultMessage": "Installera moddar, bjud in vänner och spela tillsammans, allt från Modrinth-appen."
+ "defaultMessage": "Installera moddar, bjud in vänner och spela tillsammans, allt från Modrinth App."
},
"servers.list-empty.no-servers-title": {
"defaultMessage": "Inga servrar än"
@@ -3983,6 +4310,9 @@
"servers.manage.error.details": {
"defaultMessage": "Feldetaljer:"
},
+ "servers.manage.error.title": {
+ "defaultMessage": "Servrar kunde inte laddas in"
+ },
"servers.manage.handle-error.title": {
"defaultMessage": "Ett fel inträffade"
},
@@ -4001,6 +4331,9 @@
"servers.manage.purchase-unavailable.text": {
"defaultMessage": "Betalningsinformation laddar fortfarande. Öppnar kassan så snart som möjligt."
},
+ "servers.manage.purchase-unavailable.title": {
+ "defaultMessage": "Köp otillgängligt"
+ },
"servers.manage.reload-button": {
"defaultMessage": "Ladda om"
},
@@ -4034,9 +4367,15 @@
"servers.manage.your-servers-title": {
"defaultMessage": "Dina servrar"
},
+ "servers.medal-listing.countdown.remaining": {
+ "defaultMessage": "{days} {days, plural, one {dag} other {dagar}} {hours} {hours, plural, one {timme} other {timmar}} {minutes} {minutes, plural, one {minut} other {minuter}} {seconds} {seconds, plural, one {sekund} other {sekunder}} återstår..."
+ },
"servers.medal-listing.new-server-label": {
"defaultMessage": "Ny server"
},
+ "servers.medal-listing.notice.upgrading": {
+ "defaultMessage": "Din servers hårdvara uppgraderas just nu och kommer snart vara online igen."
+ },
"servers.medal-listing.owner-avatar-alt": {
"defaultMessage": "{username}s avatar"
},
@@ -4232,6 +4571,12 @@
"servers.setup.onboarding.modpack-upload-failed.title": {
"defaultMessage": "Modpaket-uppladdning misslyckades"
},
+ "servers.setup.onboarding.setup-server.button": {
+ "defaultMessage": "Ställ in server"
+ },
+ "servers.setup.onboarding.step.choose.description": {
+ "defaultMessage": "Välj ditt favorit modpaket från Modrinth, eller välj en loader och lägg till de moddar du vill."
+ },
"servers.setup.onboarding.step.choose.title": {
"defaultMessage": "Välj vad du vill spela"
},
@@ -4241,6 +4586,9 @@
"servers.setup.onboarding.step.invite-friends.title": {
"defaultMessage": "Bjud in dina vänner"
},
+ "servers.setup.onboarding.steps.heading": {
+ "defaultMessage": "Ställ in din server (≈ 2 min)"
+ },
"servers.setup.onboarding.uploading.progress": {
"defaultMessage": "Laddar upp ({percent, number}%)"
},
@@ -4275,7 +4623,7 @@
"defaultMessage": "Dina applikationer"
},
"settings.authorized-apps.title": {
- "defaultMessage": "Auktoriserade appar"
+ "defaultMessage": "Behöriga appar"
},
"settings.billing.title": {
"defaultMessage": "Prenumerationer"
@@ -4293,10 +4641,10 @@
"defaultMessage": "OLED"
},
"settings.display.theme.preferred-dark-theme": {
- "defaultMessage": "Önskat mörkt tema"
+ "defaultMessage": "Föredraget mörkt tema"
},
"settings.display.theme.preferred-light-theme": {
- "defaultMessage": "Önskat ljust tema"
+ "defaultMessage": "Föredraget ljust tema"
},
"settings.display.theme.retro": {
"defaultMessage": "Retro"
@@ -4340,9 +4688,177 @@
"settings.pats.title": {
"defaultMessage": "Personliga åtkomstnycklar"
},
+ "settings.profile.bio.title": {
+ "defaultMessage": "Biografi"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "Profil"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "Profilbild"
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "Misslyckades att uppdatera profil"
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "Logga in på ett Modrinth-konto för att anpassa din offentliga profil."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Modrinth-konto behövs"
+ },
"settings.sessions.title": {
"defaultMessage": "Sessioner"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "Åtgärder"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Användare"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Det här är användare du har blockat på Modrinth. De kan inte:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "Du har inte blockerat någon."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "Blockerade användare kunde inte laddas in."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "Laddar in blockerade användare…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "Skicka vänförfrågan till dig"
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "Bjuda in dig till en delad instans"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "Blockerade användare"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "Avblockera"
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "Avblockera {username}"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "{username}s avatar"
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "Vänförfrågningar"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "Kommer snart!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "Alla"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "Vänner"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "Vänners vänner"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "Ingen"
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "Inbjudningar"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Modrinth-konto krävs"
+ },
+ "sharing.invite-players-modal.add": {
+ "defaultMessage": "Lägg till"
+ },
+ "sharing.invite-players-modal.added": {
+ "defaultMessage": "Tillagd"
+ },
+ "sharing.invite-players-modal.already-invited": {
+ "defaultMessage": "Den här användaren har redan bjudits in."
+ },
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "Tillämpa"
+ },
+ "sharing.invite-players-modal.avatar-alt": {
+ "defaultMessage": "{username}s avatar"
+ },
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "Anpassat..."
+ },
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "Anpassat: {date}"
+ },
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "Om 1 dag"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "Om 1 timme"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "Om 7 dagar"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "Om 6 timmar"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "Om 3 dagar"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "Om 12 timmar"
+ },
+ "sharing.invite-players-modal.expiry-label": {
+ "defaultMessage": "Utgångsdatum"
+ },
+ "sharing.invite-players-modal.friends-heading": {
+ "defaultMessage": "Dina vänner – {count}"
+ },
+ "sharing.invite-players-modal.invite": {
+ "defaultMessage": "Bjud in"
+ },
+ "sharing.invite-players-modal.invite-expiry-description": {
+ "defaultMessage": "Din inbjudningslänk går ut om {duration}."
+ },
+ "sharing.invite-players-modal.invite-link-heading": {
+ "defaultMessage": "Eller använd en inbjudningslänk"
+ },
+ "sharing.invite-players-modal.link-copied-text": {
+ "defaultMessage": "Inbjudningslänken har kopierats till urklippet."
+ },
+ "sharing.invite-players-modal.link-copied-title": {
+ "defaultMessage": "Länk kopierad"
+ },
+ "sharing.invite-players-modal.link-copy-failed-title": {
+ "defaultMessage": "Kunde inte kopiera länk"
+ },
+ "sharing.invite-players-modal.max-uses-label": {
+ "defaultMessage": "Högst antal användningar"
+ },
+ "sharing.invite-players-modal.no-friends": {
+ "defaultMessage": "Inga vänner hittades."
+ },
+ "sharing.invite-players-modal.no-search-results": {
+ "defaultMessage": "Inga matchande användare hittades."
+ },
+ "sharing.invite-players-modal.requested": {
+ "defaultMessage": "Förfrågan skickad"
+ },
+ "sharing.invite-players-modal.requested-tooltip": {
+ "defaultMessage": "{username} behöver acceptera din vänförfrågan först"
+ },
+ "sharing.invite-players-modal.save-button": {
+ "defaultMessage": "Spara"
+ },
+ "sharing.invite-players-modal.search-placeholder": {
+ "defaultMessage": "Ange Modrinth-användarnamn"
+ },
+ "sharing.invite-players-modal.searching": {
+ "defaultMessage": "Söker..."
+ },
+ "sharing.invite-players-modal.update-invite-link-failed-title": {
+ "defaultMessage": "Kunde inte uppdatera inbjudningslänken"
+ },
"tag.category.128x": {
"defaultMessage": "128x"
},
@@ -4844,6 +5360,9 @@
"ui.confirm-leave-modal.title": {
"defaultMessage": "Lämna sidan?"
},
+ "ui.stacked-admonitions.dismiss-all": {
+ "defaultMessage": "Avvisa alla"
+ },
"unknown-file-warning-modal.dont-install": {
"defaultMessage": "Installera inte"
},
@@ -4889,12 +5408,18 @@
"user.profile.badge.pride.about.1": {
"defaultMessage": "Denna användare har deltagit i åtminstone ett av Modrinths Pride-insamlingar för LGBTQ+ gemenskapen."
},
+ "user.profile.badge.staff.name": {
+ "defaultMessage": "Modrinth-team"
+ },
"version.content.name": {
"defaultMessage": "Namn"
},
"version.content.version": {
"defaultMessage": "Version"
},
+ "version.file-type.primary": {
+ "defaultMessage": "Primär"
+ },
"version.file-type.signature": {
"defaultMessage": "Signaturfil"
},
@@ -4925,6 +5450,9 @@
"version.section.included-content": {
"defaultMessage": "Inkluderat innehåll"
},
+ "version.section.no-modpack-mod-loader": {
+ "defaultMessage": "Ingen modloader"
+ },
"version.supplementary-resources.file": {
"defaultMessage": "Fil"
},
@@ -4935,3 +5463,4 @@
"defaultMessage": "Typ"
}
}
+
diff --git a/packages/ui/src/locales/th-TH/index.json b/packages/ui/src/locales/th-TH/index.json
index 4908b72a79..3313c10a83 100644
--- a/packages/ui/src/locales/th-TH/index.json
+++ b/packages/ui/src/locales/th-TH/index.json
@@ -663,3 +663,4 @@
"defaultMessage": "ภาษา"
}
}
+
diff --git a/packages/ui/src/locales/tr-TR/index.json b/packages/ui/src/locales/tr-TR/index.json
index 5d52c8ea46..8fa466b737 100644
--- a/packages/ui/src/locales/tr-TR/index.json
+++ b/packages/ui/src/locales/tr-TR/index.json
@@ -467,9 +467,21 @@
"content.diff-modal.external-diff-type.updated": {
"defaultMessage": "Güncellendi"
},
+ "content.diff-modal.file-count": {
+ "defaultMessage": "{count, plural,one {# dosya}other {# dosya}}"
+ },
+ "content.diff-modal.game-version-updated": {
+ "defaultMessage": "Oyun sürümü"
+ },
"content.diff-modal.install-anyway": {
"defaultMessage": "Yine de indir"
},
+ "content.diff-modal.loader-updated": {
+ "defaultMessage": "Yükleyici"
+ },
+ "content.diff-modal.modpack-linked": {
+ "defaultMessage": "Bağlantılı mod paketi"
+ },
"content.diff-modal.removed-count": {
"defaultMessage": "{count} kaldırıldı"
},
@@ -1160,6 +1172,15 @@
"external-files.permissions-card.reason.special-permission.description": {
"defaultMessage": "Bu çalışmayı mod paketinizde yeniden dağıtmak için özel izin alınmıştır."
},
+ "external-files.permissions-card.remove-group": {
+ "defaultMessage": "Grubu sil"
+ },
+ "external-files.permissions-card.remove-group-confirmation.title": {
+ "defaultMessage": "{title} silinsin mi?"
+ },
+ "external-files.permissions-card.remove-group-error.title": {
+ "defaultMessage": "Grup silinemedi"
+ },
"external-files.permissions-card.split-file": {
"defaultMessage": "Gruptan kaldır"
},
@@ -1253,9 +1274,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Dosya kaydedildi"
},
- "files.editor.find-close": {
- "defaultMessage": "Kapat"
- },
"files.editor.find-in-file": {
"defaultMessage": "Bul"
},
@@ -2039,6 +2057,9 @@
"instances.modpack-content-modal.empty-title": {
"defaultMessage": "İçerik bulunamadı"
},
+ "instances.modpack-content-modal.external-content": {
+ "defaultMessage": "Harici"
+ },
"instances.modpack-content-modal.header": {
"defaultMessage": "Mod paketi içeriği"
},
@@ -2792,6 +2813,42 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Bir Modrinth kullanıcısı."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "Bu kullanıcıyı engellemek istediğinize emin misiniz?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "Kullanıcıyı engellerken bir sorun oluştu. Lütfen tekrar deneyin."
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} engellendi."
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Kullanıcı engellendi"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "{username}'i engelle"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Kullanıcı analizlerini göster"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Engelle"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Kullanıcı detaylarını göster"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Engellemeyi kaldır"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural,one{# proje} other{# proje}}"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "Kullanıcı profili yüklenemedi."
+ },
"profile.label.badges": {
"defaultMessage": "Rozetler"
},
diff --git a/packages/ui/src/locales/uk-UA/index.json b/packages/ui/src/locales/uk-UA/index.json
index 67d677efb3..95bbf42123 100644
--- a/packages/ui/src/locales/uk-UA/index.json
+++ b/packages/ui/src/locales/uk-UA/index.json
@@ -374,6 +374,9 @@
"content.confirm-deletion.header": {
"defaultMessage": "Видалити {itemType}"
},
+ "content.confirm-disable.header": {
+ "defaultMessage": "Вимкнути {itemType}"
+ },
"content.confirm-modpack-update.admonition-body": {
"defaultMessage": "{action, select, downgrade {Пониження} other {Підвищення}} може спричинити проблеми сумісности. Моди чи вміст, який ви додали в збірку, буде збережено, але може бути несумісним із новою версією."
},
@@ -443,12 +446,18 @@
"content.diff-modal.added-count": {
"defaultMessage": "Додано {count}"
},
+ "content.diff-modal.config-files-updated": {
+ "defaultMessage": "Змінені конфігураційні файли"
+ },
"content.diff-modal.diff-type.added": {
"defaultMessage": "Додано (залежності)"
},
"content.diff-modal.diff-type.removed": {
"defaultMessage": "Вимкнено"
},
+ "content.diff-modal.diff-type.removed-disabled": {
+ "defaultMessage": "Видалено (вимкнено)"
+ },
"content.diff-modal.diff-type.updated": {
"defaultMessage": "Оновлено"
},
@@ -464,12 +473,36 @@
"content.diff-modal.external-diff-type.updated": {
"defaultMessage": "Оновлено"
},
+ "content.diff-modal.file-count": {
+ "defaultMessage": "{count, plural, one {# файл} few {# файли} many {# файлів} other {# файлу}}"
+ },
+ "content.diff-modal.game-version-updated": {
+ "defaultMessage": "Версія гри"
+ },
"content.diff-modal.install-anyway": {
"defaultMessage": "Усе одно встановити"
},
+ "content.diff-modal.loader-updated": {
+ "defaultMessage": "Завантажувач"
+ },
+ "content.diff-modal.modpack-linked": {
+ "defaultMessage": "Прив'язана збірка"
+ },
+ "content.diff-modal.modpack-unlinked": {
+ "defaultMessage": "Відв'язана збірка"
+ },
+ "content.diff-modal.modpack-updated": {
+ "defaultMessage": "Оновлена збірка"
+ },
+ "content.diff-modal.no-content-changes": {
+ "defaultMessage": "Без змін у вмісті"
+ },
"content.diff-modal.removed-count": {
"defaultMessage": "Видалено {count}"
},
+ "content.diff-modal.removed-disabled-count": {
+ "defaultMessage": "Видалено (вимкнено): {count}"
+ },
"content.diff-modal.reviewed-files": {
"defaultMessage": "Файл перевірятиметься, лише якщо його опубліковано на Modrinth, незалежно від його формату (включно з .mrpack)."
},
@@ -525,11 +558,14 @@
"defaultMessage": "Утримуйте клавішу Shift під час натискання, щоб пропустити підтвердження."
},
"content.inline-backup.warning-body": {
- "defaultMessage": "Ми рекомендуємо створити резервну копію перш ніж продовжувати, щоб ви могли відновити свій {type}, якщо щось піде не так."
+ "defaultMessage": "Радимо створити резервну копію перед тим, як продовжити, щоб ви могли відновити ваш {type}, якщо щось зламається."
},
"content.inline-backup.world-label": {
"defaultMessage": "світ"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "Налаштування інсталяції"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "Додатковий уміст"
},
@@ -810,7 +846,7 @@
"defaultMessage": "Переглянути збірки"
},
"creation-flow.modal.modpack.action.import": {
- "defaultMessage": "Імпортувати збірку"
+ "defaultMessage": "Перенести збірку"
},
"creation-flow.modal.modpack.known-modpack.prompt": {
"defaultMessage": "Уже знаєте яку збірку хочете встановити?"
@@ -831,13 +867,13 @@
"defaultMessage": "Власне налаштування"
},
"creation-flow.modal.setup-type.option.import-instance.description": {
- "defaultMessage": "Імпортуйте збірку з Prism, CurseForge або подібних програм."
+ "defaultMessage": "Перенесіть збірку з Prism, CurseForge абощо."
},
"creation-flow.modal.setup-type.option.import-instance.title": {
"defaultMessage": "Імпорт збірки"
},
"creation-flow.modal.setup-type.option.modpack-base.description": {
- "defaultMessage": "Перегляньте збірки на Modrinth або імпортуйте їх з файлу."
+ "defaultMessage": "Перегляньте збірки на Modrinth або перенесіть їх із файлу."
},
"creation-flow.modal.setup-type.option.modpack-base.title": {
"defaultMessage": "Установити збірку"
@@ -1115,6 +1151,21 @@
"external-files.permissions-card.reason.special-permission.description": {
"defaultMessage": "Ви отримали особливі дозволи для поширення цієї роботи у вашій збірці."
},
+ "external-files.permissions-card.remove-group": {
+ "defaultMessage": "Видалити групу"
+ },
+ "external-files.permissions-card.remove-group-confirmation.description": {
+ "defaultMessage": "Це назавжди видалить цю групу атрибуції та всі файли в ній. Цю дію неможливо скасувати."
+ },
+ "external-files.permissions-card.remove-group-confirmation.title": {
+ "defaultMessage": "Видалити {title}?"
+ },
+ "external-files.permissions-card.remove-group-error.title": {
+ "defaultMessage": "Групу не видалено"
+ },
+ "external-files.permissions-card.remove-group-shift-hint": {
+ "defaultMessage": "Утримуйте Shift під час кліку, щоб пропустити підтвердження."
+ },
"external-files.permissions-card.split-file": {
"defaultMessage": "Видалити з групи"
},
@@ -1208,9 +1259,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Файл збережено"
},
- "files.editor.find-close": {
- "defaultMessage": "Закрити"
- },
"files.editor.find-in-file": {
"defaultMessage": "Знайти"
},
@@ -1800,10 +1848,10 @@
"defaultMessage": "Редагувати інсталяцію"
},
"installation-settings.edit.warning-instance": {
- "defaultMessage": "Ми не рекомендуємо змінювати налаштування інсталяції після встановлення вмісту. Якщо ви все ж хочете їх змінити, будьте обережні, оскільки це може спричинити проблеми."
+ "defaultMessage": "Не радимо відміняти налаштування інсталяції після встановлення вмісту. Коли все ж бажаєте їх змінити, то будьте обережні, адже це може завдати вам клопоту."
},
"installation-settings.edit.warning-server": {
- "defaultMessage": "Ми не рекомендуємо змінювати налаштування інсталяції після встановлення вмісту. Якщо ви все ж хочете їх змінити, скиньте ваш сервер."
+ "defaultMessage": "Не радимо змінювати налаштування інсталяції після встановлення вмісту. Коли все ж хочете їх змінити, то скиньте свій сервер."
},
"installation-settings.incompatible-content.auto-fix-button": {
"defaultMessage": "Виправити автоматично"
@@ -1994,6 +2042,12 @@
"instances.modpack-content-modal.empty-title": {
"defaultMessage": "Умісту не знайдено"
},
+ "instances.modpack-content-modal.external-content": {
+ "defaultMessage": "Зовнішні"
+ },
+ "instances.modpack-content-modal.external-content-description": {
+ "defaultMessage": "Цей файл не опубліковано на Modrinth."
+ },
"instances.modpack-content-modal.header": {
"defaultMessage": "Уміст збірки"
},
@@ -2003,6 +2057,9 @@
"instances.modpack-content-modal.no-results": {
"defaultMessage": "За вашим запитом не знайдено жодного проєкту."
},
+ "instances.modpack-content-modal.open-in-slicer": {
+ "defaultMessage": "Відкрити в Slicer"
+ },
"instances.modpack-content-modal.search-placeholder": {
"defaultMessage": "Пошук {count, number} {count, plural, one {проєкту} other {проєктів}}"
},
@@ -2138,6 +2195,9 @@
"label.details": {
"defaultMessage": "Деталі"
},
+ "label.discover-content": {
+ "defaultMessage": "Огляд вмісту"
+ },
"label.done": {
"defaultMessage": "Готово"
},
@@ -2216,6 +2276,9 @@
"label.password": {
"defaultMessage": "Пароль"
},
+ "label.permissions": {
+ "defaultMessage": "Дозволи"
+ },
"label.plan-custom": {
"defaultMessage": "Власний"
},
@@ -2747,9 +2810,162 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "Творець Modrinth."
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "Користувач Modrinth."
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} Не зможе надсилати вам запити в друзі, запрошувати до спільних збірок або запрошувати на сервери Modrinth Hosting."
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "Дійсно заблокувати цього користувача?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "Виникла помилка під час блокування користувача. Спробуйте знову."
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "Не вдалося заблокувати користувача"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} заблоковано."
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "Користувача заблоковано"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "Заблокувати {username}"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "Переглянути аналітику користувача"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "Керувати виплатами користувача"
+ },
+ "profile.button.block": {
+ "defaultMessage": "Заблокувати"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "Створити добірку"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "Створити проєкт"
+ },
+ "profile.button.info": {
+ "defaultMessage": "Деталі про користувача"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "Керувати проєктами"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "Видалити як партнера"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "Призначити партнером"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "Розблокувати"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural, one {# проєкт} few {# проєкти} many {# проєктів} other {# проєкту}}"
+ },
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "Дозвольте спливні вікна для Modrinth, потім спробуйте знову."
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "Не вдалося отримати профіль GitHub. Спробуйте знову."
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "Не вдалося відкрити профіль GitHub"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "Сервіси автентифікації"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "Підтверджена електронна пошта"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "Має пароль"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "Має TOTP"
+ },
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "Завантаження…"
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "Способи оплати"
+ },
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "Переглянути профіль"
+ },
+ "profile.details.title": {
+ "defaultMessage": "Деталі користувача"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "Пошту не підтверджено"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "Пошту підтверджено"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "Не вдалося завантажити профіль користувача."
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "Користувача не знайдено"
+ },
+ "profile.label.affiliate": {
+ "defaultMessage": "Партнер"
+ },
"profile.label.badges": {
"defaultMessage": "Значки"
},
+ "profile.label.collection": {
+ "defaultMessage": "Добірка"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, one {завантаження} few {завантаження} many {завантажень} other {завантаження}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "Приєднався"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "Цей користувач не має добірок!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "Ви поки не маєте добірок."
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "Цей користувач не має проєктів!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "Ви поки не маєте проєктів."
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "Організації"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural, one {проєкт} few {проєкти} many {проєктів} other {проєктів}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Офіційний обліковий запис Modrinth"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "Офіційний обліковий запис Modrinth. Зв'язатися з підтримкою можна за або через електронну пошту за "
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "Виникла помилка під час розблокування користувача. Спробуйте знову."
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "Не вдалося розблокувати користувача"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "{username} розблоковано."
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "Користувача розблоковано"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "Опубліковано {date}"
},
@@ -2765,12 +2981,21 @@
"project-card.environment.client-or-server": {
"defaultMessage": "Клієнт чи сервер"
},
+ "project-card.environment.dedicated-server": {
+ "defaultMessage": "Виділений сервер"
+ },
"project-card.environment.server": {
"defaultMessage": "Сервер"
},
+ "project-card.environment.singleplayer": {
+ "defaultMessage": "Одиночна гра"
+ },
"project-type.all": {
"defaultMessage": "Усі"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "Добірки"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, one {Пакет даних} few {Пакети даних} many {Пакетів даних} other {Пакетів даних}}"
},
@@ -4997,9 +5222,216 @@
"settings.pats.title": {
"defaultMessage": "Особистий токен доступу"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "Короткий опис, щоб розповісти іншим трохи про себе."
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "Про себе"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "Профіль"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "Зображення профілю"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "Інформація з вашого профілю є загальнодоступною на Modrinth та через Modrinth API ."
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "Не вдалося оновити профіль"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "Виникла помилка під час оновлення вашого профілю Спробуйте знову."
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "Увійдіть за допомогою облікового запису Modrinth, щоб налаштувати свій публічний профіль."
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "Потрібен обліковий запис Modrinth"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "Унікальне ім'я для ідентифікації вашого профілю."
+ },
"settings.sessions.title": {
"defaultMessage": "Сеанси"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "Дії"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "Користувач"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "Це користувачі, яких ви заблокували на Modrinth. Вони не можуть:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "Ви нікого не заблокували."
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "Не вдалося завантажити заблокованих користувачів."
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "Завантаження заблокованих користувачів…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "Надсилати вам запити в друзі"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "Запрошувати вас керувати сервером Modrinth Hosting."
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "Запрошувати вас до спільних збірок"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "Заблоковані користувачі"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "Розблокувати"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "Не вдалося розблокувати користувача"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "Сталася помилка під час розблокування цього користувача. Будь ласка, спробуйте ще раз."
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "Розблокувати {username}"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "Аватар користувача {username}"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "Керуйте тим, хто може надсилати вам запити в друзі на Modrinth."
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "Запити в друзі"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "Незабаром!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "Усі"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "Друзі"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "Друзі друзів"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "Ніхто"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "Керуйте тим, хто може надсилати вам запрошення до спільних збірок та панелей Modrinth Hosting."
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "Запрошення"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "З обліковим записом Modrinth ви можете налаштувати, хто може взаємодіяти з вами, або керувати заблокованими користувачами"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "Потрібен обліковий запис Modrinth"
+ },
+ "settings.social.title": {
+ "defaultMessage": "Соціальні мережі"
+ },
+ "sharing.invite-players-modal.add": {
+ "defaultMessage": "Додати"
+ },
+ "sharing.invite-players-modal.added": {
+ "defaultMessage": "Додано"
+ },
+ "sharing.invite-players-modal.already-invited": {
+ "defaultMessage": "Цього користувача вже запрошено."
+ },
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "Застосувати"
+ },
+ "sharing.invite-players-modal.avatar-alt": {
+ "defaultMessage": "Аватар користувача {username}"
+ },
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "Власна…"
+ },
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "Власна: {date}"
+ },
+ "sharing.invite-players-modal.edit-invite-link": {
+ "defaultMessage": "Редагувати посилання-запрошення."
+ },
+ "sharing.invite-players-modal.edit-invite-link-title": {
+ "defaultMessage": "Редагувати посилання-запрошення"
+ },
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "Через 1 день"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "Через 1 годину"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "Через 7 днів"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "Через 6 годин"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "Через 3 дні"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "Через 12 годин"
+ },
+ "sharing.invite-players-modal.expiry-label": {
+ "defaultMessage": "Термін дії"
+ },
+ "sharing.invite-players-modal.friends-heading": {
+ "defaultMessage": "Ваші друзі — {count}"
+ },
+ "sharing.invite-players-modal.invite": {
+ "defaultMessage": "Запросити"
+ },
+ "sharing.invite-players-modal.invite-expiry-description": {
+ "defaultMessage": "Термін дії вашого посилання-запрошення закінчується через {duration}."
+ },
+ "sharing.invite-players-modal.invite-link-heading": {
+ "defaultMessage": "Або використайте посилання-запрошення"
+ },
+ "sharing.invite-players-modal.link-copied-text": {
+ "defaultMessage": "Посилання-запрошення скопійовано до буфера обміну."
+ },
+ "sharing.invite-players-modal.link-copied-title": {
+ "defaultMessage": "Посилання скопійовано"
+ },
+ "sharing.invite-players-modal.link-copy-failed-title": {
+ "defaultMessage": "Не вдалося скопіювати посилання"
+ },
+ "sharing.invite-players-modal.max-uses-label": {
+ "defaultMessage": "Максимальна кількість використань"
+ },
+ "sharing.invite-players-modal.no-friends": {
+ "defaultMessage": "Не знайдено друзів."
+ },
+ "sharing.invite-players-modal.no-search-results": {
+ "defaultMessage": "Відповідних користувачів не знайдено."
+ },
+ "sharing.invite-players-modal.requested": {
+ "defaultMessage": "Запит відправлено"
+ },
+ "sharing.invite-players-modal.requested-tooltip": {
+ "defaultMessage": "{username} спочатку має прийняти ваш запит у друзі"
+ },
+ "sharing.invite-players-modal.save-button": {
+ "defaultMessage": "Зберегти"
+ },
+ "sharing.invite-players-modal.search-placeholder": {
+ "defaultMessage": "Уведіть ім’я користувача Modrinth"
+ },
+ "sharing.invite-players-modal.searching": {
+ "defaultMessage": "Шукаємо…"
+ },
+ "sharing.invite-players-modal.update-invite-link-failed-title": {
+ "defaultMessage": "Не вдалося оновити посилання"
+ },
"tag.category.128x": {
"defaultMessage": "×128"
},
@@ -5166,7 +5598,7 @@
"defaultMessage": "Низьке"
},
"tag.category.magic": {
- "defaultMessage": "Магія"
+ "defaultMessage": "Чаклунство"
},
"tag.category.management": {
"defaultMessage": "Керування"
@@ -5190,7 +5622,7 @@
"defaultMessage": "ММО"
},
"tag.category.mobs": {
- "defaultMessage": "Моби"
+ "defaultMessage": "Сутності"
},
"tag.category.modded": {
"defaultMessage": "Для модів"
@@ -5550,13 +5982,13 @@
"defaultMessage": "Шкідливе програмне забезпечення часто поширюють через моди, які публікуються на таких платформах, як Discord."
},
"unknown-file-warning-modal.mod-warning-body": {
- "defaultMessage": " не є опублікований на Modrinth. Ми наполегливо рекомендуємо встановлювати лише ті файли, яким довіряєте."
+ "defaultMessage": " не викладено на Modrinth. Наполегливо радимо встановлювати вміст лише з тих джерел, яким ви довіряєте."
},
"unknown-file-warning-modal.mod-warning-title": {
"defaultMessage": "Попередження про невідомий файл"
},
"unknown-file-warning-modal.modpack-warning-body": {
- "defaultMessage": " містить файли, які не є опубліковані на Modrinth. Ми наполегливо рекомендуємо встановлювати лише ті файли, яким довіряєте."
+ "defaultMessage": " містить файли, котрі не викладені на Modrinth. Наполегливо радимо встановлювати вміст лише з тих джерел, яким ви довіряєте."
},
"unknown-file-warning-modal.modpack-warning-title": {
"defaultMessage": "Попередження про невідомі файли"
diff --git a/packages/ui/src/locales/vi-VN/index.json b/packages/ui/src/locales/vi-VN/index.json
index 50d370d6d4..f65e18d54c 100644
--- a/packages/ui/src/locales/vi-VN/index.json
+++ b/packages/ui/src/locales/vi-VN/index.json
@@ -935,9 +935,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "Tệp đã được lưu"
},
- "files.editor.find-close": {
- "defaultMessage": "Đóng"
- },
"files.editor.find-in-file": {
"defaultMessage": "Tìm"
},
@@ -5082,3 +5079,4 @@
"defaultMessage": "Đội ngũ Modrinth"
}
}
+
diff --git a/packages/ui/src/locales/zh-CN/index.json b/packages/ui/src/locales/zh-CN/index.json
index e4f883d767..91aa213378 100644
--- a/packages/ui/src/locales/zh-CN/index.json
+++ b/packages/ui/src/locales/zh-CN/index.json
@@ -566,6 +566,9 @@
"content.inline-backup.world-label": {
"defaultMessage": "世界"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "安装设置"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "附加内容"
},
@@ -1301,9 +1304,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "文件已保存"
},
- "files.editor.find-close": {
- "defaultMessage": "关闭"
- },
"files.editor.find-in-file": {
"defaultMessage": "查找"
},
@@ -2240,6 +2240,9 @@
"label.details": {
"defaultMessage": "信息"
},
+ "label.discover-content": {
+ "defaultMessage": "发现内容"
+ },
"label.done": {
"defaultMessage": "完成"
},
@@ -2318,6 +2321,9 @@
"label.password": {
"defaultMessage": "密码"
},
+ "label.permissions": {
+ "defaultMessage": "权限"
+ },
"label.plan-custom": {
"defaultMessage": "自定义"
},
@@ -2849,9 +2855,162 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "一位 Modrinth 创作者。"
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "一位 Modrinth 用户。"
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} 将无法向你发送好友请求、将你邀请到共享实例或 Modrinth Hosting 服务器。"
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "你确定要屏蔽该用户吗?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "屏蔽该用户时发生了错误。请重试。"
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "屏蔽用户失败"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} 已被屏蔽。"
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "用户已屏蔽"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "屏蔽 {username}"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "查看用户分析"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "管理用户财务"
+ },
+ "profile.button.block": {
+ "defaultMessage": "屏蔽"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "创建收藏夹"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "创建项目"
+ },
+ "profile.button.info": {
+ "defaultMessage": "查看用户详情"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "管理项目"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "解除作为联盟伙伴"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "设置为联盟伙伴"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "解除屏蔽"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural, other {# 个项目}}"
+ },
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "请在来自 Modrinth 的弹出窗口中选择允许,然后重试。"
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "无法获取 GitHub 个人资料。请重试。"
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "无法打开 GitHub 个人主页"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "身份验证提供器"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "电子邮箱已验证"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "是否有密码"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "是否有 TOTP"
+ },
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "正在加载……"
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "支付方式"
+ },
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "查看个人资料"
+ },
+ "profile.details.title": {
+ "defaultMessage": "用户详情"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "电子邮箱未验证"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "电子邮箱已验证"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "无法加载该用户的个人资料。"
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "未找到用户"
+ },
+ "profile.label.affiliate": {
+ "defaultMessage": "联盟"
+ },
"profile.label.badges": {
"defaultMessage": "荣誉徽章"
},
+ "profile.label.collection": {
+ "defaultMessage": "收藏"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, other {次下载}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "加入于"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "该用户没有收藏夹!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "你还没有任何收藏夹。"
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "该用户没有项目!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "你还没有任何项目。"
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "组织"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural, other {项目}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "官方 Modrinth 账户"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "Modrinth 的官方用户账号。可通过 或电子邮件 获取支持"
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "解除屏蔽该用户时发生了错误。请重试。"
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "解除屏蔽用户失败"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "{username} 已被解除屏蔽。"
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "用户已解除屏蔽"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "发布于 {date}"
},
@@ -2879,6 +3038,9 @@
"project-type.all": {
"defaultMessage": "全部"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "收藏夹"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, other {数据包}}"
},
@@ -3564,10 +3726,10 @@
"defaultMessage": "视图"
},
"project.stats.downloads-label": {
- "defaultMessage": "{count, plural, other {下载量}}"
+ "defaultMessage": "{count, plural, other {次下载}}"
},
"project.stats.followers-label": {
- "defaultMessage": "{count, plural, other {关注者}}"
+ "defaultMessage": "{count, plural, other {人关注}}"
},
"project.versions.channel.alpha.symbol": {
"defaultMessage": "A"
@@ -3969,7 +4131,7 @@
"defaultMessage": "角色:{role}"
},
"servers.access-page.role.editor": {
- "defaultMessage": "编辑"
+ "defaultMessage": "编辑者"
},
"servers.access-page.role.editor-description": {
"defaultMessage": "管理实例内容、文件、备份及其他设置。"
@@ -3984,13 +4146,13 @@
"defaultMessage": "受限"
},
"servers.access-page.role.viewer-description": {
- "defaultMessage": "可启动、停止并查看服务器状态,但无法进行更改。"
+ "defaultMessage": "可启动、停止和查看服务器,但无法进行更改。"
},
"servers.access-page.search-users-placeholder": {
"defaultMessage": "搜索 {count} {count, plural, one {用户} other {用户}}………"
},
"servers.access-role.editor": {
- "defaultMessage": "编辑"
+ "defaultMessage": "编辑者"
},
"servers.access-role.owner": {
"defaultMessage": "所有者"
@@ -4467,7 +4629,7 @@
"defaultMessage": "邀请"
},
"servers.grant-access-modal.permissions-help": {
- "defaultMessage": "在 这里查看各职务的完整清单。"
+ "defaultMessage": "在 这里查看各角色权限的完整列表。"
},
"servers.grant-access-modal.role.editor": {
"defaultMessage": "编辑"
@@ -4476,13 +4638,13 @@
"defaultMessage": "管理实例内容、文件、备份及其他设置。"
},
"servers.grant-access-modal.role.label": {
- "defaultMessage": "选择职能"
+ "defaultMessage": "选择角色"
},
"servers.grant-access-modal.role.viewer": {
- "defaultMessage": "受制"
+ "defaultMessage": "受限"
},
"servers.grant-access-modal.role.viewer-description": {
- "defaultMessage": "可以启动、停止与查看服务器,但无法进行任何更改。"
+ "defaultMessage": "可启动、停止和查看服务器,但无法进行更改。"
},
"servers.grant-access-modal.suggestion-avatar-alt": {
"defaultMessage": "{username}的头像"
@@ -5105,9 +5267,120 @@
"settings.pats.title": {
"defaultMessage": "个人访问令牌"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "用一段简短的描述,向大家展示你自己。"
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "简介"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "个人资料"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "头像"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "您的个人资料信息可以在 Modrinth 上公开查看 ,也可通过 Modrinth API 获取。"
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "更新档案失败"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "更新个人资料失败,请稍后重试。"
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "登录 Modrinth 账号以自定义您的公开资料。"
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "需要 Modrinth 账户"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "用于识别您个人资料的唯一名称。"
+ },
"settings.sessions.title": {
"defaultMessage": "会话"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "活动"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "用户"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "这些是你在 Modrinth 中屏蔽的用户。他们无法:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "你还没有屏蔽任何人。"
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "无法加载被屏蔽的用户。"
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "正在加载被屏蔽的用户…"
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "给你发送好友邀请"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "邀请你管理 Modrinth 托管服务器。"
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "邀请你加入共享实例"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "被屏蔽的用户"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "解除屏蔽"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "解除屏蔽用户失败"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "解除屏蔽该用户时发生了错误。请重试。"
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "解除屏蔽 {username}"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "{username} 的头像"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "控制谁可以在 Modrinth 上向你发送好友申请。"
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "好友邀请"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "即将到来!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "所有人"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "好友"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "好友的好友"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "无"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "控制谁可以向您发送共享实例和 Modrinth 托管面板的邀请。"
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "邀请"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "使用 Modrinth 账号,你可以控制谁能与你互动,并管理黑名单用户"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "需要登录 Modrinth 账号"
+ },
+ "settings.social.title": {
+ "defaultMessage": "社交"
+ },
"sharing.invite-players-modal.add": {
"defaultMessage": "添加"
},
@@ -5117,14 +5390,17 @@
"sharing.invite-players-modal.already-invited": {
"defaultMessage": "此用户已被邀请。"
},
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "应用"
+ },
"sharing.invite-players-modal.avatar-alt": {
"defaultMessage": "{username} 的头像"
},
- "sharing.invite-players-modal.cancel": {
- "defaultMessage": "取消"
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "自定义……"
},
- "sharing.invite-players-modal.cancel-button": {
- "defaultMessage": "取消"
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "自定义:{date}"
},
"sharing.invite-players-modal.edit-invite-link": {
"defaultMessage": "编辑邀请链接。"
@@ -5132,6 +5408,24 @@
"sharing.invite-players-modal.edit-invite-link-title": {
"defaultMessage": "编辑邀请链接"
},
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "1 天"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "1 小时"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "7 天"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "6 小时"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "3 天"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "12 小时"
+ },
"sharing.invite-players-modal.expiry-label": {
"defaultMessage": "过期日期"
},
@@ -5937,3 +6231,4 @@
"defaultMessage": "类型"
}
}
+
diff --git a/packages/ui/src/locales/zh-TW/index.json b/packages/ui/src/locales/zh-TW/index.json
index 191ff0108f..c7cb96b9eb 100644
--- a/packages/ui/src/locales/zh-TW/index.json
+++ b/packages/ui/src/locales/zh-TW/index.json
@@ -561,11 +561,14 @@
"defaultMessage": "按住 Shift 鍵並點選以跳過確認。"
},
"content.inline-backup.warning-body": {
- "defaultMessage": "我們建議您在繼續操作之前建立備份,以便在出現任何問題時可以還原您的{type}。"
+ "defaultMessage": "我們建議在繼續操作前先建立備份,以便在發生問題時還原你的{type}。"
},
"content.inline-backup.world-label": {
"defaultMessage": "世界"
},
+ "content.modpack-card.installation-settings": {
+ "defaultMessage": "安裝設定"
+ },
"content.page-layout.additional-content": {
"defaultMessage": "額外內容"
},
@@ -1278,10 +1281,10 @@
"defaultMessage": "刪除檔案"
},
"files.delete-modal.warning.file": {
- "defaultMessage": "此檔案將永久刪除。此操作無法撤銷。"
+ "defaultMessage": "這個檔案將永久刪除,這項動作無法復原。"
},
"files.delete-modal.warning.folder": {
- "defaultMessage": "此資料夾及其所有內容將永久刪除。此操作無法撤銷。"
+ "defaultMessage": "這個資料夾及其所有內容將永久刪除,這項動作無法復原。"
},
"files.editor.failed-to-open-text": {
"defaultMessage": "無法載入檔案內容。"
@@ -1301,9 +1304,6 @@
"files.editor.file-saved-title": {
"defaultMessage": "已儲存檔案"
},
- "files.editor.find-close": {
- "defaultMessage": "關閉"
- },
"files.editor.find-in-file": {
"defaultMessage": "尋找"
},
@@ -2240,6 +2240,9 @@
"label.details": {
"defaultMessage": "詳細資訊"
},
+ "label.discover-content": {
+ "defaultMessage": "探索內容"
+ },
"label.done": {
"defaultMessage": "完成"
},
@@ -2318,6 +2321,9 @@
"label.password": {
"defaultMessage": "密碼"
},
+ "label.permissions": {
+ "defaultMessage": "權限"
+ },
"label.plan-custom": {
"defaultMessage": "自訂"
},
@@ -2766,7 +2772,7 @@
"defaultMessage": "由工作人員設為不公開"
},
"omorphia.component.copy.action.copy": {
- "defaultMessage": "將程式碼複製到剪貼簿"
+ "defaultMessage": "將代碼複製到剪貼簿"
},
"omorphia.component.environment-indicator.label.client": {
"defaultMessage": "用戶端"
@@ -2849,9 +2855,162 @@
"payment-method.visa": {
"defaultMessage": "Visa"
},
+ "profile.bio.fallback.creator": {
+ "defaultMessage": "一位 Modrinth 創作者。"
+ },
+ "profile.bio.fallback.user": {
+ "defaultMessage": "一位 Modrinth 使用者。"
+ },
+ "profile.block-user.admonition-body": {
+ "defaultMessage": "{username} 將無法向你傳送好友邀請、邀請你加入共用實例,或邀請你加入 Modrinth Hosting 伺服器。"
+ },
+ "profile.block-user.admonition-title": {
+ "defaultMessage": "確定要封鎖這位使用者嗎?"
+ },
+ "profile.block-user.error-description": {
+ "defaultMessage": "封鎖使用者時發生錯誤,請再試一次。"
+ },
+ "profile.block-user.error-title": {
+ "defaultMessage": "無法封鎖使用者"
+ },
+ "profile.block-user.success-description": {
+ "defaultMessage": "{username} 已被封鎖。"
+ },
+ "profile.block-user.success-title": {
+ "defaultMessage": "使用者已封鎖"
+ },
+ "profile.block-user.title": {
+ "defaultMessage": "封鎖 {username}"
+ },
+ "profile.button.analytics": {
+ "defaultMessage": "檢視使用者數據分析"
+ },
+ "profile.button.billing": {
+ "defaultMessage": "管理使用者帳務"
+ },
+ "profile.button.block": {
+ "defaultMessage": "封鎖"
+ },
+ "profile.button.create-collection": {
+ "defaultMessage": "建立收藏"
+ },
+ "profile.button.create-project": {
+ "defaultMessage": "建立專案"
+ },
+ "profile.button.info": {
+ "defaultMessage": "檢視使用者詳細資訊"
+ },
+ "profile.button.manage-projects": {
+ "defaultMessage": "管理專案"
+ },
+ "profile.button.remove-affiliate": {
+ "defaultMessage": "移除聯盟行銷夥伴資格"
+ },
+ "profile.button.set-affiliate": {
+ "defaultMessage": "設為聯盟行銷夥伴"
+ },
+ "profile.button.unblock": {
+ "defaultMessage": "解除封鎖"
+ },
+ "profile.collection.projects-count": {
+ "defaultMessage": "{count, plural, other {# 個專案}}"
+ },
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "請允許 Modrinth 的彈出式視窗,然後再試一次。"
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "無法擷取 GitHub 個人檔案,請再試一次。"
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "無法開啟 GitHub 個人檔案"
+ },
+ "profile.details.label.auth-providers": {
+ "defaultMessage": "驗證提供商"
+ },
+ "profile.details.label.email-verified": {
+ "defaultMessage": "電子郵件已驗證"
+ },
+ "profile.details.label.has-password": {
+ "defaultMessage": "是否有密碼"
+ },
+ "profile.details.label.has-totp": {
+ "defaultMessage": "是否有 TOTP"
+ },
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "載入中..."
+ },
+ "profile.details.label.payment-methods": {
+ "defaultMessage": "付款方式"
+ },
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "查看個人檔案"
+ },
+ "profile.details.title": {
+ "defaultMessage": "使用者詳細資訊"
+ },
+ "profile.details.tooltip.email-not-verified": {
+ "defaultMessage": "電子郵件尚未驗證"
+ },
+ "profile.details.tooltip.email-verified": {
+ "defaultMessage": "電子郵件已驗證"
+ },
+ "profile.error.load-description": {
+ "defaultMessage": "無法載入使用者個人檔案。"
+ },
+ "profile.error.not-found": {
+ "defaultMessage": "找不到使用者"
+ },
+ "profile.label.affiliate": {
+ "defaultMessage": "聯盟行銷"
+ },
"profile.label.badges": {
"defaultMessage": "徽章"
},
+ "profile.label.collection": {
+ "defaultMessage": "收藏"
+ },
+ "profile.label.download-count": {
+ "defaultMessage": "{count, plural, other {次下載}}"
+ },
+ "profile.label.joined": {
+ "defaultMessage": "加入時間:"
+ },
+ "profile.label.no-collections": {
+ "defaultMessage": "這位使用者沒有任何收藏!"
+ },
+ "profile.label.no-collections-auth-description": {
+ "defaultMessage": "你還沒有任何收藏。"
+ },
+ "profile.label.no-projects": {
+ "defaultMessage": "這位使用者沒有任何專案!"
+ },
+ "profile.label.no-projects-auth-description": {
+ "defaultMessage": "你還沒有任何專案。"
+ },
+ "profile.label.organizations": {
+ "defaultMessage": "組織"
+ },
+ "profile.label.project-count": {
+ "defaultMessage": "{count, plural, other {個專案}}"
+ },
+ "profile.official-account": {
+ "defaultMessage": "Modrinth 官方帳號"
+ },
+ "profile.official-account.bio": {
+ "defaultMessage": "Modrinth 的官方使用者帳號。請至 取得支援,或透過電子郵件 聯絡客服團隊"
+ },
+ "profile.unblock-user.error-description": {
+ "defaultMessage": "解除封鎖使用者時發生錯誤,請再試一次。"
+ },
+ "profile.unblock-user.error-title": {
+ "defaultMessage": "無法解除封鎖使用者"
+ },
+ "profile.unblock-user.success-description": {
+ "defaultMessage": "{username} 已解除封鎖。"
+ },
+ "profile.unblock-user.success-title": {
+ "defaultMessage": "使用者已解除封鎖"
+ },
"project-card.date.published.tooltip": {
"defaultMessage": "發布時間:{date}"
},
@@ -2879,6 +3038,9 @@
"project-type.all": {
"defaultMessage": "全部"
},
+ "project-type.collection.plural": {
+ "defaultMessage": "收藏"
+ },
"project-type.datapack.capital": {
"defaultMessage": "{count, plural, other {資料包}}"
},
@@ -3540,7 +3702,7 @@
"defaultMessage": "成員"
},
"project.settings.notice.no-permission.description": {
- "defaultMessage": "你沒有編輯這個設定的權限。"
+ "defaultMessage": "你沒有編輯這項設定的權限。"
},
"project.settings.notice.no-permission.title": {
"defaultMessage": "沒有權限"
@@ -3561,7 +3723,7 @@
"defaultMessage": "版本"
},
"project.settings.view.title": {
- "defaultMessage": "檢視"
+ "defaultMessage": "檢視方式"
},
"project.stats.downloads-label": {
"defaultMessage": "{count, plural, other {次下載}}"
@@ -4011,7 +4173,7 @@
"defaultMessage": "{seconds} 秒後可重新傳送"
},
"servers.access-table.column.actions": {
- "defaultMessage": "操作"
+ "defaultMessage": "動作"
},
"servers.access-table.column.joined": {
"defaultMessage": "加入時間"
@@ -5105,9 +5267,120 @@
"settings.pats.title": {
"defaultMessage": "個人存取權杖"
},
+ "settings.profile.bio.description": {
+ "defaultMessage": "簡單介紹一下你自己。"
+ },
+ "settings.profile.bio.title": {
+ "defaultMessage": "關於我"
+ },
+ "settings.profile.navigation-title": {
+ "defaultMessage": "個人檔案"
+ },
+ "settings.profile.profile-picture.title": {
+ "defaultMessage": "個人檔案相片"
+ },
+ "settings.profile.public-information.description": {
+ "defaultMessage": "你的個人檔案資訊會公開顯示在 Modrinth 上 ,並可透過 Modrinth API 查詢。"
+ },
+ "settings.profile.save-error": {
+ "defaultMessage": "無法更新個人檔案"
+ },
+ "settings.profile.save-error-description": {
+ "defaultMessage": "更新個人檔案時發生錯誤,請再試一次。"
+ },
+ "settings.profile.sign-in-required.description": {
+ "defaultMessage": "登入 Modrinth 帳號即可自訂你的公開個人檔案。"
+ },
+ "settings.profile.sign-in-required.title": {
+ "defaultMessage": "需要 Modrinth 帳號"
+ },
+ "settings.profile.username.description": {
+ "defaultMessage": "獨特且不區分大小寫的名稱,用於識別你的個人檔案。"
+ },
"settings.sessions.title": {
"defaultMessage": "工作階段"
},
+ "settings.social.blocked-users.column.actions": {
+ "defaultMessage": "動作"
+ },
+ "settings.social.blocked-users.column.user": {
+ "defaultMessage": "使用者"
+ },
+ "settings.social.blocked-users.description": {
+ "defaultMessage": "以下是你在 Modrinth 上封鎖的使用者。他們無法:"
+ },
+ "settings.social.blocked-users.empty": {
+ "defaultMessage": "你沒有封鎖任何使用者。"
+ },
+ "settings.social.blocked-users.load-error": {
+ "defaultMessage": "無法載入已封鎖的使用者。"
+ },
+ "settings.social.blocked-users.loading": {
+ "defaultMessage": "正在載入已封鎖的使用者..."
+ },
+ "settings.social.blocked-users.restriction.friend-requests": {
+ "defaultMessage": "傳送好友邀請給你"
+ },
+ "settings.social.blocked-users.restriction.hosting": {
+ "defaultMessage": "邀請你管理 Modrinth Hosting 伺服器。"
+ },
+ "settings.social.blocked-users.restriction.shared-instances": {
+ "defaultMessage": "邀請你加入共用實例"
+ },
+ "settings.social.blocked-users.title": {
+ "defaultMessage": "封鎖名單"
+ },
+ "settings.social.blocked-users.unblock": {
+ "defaultMessage": "解除封鎖"
+ },
+ "settings.social.blocked-users.unblock-error": {
+ "defaultMessage": "無法解除封鎖使用者"
+ },
+ "settings.social.blocked-users.unblock-error-description": {
+ "defaultMessage": "解除封鎖使用者時發生錯誤,請再試一次。"
+ },
+ "settings.social.blocked-users.unblock-user": {
+ "defaultMessage": "解除封鎖 {username}"
+ },
+ "settings.social.blocked-users.user-avatar": {
+ "defaultMessage": "{username} 的顯示圖片"
+ },
+ "settings.social.friend-requests.description": {
+ "defaultMessage": "控制誰可以在 Modrinth 向你傳送好友邀請。"
+ },
+ "settings.social.friend-requests.title": {
+ "defaultMessage": "好友邀請"
+ },
+ "settings.social.interaction-source.coming-soon": {
+ "defaultMessage": "即將推出!"
+ },
+ "settings.social.interaction-source.everyone": {
+ "defaultMessage": "所有人"
+ },
+ "settings.social.interaction-source.friends": {
+ "defaultMessage": "好友"
+ },
+ "settings.social.interaction-source.friends-of-friends": {
+ "defaultMessage": "好友的好友"
+ },
+ "settings.social.interaction-source.no-one": {
+ "defaultMessage": "沒有人"
+ },
+ "settings.social.shared-instance-invites.description": {
+ "defaultMessage": "控制誰可以向你傳送共用實例和 Modrinth Hosting 面板的邀請。"
+ },
+ "settings.social.shared-instance-invites.title": {
+ "defaultMessage": "邀請"
+ },
+ "settings.social.sign-in-required.description": {
+ "defaultMessage": "你可以透過 Modrinth 帳號控制誰可以與你互動,並管理被封鎖的使用者"
+ },
+ "settings.social.sign-in-required.title": {
+ "defaultMessage": "需要 Modrinth 帳號"
+ },
+ "settings.social.title": {
+ "defaultMessage": "社交"
+ },
"sharing.invite-players-modal.add": {
"defaultMessage": "新增"
},
@@ -5115,16 +5388,19 @@
"defaultMessage": "已加入"
},
"sharing.invite-players-modal.already-invited": {
- "defaultMessage": "這個使用者已經被邀請。"
+ "defaultMessage": "這位使用者已經被邀請。"
+ },
+ "sharing.invite-players-modal.apply-button": {
+ "defaultMessage": "套用"
},
"sharing.invite-players-modal.avatar-alt": {
"defaultMessage": "{username} 的顯示圖片"
},
- "sharing.invite-players-modal.cancel": {
- "defaultMessage": "取消"
+ "sharing.invite-players-modal.custom-expiry": {
+ "defaultMessage": "自訂..."
},
- "sharing.invite-players-modal.cancel-button": {
- "defaultMessage": "取消"
+ "sharing.invite-players-modal.custom-expiry-value": {
+ "defaultMessage": "自訂:{date}"
},
"sharing.invite-players-modal.edit-invite-link": {
"defaultMessage": "編輯邀請連結。"
@@ -5132,8 +5408,26 @@
"sharing.invite-players-modal.edit-invite-link-title": {
"defaultMessage": "編輯邀請連結"
},
+ "sharing.invite-players-modal.expiry-in-one-day": {
+ "defaultMessage": "1 天"
+ },
+ "sharing.invite-players-modal.expiry-in-one-hour": {
+ "defaultMessage": "1 小時"
+ },
+ "sharing.invite-players-modal.expiry-in-seven-days": {
+ "defaultMessage": "7 天"
+ },
+ "sharing.invite-players-modal.expiry-in-six-hours": {
+ "defaultMessage": "6 小時"
+ },
+ "sharing.invite-players-modal.expiry-in-three-days": {
+ "defaultMessage": "3 天"
+ },
+ "sharing.invite-players-modal.expiry-in-twelve-hours": {
+ "defaultMessage": "12 小時"
+ },
"sharing.invite-players-modal.expiry-label": {
- "defaultMessage": "有效期限"
+ "defaultMessage": "有效時間"
},
"sharing.invite-players-modal.friends-heading": {
"defaultMessage": "你的好友 - {count}"
@@ -5937,3 +6231,4 @@
"defaultMessage": "類型"
}
}
+
diff --git a/packages/ui/src/providers/project-page.ts b/packages/ui/src/providers/project-page.ts
index c81f83b9fd..dce8569c92 100644
--- a/packages/ui/src/providers/project-page.ts
+++ b/packages/ui/src/providers/project-page.ts
@@ -15,7 +15,7 @@ export interface ProjectPageContext {
allMembers: Ref
organization: Ref
// Lazy version loading (client-side only)
- versions: Ref
+ versions: Ref
versionsLoading: Ref
versionsLoaded: Ref
// Lazy dependencies loading (client-side only)
diff --git a/packages/ui/src/stories/add-stories.md b/packages/ui/src/stories/add-stories.md
index 19f83c3ba9..2132d4f14c 100644
--- a/packages/ui/src/stories/add-stories.md
+++ b/packages/ui/src/stories/add-stories.md
@@ -153,16 +153,14 @@ For components that need user interaction to show:
```typescript
export const Default: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { Button, NewModal },
setup() {
const modalRef = ref | null>(null)
return { modalRef }
},
template: /* html */ `
-
- Open Modal
-
+
Open Modal
Modal content
@@ -199,10 +197,10 @@ Components should use relative imports, not the package alias:
```typescript
// ❌ BAD - Causes circular dependency in Storybook
-import { ButtonStyled } from '@modrinth/ui'
+import { Button } from '@modrinth/ui'
// ✅ GOOD - Use relative imports
-import ButtonStyled from '../base/ButtonStyled.vue'
+import Button from '../components/base/buttons/Button.vue'
```
### 2. Object/Array Prop Defaults Must Be Factory Functions
diff --git a/packages/ui/src/stories/base/Admonition.stories.ts b/packages/ui/src/stories/base/Admonition.stories.ts
index 413e2a1b6d..bcd6894084 100644
--- a/packages/ui/src/stories/base/Admonition.stories.ts
+++ b/packages/ui/src/stories/base/Admonition.stories.ts
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite'
import { ref } from 'vue'
import Admonition from '../../components/base/Admonition.vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button } from '../../components/base/buttons'
const meta = {
title: 'Base/Admonition',
@@ -78,7 +78,7 @@ export const HeaderWithTimestamp: Story = {
export const WithTopRightActions: Story = {
render: () => ({
- components: { Admonition, ButtonStyled },
+ components: { Admonition, Button },
template: /*html*/ `
Uploading server files...
-
- Cancel
-
+ Cancel
Something went wrong while extracting the archive.
-
- Retry
-
+ Retry
@@ -115,7 +111,7 @@ export const WithTopRightActions: Story = {
export const WithProgressBar: Story = {
render: () => ({
- components: { Admonition, ButtonStyled },
+ components: { Admonition, Button },
template: /*html*/ `
128 KB / 1.2 MB (45%)
-
- Cancel
-
+ Cancel
24 MB extracted — config/settings.yml
-
- Cancel
-
+ Cancel
({
- components: { Button },
- setup() {
- return { args }
- },
- template: /*html*/ `
- Click me
- `,
- }),
-} satisfies Meta
-
-export default meta
-type Story = StoryObj
-
-export const Default: Story = {}
-
-export const Primary: Story = {
- args: {
- color: 'primary',
- },
-}
-
-export const Danger: Story = {
- args: {
- color: 'danger',
- },
-}
-
-export const AllColors: Story = {
- render: () => ({
- components: { Button },
- template: /*html*/ `
-
- Default
- Primary
- Danger
- Red
- Orange
- Green
- Blue
- Purple
-
- `,
- }),
-}
-
-export const Large: Story = {
- args: {
- large: true,
- },
-}
-
-export const Outline: Story = {
- args: {
- outline: true,
- },
-}
-
-export const Transparent: Story = {
- args: {
- transparent: true,
- },
-}
-
-export const Disabled: Story = {
- args: {
- disabled: true,
- },
-}
-
-export const AsLink: Story = {
- args: {
- link: 'https://modrinth.com',
- external: true,
- },
-}
diff --git a/packages/ui/src/stories/base/ButtonStyled.stories.ts b/packages/ui/src/stories/base/ButtonStyled.stories.ts
deleted file mode 100644
index 852ceab118..0000000000
--- a/packages/ui/src/stories/base/ButtonStyled.stories.ts
+++ /dev/null
@@ -1,226 +0,0 @@
-import { DownloadIcon, HeartIcon, SettingsIcon } from '@modrinth/assets'
-import type { Meta, StoryObj } from '@storybook/vue3-vite'
-
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
-
-const colors = ['standard', 'brand', 'red', 'orange', 'green', 'blue', 'purple'] as const
-const types = [
- 'standard',
- 'outlined',
- 'transparent',
- 'highlight',
- 'highlight-colored-text',
- 'chip',
-] as const
-const sizes = ['small', 'standard', 'large'] as const
-
-const meta = {
- title: 'Base/ButtonStyled',
- component: ButtonStyled,
- argTypes: {
- color: {
- control: 'select',
- options: [...colors, 'medal-promo'],
- },
- size: {
- control: 'select',
- options: [...sizes],
- },
- type: {
- control: 'select',
- options: [...types],
- },
- circular: { control: 'boolean' },
- colorFill: {
- control: 'select',
- options: ['auto', 'background', 'text', 'none'],
- },
- hoverColorFill: {
- control: 'select',
- options: ['auto', 'background', 'text', 'none'],
- },
- highlighted: { control: 'boolean' },
- highlightedStyle: {
- control: 'select',
- options: ['main-nav-primary', 'main-nav-secondary'],
- },
- },
- args: {
- color: 'standard',
- size: 'standard',
- type: 'standard',
- circular: false,
- colorFill: 'auto',
- hoverColorFill: 'auto',
- highlighted: false,
- highlightedStyle: 'main-nav-primary',
- },
- render: (args) => ({
- components: { ButtonStyled, DownloadIcon },
- setup() {
- return { args }
- },
- template: /*html*/ `
-
- Button
-
- `,
- }),
-} satisfies Meta
-
-export default meta
-type Story = StoryObj
-
-export const Default: Story = {
- args: {
- type: 'standard',
- },
-}
-
-export const AllVariants: Story = {
- render: () => ({
- components: { ButtonStyled },
- setup() {
- return { colors, types }
- },
- template: /*html*/ `
-
-
-
-
- Color / Type
- {{ type }}
-
-
-
-
- {{ color }}
-
-
- Button
-
-
-
-
-
-
- `,
- }),
-}
-
-export const AllVariantsHighlighted: Story = {
- render: () => ({
- components: { ButtonStyled },
- setup() {
- return { colors, types }
- },
- template: /*html*/ `
-
-
-
-
- Color / Type
- {{ type }}
-
-
-
-
- {{ color }}
-
-
- Button
-
-
-
-
-
-
- `,
- }),
-}
-
-export const Sizes: Story = {
- render: () => ({
- components: { ButtonStyled },
- setup() {
- return { sizes, types }
- },
- template: /*html*/ `
-
-
-
-
- Size / Type
- {{ type }}
-
-
-
-
- {{ size }}
-
-
- Button
-
-
-
-
-
-
- `,
- }),
-}
-
-export const WithIcons: Story = {
- render: () => ({
- components: { ButtonStyled, DownloadIcon, HeartIcon, SettingsIcon },
- setup() {
- return { types }
- },
- template: /*html*/ `
-
-
-
-
- Variant
- {{ type }}
-
-
-
-
- Icon + text
-
-
- Download
-
-
-
-
- Icon only
-
-
-
-
-
-
-
-
-
- `,
- }),
-}
-
-export const Disabled: Story = {
- render: () => ({
- components: { ButtonStyled },
- setup() {
- return { types }
- },
- template: /*html*/ `
-
-
- {{ type }}
-
-
- `,
- }),
-}
diff --git a/packages/ui/src/stories/base/EmptyState.stories.ts b/packages/ui/src/stories/base/EmptyState.stories.ts
index f698148b9b..8fa5be7f23 100644
--- a/packages/ui/src/stories/base/EmptyState.stories.ts
+++ b/packages/ui/src/stories/base/EmptyState.stories.ts
@@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/vue3-vite'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button } from '../../components/base/buttons'
import EmptyState from '../../components/base/EmptyState.vue'
const meta = {
@@ -42,7 +42,7 @@ export const Default: Story = {
export const WithActions: StoryObj = {
render: () => ({
- components: { EmptyState, ButtonStyled },
+ components: { EmptyState, Button },
template: /*html*/ `
-
- Create backup
-
+ Create backup
`,
diff --git a/packages/ui/src/stories/base/FileTreeSelect.stories.ts b/packages/ui/src/stories/base/FileTreeSelect.stories.ts
index a85d13ab5e..acaf6eb8e4 100644
--- a/packages/ui/src/stories/base/FileTreeSelect.stories.ts
+++ b/packages/ui/src/stories/base/FileTreeSelect.stories.ts
@@ -39,30 +39,37 @@ export const ModpackExport: StoryObj = {
render: () => ({
components: { FileTreeSelect },
setup() {
- const selected = ref([
- 'config/fabric_loader_dependencies.json',
- 'config/crash_assistant/settings.toml',
- 'config/defaultoptions/options.txt',
- 'mods/sodium-fabric-0.6.13+mc1.21.6.jar',
- 'mods/iris-fabric-1.8.8+mc1.21.6.jar',
- 'resourcepacks/FreshAnimations_v1.9.3.zip',
- 'shaderpacks/ComplementaryUnbound_r5.5.1.zip',
- ])
- const selectedLabel = computed(() => `${selected.value.length} selected`)
+ const included = ref(['config', 'mods'])
+ const excluded = ref(['config/defaultoptions'])
+ const selectedLabel = computed(
+ () => `${included.value.length} includes, ${excluded.value.length} exclusions`,
+ )
return {
+ excluded,
+ included,
items: MODPACK_FILES,
- selected,
selectedLabel,
}
},
template: /*html*/ `
-
+
{{ selectedLabel }}
-
-
{{ path }}
+
+
+ Included
+ {{ path }}
+
+
+ Excluded
+ {{ path }}
+
@@ -74,12 +81,17 @@ export const EmptyRoot: StoryObj = {
render: () => ({
components: { FileTreeSelect },
setup() {
- const selected = ref
([])
- return { selected }
+ const excluded = ref([])
+ const included = ref([])
+ return { excluded, included }
},
template: /*html*/ `
-
+
`,
}),
diff --git a/packages/ui/src/stories/base/JoinedButtons.stories.ts b/packages/ui/src/stories/base/JoinedButtons.stories.ts
deleted file mode 100644
index c007e3631d..0000000000
--- a/packages/ui/src/stories/base/JoinedButtons.stories.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-import { PlayIcon, SlashIcon, StopCircleIcon, UpdatedIcon } from '@modrinth/assets'
-import type { Meta, StoryObj } from '@storybook/vue3-vite'
-
-import JoinedButtons from '../../components/base/JoinedButtons.vue'
-
-const meta = {
- title: 'Base/JoinedButtons',
- component: JoinedButtons,
- argTypes: {
- color: {
- control: 'select',
- options: ['standard', 'brand', 'red', 'orange', 'green', 'blue', 'purple'],
- },
- size: {
- control: 'select',
- options: ['small', 'standard', 'large'],
- },
- disabled: { control: 'boolean' },
- primaryDisabled: { control: 'boolean' },
- dropdownDisabled: { control: 'boolean' },
- primaryMuted: { control: 'boolean' },
- },
-} satisfies Meta
-
-export default meta
-type Story = StoryObj
-
-export const Start: Story = {
- args: {
- color: 'brand',
- size: 'large',
- actions: [
- {
- id: 'start',
- label: 'Start',
- icon: PlayIcon,
- action: () => console.log('Start'),
- },
- ],
- },
-}
-
-export const StopWithKill: Story = {
- args: {
- color: 'red',
- size: 'large',
- actions: [
- {
- id: 'stop',
- label: 'Stop',
- icon: StopCircleIcon,
- action: () => console.log('Stop'),
- },
- {
- id: 'kill_server',
- label: 'Kill server',
- icon: SlashIcon,
- action: () => console.log('Kill'),
- },
- ],
- },
-}
-
-export const Stopping: Story = {
- args: {
- color: 'red',
- size: 'large',
- primaryDisabled: true,
- primaryMuted: true,
- actions: [
- {
- id: 'stop',
- label: 'Stopping',
- icon: StopCircleIcon,
- action: () => console.log('Stop'),
- },
- {
- id: 'kill_server',
- label: 'Kill server',
- icon: SlashIcon,
- action: () => console.log('Kill'),
- },
- ],
- },
-}
-
-export const Restart: Story = {
- args: {
- color: 'orange',
- size: 'large',
- actions: [
- {
- id: 'restart',
- label: 'Restart',
- icon: UpdatedIcon,
- action: () => console.log('Restart'),
- },
- ],
- },
-}
-
-export const Disabled: Story = {
- args: {
- color: 'red',
- size: 'large',
- disabled: true,
- actions: [
- {
- id: 'stop',
- label: 'Stop',
- icon: StopCircleIcon,
- action: () => console.log('Stop'),
- },
- {
- id: 'kill_server',
- label: 'Kill server',
- icon: SlashIcon,
- action: () => console.log('Kill'),
- },
- ],
- },
-}
diff --git a/packages/ui/src/stories/base/OverflowMenu.stories.ts b/packages/ui/src/stories/base/OverflowMenu.stories.ts
deleted file mode 100644
index 0adec75cf2..0000000000
--- a/packages/ui/src/stories/base/OverflowMenu.stories.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import { MoreHorizontalIcon } from '@modrinth/assets'
-import type { Meta, StoryObj } from '@storybook/vue3-vite'
-
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
-import OverflowMenu from '../../components/base/OverflowMenu.vue'
-
-const meta = {
- title: 'Base/OverflowMenu',
- component: OverflowMenu,
- render: (args) => ({
- components: { OverflowMenu, MoreHorizontalIcon, ButtonStyled },
- setup() {
- return { args }
- },
- template: /*html*/ `
-
-
-
- Edit
- Delete
- Share
-
-
- `,
- }),
-} satisfies Meta
-
-export default meta
-type Story = StoryObj
-
-export const Default: Story = {
- args: {
- options: [
- { id: 'edit', action: () => console.log('Edit clicked') },
- { id: 'share', action: () => console.log('Share clicked') },
- { divider: true },
- { id: 'delete', action: () => console.log('Delete clicked'), color: 'danger' },
- ],
- },
-}
-
-export const WithDifferentPlacements: StoryObj = {
- render: () => ({
- components: { OverflowMenu, MoreHorizontalIcon, ButtonStyled },
- template: /*html*/ `
-
-
- bottom-end (default)
-
-
-
- Edit
- Delete
-
-
-
-
- bottom-start
-
-
-
- Edit
- Delete
-
-
-
-
- `,
- }),
-}
diff --git a/packages/ui/src/stories/base/PageHeader.stories.ts b/packages/ui/src/stories/base/PageHeader.stories.ts
index 73ad628820..a8344567da 100644
--- a/packages/ui/src/stories/base/PageHeader.stories.ts
+++ b/packages/ui/src/stories/base/PageHeader.stories.ts
@@ -20,9 +20,13 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite'
import AutoLink from '../../components/base/AutoLink.vue'
import Avatar from '../../components/base/Avatar.vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import {
+ Button,
+ IconButton,
+ SplitButton,
+ TeleportOverflowMenu,
+} from '../../components/base/buttons'
import FormattedTag from '../../components/base/FormattedTag.vue'
-import JoinedButtons from '../../components/base/JoinedButtons.vue'
import PageHeader from '../../components/base/page-header/index.vue'
import PageHeaderMetadata from '../../components/base/page-header/metadata/index.vue'
import PageHeaderMetadataItem from '../../components/base/page-header/metadata/page-header-metadata-item.vue'
@@ -31,9 +35,8 @@ import PageHeaderMetadataTagsItem from '../../components/base/page-header/metada
import PageHeaderMetadataTimeItem from '../../components/base/page-header/metadata/page-header-metadata-time-item.vue'
import PageHeaderActions from '../../components/base/page-header/page-header-actions.vue'
import PageHeaderBadgeItem from '../../components/base/page-header/page-header-badge-item.vue'
+import TagIcon from '../../components/base/TagIcon.vue'
import TagItem from '../../components/base/TagItem.vue'
-import TeleportOverflowMenu from '../../components/base/TeleportOverflowMenu.vue'
-import LoaderIcon from '../../components/servers/icons/LoaderIcon.vue'
import ServerIcon from '../../components/servers/icons/ServerIcon.vue'
const noop = () => undefined
@@ -87,9 +90,10 @@ const pageHeaderIcons = {
const pageHeaderComponents = {
AutoLink,
Avatar,
- ButtonStyled,
+ Button,
FormattedTag,
- JoinedButtons,
+ IconButton,
+ SplitButton,
PageHeader,
PageHeaderActions,
PageHeaderBadgeItem,
@@ -111,7 +115,7 @@ const meta = {
},
decorators: [
(story) => ({
- components: { story },
+ components: { story, TeleportOverflowMenu },
template: '
',
}),
],
@@ -157,17 +161,13 @@ export const ProjectHeader: Story = {
-
-
-
- Download
-
-
-
-
-
-
-
+
+
+ Download
+
+
+
+
@@ -207,12 +207,10 @@ export const CreatorHeader: Story = {
-
-
-
- Follow
-
-
+
+
+ Follow
+
@@ -222,14 +220,11 @@ export const CreatorHeader: Story = {
export const AppInstanceHeader: Story = {
render: () => ({
- components: {
- ...pageHeaderComponents,
- LoaderIcon,
- },
+ components: { ...pageHeaderComponents, TagIcon, TeleportOverflowMenu },
setup() {
return {
...pageHeaderIcons,
- LoaderIcon,
+ TagIcon,
menuActions,
noop,
}
@@ -243,7 +238,7 @@ export const AppInstanceHeader: Story = {
Minecraft 1.20.1
-
+
Fabric 0.16.14
12 hours
@@ -252,22 +247,16 @@ export const AppInstanceHeader: Story = {
-
-
-
- Play
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ Play
+
+
+
+
+
+
+
@@ -277,25 +266,20 @@ export const AppInstanceHeader: Story = {
export const BrowseHeader: Story = {
render: () => ({
- components: {
- ...pageHeaderComponents,
- LoaderIcon,
- },
+ components: { ...pageHeaderComponents, TagIcon, TeleportOverflowMenu },
setup() {
return {
...pageHeaderIcons,
- LoaderIcon,
+ TagIcon,
noop,
}
},
template: `
-
-
-
-
-
+
+
+
@@ -305,7 +289,7 @@ export const BrowseHeader: Story = {
Minecraft 1.20.1
-
+
Fabric
@@ -317,10 +301,7 @@ export const BrowseHeader: Story = {
export const ServerPanelRootHeader: Story = {
render: () => ({
- components: {
- ...pageHeaderComponents,
- ServerIcon,
- },
+ components: { ...pageHeaderComponents, ServerIcon, TeleportOverflowMenu },
setup() {
return {
...pageHeaderIcons,
@@ -346,17 +327,13 @@ export const ServerPanelRootHeader: Story = {
-
-
-
- Start server
-
-
-
-
-
-
-
+
+
+ Start server
+
+
+
+
@@ -366,32 +343,27 @@ export const ServerPanelRootHeader: Story = {
export const ServerPanelInstanceHeader: Story = {
render: () => ({
- components: {
- ...pageHeaderComponents,
- LoaderIcon,
- },
+ components: { ...pageHeaderComponents, TagIcon, TeleportOverflowMenu },
setup() {
return {
...pageHeaderIcons,
joinedActions,
- LoaderIcon,
+ TagIcon,
noop,
}
},
template: `
-
-
-
-
-
+
+
+
Minecraft 1.20.1
-
+
Fabric 0.19.2
Last active 2 weeks ago
@@ -400,18 +372,24 @@ export const ServerPanelInstanceHeader: Story = {
-
-
-
- Start instance
-
-
-
-
-
-
-
-
+
+
+ Start instance
+
+
+
+ Stop
+
+
+
+
diff --git a/packages/ui/src/stories/base/PopoutMenu.stories.ts b/packages/ui/src/stories/base/PopoutMenu.stories.ts
deleted file mode 100644
index 7e3d02a512..0000000000
--- a/packages/ui/src/stories/base/PopoutMenu.stories.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-import { SettingsIcon } from '@modrinth/assets'
-import type { Meta, StoryObj } from '@storybook/vue3-vite'
-
-import Button from '../../components/base/Button.vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
-import PopoutMenu from '../../components/base/PopoutMenu.vue'
-
-const meta = {
- title: 'Base/PopoutMenu',
- component: PopoutMenu,
- render: (args) => ({
- components: { PopoutMenu, Button, ButtonStyled, SettingsIcon },
- setup() {
- return { args }
- },
- template: /*html*/ `
-
-
-
-
-
- Option 1
- Option 2
- Option 3
-
-
-
-
- `,
- }),
-} satisfies Meta
-
-export default meta
-type Story = StoryObj
-
-export const Default: Story = {}
-
-export const WithTooltip: Story = {
- args: {
- tooltip: 'Click for more options',
- },
-}
-
-export const DifferentPlacements: StoryObj = {
- render: () => ({
- components: { PopoutMenu, Button, ButtonStyled, SettingsIcon },
- template: /*html*/ `
-
-
-
bottom-end (default)
-
-
-
-
-
- Option 1
- Option 2
-
-
-
-
-
-
-
bottom-start
-
-
-
-
-
- Option 1
- Option 2
-
-
-
-
-
-
-
top-end
-
-
-
-
-
- Option 1
- Option 2
-
-
-
-
-
-
- `,
- }),
-}
diff --git a/packages/ui/src/stories/base/StackedAdmonitions.stories.ts b/packages/ui/src/stories/base/StackedAdmonitions.stories.ts
index c0683ad7df..fbef68fb42 100644
--- a/packages/ui/src/stories/base/StackedAdmonitions.stories.ts
+++ b/packages/ui/src/stories/base/StackedAdmonitions.stories.ts
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite'
import { ref } from 'vue'
import Admonition from '../../components/base/Admonition.vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button } from '../../components/base/buttons'
import StackedAdmonitionsRaw, {
type StackedAdmonitionItem,
} from '../../components/base/StackedAdmonitions.vue'
@@ -383,7 +383,7 @@ interface RichItem extends StackedAdmonitionItem {
export const RichContent: Story = {
render: () => ({
- components: { StackedAdmonitions, Admonition, ButtonStyled },
+ components: { StackedAdmonitions, Admonition, Button },
setup() {
const items = ref([
{
@@ -429,12 +429,8 @@ export const RichContent: Story = {
>
{{ item.body }}
-
- Cancel
-
-
- Retry
-
+ Cancel
+ Retry
diff --git a/packages/ui/src/stories/base/Table.stories.ts b/packages/ui/src/stories/base/Table.stories.ts
index 157c1ffbcb..6448cbe7bd 100644
--- a/packages/ui/src/stories/base/Table.stories.ts
+++ b/packages/ui/src/stories/base/Table.stories.ts
@@ -3,8 +3,7 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite'
import { computed, ref } from 'vue'
import Badge from '../../components/base/Badge.vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
-import OverflowMenu from '../../components/base/OverflowMenu.vue'
+import { Button, TeleportOverflowMenu } from '../../components/base/buttons'
import Table from '../../components/base/Table.vue'
interface User {
@@ -54,7 +53,7 @@ export default meta
export const Default: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -74,7 +73,7 @@ export const Default: StoryObj = {
export const HorizontalOverflow: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -103,7 +102,7 @@ export const HorizontalOverflow: StoryObj = {
export const CustomClasses: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name', cellClass: '!overflow-visible py-3' },
@@ -129,7 +128,7 @@ export const CustomClasses: StoryObj = {
export const WithSelection: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -160,7 +159,7 @@ export const WithSelection: StoryObj = {
export const WithSelectionData: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -193,7 +192,7 @@ export const WithSelectionData: StoryObj = {
export const WithSelectionIds: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -233,7 +232,7 @@ export const WithSorting: StoryObj = {
},
},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name', enableSorting: true },
@@ -269,7 +268,7 @@ export const WithSorting: StoryObj = {
export const WithColumnAlignment: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name', align: 'left' as const },
@@ -289,7 +288,7 @@ export const WithColumnAlignment: StoryObj = {
export const WithCustomCellSlots: StoryObj = {
args: {},
render: () => ({
- components: { Table, Badge },
+ components: { Table, Badge, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -335,7 +334,7 @@ export const WithCustomCellSlots: StoryObj = {
export const WithCustomHeaderSlots: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -365,7 +364,7 @@ export const WithCustomHeaderSlots: StoryObj = {
export const WithHeaderSlot: StoryObj = {
args: {},
render: () => ({
- components: { Table, ButtonStyled },
+ components: { Table, Button, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -383,9 +382,7 @@ export const WithHeaderSlot: StoryObj = {
Team Members
-
- Invite member
-
+ Invite member
@@ -397,7 +394,7 @@ export const WithHeaderSlot: StoryObj = {
export const WithActionsColumn: StoryObj = {
args: {},
render: () => ({
- components: { Table, ButtonStyled, EditIcon, TrashIcon },
+ components: { Table, EditIcon, TrashIcon, Button, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -421,18 +418,14 @@ export const WithActionsColumn: StoryObj = {
-
-
-
- Edit
-
-
-
-
-
- Delete
-
-
+
+
+ Edit
+
+
+
+ Delete
+
@@ -443,7 +436,7 @@ export const WithActionsColumn: StoryObj = {
export const WithLocalizedActionsColumn: StoryObj = {
args: {},
render: () => ({
- components: { Table, ButtonStyled, EditIcon, TrashIcon },
+ components: { Table, EditIcon, TrashIcon, Button, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Nombre' },
@@ -467,18 +460,14 @@ export const WithLocalizedActionsColumn: StoryObj = {
-
-
-
- Editar
-
-
-
-
-
- Eliminar
-
-
+
+
+ Editar
+
+
+
+ Eliminar
+
@@ -489,7 +478,7 @@ export const WithLocalizedActionsColumn: StoryObj = {
export const FullFeatured: StoryObj = {
args: {},
render: () => ({
- components: { Table, Badge, ButtonStyled, EditIcon, TrashIcon },
+ components: { Table, Badge, EditIcon, TrashIcon, Button, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name', enableSorting: true },
@@ -565,18 +554,14 @@ export const FullFeatured: StoryObj = {
-
-
-
- Edit
-
-
-
-
-
- Delete
-
-
+
+
+ Edit
+
+
+
+ Delete
+
@@ -592,7 +577,7 @@ export const FullFeatured: StoryObj = {
export const VirtualizedLargeData: StoryObj = {
args: {},
render: () => ({
- components: { Table, Badge },
+ components: { Table, Badge, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name', enableSorting: true },
@@ -710,7 +695,15 @@ export const VirtualizedLargeData: StoryObj = {
export const WithOverflowMenu: StoryObj = {
args: {},
render: () => ({
- components: { Table, Badge, ButtonStyled, OverflowMenu, MoreVerticalIcon, EditIcon, TrashIcon },
+ components: {
+ Table,
+ Badge,
+ MoreVerticalIcon,
+ EditIcon,
+ TrashIcon,
+ Button,
+ TeleportOverflowMenu,
+ },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
@@ -737,17 +730,19 @@ export const WithOverflowMenu: StoryObj = {
const getMenuOptions = (row: User) => [
{
id: 'edit',
+ label: 'Edit',
action: () => alert(`Edit user: ${row.name}`),
},
{
id: 'duplicate',
+ label: 'Duplicate',
action: () => alert(`Duplicate user: ${row.name}`),
},
- { divider: true },
+ { type: 'divider' },
{
id: 'delete',
- color: 'red' as const,
- hoverFilled: true,
+ label: 'Delete',
+ tone: 'red',
action: () => alert(`Delete user: ${row.name}`),
},
]
@@ -766,26 +761,23 @@ export const WithOverflowMenu: StoryObj = {
-
-
-
-
-
- Edit
-
-
-
- Duplicate
-
-
-
- Delete
-
-
-
+
+
+
+ Edit
+
+
+
+ Duplicate
+
+
+
+ Delete
+
+
@@ -796,7 +788,7 @@ export const WithOverflowMenu: StoryObj = {
export const EmptyState: StoryObj = {
args: {},
render: () => ({
- components: { Table },
+ components: { Table, TeleportOverflowMenu },
setup() {
const columns = [
{ key: 'name', label: 'Name' },
diff --git a/packages/ui/src/stories/buttons/Button.stories.ts b/packages/ui/src/stories/buttons/Button.stories.ts
new file mode 100644
index 0000000000..85bfe95332
--- /dev/null
+++ b/packages/ui/src/stories/buttons/Button.stories.ts
@@ -0,0 +1,213 @@
+import { DownloadIcon, ExternalIcon, HeartIcon, SettingsIcon } from '@modrinth/assets'
+import type { Meta, StoryObj } from '@storybook/vue3-vite'
+
+import Button from '../../components/base/buttons/Button.vue'
+import ButtonLink from '../../components/base/buttons/ButtonLink.vue'
+import IconButton from '../../components/base/buttons/IconButton.vue'
+
+const types = ['base', 'colored', 'outlined', 'quiet'] as const
+const sizes = ['sm', 'md', 'lg', 'xl'] as const
+const colors = ['brand', 'red', 'orange', 'green', 'blue', 'purple', 'medal_promotion'] as const
+const sizeColumns = [
+ { value: 'sm', label: 'Small' },
+ { value: 'md', label: 'Medium' },
+ { value: 'lg', label: 'Large' },
+ { value: 'xl', label: 'Extra large' },
+] as const
+const typeRows = [
+ { label: 'Base', type: 'base' },
+ { label: 'Outlined', type: 'outlined' },
+ { label: 'Quiet', type: 'quiet' },
+ ...colors.map((color) => ({
+ label: `Colored / ${color.charAt(0).toUpperCase()}${color.slice(1)}`,
+ type: 'colored' as const,
+ color,
+ })),
+ ...colors.map((color) => ({
+ label: `Outlined / ${color.charAt(0).toUpperCase()}${color.slice(1)}`,
+ type: 'outlined' as const,
+ color,
+ })),
+ ...colors.map((color) => ({
+ label: `Quiet / ${color.charAt(0).toUpperCase()}${color.slice(1)}`,
+ type: 'quiet' as const,
+ color,
+ })),
+]
+
+const meta = {
+ title: 'Buttons/Button',
+ component: Button,
+ argTypes: {
+ type: {
+ control: 'select',
+ options: types,
+ },
+ size: {
+ control: 'select',
+ options: sizes,
+ },
+ color: {
+ control: 'select',
+ options: colors,
+ },
+ nativeType: {
+ control: 'select',
+ options: ['button', 'submit', 'reset'],
+ },
+ disabled: { control: 'boolean' },
+ loading: { control: 'boolean' },
+ },
+ args: {
+ type: 'base',
+ size: 'md',
+ color: 'brand',
+ nativeType: 'button',
+ disabled: false,
+ loading: false,
+ },
+ render: (args) => ({
+ components: { Button, DownloadIcon },
+ setup() {
+ return { args }
+ },
+ template: /*html*/ `
+
+
+ Download
+
+ `,
+ }),
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Playground: Story = {}
+
+export const AllTypes: Story = {
+ render: () => ({
+ components: { Button, DownloadIcon },
+ setup() {
+ return { sizeColumns, typeRows }
+ },
+ template: /*html*/ `
+
+
+
+ {{ size.label }}
+
+
+
+ {{ row.label }}
+
+ Button
+
+
+
+ `,
+ }),
+}
+
+export const Quiet: Story = {
+ render: () => ({
+ components: { Button, DownloadIcon, IconButton, SettingsIcon },
+ template: /*html*/ `
+
+ Quiet
+ Quiet destructive
+
+
+ `,
+ }),
+}
+
+export const Sizes: Story = {
+ render: () => ({
+ components: { Button, DownloadIcon, IconButton },
+ setup() {
+ return { sizes }
+ },
+ template: /*html*/ `
+
+
+ {{ size }}
+
+
+
+ `,
+ }),
+}
+
+export const Colors: Story = {
+ render: () => ({
+ components: { Button },
+ setup() {
+ return { colors }
+ },
+ template: /*html*/ `
+
+
+ {{ color }}
+
+
+ `,
+ }),
+}
+
+export const Content: Story = {
+ render: () => ({
+ components: { Button, DownloadIcon, SettingsIcon },
+ template: /*html*/ `
+
+ Text only
+ Leading icon
+ Trailing icon
+ Full width
+ Continue with a deliberately long translated action label
+
+ `,
+ }),
+}
+
+export const InteractionStates: Story = {
+ render: () => ({
+ components: { Button },
+ template: /*html*/ `
+
+ Enabled
+ Disabled
+ Loading
+ Colored
+ Colored disabled
+ Outlined
+ Quiet
+
+ `,
+ }),
+}
+
+export const LinksAndIconButton: Story = {
+ render: () => ({
+ components: { ButtonLink, ExternalIcon, HeartIcon, IconButton },
+ template: /*html*/ `
+
+ Internal link
+
+ Modrinth
+
+ Disabled link
+
+
+
+
+
+ `,
+ }),
+}
diff --git a/packages/ui/src/stories/buttons/ButtonGroup.stories.ts b/packages/ui/src/stories/buttons/ButtonGroup.stories.ts
new file mode 100644
index 0000000000..3f234148c4
--- /dev/null
+++ b/packages/ui/src/stories/buttons/ButtonGroup.stories.ts
@@ -0,0 +1,82 @@
+import { PlayIcon, SettingsIcon, StopCircleIcon, TrashIcon } from '@modrinth/assets'
+import type { Meta, StoryObj } from '@storybook/vue3-vite'
+
+import Button from '../../components/base/buttons/Button.vue'
+import ButtonGroup from '../../components/base/buttons/ButtonGroup.vue'
+import SplitButton from '../../components/base/buttons/SplitButton.vue'
+import type { OverflowMenuOption } from '../../components/base/buttons/types'
+
+const splitOptions: OverflowMenuOption[] = [
+ {
+ id: 'settings',
+ label: 'Server settings',
+ icon: SettingsIcon,
+ action: () => undefined,
+ },
+ { type: 'divider' },
+ {
+ id: 'delete',
+ label: 'Delete server',
+ icon: TrashIcon,
+ tone: 'red',
+ action: () => undefined,
+ },
+]
+
+const meta = {
+ title: 'Buttons/Button Group',
+ component: ButtonGroup,
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Joined: Story = {
+ render: () => ({
+ components: { Button, ButtonGroup },
+ template: /*html*/ `
+
+ Previous
+ Next
+
+ `,
+ }),
+}
+
+export const Split: Story = {
+ render: () => ({
+ components: { PlayIcon, SplitButton },
+ setup() {
+ return { splitOptions }
+ },
+ template: /*html*/ `
+
+ Start server
+
+ `,
+ }),
+}
+
+export const IndependentDisabledStates: Story = {
+ render: () => ({
+ components: { SplitButton, StopCircleIcon },
+ setup() {
+ return { splitOptions }
+ },
+ template: /*html*/ `
+
+
+ Primary disabled
+
+
+ Menu disabled
+
+
+ `,
+ }),
+}
diff --git a/packages/ui/src/stories/buttons/FileButton.stories.ts b/packages/ui/src/stories/buttons/FileButton.stories.ts
new file mode 100644
index 0000000000..2f07b27acc
--- /dev/null
+++ b/packages/ui/src/stories/buttons/FileButton.stories.ts
@@ -0,0 +1,61 @@
+import { UploadIcon } from '@modrinth/assets'
+import type { Meta, StoryObj } from '@storybook/vue3-vite'
+
+import FileButton from '../../components/base/buttons/FileButton.vue'
+
+const meta = {
+ title: 'Buttons/File Button',
+ component: FileButton,
+ argTypes: {
+ type: {
+ control: 'select',
+ options: ['base', 'colored', 'outlined', 'quiet'],
+ },
+ size: {
+ control: 'select',
+ options: ['sm', 'md', 'lg', 'xl'],
+ },
+ color: {
+ control: 'select',
+ options: ['brand', 'red', 'orange', 'green', 'blue', 'purple', 'medal_promotion'],
+ },
+ },
+ args: {
+ prompt: 'Select file',
+ type: 'base',
+ size: 'md',
+ multiple: false,
+ disabled: false,
+ },
+ render: (args) => ({
+ components: { FileButton, UploadIcon },
+ setup() {
+ return { args }
+ },
+ template: /*html*/ `
+
+
+
+ `,
+ }),
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Default: Story = {}
+
+export const MultipleImages: Story = {
+ args: {
+ prompt: 'Select images',
+ accept: 'image/*',
+ multiple: true,
+ type: 'colored',
+ },
+}
+
+export const Disabled: Story = {
+ args: {
+ disabled: true,
+ },
+}
diff --git a/packages/ui/src/stories/buttons/TeleportOverflowMenu.stories.ts b/packages/ui/src/stories/buttons/TeleportOverflowMenu.stories.ts
new file mode 100644
index 0000000000..5ed21392f1
--- /dev/null
+++ b/packages/ui/src/stories/buttons/TeleportOverflowMenu.stories.ts
@@ -0,0 +1,104 @@
+import {
+ DownloadIcon,
+ ExternalIcon,
+ MoreVerticalIcon,
+ SettingsIcon,
+ TrashIcon,
+} from '@modrinth/assets'
+import type { Meta, StoryObj } from '@storybook/vue3-vite'
+
+import TeleportOverflowMenu from '../../components/base/buttons/TeleportOverflowMenu.vue'
+import type { OverflowMenuOption } from '../../components/base/buttons/types'
+
+const options: OverflowMenuOption[] = [
+ {
+ id: 'download',
+ label: 'Download',
+ icon: DownloadIcon,
+ action: () => undefined,
+ },
+ {
+ id: 'settings',
+ label: 'Project settings',
+ icon: SettingsIcon,
+ type: 'link',
+ to: '/settings',
+ },
+ {
+ id: 'website',
+ label: 'Open website',
+ icon: ExternalIcon,
+ type: 'link',
+ href: 'https://modrinth.com',
+ target: '_blank',
+ },
+ {
+ id: 'unavailable',
+ label: 'Unavailable action',
+ disabled: true,
+ tooltip: 'This action is currently unavailable',
+ action: () => undefined,
+ },
+ { type: 'divider' },
+ {
+ id: 'delete',
+ label: 'Delete project',
+ icon: TrashIcon,
+ tone: 'red',
+ action: () => undefined,
+ },
+]
+
+const meta = {
+ title: 'Buttons/Teleport Overflow Menu',
+ component: TeleportOverflowMenu,
+ args: {
+ label: 'More actions',
+ options,
+ type: 'base',
+ size: 'md',
+ placement: 'bottom-end',
+ disabled: false,
+ hoverable: false,
+ },
+ render: (args) => ({
+ components: { MoreVerticalIcon, TeleportOverflowMenu },
+ setup() {
+ return { args }
+ },
+ template: /*html*/ `
+
+
+
+ `,
+ }),
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Default: Story = {}
+
+export const ColoredTrigger: Story = {
+ args: {
+ type: 'colored',
+ },
+}
+
+export const OutlinedTrigger: Story = {
+ args: {
+ type: 'outlined',
+ },
+}
+
+export const QuietTrigger: Story = {
+ args: {
+ type: 'quiet',
+ },
+}
+
+export const Hoverable: Story = {
+ args: {
+ hoverable: true,
+ },
+}
diff --git a/packages/ui/src/stories/buttons/TeleportPopoutMenu.stories.ts b/packages/ui/src/stories/buttons/TeleportPopoutMenu.stories.ts
new file mode 100644
index 0000000000..d6b183197c
--- /dev/null
+++ b/packages/ui/src/stories/buttons/TeleportPopoutMenu.stories.ts
@@ -0,0 +1,50 @@
+import { SettingsIcon } from '@modrinth/assets'
+import type { Meta, StoryObj } from '@storybook/vue3-vite'
+
+import Button from '../../components/base/buttons/Button.vue'
+import TeleportPopoutMenu from '../../components/base/buttons/TeleportPopoutMenu.vue'
+
+const meta = {
+ title: 'Buttons/Teleport Popout Menu',
+ component: TeleportPopoutMenu,
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const ArbitraryContent: Story = {
+ render: () => ({
+ components: { Button, SettingsIcon, TeleportPopoutMenu },
+ template: /*html*/ `
+
+
+ Configure
+
+
+
+
+
+ Version name
+
+
+ Apply
+
+
+
+ `,
+ }),
+}
+
+export const IconTrigger: Story = {
+ render: () => ({
+ components: { SettingsIcon, TeleportPopoutMenu },
+ template: /*html*/ `
+
+
+
+ Arbitrary teleported content can live here.
+
+
+ `,
+ }),
+}
diff --git a/packages/ui/src/stories/instances/ContentCardTable.stories.ts b/packages/ui/src/stories/instances/ContentCardTable.stories.ts
index 486a4c909e..e7a90ebbea 100644
--- a/packages/ui/src/stories/instances/ContentCardTable.stories.ts
+++ b/packages/ui/src/stories/instances/ContentCardTable.stories.ts
@@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite'
import { fn } from 'storybook/test'
import { onMounted, onUnmounted, ref } from 'vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button, IconButton } from '../../components/base/buttons'
import ContentCardTable from '../../layouts/shared/content-tab/components/ContentCardTable.vue'
import type { ContentCardTableItem } from '../../layouts/shared/content-tab/types'
@@ -539,7 +539,7 @@ export const InteractiveActions: Story = {
export const WithCustomItemButtons: Story = {
render: () => ({
- components: { ContentCardTable, ButtonStyled, EyeIcon, FolderOpenIcon, DownloadIcon },
+ components: { ContentCardTable, EyeIcon, FolderOpenIcon, DownloadIcon, Button, IconButton },
setup() {
return { items: sampleItems }
},
@@ -551,23 +551,17 @@ export const WithCustomItemButtons: Story = {
@delete="(id) => console.log('Delete', id)"
>
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
`,
@@ -582,15 +576,13 @@ export const WithEmptyState: Story = {
export const WithCustomEmptyState: Story = {
render: () => ({
- components: { ContentCardTable, ButtonStyled },
+ components: { ContentCardTable, Button, IconButton },
template: /*html*/ `
No mods installed
-
- Browse mods
-
+ Browse mods
@@ -781,7 +773,7 @@ export const WithOverflowMenu: Story = {
export const BulkActionsDemo: Story = {
render: () => ({
- components: { ContentCardTable, ButtonStyled },
+ components: { ContentCardTable, Button, IconButton },
setup() {
const items = ref([
{ ...sodiumItem, enabled: true },
@@ -825,15 +817,9 @@ export const BulkActionsDemo: Story = {
{{ selectedIds.length }} selected
-
- Enable
-
-
- Disable
-
-
- Delete
-
+ Enable
+ Disable
+ Delete
export const InstanceDependency: Story = {
render: () => ({
- components: { ButtonStyled, ContentDependencyWarningModal },
+ components: { ContentDependencyWarningModal, Button },
setup() {
const modalRef = ref | null>(null)
const deleted = ref(false)
@@ -186,9 +186,7 @@ export const InstanceDependency: Story = {
},
template: /* html */ `
-
- Delete dependency
-
+
Delete dependency
Dependency deletion confirmed
({
- components: { ButtonStyled, ContentDependencyWarningModal },
+ components: { ContentDependencyWarningModal, Button },
setup() {
const modalRef = ref | null>(null)
const deleted = ref(false)
@@ -227,9 +225,7 @@ export const ServerDependency: Story = {
},
template: /* html */ `
-
- Delete server dependency
-
+
Delete server dependency
Server dependency deletion confirmed
({
- components: { ButtonStyled, ContentDependencyWarningModal },
+ components: { ContentDependencyWarningModal, Button },
setup() {
const modalRef = ref | null>(null)
const deleted = ref(false)
@@ -267,9 +263,7 @@ export const BulkDependencies: Story = {
},
template: /* html */ `
-
- Delete selected dependencies
-
+
Delete selected dependencies
Bulk dependency deletion confirmed
export const ModExample: Story = {
render: (args) => ({
- components: { ContentUpdaterModal, ButtonStyled },
+ components: { ContentUpdaterModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show()
@@ -277,9 +277,7 @@ export const ModExample: Story = {
},
template: /*html*/ `
-
- Update Sodium
-
+
Update Sodium
({
- components: { ContentUpdaterModal, ButtonStyled },
+ components: { ContentUpdaterModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show()
@@ -318,9 +316,7 @@ export const ModpackExample: Story = {
},
template: /*html*/ `
-
- Update Cobblemon Modpack
-
+
Update Cobblemon Modpack
({
- components: { ContentUpdaterModal, ButtonStyled },
+ components: { ContentUpdaterModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show()
@@ -355,9 +351,7 @@ export const WithIncompatibleVersions: Story = {
},
template: /*html*/ `
-
- Update (Shows Incompatible)
-
+
Update (Shows Incompatible)
({
- components: { ContentUpdaterModal, ButtonStyled },
+ components: { ContentUpdaterModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show()
@@ -389,9 +383,7 @@ export const AllVersionTypes: Story = {
},
template: /*html*/ `
-
- View All Version Types
-
+
View All Version Types
export const Default: Story = {
render: () => ({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show(mixedModpackContent)
@@ -417,9 +417,7 @@ export const Default: Story = {
},
template: /*html*/ `
-
- View Modpack Content (Mixed)
-
+
View Modpack Content (Mixed)
({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show(modsOnlyContent)
@@ -440,9 +438,7 @@ export const ModsOnly: Story = {
},
template: /*html*/ `
-
- View Modpack Content (Mods Only)
-
+ View Modpack Content (Mods Only)
`,
@@ -455,7 +451,7 @@ export const ModsOnly: Story = {
export const LoadingState: Story = {
render: () => ({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => {
@@ -469,9 +465,7 @@ export const LoadingState: Story = {
},
template: /*html*/ `
-
- View Content (With Loading)
-
+
View Content (With Loading)
({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show([])
@@ -496,9 +490,7 @@ export const EmptyContent: Story = {
},
template: /*html*/ `
-
- View Empty Modpack
-
+ View Empty Modpack
`,
@@ -511,7 +503,7 @@ export const EmptyContent: Story = {
export const LargeModpack: Story = {
render: () => ({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show(largeModpackContent)
@@ -519,9 +511,7 @@ export const LargeModpack: Story = {
},
template: /*html*/ `
-
- View Large Modpack (47 items)
-
+
View Large Modpack (47 items)
({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show(mixedModpackContent)
@@ -549,9 +539,7 @@ export const SearchDemo: Story = {
Click the button and try searching for "sodium", "shader", or "faithful" to test the search functionality.
-
- Test Search
-
+ Test Search
`,
@@ -564,7 +552,7 @@ export const SearchDemo: Story = {
export const FilterDemo: Story = {
render: () => ({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show(mixedModpackContent)
@@ -575,9 +563,7 @@ export const FilterDemo: Story = {
Click the button and try the filter chips (Mods, Shaders, Resource Packs) to filter content by type.
-
- Test Filters
-
+ Test Filters
`,
@@ -590,7 +576,7 @@ export const FilterDemo: Story = {
export const MixedOwnerTypes: Story = {
render: () => ({
- components: { ModpackContentModal, ButtonStyled },
+ components: { ModpackContentModal, Button },
setup() {
const modalRef = ref | null>(null)
// Mix of user and organization owners
@@ -608,9 +594,7 @@ export const MixedOwnerTypes: Story = {
Shows content with different owner types: users (circular avatar) and organizations (rounded + icon).
-
- View Mixed Owners
-
+ View Mixed Owners
`,
diff --git a/packages/ui/src/stories/modal/ConfirmLeaveModal.stories.ts b/packages/ui/src/stories/modal/ConfirmLeaveModal.stories.ts
index 9509d27ac1..ac33eb8886 100644
--- a/packages/ui/src/stories/modal/ConfirmLeaveModal.stories.ts
+++ b/packages/ui/src/stories/modal/ConfirmLeaveModal.stories.ts
@@ -1,7 +1,7 @@
import type { StoryObj } from '@storybook/vue3-vite'
import { ref } from 'vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button } from '../../components/base/buttons'
import ConfirmLeaveModal from '../../components/modal/ConfirmLeaveModal.vue'
const meta = {
@@ -14,7 +14,7 @@ type Story = StoryObj
export const Default: Story = {
render: () => ({
- components: { ConfirmLeaveModal, ButtonStyled },
+ components: { ConfirmLeaveModal, Button },
setup() {
const modalRef = ref | null>(null)
const result = ref('')
@@ -27,9 +27,7 @@ export const Default: Story = {
},
template: /* html */ `
-
- Trigger Leave Confirmation
-
+
Trigger Leave Confirmation
{{ result }}
@@ -39,7 +37,7 @@ export const Default: Story = {
export const CustomMessages: Story = {
render: () => ({
- components: { ConfirmLeaveModal, ButtonStyled },
+ components: { ConfirmLeaveModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.prompt()
@@ -47,9 +45,7 @@ export const CustomMessages: Story = {
},
template: /* html */ `
-
- Discard Draft?
-
+
Discard Draft?
({
- components: { ConfirmLeaveModal, ButtonStyled },
+ components: { ConfirmLeaveModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.prompt()
@@ -73,9 +69,7 @@ export const WarningAdmonition: Story = {
},
template: /* html */ `
-
- Open Warning Variant
-
+
Open Warning Variant
export const Default: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show()
@@ -22,9 +22,7 @@ export const Default: Story = {
},
template: `
-
- Open Modal
-
+
Open Modal
This is the modal content.
You can put any content here.
@@ -36,7 +34,7 @@ export const Default: Story = {
export const WithActions: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => modalRef.value?.show()
@@ -44,19 +42,13 @@ export const WithActions: Story = {
},
template: `
-
- Open Modal with Actions
-
+
Open Modal with Actions
Are you sure you want to proceed with this action?
-
- Cancel
-
-
- Confirm
-
+ Cancel
+ Confirm
@@ -67,7 +59,7 @@ export const WithActions: Story = {
export const DangerFade: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => modalRef.value?.show()
@@ -75,19 +67,13 @@ export const DangerFade: Story = {
},
template: `
-
- Open Danger Modal
-
+
Open Danger Modal
Are you sure you want to delete this item? This action cannot be undone.
-
- Cancel
-
-
- Delete
-
+ Cancel
+ Delete
@@ -98,7 +84,7 @@ export const DangerFade: Story = {
export const WarningFade: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => modalRef.value?.show()
@@ -106,19 +92,13 @@ export const WarningFade: Story = {
},
template: `
-
- Open Warning Modal
-
+
Open Warning Modal
This action may have unintended consequences. Please review before proceeding.
-
- Cancel
-
-
- Proceed
-
+ Cancel
+ Proceed
@@ -129,7 +109,7 @@ export const WarningFade: Story = {
export const Scrollable: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => modalRef.value?.show()
@@ -137,9 +117,7 @@ export const Scrollable: Story = {
},
template: `
-
- Open Scrollable Modal
-
+
Open Scrollable Modal
@@ -148,9 +126,7 @@ export const Scrollable: Story = {
-
- Close
-
+ Close
@@ -161,7 +137,7 @@ export const Scrollable: Story = {
export const MergedHeader: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => modalRef.value?.show()
@@ -169,9 +145,7 @@ export const MergedHeader: Story = {
},
template: `
-
- Open Modal (Merged Header)
-
+
Open Modal (Merged Header)
Custom Header Area
@@ -185,7 +159,7 @@ export const MergedHeader: Story = {
export const NotClosable: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => modalRef.value?.show()
@@ -193,17 +167,13 @@ export const NotClosable: Story = {
},
template: `
-
- Open Non-Closable Modal
-
+
Open Non-Closable Modal
This modal cannot be closed by clicking outside or pressing escape.
Only the action button can close it.
-
- I understand, close
-
+ I understand, close
@@ -214,7 +184,7 @@ export const NotClosable: Story = {
export const NoPadding: Story = {
render: () => ({
- components: { NewModal, ButtonStyled },
+ components: { NewModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => modalRef.value?.show()
@@ -222,16 +192,12 @@ export const NoPadding: Story = {
},
template: `
-
- Open Modal (No Padding)
-
+
Open Modal (No Padding)
This modal has no default padding on the content area.
-
- Close
-
+ Close
diff --git a/packages/ui/src/stories/modal/ShareModal.stories.ts b/packages/ui/src/stories/modal/ShareModal.stories.ts
index 10b07701f4..28c81af2ae 100644
--- a/packages/ui/src/stories/modal/ShareModal.stories.ts
+++ b/packages/ui/src/stories/modal/ShareModal.stories.ts
@@ -1,7 +1,7 @@
import type { StoryObj } from '@storybook/vue3-vite'
import { ref } from 'vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button } from '../../components/base/buttons'
import ShareModal from '../../components/modal/ShareModal.vue'
const meta = {
@@ -20,7 +20,7 @@ export const LinkShare: Story = {
link: true,
},
render: (args) => ({
- components: { ShareModal, ButtonStyled },
+ components: { ShareModal, Button },
setup() {
const modalRef = ref
| null>(null)
const openModal = () => {
@@ -30,9 +30,7 @@ export const LinkShare: Story = {
},
template: `
-
- Open Link Share Modal
-
+ Open Link Share Modal
`,
@@ -47,7 +45,7 @@ export const TextShare: Story = {
link: false,
},
render: (args) => ({
- components: { ShareModal, ButtonStyled },
+ components: { ShareModal, Button },
setup() {
const modalRef = ref | null>(null)
const openModal = () => {
@@ -57,9 +55,7 @@ export const TextShare: Story = {
},
template: `
-
- Open Text Share Modal
-
+ Open Text Share Modal
`,
diff --git a/packages/ui/src/stories/modal/TabbedModal.stories.ts b/packages/ui/src/stories/modal/TabbedModal.stories.ts
index aee894f212..5d85e192ef 100644
--- a/packages/ui/src/stories/modal/TabbedModal.stories.ts
+++ b/packages/ui/src/stories/modal/TabbedModal.stories.ts
@@ -14,7 +14,7 @@ import {
import type { StoryObj } from '@storybook/vue3-vite'
import { defineComponent, h, ref } from 'vue'
-import ButtonStyled from '../../components/base/ButtonStyled.vue'
+import { Button } from '../../components/base/buttons'
import UnsavedChangesPopup from '../../components/base/UnsavedChangesPopup.vue'
import TabbedModal from '../../components/modal/TabbedModal.vue'
@@ -42,7 +42,7 @@ export default meta
export const Default: StoryObj = {
render: () => ({
- components: { TabbedModal, ButtonStyled },
+ components: { TabbedModal, Button },
setup() {
const modalRef = ref | null>(null)
const tabs = [
@@ -66,9 +66,7 @@ export const Default: StoryObj = {
},
template: /* html */ `
-
- Open Tabbed Modal
-
+ Open Tabbed Modal
`,
@@ -77,7 +75,7 @@ export const Default: StoryObj = {
export const WithTitleSlot: StoryObj = {
render: () => ({
- components: { TabbedModal, ButtonStyled, SettingsIcon },
+ components: { TabbedModal, SettingsIcon, Button },
setup() {
const modalRef = ref | null>(null)
const tabs = [
@@ -96,9 +94,7 @@ export const WithTitleSlot: StoryObj = {
},
template: /* html */ `
-
- Open with Title Slot
-
+ Open with Title Slot