mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 21:26:40 +00:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79dd0ba3b4 | ||
|
|
2343f82560 | ||
|
|
59972e0401 | ||
|
|
6d0c3ff9db | ||
|
|
2c7d58575c |
+4
-1
@@ -1,6 +1,9 @@
|
||||
# Windows has stack overflows when calling from Tauri, so we increase the default stack size used by the compiler
|
||||
[target.'cfg(windows)']
|
||||
rustflags = ["-C", "link-args=/STACK:16777220"]
|
||||
rustflags = ["-C", "link-args=/STACK:16777220", "--cfg", "tokio_unstable"]
|
||||
|
||||
[target.x86_64-pc-windows-msvc]
|
||||
linker = "rust-lld"
|
||||
|
||||
[build]
|
||||
rustflags = ["--cfg", "tokio_unstable"]
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
name: 🎮 Bug with Modrinth App
|
||||
description: For issues with Modrinth App.
|
||||
labels: [app]
|
||||
type: 'bug'
|
||||
name: 🎮 Modrinth App bug
|
||||
description: Report an issue in the Modrinth Launcher.
|
||||
labels: [bug, app]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
name: 🌐 Bug with Modrinth.com
|
||||
description: For issues with the Modrinth website.
|
||||
labels: [website]
|
||||
type: 'bug'
|
||||
name: 🌐 Website bug (modrinth.com)
|
||||
description: Report an issue on the Modrinth website.
|
||||
labels: [bug, web]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
name: 🛠 Bug with Modrinth API
|
||||
description: For issues with the Modrinth API for developers.
|
||||
labels: [api, backend]
|
||||
type: 'bug'
|
||||
name: 🛠️ API issue (api.modrinth.com)
|
||||
description: Report an issue regarding the Modrinth API.
|
||||
labels: [bug, backend]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
@@ -1,63 +0,0 @@
|
||||
name: 👥 Bug with Modrinth Hosting
|
||||
description: For issues with a Modrinth Hosting product.
|
||||
labels: [hosting]
|
||||
type: 'bug'
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Please confirm the following.
|
||||
options:
|
||||
- label: I checked the [existing issues](https://github.com/modrinth/code/issues?q=is%3Aissue) for duplicate problems
|
||||
required: true
|
||||
- label: I have tried resolving the issue using the [support portal](https://support.modrinth.com)
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: issue-location
|
||||
attributes:
|
||||
label: Is this an issue in the control panel or with the Minecraft server itself?
|
||||
options:
|
||||
- Control panel (on Modrinth.com)
|
||||
- Minecraft server
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: browsers
|
||||
attributes:
|
||||
label: What browsers are you seeing the problem on? (if a panel issue)
|
||||
multiple: true
|
||||
options:
|
||||
- N/A
|
||||
- Chrome (including Arc, Brave, Opera, Vivaldi)
|
||||
- Microsoft Edge
|
||||
- Firefox
|
||||
- Safari
|
||||
- Other (please specify)
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of what the bug is. Include screenshots if applicable.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Steps to reproduce the behavior.
|
||||
placeholder: |
|
||||
1. Go to '...'
|
||||
2. Click on '...'
|
||||
3. Scroll down to '...'
|
||||
4. See error
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here.
|
||||
validations:
|
||||
required: false
|
||||
+5
-6
@@ -1,6 +1,6 @@
|
||||
name: 💡 Feature request
|
||||
name: 💡 Feature Request
|
||||
description: Suggest an idea
|
||||
type: 'feature'
|
||||
labels: [enhancement]
|
||||
|
||||
body:
|
||||
- type: checkboxes
|
||||
@@ -17,10 +17,9 @@ body:
|
||||
label: What parts of Modrinth is your feature request related too?
|
||||
multiple: true
|
||||
options:
|
||||
- Modrinth App
|
||||
- Modrinth.com website
|
||||
- Modrinth Hosting
|
||||
- Modrinth API for developers
|
||||
- App
|
||||
- Website
|
||||
- API
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Is your suggested feature related to a problem? Please describe.
|
||||
@@ -1,8 +1,14 @@
|
||||
blank_issues_enabled: false
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: 🫶 Support portal
|
||||
about: Get support using through our support website.
|
||||
- name: 🫶 Support Portal
|
||||
about: Get support using through our portal.
|
||||
url: https://support.modrinth.com
|
||||
- name: 💬 Chat on Discord
|
||||
- name: 💬 Chat
|
||||
about: Join our Discord server to chat about Modrinth.
|
||||
url: https://discord.modrinth.com
|
||||
- name: 🛣️ Roadmap
|
||||
about: View our Roadmap. Please do not open issues for items on our roadmap.
|
||||
url: https://roadmap.modrinth.com
|
||||
- name: 📚 Documentation
|
||||
about: Useful documentation about Modrinth's API
|
||||
url: https://docs.modrinth.com
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
---
|
||||
applyTo: '**/*.vue'
|
||||
---
|
||||
|
||||
You are given a Nuxt/Vue single-file component (.vue). Your task is to convert every hard-coded natural-language string in the <template> into our localization system using vue-i18n with utilities from `@modrinth/ui`.
|
||||
|
||||
Please follow these rules precisely:
|
||||
|
||||
1. Identify translatable strings
|
||||
|
||||
- Scan the <template> for all user-visible strings (inner text, alt attributes, placeholders, button labels, etc.). Do not extract dynamic expressions (like {{ user.name }}) or HTML tags. Only extract static human-readable text.
|
||||
- There may be strings within the <script> block, e.g dropdown option labels, notifications etc.
|
||||
|
||||
2. Create message definitions
|
||||
|
||||
- In the <script setup> block, import `defineMessage` or `defineMessages` from `@modrinth/ui`.
|
||||
- For each extracted string, define a message with a unique `id` (use a descriptive prefix based on the component path, e.g. `auth.welcome.long-title`) and a `defaultMessage` equal to the original English string.
|
||||
Example:
|
||||
const messages = defineMessages({
|
||||
welcomeTitle: { id: 'auth.welcome.title', defaultMessage: 'Welcome' },
|
||||
welcomeDescription: { id: 'auth.welcome.description', defaultMessage: 'You're now part of the community…' },
|
||||
})
|
||||
|
||||
3. Handle variables and ICU formats
|
||||
|
||||
- Replace dynamic parts with ICU placeholders: "Hello, ${user.name}!" → `{name}` and defaultMessage: 'Hello, {name}!'
|
||||
- For numbers/dates/times, use ICU options (e.g., currency): `{price, number, ::currency/USD}`
|
||||
- For plurals/selects, use ICU: `'{count, plural, one {# message} other {# messages}}'`
|
||||
|
||||
4. Rich-text messages (links/markup)
|
||||
|
||||
- In `defaultMessage`, wrap link/markup ranges with tags, e.g.:
|
||||
"By creating an account, you agree to our <terms-link>Terms</terms-link> and <privacy-link>Privacy Policy</privacy-link>."
|
||||
- Render rich-text messages with `<IntlFormatted>` from `@modrinth/ui` using named slots:
|
||||
<IntlFormatted :message-id="messages.tosLabel">
|
||||
<template #terms-link="{ children }">
|
||||
<NuxtLink to="/terms">
|
||||
<component :is="() => children" />
|
||||
</NuxtLink>
|
||||
</template>
|
||||
<template #privacy-link="{ children }">
|
||||
<NuxtLink to="/privacy">
|
||||
<component :is="() => children" />
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</IntlFormatted>
|
||||
- For simple emphasis: `'Welcome to <strong>Modrinth</strong>!'` with a slot:
|
||||
<template #strong="{ children }">
|
||||
<strong><component :is="() => children" /></strong>
|
||||
</template>
|
||||
- For more complex child handling, use `normalizeChildren` from `@modrinth/ui`:
|
||||
<template #bold="{ children }">
|
||||
<strong><component :is="() => normalizeChildren(children)" /></strong>
|
||||
</template>
|
||||
|
||||
5. Formatting in templates
|
||||
|
||||
- Import and use `useVIntl()` from `@modrinth/ui`; prefer `formatMessage` for simple strings:
|
||||
`const { formatMessage } = useVIntl()`
|
||||
`<button>{{ formatMessage(messages.welcomeTitle) }}</button>`
|
||||
- Pass variables as a second argument:
|
||||
`{{ formatMessage(messages.greeting, { name: user.name }) }}`
|
||||
|
||||
6. Naming conventions and id stability
|
||||
|
||||
- Make `id`s descriptive and stable (e.g., `error.generic.default.title`). Group related messages with `defineMessages`.
|
||||
|
||||
7. Avoid Vue/ICU delimiter collisions
|
||||
|
||||
- If an ICU placeholder would end right before `}}` in a Vue template, insert a space so it becomes `} }` to avoid parsing issues.
|
||||
|
||||
8. Update imports and remove literals
|
||||
|
||||
- Ensure imports from `@modrinth/ui` are present: `defineMessage`/`defineMessages`, `useVIntl`, `IntlFormatted`, and optionally `normalizeChildren`.
|
||||
- Replace all hard-coded strings with `formatMessage(...)` or `<IntlFormatted>` and remove the literals.
|
||||
|
||||
9. Preserve functionality
|
||||
|
||||
- Do not change logic, layout, reactivity, or bindings—only refactor strings into i18n.
|
||||
|
||||
Use existing patterns from our codebase:
|
||||
|
||||
- Variables/plurals: see `apps/frontend/src/pages/frog.vue`
|
||||
- Rich-text link tags: see `apps/frontend/src/pages/auth/welcome.vue` and `apps/frontend/src/error.vue`
|
||||
|
||||
When you finish, there should be no hard-coded English strings left in the template—everything comes from `formatMessage` or `<IntlFormatted>`.
|
||||
@@ -1,3 +0,0 @@
|
||||
# Copying
|
||||
|
||||
Modrinth's Github workflows are licensed under the MIT License, which is provided in the file [LICENSE](./LICENSE).
|
||||
@@ -1,7 +0,0 @@
|
||||
Copyright 2025 Rinth, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,27 +0,0 @@
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
SQLX_OFFLINE: true
|
||||
|
||||
jobs:
|
||||
typos:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: crate-ci/typos@v1.43.1
|
||||
|
||||
# see <https://github.com/influxdata/datafusion-udf-wasm/pull/275>
|
||||
tombi:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: tombi
|
||||
- run: tombi lint
|
||||
- run: tombi fmt --check
|
||||
@@ -1,19 +0,0 @@
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
SQLX_OFFLINE: true
|
||||
|
||||
jobs:
|
||||
shear:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: cargo-bins/cargo-binstall@main
|
||||
- run: cargo binstall --no-confirm cargo-shear
|
||||
- run: cargo shear
|
||||
@@ -1,143 +0,0 @@
|
||||
name: Deploy frontend
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- prod
|
||||
paths:
|
||||
- 'apps/frontend/**/*'
|
||||
- 'packages/ui/**/*'
|
||||
- 'packages/utils/**/*'
|
||||
- 'packages/assets/**/*'
|
||||
- '**/wrangler.jsonc'
|
||||
- '**/pnpm-*.yaml'
|
||||
- '.github/workflows/frontend-deploy.yml'
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
inputs:
|
||||
environment:
|
||||
required: true
|
||||
type: string
|
||||
description: 'The environment to deploy to (staging-preview or production-preview)'
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure environment
|
||||
id: meta
|
||||
run: |
|
||||
echo "cmd=deploy" >> $GITHUB_OUTPUT
|
||||
|
||||
ENV_INPUT="${{ inputs.environment }}"
|
||||
REF="${{ github.ref }}"
|
||||
SHA_SHORT="${GITHUB_SHA::8}"
|
||||
|
||||
if [ "$ENV_INPUT" = "staging-preview" ]; then
|
||||
echo "env=staging" >> $GITHUB_OUTPUT
|
||||
echo "url=https://git-$SHA_SHORT-frontend-staging.modrinth.workers.dev" >> $GITHUB_OUTPUT
|
||||
echo "cmd=versions upload --preview-alias git-$SHA_SHORT --var PREVIEW:true" >> $GITHUB_OUTPUT
|
||||
|
||||
elif [ "$ENV_INPUT" = "production-preview" ]; then
|
||||
echo "env=production" >> $GITHUB_OUTPUT
|
||||
echo "url=https://git-$SHA_SHORT-frontend.modrinth.workers.dev" >> $GITHUB_OUTPUT
|
||||
echo "cmd=versions upload --preview-alias git-$SHA_SHORT --var PREVIEW:true" >> $GITHUB_OUTPUT
|
||||
|
||||
elif [ "$REF" = "refs/heads/main" ]; then
|
||||
echo "env=staging" >> $GITHUB_OUTPUT
|
||||
echo "url=https://staging.modrinth.com" >> $GITHUB_OUTPUT
|
||||
|
||||
else
|
||||
# Production env (no preview)
|
||||
echo "env=production" >> $GITHUB_OUTPUT
|
||||
echo "url=https://modrinth.com" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
cache: pnpm
|
||||
|
||||
- name: Inject build variables
|
||||
working-directory: ./apps/frontend
|
||||
run: |
|
||||
if [ "${{ steps.meta.outputs.env }}" == "staging" ]; then
|
||||
echo "Injecting staging variables from wrangler.jsonc..."
|
||||
jq -r '.env.staging.vars | to_entries[] | "\(.key)=\(.value)"' wrangler.jsonc >> $GITHUB_ENV
|
||||
else
|
||||
echo "Injecting production variables from wrangler.jsonc..."
|
||||
jq -r '.vars | to_entries[] | "\(.key)=\(.value)"' wrangler.jsonc >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: ./apps/frontend
|
||||
run: pnpm install
|
||||
|
||||
- name: Build frontend
|
||||
working-directory: ./apps/frontend
|
||||
run: pnpm build
|
||||
env:
|
||||
CF_PAGES_BRANCH: ${{ github.ref_name }}
|
||||
CF_PAGES_COMMIT_SHA: ${{ github.sha }}
|
||||
CF_PAGES_URL: ${{ steps.meta.outputs.url }}
|
||||
BUILD_ENV: ${{ steps.meta.outputs.env }}
|
||||
PREVIEW: ${{ inputs.environment != '' && 'true' || 'false' }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
|
||||
- name: Create Sentry release and upload sourcemaps
|
||||
uses: getsentry/action-release@v3
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: modrinth
|
||||
SENTRY_PROJECT: knossos-server
|
||||
with:
|
||||
environment: ${{ steps.meta.outputs.env }}
|
||||
sourcemaps: ./apps/frontend/.output/server
|
||||
url_prefix: '~/'
|
||||
|
||||
- name: Deploy Cloudflare Worker
|
||||
id: wrangler
|
||||
uses: cloudflare/wrangler-action@v3
|
||||
with:
|
||||
apiToken: ${{ secrets.CF_API_TOKEN }}
|
||||
accountId: ${{ secrets.CF_ACCOUNT_ID }}
|
||||
environment: ${{ steps.meta.outputs.env != 'production' && steps.meta.outputs.env || '' }}
|
||||
workingDirectory: ./apps/frontend
|
||||
packageManager: pnpm
|
||||
wranglerVersion: '4.54.0'
|
||||
command: ${{ steps.meta.outputs.cmd }}
|
||||
|
||||
- name: Purge cache
|
||||
if: github.ref == 'refs/heads/prod'
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{ secrets.CF_API_TOKEN }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"hosts": ["modrinth.com", "www.modrinth.com", "staging.modrinth.com"]}' \
|
||||
https://api.cloudflare.com/client/v4/zones/e39df17b9c4ef44cbce2646346ee6d33/purge_cache
|
||||
|
||||
- name: Write deployment URL to file
|
||||
if: ${{ inputs.environment != '' }}
|
||||
run: |
|
||||
echo "${{ steps.meta.outputs.url }}" > deployment-url-${{ inputs.environment }}.txt
|
||||
|
||||
- name: Upload deployment URL
|
||||
if: ${{ inputs.environment != '' }}
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: deployment-url-${{ inputs.environment }}
|
||||
path: deployment-url-${{ inputs.environment }}.txt
|
||||
@@ -0,0 +1,30 @@
|
||||
name: Clear pages cache
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- prod
|
||||
|
||||
jobs:
|
||||
wait:
|
||||
if: github.repository_owner == 'modrinth'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
steps:
|
||||
- name: Cloudflare Pages deployment
|
||||
uses: WalshyDev/cf-pages-await@v1
|
||||
with:
|
||||
apiToken: ${{ secrets.CF_API_TOKEN }}
|
||||
accountId: '9ddae624c98677d68d93df6e524a6061'
|
||||
project: 'frontend'
|
||||
commitHash: ${{ steps.push-changes.outputs.commit-hash }}
|
||||
- name: Purge cache
|
||||
if: github.ref == 'refs/heads/prod'
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{ secrets.CF_API_TOKEN }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"hosts": ["modrinth.com", "www.modrinth.com"]}' \
|
||||
https://api.cloudflare.com/client/v4/zones/e39df17b9c4ef44cbce2646346ee6d33/purge_cache
|
||||
@@ -1,72 +0,0 @@
|
||||
name: Deploy frontend preview
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'apps/frontend/**/*'
|
||||
- 'packages/ui/**/*'
|
||||
- 'packages/utils/**/*'
|
||||
- 'packages/assets/**/*'
|
||||
- '**/wrangler.jsonc'
|
||||
- '**/pnpm-*.yaml'
|
||||
- '.github/workflows/frontend-preview.yml'
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
if: github.repository_owner == 'modrinth' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
uses: ./.github/workflows/frontend-deploy.yml
|
||||
secrets: inherit
|
||||
strategy:
|
||||
matrix:
|
||||
environment: [staging-preview, production-preview]
|
||||
with:
|
||||
environment: ${{ matrix.environment }}
|
||||
|
||||
comment:
|
||||
if: github.repository_owner == 'modrinth' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
runs-on: ubuntu-latest
|
||||
needs: deploy
|
||||
steps:
|
||||
- name: Download deployment URLs
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: deployment-url-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Read deployment URLs
|
||||
id: urls
|
||||
run: |
|
||||
STAGING_PREVIEW_URL=$(cat deployment-url-staging-preview.txt)
|
||||
PRODUCTION_PREVIEW_URL=$(cat deployment-url-production-preview.txt)
|
||||
|
||||
echo "Production preview URL: $PRODUCTION_PREVIEW_URL"
|
||||
echo "Staging preview URL: $STAGING_PREVIEW_URL"
|
||||
|
||||
echo "staging-preview-url=$STAGING_PREVIEW_URL" >> $GITHUB_OUTPUT
|
||||
echo "production-preview-url=$PRODUCTION_PREVIEW_URL" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Find comment
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: peter-evans/find-comment@v3
|
||||
id: fc
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-author: 'github-actions[bot]'
|
||||
body-includes: Frontend previews
|
||||
|
||||
- name: Comment deploy URL on PR
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: peter-evans/create-or-update-comment@v5
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||
body: |
|
||||
## Frontend previews
|
||||
|
||||
Last deployed commit is [${{ github.sha }}](${{ github.event.pull_request.head.repo.html_url }}/commit/${{ github.sha }})
|
||||
|
||||
| Environment | URL |
|
||||
|-------------|-----|
|
||||
| staging | ${{ steps.urls.outputs.staging-preview-url }} |
|
||||
| production | ${{ steps.urls.outputs.production-preview-url }} |
|
||||
edit-mode: replace
|
||||
@@ -11,7 +11,7 @@ concurrency:
|
||||
jobs:
|
||||
pull_translations:
|
||||
name: 'Pull translations from Crowdin'
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
if: github.ref == 'refs/heads/main'
|
||||
concurrency:
|
||||
group: i18n-pull:${{ github.ref }}
|
||||
|
||||
@@ -18,7 +18,7 @@ concurrency:
|
||||
jobs:
|
||||
push_translations:
|
||||
name: Push sources to Crowdin
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
if: github.ref == 'refs/heads/main'
|
||||
concurrency:
|
||||
group: i18n-push:${{ github.ref }}
|
||||
|
||||
@@ -7,15 +7,11 @@ on:
|
||||
paths:
|
||||
- .github/workflows/labrinth-docker.yml
|
||||
- 'apps/labrinth/**'
|
||||
- Cargo.toml
|
||||
- Cargo.lock
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
paths:
|
||||
- .github/workflows/labrinth-docker.yml
|
||||
- 'apps/labrinth/**'
|
||||
- Cargo.toml
|
||||
- Cargo.lock
|
||||
merge_group:
|
||||
types: [checks_requested]
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ on:
|
||||
sign-windows-binaries:
|
||||
description: Sign Windows binaries
|
||||
type: boolean
|
||||
default: false
|
||||
default: true
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
@@ -28,60 +28,45 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [macos-latest, windows-latest, ubuntu-latest]
|
||||
platform: [macos-latest, windows-latest, ubuntu-22.04]
|
||||
include:
|
||||
- platform: macos-latest
|
||||
artifact-target-name: universal-apple-darwin
|
||||
- platform: windows-latest
|
||||
artifact-target-name: x86_64-pc-windows-msvc
|
||||
- platform: ubuntu-latest
|
||||
- platform: ubuntu-22.04
|
||||
artifact-target-name: x86_64-unknown-linux-gnu
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
- name: 📥 Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Rust toolchain
|
||||
- name: 🧰 Setup Rust toolchain
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
rustflags: ''
|
||||
target: ${{ startsWith(matrix.platform, 'macos') && 'x86_64-apple-darwin' || '' }}
|
||||
|
||||
- name: Install pnpm
|
||||
- name: 🧰 Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
- name: 🧰 Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
cache: pnpm
|
||||
|
||||
- name: Generate tauri-dev.conf.json
|
||||
shell: bash
|
||||
run: |
|
||||
GIT_HASH=$(git rev-parse --short HEAD)
|
||||
cat > apps/app/tauri-dev.conf.json <<EOF
|
||||
{
|
||||
"productName": "Modrinth App (dev-${GIT_HASH})",
|
||||
"mainBinaryName": "Modrinth App (dev-${GIT_HASH})",
|
||||
"identifier": "ModrinthApp-dev-${GIT_HASH}",
|
||||
"bundle": {
|
||||
"fileAssociations": []
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
- name: Install Linux build dependencies
|
||||
- name: 🧰 Install Linux build dependencies
|
||||
if: startsWith(matrix.platform, 'ubuntu')
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -yq libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev
|
||||
|
||||
- name: Setup Dasel
|
||||
- name: 🧰 Setup Dasel
|
||||
uses: jaxxstorm/action-install-gh-release@v2.1.0
|
||||
with:
|
||||
repo: TomWright/dasel
|
||||
@@ -90,7 +75,7 @@ jobs:
|
||||
rename-to: ${{ startsWith(matrix.platform, 'windows') && 'dasel.exe' || 'dasel' }}
|
||||
chmod: 0755
|
||||
|
||||
- name: Set application version and environment
|
||||
- name: ⚙️ Set application version and environment
|
||||
shell: bash
|
||||
run: |
|
||||
APP_VERSION="$(git describe --tags --always | sed -E 's/-([0-9]+)-(g[0-9a-fA-F]+)$/-canary+\1.\2/')"
|
||||
@@ -101,13 +86,13 @@ jobs:
|
||||
|
||||
cp packages/app-lib/.env.prod packages/app-lib/.env
|
||||
|
||||
- name: Setup Turbo cache
|
||||
- name: 💨 Setup Turbo cache
|
||||
uses: rharkor/caching-for-turbo@v1.8
|
||||
|
||||
- name: Install dependencies
|
||||
- name: 🧰 Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Set up Windows code signing
|
||||
- name: ✍️ Set up Windows code signing
|
||||
if: startsWith(matrix.platform, 'windows')
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -117,8 +102,8 @@ jobs:
|
||||
dasel delete -f apps/app/tauri-release.conf.json 'bundle.windows.signCommand'
|
||||
fi
|
||||
|
||||
- name: Build macOS app
|
||||
run: ${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) && 'pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config tauri-release.conf.json' || 'pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config tauri-dev.conf.json' }}
|
||||
- name: 🔨 Build macOS app
|
||||
run: pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config tauri-release.conf.json
|
||||
if: startsWith(matrix.platform, 'macos')
|
||||
env:
|
||||
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
@@ -131,19 +116,19 @@ jobs:
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
|
||||
- name: Build Linux app
|
||||
run: ${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) && 'pnpm --filter=@modrinth/app run tauri build --config tauri-release.conf.json' || 'pnpm --filter=@modrinth/app run tauri build --config tauri-dev.conf.json' }}
|
||||
- name: 🔨 Build Linux app
|
||||
run: pnpm --filter=@modrinth/app run tauri build --config tauri-release.conf.json
|
||||
if: startsWith(matrix.platform, 'ubuntu')
|
||||
env:
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
|
||||
- name: Build Windows app
|
||||
- name: 🔨 Build Windows app
|
||||
run: |
|
||||
[System.Convert]::FromBase64String("$env:DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_BASE64") | Set-Content -Path signer-client-cert.p12 -AsByteStream
|
||||
$env:DIGICERT_ONE_SIGNER_CREDENTIALS = "$env:DIGICERT_ONE_SIGNER_API_KEY|$PWD\signer-client-cert.p12|$env:DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_PASSWORD"
|
||||
$env:JAVA_HOME = "$env:JAVA_HOME_17_X64"
|
||||
${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) && 'pnpm --filter=@modrinth/app run tauri build --config tauri-release.conf.json --verbose --bundles "nsis,updater"' || 'pnpm --filter=@modrinth/app run tauri build --config tauri-dev.conf.json --verbose --bundles "nsis,updater"' }}
|
||||
$env:JAVA_HOME = "$env:JAVA_HOME_11_X64"
|
||||
pnpm --filter=@modrinth/app run tauri build --config tauri-release.conf.json --verbose --bundles 'nsis,updater'
|
||||
Remove-Item -Path signer-client-cert.p12 -ErrorAction SilentlyContinue
|
||||
if: startsWith(matrix.platform, 'windows')
|
||||
env:
|
||||
@@ -153,7 +138,7 @@ jobs:
|
||||
DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_BASE64: ${{ secrets.DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_BASE64 }}
|
||||
DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_PASSWORD: ${{ secrets.DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_PASSWORD }}
|
||||
|
||||
- name: Upload app bundles
|
||||
- name: 📤 Upload app bundles
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: App bundle (${{ matrix.artifact-target-name }})
|
||||
@@ -161,13 +146,7 @@ jobs:
|
||||
target/release/bundle/appimage/Modrinth App_*.AppImage*
|
||||
target/release/bundle/deb/Modrinth App_*.deb*
|
||||
target/release/bundle/rpm/Modrinth App-*.rpm*
|
||||
target/release/bundle/appimage/Modrinth App (dev-*)_*.AppImage*
|
||||
target/release/bundle/deb/Modrinth App (dev-*)_*.deb*
|
||||
target/release/bundle/rpm/Modrinth App (dev-*)-*.rpm*
|
||||
target/universal-apple-darwin/release/bundle/macos/Modrinth App.app.tar.gz*
|
||||
target/universal-apple-darwin/release/bundle/macos/Modrinth App (dev-*)*.app.tar.gz
|
||||
target/universal-apple-darwin/release/bundle/dmg/Modrinth App (dev-*)*.dmg
|
||||
target/universal-apple-darwin/release/bundle/dmg/Modrinth App_*.dmg*
|
||||
target/release/bundle/nsis/Modrinth App_*-setup.exe*
|
||||
target/release/bundle/nsis/Modrinth App (dev-*)_*-setup.exe*
|
||||
target/release/bundle/nsis/Modrinth App_*-setup.nsis.zip*
|
||||
|
||||
@@ -11,18 +11,13 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
name: Lint and Test
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
env:
|
||||
# Ensure pnpm output is colored in GitHub Actions logs
|
||||
FORCE_COLOR: 3
|
||||
# Make cargo nextest successfully ignore projects without tests
|
||||
NEXTEST_NO_TESTS: pass
|
||||
# Fail on warnings in CI
|
||||
# (but don't do this in the root `Cargo.toml`,
|
||||
# since we don't want warnings to become errors
|
||||
# while developing)
|
||||
RUSTFLAGS: -Dwarnings
|
||||
|
||||
steps:
|
||||
- name: 📥 Check out code
|
||||
@@ -70,37 +65,23 @@ jobs:
|
||||
- name: 🧰 Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: ⚙️ Set app environment
|
||||
working-directory: packages/app-lib
|
||||
run: cp .env.staging .env
|
||||
|
||||
# check if labrinth tests will actually run (cache miss)
|
||||
- name: 🔍 Check if labrinth tests need to run
|
||||
id: check-labrinth
|
||||
run: |
|
||||
LABRINTH_TEST_STATUS=$(pnpm turbo run test --filter=@modrinth/labrinth --dry-run=json | jq -r '.tasks[] | select(.task == "test") | .cache.status')
|
||||
echo "Labrinth test cache status: $LABRINTH_TEST_STATUS"
|
||||
if [ "$LABRINTH_TEST_STATUS" = "HIT" ]; then
|
||||
echo "needs_services=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "needs_services=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: ⚙️ Start services
|
||||
if: steps.check-labrinth.outputs.needs_services == 'true'
|
||||
run: docker compose up --wait
|
||||
|
||||
- name: ⚙️ Setup labrinth environment and database
|
||||
if: steps.check-labrinth.outputs.needs_services == 'true'
|
||||
working-directory: apps/labrinth
|
||||
run: |
|
||||
cp .env.local .env
|
||||
sqlx database setup
|
||||
|
||||
- name: ⚙️ Set app environment
|
||||
working-directory: packages/app-lib
|
||||
run: cp .env.staging .env
|
||||
|
||||
- name: 🔍 Lint and test
|
||||
run: pnpm run ci
|
||||
|
||||
- name: 🔍 Verify intl:extract has been run
|
||||
run: |
|
||||
pnpm turbo run intl:extract --force
|
||||
pnpm intl:extract
|
||||
git diff --exit-code --color */*/src/locales/en-US/index.json
|
||||
|
||||
-14
@@ -27,7 +27,6 @@ node_modules
|
||||
.idea/*
|
||||
!.idea/code.iml
|
||||
!.idea/gradle.xml
|
||||
!.idea/icon.svg
|
||||
!.idea/modules.xml
|
||||
!.idea/vcs.xml
|
||||
|
||||
@@ -64,16 +63,3 @@ generated
|
||||
app-playground-data/*
|
||||
|
||||
.astro
|
||||
.claude
|
||||
.letta
|
||||
|
||||
# labrinth demo fixtures
|
||||
apps/labrinth/fixtures/demo
|
||||
|
||||
*storybook.log
|
||||
storybook-static
|
||||
|
||||
.wrangler/
|
||||
|
||||
# frontend robots.txt
|
||||
apps/frontend/src/public/robots.txt
|
||||
|
||||
Generated
+1
-7
@@ -11,15 +11,9 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/apps/labrinth/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/app-lib/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/ariadne/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/path-util/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/modrinth-log/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/modrinth-maxmind/examples" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/modrinth-maxmind/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/modrinth-util/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/muralpay/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
</module>
|
||||
|
||||
Generated
-4
@@ -1,4 +0,0 @@
|
||||
<svg width="512" height="514" viewBox="0 0 512 514" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M503.16 323.56C514.55 281.47 515.32 235.91 503.2 190.76C466.57 54.2299 326.04 -26.8001 189.33 9.77991C83.8101 38.0199 11.3899 128.07 0.689941 230.47H43.99C54.29 147.33 113.74 74.7298 199.75 51.7098C306.05 23.2598 415.13 80.6699 453.17 181.38L411.03 192.65C391.64 145.8 352.57 111.45 306.3 96.8198L298.56 140.66C335.09 154.13 364.72 184.5 375.56 224.91C391.36 283.8 361.94 344.14 308.56 369.17L320.09 412.16C390.25 383.21 432.4 310.3 422.43 235.14L464.41 223.91C468.91 252.62 467.35 281.16 460.55 308.07L503.16 323.56Z" fill="#00af5c"/>
|
||||
<path d="M321.99 504.22C185.27 540.8 44.7501 459.77 8.11011 323.24C3.84011 307.31 1.17 291.33 0 275.46H43.27C44.36 287.37 46.4699 299.35 49.6799 311.29C53.0399 323.8 57.45 335.75 62.79 347.07L101.38 323.92C98.1299 316.42 95.39 308.6 93.21 300.47C69.17 210.87 122.41 118.77 212.13 94.7601C229.13 90.2101 246.23 88.4401 262.93 89.1501L255.19 133C244.73 133.05 234.11 134.42 223.53 137.25C157.31 154.98 118.01 222.95 135.75 289.09C136.85 293.16 138.13 297.13 139.59 300.99L188.94 271.38L174.07 231.95L220.67 184.08L279.57 171.39L296.62 192.38L269.47 219.88L245.79 227.33L228.87 244.72L237.16 267.79C237.16 267.79 253.95 285.63 253.98 285.64L277.7 279.33L294.58 260.79L331.44 249.12L342.42 273.82L304.39 320.45L240.66 340.63L212.08 308.81L162.26 338.7C187.8 367.78 226.2 383.93 266.01 380.56L277.54 423.55C218.13 431.41 160.1 406.82 124.05 361.64L85.6399 384.68C136.25 451.17 223.84 484.11 309.61 461.16C371.35 444.64 419.4 402.56 445.42 349.38L488.06 364.88C457.17 431.16 398.22 483.82 321.99 504.22Z" fill="#00af5c"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
Vendored
+1
-19
@@ -11,23 +11,5 @@
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.organizeImports": "always"
|
||||
},
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"[vue]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[scss]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[css]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[rust]": {
|
||||
"editor.defaultFormatter": "rust-lang.rust-analyzer"
|
||||
}
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
# Architecture
|
||||
|
||||
Use TAB instead of spaces.
|
||||
|
||||
## Frontend
|
||||
|
||||
There are two similar frontends in the Modrinth monorepo, the website (apps/frontend) and the app frontend (apps/app-frontend).
|
||||
|
||||
Both use Tailwind v3, and their respective configs can be seen at `tailwind.config.ts` and `tailwind.config.js` respectively.
|
||||
|
||||
Both utilize shared and common components from `@modrinth/ui` which can be found at `packages/ui`, and stylings from `@modrinth/assets` which can be found at `packages/assets`.
|
||||
|
||||
Both can utilize icons from `@modrinth/assets`, which are automatically generated based on what's available within the `icons` folder of the `packages/assets` directory. You can see the generated icons list in `generated-icons.ts`.
|
||||
|
||||
Both have access to our dependency injection framework, examples as seen in `packages/ui/src/providers/`. Ideally any state which is shared between a page and it's subpages should be shared using this dependency injection framework.
|
||||
|
||||
### Website (apps/frontend)
|
||||
|
||||
Before a pull request can be opened for the website, run `pnpm prepr:frontend:web` from the root folder, otherwise CI will fail.
|
||||
|
||||
To run a development version of the frontend, you must first copy over the relevant `.env` template file (prod, staging or local, usually prod) within the `apps/frontend` folder into `apps/frontend/.env`. Then you can run the frontend by running `pnpm web:dev` in the root folder.
|
||||
|
||||
### App Frontend (apps/app-frontend)
|
||||
|
||||
Before a pull request can be opened for the app frontend, run `pnpm prepr:frontend:app` from the root folder, otherwise CI will fail.
|
||||
|
||||
To run a development version of the app frontend, you must first copy over the relevant `.env` template file (prod, staging or local, usually prod) within `packages/app-lib` into `packages/app-lib/.env`. Then you must run the app itself by running `pnpm app:dev` in the root folder.
|
||||
|
||||
### Localization
|
||||
|
||||
Refer to `.github/instructions/i18n-convert.instructions.md` if the user asks you to perform any i18n conversion work on a component, set of components, pages or sets of pages.
|
||||
|
||||
## Labrinth
|
||||
|
||||
Labrinth is the backend API service for Modrinth.
|
||||
|
||||
### Testing
|
||||
|
||||
Before a pull request can be opened, run `cargo clippy -p labrinth --all-targets` and make sure there are ZERO warnings, otherwise CI will fail.
|
||||
|
||||
Use `cargo test -p labrinth --all-targets` to test your changes. All tests must pass, otherwise CI will fail.
|
||||
|
||||
To prepare the sqlx cache, cd into `apps/labrinth` and run `cargo sqlx prepare`. Make sure to NEVER run `cargo sqlx prepare --workspace`.
|
||||
|
||||
Read the root `docker-compose.yml` to see what running services are available while developing. Use `docker exec` to access these services.
|
||||
|
||||
When the user refers to "performing pre-PR checks", do the following:
|
||||
|
||||
- Run clippy as described above
|
||||
- DO NOT run tests unless explicitly requested (they take a long time)
|
||||
- Prepare the sqlx cache
|
||||
|
||||
### Clickhouse
|
||||
|
||||
Use `docker exec labrinth-clickhouse clickhouse-client` to access the Clickhouse instance. We use the `staging_ariadne` database to store data in testing.
|
||||
|
||||
### Postgres
|
||||
|
||||
Use `docker exec labrinth-postgres psql -U labrinth -d labrinth -c "SELECT 1"` to access the PostgreSQL instance, replacing the `SELECT 1` with your query.
|
||||
|
||||
# Guidelines
|
||||
|
||||
- Do not create new non-source code files (e.g. Bash scripts, SQL scripts) unless explicitly prompted to.
|
||||
+1
-9
@@ -8,14 +8,6 @@ For detailed information, consult each package's COPYING.md, LICENSE.txt, or LIC
|
||||
|
||||
The use of Modrinth branding elements, including but not limited to the wrench-in-labyrinth logo, the landing image, and any variations thereof, is strictly prohibited without explicit written permission from Rinth, Inc. This includes trademarks, logos, or other branding elements.
|
||||
|
||||
> All rights reserved. © 2020-2025 Rinth, Inc.
|
||||
|
||||
This includes, but may not be limited to, the following files:
|
||||
|
||||
- .idea/icon.svg
|
||||
- .github/api_cover.png
|
||||
- .github/app_cover.png
|
||||
- .github/monorepo_cover.png
|
||||
- .github/web_cover.png
|
||||
All rights reserved. © 2020-2024 Rinth, Inc.
|
||||
|
||||
If you fork this repository, you must remove all Modrinth branding assets from your fork.
|
||||
|
||||
Generated
+1226
-2340
File diff suppressed because it is too large
Load Diff
+114
-148
@@ -1,189 +1,160 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"apps/app",
|
||||
"apps/app-playground",
|
||||
"apps/daedalus_client",
|
||||
"apps/labrinth",
|
||||
"packages/app-lib",
|
||||
"packages/ariadne",
|
||||
"packages/daedalus",
|
||||
"packages/modrinth-log",
|
||||
"packages/modrinth-maxmind",
|
||||
"packages/modrinth-util",
|
||||
"packages/path-util",
|
||||
"apps/app",
|
||||
"apps/app-playground",
|
||||
"apps/daedalus_client",
|
||||
"apps/labrinth",
|
||||
"packages/app-lib",
|
||||
"packages/ariadne",
|
||||
"packages/daedalus",
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
edition = "2024"
|
||||
rust-version = "1.90.0"
|
||||
repository = "https://github.com/modrinth/code"
|
||||
|
||||
[workspace.dependencies]
|
||||
actix-cors = "0.7.1"
|
||||
actix-files = "0.6.8"
|
||||
actix-http = "3.11.2"
|
||||
actix-files = "0.6.6"
|
||||
actix-http = "3.11.0"
|
||||
actix-multipart = "0.7.2"
|
||||
actix-rt = "2.11.0"
|
||||
actix-rt = "2.10.0"
|
||||
actix-web = "4.11.0"
|
||||
actix-web-prom = "0.10.0"
|
||||
actix-ws = "0.3.0"
|
||||
arc-swap = "1.7.1"
|
||||
argon2 = { version = "0.5.3", features = ["std"] }
|
||||
ariadne = { path = "packages/ariadne" }
|
||||
async-compression = { version = "0.4.32", default-features = false }
|
||||
async_zip = "0.0.17"
|
||||
async-compression = { version = "0.4.27", default-features = false }
|
||||
async-recursion = "1.1.1"
|
||||
async-stripe = { version = "0.41.0", default-features = false, features = [
|
||||
"runtime-tokio-hyper-rustls",
|
||||
] }
|
||||
async-trait = "0.1.89"
|
||||
async-tungstenite = { version = "0.31.0", default-features = false, features = [
|
||||
"futures-03-sink"
|
||||
"runtime-tokio-hyper-rustls",
|
||||
] }
|
||||
async-trait = "0.1.88"
|
||||
async-tungstenite = { version = "0.30.0", default-features = false, features = ["futures-03-sink"] }
|
||||
async-walkdir = "2.1.0"
|
||||
async_zip = "0.0.18"
|
||||
base64 = "0.22.1"
|
||||
bitflags = "2.9.4"
|
||||
bytemuck = "1.24.0"
|
||||
bitflags = "2.9.1"
|
||||
bytemuck = "1.23.1"
|
||||
bytes = "1.10.1"
|
||||
censor = "0.3.0"
|
||||
chardetng = "0.1.17"
|
||||
chrono = "0.4.42"
|
||||
cidre = { version = "0.11.3", default-features = false, features = [
|
||||
"macos_15_0"
|
||||
] }
|
||||
clap = "4.5.48"
|
||||
clickhouse = "0.14.0"
|
||||
color-eyre = "0.6.5"
|
||||
chrono = "0.4.41"
|
||||
clap = "4.5.43"
|
||||
clickhouse = "0.13.3"
|
||||
color-thief = "0.2.2"
|
||||
const_format = "0.2.34"
|
||||
console-subscriber = "0.4.1"
|
||||
daedalus = { path = "packages/daedalus" }
|
||||
dashmap = "6.1.0"
|
||||
data-url = "0.3.2"
|
||||
deadpool-redis = { git = "https://github.com/modrinth/deadpool", rev = "db5fb00b036ecc8fe5f18853c559b745ffe47bde", version = "0.22.1" }
|
||||
data-url = "0.3.1"
|
||||
deadpool-redis = "0.22.0"
|
||||
derive_more = "2.0.1"
|
||||
directories = "6.0.0"
|
||||
dirs = "6.0.0"
|
||||
discord-rich-presence = "1.0.0"
|
||||
discord-rich-presence = "0.2.5"
|
||||
dotenv-build = "0.1.1"
|
||||
dotenvy = "0.15.7"
|
||||
dunce = "1.0.5"
|
||||
either = "1.15.0"
|
||||
encoding_rs = "0.8.35"
|
||||
enumset = "1.1.10"
|
||||
eyre = "0.6.12"
|
||||
flate2 = "1.1.4"
|
||||
enumset = "1.1.7"
|
||||
flate2 = "1.1.2"
|
||||
fs4 = { version = "0.13.1", default-features = false }
|
||||
futures = "0.3.31"
|
||||
futures = { version = "0.3.31", default-features = false }
|
||||
futures-util = "0.3.31"
|
||||
heck = "0.5.0"
|
||||
hex = "0.4.3"
|
||||
hickory-resolver = "0.25.2"
|
||||
hmac = "0.12.1"
|
||||
hyper = "1.7.0"
|
||||
hyper = "1.6.0"
|
||||
hyper-rustls = { version = "0.27.7", default-features = false, features = [
|
||||
"aws-lc-rs",
|
||||
"http1",
|
||||
"native-tokio",
|
||||
"tls12",
|
||||
"http1",
|
||||
"native-tokio",
|
||||
"ring",
|
||||
"tls12",
|
||||
] }
|
||||
hyper-util = "0.1.17"
|
||||
iana-time-zone = "0.1.64"
|
||||
image = { version = "0.25.8", default-features = false, features = ["rayon"] }
|
||||
indexmap = "2.11.4"
|
||||
hyper-util = "0.1.16"
|
||||
iana-time-zone = "0.1.63"
|
||||
image = { version = "0.25.6", default-features = false, features = ["rayon"] }
|
||||
indexmap = "2.10.0"
|
||||
indicatif = "0.18.0"
|
||||
itertools = "0.14.0"
|
||||
jemalloc_pprof = "0.8.1"
|
||||
json-patch = { version = "4.1.0", default-features = false }
|
||||
lettre = { version = "0.11.19", default-features = false, features = [
|
||||
"aws-lc-rs",
|
||||
"builder",
|
||||
"hostname",
|
||||
"pool",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"smtp-transport",
|
||||
"tokio1",
|
||||
"tokio1-rustls",
|
||||
json-patch = { version = "4.0.0", default-features = false }
|
||||
lettre = { version = "0.11.18", default-features = false, features = [
|
||||
"builder",
|
||||
"hostname",
|
||||
"pool",
|
||||
"ring",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"smtp-transport",
|
||||
] }
|
||||
maxminddb = "0.26.0"
|
||||
meilisearch-sdk = { version = "0.30.0", default-features = false }
|
||||
modrinth-log = { path = "packages/modrinth-log" }
|
||||
modrinth-util = { path = "packages/modrinth-util" }
|
||||
muralpay = { path = "packages/muralpay" }
|
||||
meilisearch-sdk = { version = "0.29.1", default-features = false }
|
||||
murmur2 = "0.1.0"
|
||||
native-dialog = "0.9.2"
|
||||
native-dialog = "0.9.0"
|
||||
notify = { version = "8.2.0", default-features = false }
|
||||
notify-debouncer-mini = { version = "0.7.0", default-features = false }
|
||||
p256 = "0.13.2"
|
||||
parking_lot = "0.12.5"
|
||||
paste = "1.0.15"
|
||||
path-util = { path = "packages/path-util" }
|
||||
phf = { version = "0.13.1", features = ["macros"] }
|
||||
png = "0.18.0"
|
||||
phf = { version = "0.12.1", features = ["macros"] }
|
||||
png = "0.17.16"
|
||||
prometheus = "0.14.0"
|
||||
quartz_nbt = "0.2.9"
|
||||
quick-xml = "0.38.3"
|
||||
rand = "=0.8.5" # Locked on 0.8 until argon2 and p256 update to 0.9
|
||||
rand_chacha = "=0.3.1" # Locked on 0.3 until we can update rand to 0.9
|
||||
redis = "0.32.7"
|
||||
regex = "1.12.2"
|
||||
reqwest = { version = "0.12.24", default-features = false }
|
||||
quick-xml = "0.38.1"
|
||||
rand = "=0.8.5" # Locked on 0.8 until argon2 and p256 update to 0.9
|
||||
rand_chacha = "=0.3.1" # Locked on 0.3 until we can update rand to 0.9
|
||||
redis = "0.32.4"
|
||||
regex = "1.11.1"
|
||||
reqwest = { version = "0.12.22", default-features = false }
|
||||
rgb = "0.8.52"
|
||||
rust_decimal = { version = "1.39.0", features = [
|
||||
"serde-with-float",
|
||||
"serde-with-str"
|
||||
] }
|
||||
rust_decimal = { version = "1.37.2", features = ["serde-with-float", "serde-with-str"] }
|
||||
rust_iso3166 = "0.1.14"
|
||||
rust-s3 = { version = "0.37.0", default-features = false, features = [
|
||||
"fail-on-err",
|
||||
"tags",
|
||||
"tokio-rustls-tls",
|
||||
rust-s3 = { version = "0.35.1", default-features = false, features = [
|
||||
"fail-on-err",
|
||||
"tags",
|
||||
"tokio-rustls-tls",
|
||||
] }
|
||||
rustls = "0.23.32"
|
||||
rusty-money = "0.4.1"
|
||||
secrecy = "0.10.3"
|
||||
sentry = { version = "0.45.0", default-features = false, features = [
|
||||
"backtrace",
|
||||
"contexts",
|
||||
"debug-images",
|
||||
"panic",
|
||||
"reqwest",
|
||||
"rustls",
|
||||
sentry = { version = "0.42.0", default-features = false, features = [
|
||||
"backtrace",
|
||||
"contexts",
|
||||
"debug-images",
|
||||
"panic",
|
||||
"reqwest",
|
||||
"rustls",
|
||||
] }
|
||||
serde = "1.0.228"
|
||||
serde_bytes = "0.11.19"
|
||||
sentry-actix = "0.42.0"
|
||||
serde = "1.0.219"
|
||||
serde_bytes = "0.11.17"
|
||||
serde_cbor = "0.11.2"
|
||||
serde_ini = "0.2.0"
|
||||
serde_json = "1.0.145"
|
||||
serde_with = "3.15.0"
|
||||
serde-xml-rs = "0.8.1" # Also an XML (de)serializer, consider dropping yaserde in favor of this
|
||||
serde_json = "1.0.142"
|
||||
serde_with = "3.14.0"
|
||||
serde-xml-rs = "0.8.1" # Also an XML (de)serializer, consider dropping yaserde in favor of this
|
||||
sha1 = "0.10.6"
|
||||
sha1_smol = { version = "1.0.1", features = ["std"] }
|
||||
sha2 = "0.10.9"
|
||||
shlex = "1.3.0"
|
||||
spdx = "0.12.0"
|
||||
spdx = "0.10.9"
|
||||
sqlx = { version = "0.8.6", default-features = false }
|
||||
sqlx-tracing = { path = "packages/sqlx-tracing" }
|
||||
strum = "0.27.2"
|
||||
sysinfo = { version = "0.37.2", default-features = false }
|
||||
sysinfo = { version = "0.36.1", default-features = false }
|
||||
tar = "0.4.44"
|
||||
tauri = "2.8.5"
|
||||
tauri-build = "2.4.1"
|
||||
tauri-plugin-deep-link = "2.4.3"
|
||||
tauri-plugin-dialog = "2.4.0"
|
||||
tauri-plugin-http = "2.5.2"
|
||||
tauri-plugin-opener = "2.5.0"
|
||||
tauri-plugin-os = "2.3.1"
|
||||
tauri-plugin-single-instance = "2.3.4"
|
||||
tauri = "2.7.0"
|
||||
tauri-build = "2.3.1"
|
||||
tauri-plugin-deep-link = "2.4.1"
|
||||
tauri-plugin-dialog = "2.3.2"
|
||||
tauri-plugin-http = "2.5.1"
|
||||
tauri-plugin-opener = "2.4.0"
|
||||
tauri-plugin-os = "2.3.0"
|
||||
tauri-plugin-single-instance = "2.3.2"
|
||||
tauri-plugin-updater = { version = "2.9.0", default-features = false, features = [
|
||||
"rustls-tls",
|
||||
"zip",
|
||||
"rustls-tls",
|
||||
"zip",
|
||||
] }
|
||||
tauri-plugin-window-state = "2.4.0"
|
||||
tempfile = "3.23.0"
|
||||
tempfile = "3.20.0"
|
||||
theseus = { path = "packages/app-lib" }
|
||||
thiserror = "2.0.17"
|
||||
thiserror = "2.0.12"
|
||||
tikv-jemalloc-ctl = "0.6.0"
|
||||
tikv-jemallocator = "0.6.0"
|
||||
tokio = "1.47.1"
|
||||
@@ -191,32 +162,23 @@ tokio-stream = "0.1.17"
|
||||
tokio-util = "0.7.16"
|
||||
totp-rs = "5.7.0"
|
||||
tracing = "0.1.41"
|
||||
tracing-actix-web = { version = "0.7.19", default-features = false }
|
||||
tracing-ecs = "0.5.0"
|
||||
tracing-actix-web = "0.7.19"
|
||||
tracing-error = "0.2.1"
|
||||
tracing-subscriber = "0.3.20"
|
||||
typed-path = "0.12.0"
|
||||
url = "2.5.7"
|
||||
tracing-subscriber = "0.3.19"
|
||||
url = "2.5.4"
|
||||
urlencoding = "2.1.3"
|
||||
utoipa = { version = "5.4.0", features = ["actix_extras", "chrono", "decimal"] }
|
||||
utoipa-actix-web = { version = "0.1.2" }
|
||||
utoipa-swagger-ui = { version = "9.0.2", features = ["actix-web", "vendored"] }
|
||||
uuid = "1.18.1"
|
||||
uuid = "1.17.0"
|
||||
validator = "0.20.0"
|
||||
webp = { version = "0.3.1", default-features = false }
|
||||
webview2-com = "0.38.0" # Should be updated in lockstep with wry
|
||||
whoami = "1.6.1"
|
||||
windows = "=0.61.3" # Locked on 0.61 until we can update windows-core to 0.62
|
||||
windows-core = "=0.61.2" # Locked on 0.61 until webview2-com updates to 0.62
|
||||
webp = { version = "0.3.0", default-features = false }
|
||||
whoami = "1.6.0"
|
||||
winreg = "0.55.0"
|
||||
woothee = "0.13.0"
|
||||
yaserde = "0.12.0"
|
||||
zbus = "5.11.0"
|
||||
zip = { version = "6.0.0", default-features = false, features = [
|
||||
"bzip2",
|
||||
"deflate",
|
||||
"deflate64",
|
||||
"zstd",
|
||||
zip = { version = "4.3.0", default-features = false, features = [
|
||||
"bzip2",
|
||||
"deflate",
|
||||
"deflate64",
|
||||
"zstd",
|
||||
] }
|
||||
zxcvbn = "3.1.0"
|
||||
|
||||
@@ -240,7 +202,7 @@ manual_assert = "warn"
|
||||
manual_instant_elapsed = "warn"
|
||||
manual_is_variant_and = "warn"
|
||||
manual_let_else = "warn"
|
||||
map_unwrap_or = "allow"
|
||||
map_unwrap_or = "warn"
|
||||
match_bool = "warn"
|
||||
needless_collect = "warn"
|
||||
negative_feature_names = "warn"
|
||||
@@ -251,24 +213,28 @@ redundant_clone = "warn"
|
||||
redundant_feature_names = "warn"
|
||||
redundant_type_annotations = "warn"
|
||||
todo = "warn"
|
||||
too_many_arguments = "allow"
|
||||
uninlined_format_args = "warn"
|
||||
unnested_or_patterns = "warn"
|
||||
wildcard_dependencies = "warn"
|
||||
|
||||
[profile.dev.package.sqlx-macros]
|
||||
opt-level = 3
|
||||
[workspace.lints.rust]
|
||||
# Turn warnings into errors by default
|
||||
warnings = "deny"
|
||||
|
||||
[patch.crates-io]
|
||||
wry = { git = "https://github.com/modrinth/wry", rev = "f2ce0b0" }
|
||||
|
||||
# Optimize for speed and reduce size on release builds
|
||||
[profile.release]
|
||||
opt-level = "s" # Optimize for binary size
|
||||
strip = true # Remove debug symbols
|
||||
lto = true # Enables link to optimizations
|
||||
panic = "abort" # Strip expensive panic clean-up logic
|
||||
codegen-units = 1 # Compile crates one after another so the compiler can optimize better
|
||||
opt-level = "s" # Optimize for binary size
|
||||
strip = true # Remove debug symbols
|
||||
lto = true # Enables link to optimizations
|
||||
panic = "abort" # Strip expensive panic clean-up logic
|
||||
codegen-units = 1 # Compile crates one after another so the compiler can optimize better
|
||||
|
||||
# Specific profile for labrinth production builds
|
||||
[profile.release-labrinth]
|
||||
inherits = "release"
|
||||
strip = false # Keep debug symbols for Sentry
|
||||
panic = "unwind" # Don't exit the whole app on panic in production
|
||||
panic = "unwind" # Don't exit the whole app on panic in production
|
||||
|
||||
[profile.dev.package.sqlx-macros]
|
||||
opt-level = 3
|
||||
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
[files]
|
||||
extend-exclude = [
|
||||
"**/src/locales/",
|
||||
"apps/frontend/",
|
||||
"patches/",
|
||||
"packages/utils/",
|
||||
"packages/ui/",
|
||||
"packages/blog/",
|
||||
# contains licenses like `CC-BY-ND-4.0`
|
||||
"packages/moderation/src/data/stages/license.ts",
|
||||
# contains payment card IDs like `IY1VMST1MOXS` which are flagged
|
||||
"apps/labrinth/src/queue/payouts/mod.rs",
|
||||
]
|
||||
|
||||
[default.extend-words]
|
||||
# Terms Of Use in `tou-link`
|
||||
tou = "tou"
|
||||
# Google Ad Manager
|
||||
gam = "gam"
|
||||
# short for "constants"
|
||||
consts = "consts"
|
||||
# short for "Copy"
|
||||
Cpy = "Cpy"
|
||||
@@ -1,9 +1,13 @@
|
||||
# Copying
|
||||
|
||||
The source code of Modrinth App's frontend is licensed under the GNU General Public License, Version 3 only, which is provided in the file [LICENSE](./LICENSE). However, some files listed below are licensed under a different license.
|
||||
The source code of the theseus repository is licensed under the GNU General Public License, Version 3 only, which is provided in the file [LICENSE](./LICENSE). However, some files listed below are licensed under a different license.
|
||||
|
||||
## Modrinth logo
|
||||
|
||||
The use of Modrinth branding elements, including but not limited to the wrench-in-labyrinth logo, the landing image, and any variations thereof, is strictly prohibited without explicit written permission from Rinth, Inc. This includes trademarks, logos, or other branding elements.
|
||||
|
||||
> All rights reserved. © 2020-2025 Rinth, Inc.
|
||||
> All rights reserved. © 2020-2023 Rinth, Inc.
|
||||
|
||||
This includes, but may not be limited to, the following files:
|
||||
|
||||
- theseus_gui/src-tauri/icons/\*
|
||||
|
||||
@@ -13,13 +13,11 @@
|
||||
"test": "vue-tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modrinth/api-client": "workspace:^",
|
||||
"@geometrically/minecraft-motd-parser": "^1.1.4",
|
||||
"@modrinth/assets": "workspace:*",
|
||||
"@modrinth/ui": "workspace:*",
|
||||
"@modrinth/utils": "workspace:*",
|
||||
"@sentry/vue": "^8.27.0",
|
||||
"@sfirew/minecraft-motd-parser": "^1.1.6",
|
||||
"@tanstack/vue-query": "^5.90.7",
|
||||
"@tauri-apps/api": "^2.5.0",
|
||||
"@tauri-apps/plugin-dialog": "^2.2.1",
|
||||
"@tauri-apps/plugin-http": "^2.5.0",
|
||||
@@ -28,28 +26,27 @@
|
||||
"@tauri-apps/plugin-updater": "^2.7.1",
|
||||
"@tauri-apps/plugin-window-state": "^2.2.2",
|
||||
"@types/three": "^0.172.0",
|
||||
"intl-messageformat": "^10.7.7",
|
||||
"vue-i18n": "^10.0.0",
|
||||
"@vintl/vintl": "^4.4.1",
|
||||
"@vueuse/core": "^11.1.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"floating-vue": "^5.2.2",
|
||||
"ofetch": "^1.3.4",
|
||||
"pinia": "^3.0.0",
|
||||
"pinia": "^2.1.7",
|
||||
"posthog-js": "^1.158.2",
|
||||
"three": "^0.172.0",
|
||||
"vite-svg-loader": "^5.1.0",
|
||||
"vue": "^3.5.13",
|
||||
"vue-multiselect": "3.0.0",
|
||||
"vue-router": "^4.6.0",
|
||||
"vue-router": "4.3.0",
|
||||
"vue-virtual-scroller": "v2.0.0-beta.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@modrinth/tooling-config": "workspace:*",
|
||||
"@eslint/compat": "^1.1.1",
|
||||
"@formatjs/cli": "^6.2.12",
|
||||
"@modrinth/tooling-config": "workspace:*",
|
||||
"@nuxt/eslint-config": "^0.5.6",
|
||||
"@taijased/vue-render-tracker": "^1.0.7",
|
||||
"@vitejs/plugin-vue": "^6.0.3",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"eslint": "^9.9.1",
|
||||
"eslint-plugin-turbo": "^2.5.4",
|
||||
@@ -58,8 +55,7 @@
|
||||
"sass": "^1.74.1",
|
||||
"tailwindcss": "^3.4.4",
|
||||
"typescript": "^5.5.4",
|
||||
"vite": "^6.0.0",
|
||||
"vue-component-type-helpers": "^3.1.8",
|
||||
"vite": "^5.4.6",
|
||||
"vue-tsc": "^2.1.6"
|
||||
},
|
||||
"packageManager": "pnpm@9.4.0",
|
||||
|
||||
+78
-495
@@ -1,11 +1,9 @@
|
||||
<script setup>
|
||||
import { AuthFeature, PanelVersionFeature, TauriModrinthClient } from '@modrinth/api-client'
|
||||
import {
|
||||
ArrowBigUpDashIcon,
|
||||
ChangeSkinIcon,
|
||||
CompassIcon,
|
||||
DownloadIcon,
|
||||
ExternalIcon,
|
||||
HomeIcon,
|
||||
LeftArrowIcon,
|
||||
LibraryIcon,
|
||||
@@ -16,40 +14,28 @@ import {
|
||||
NewspaperIcon,
|
||||
NotepadTextIcon,
|
||||
PlusIcon,
|
||||
RefreshCwIcon,
|
||||
RestoreIcon,
|
||||
RightArrowIcon,
|
||||
ServerIcon,
|
||||
SettingsIcon,
|
||||
UserIcon,
|
||||
WorldIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
Avatar,
|
||||
Button,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
I18nDebugPanel,
|
||||
NewsArticleCard,
|
||||
NotificationPanel,
|
||||
OverflowMenu,
|
||||
ProgressSpinner,
|
||||
provideModrinthClient,
|
||||
provideNotificationManager,
|
||||
providePageContext,
|
||||
useDebugLogger,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { renderString } from '@modrinth/utils'
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
import { getVersion } from '@tauri-apps/api/app'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import { type } from '@tauri-apps/plugin-os'
|
||||
import { check } from '@tauri-apps/plugin-updater'
|
||||
import { saveWindowState, StateFlags } from '@tauri-apps/plugin-window-state'
|
||||
import { $fetch } from 'ofetch'
|
||||
import { computed, onMounted, onUnmounted, provide, ref, watch } from 'vue'
|
||||
@@ -72,33 +58,18 @@ import PromotionWrapper from '@/components/ui/PromotionWrapper.vue'
|
||||
import QuickInstanceSwitcher from '@/components/ui/QuickInstanceSwitcher.vue'
|
||||
import RunningAppBar from '@/components/ui/RunningAppBar.vue'
|
||||
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||
import UpdateAvailableToast from '@/components/ui/UpdateAvailableToast.vue'
|
||||
import UpdateToast from '@/components/ui/UpdateToast.vue'
|
||||
import URLConfirmModal from '@/components/ui/URLConfirmModal.vue'
|
||||
import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
|
||||
import { hide_ads_window, init_ads_window, show_ads_window } from '@/helpers/ads.js'
|
||||
import { debugAnalytics, initAnalytics, trackEvent } from '@/helpers/analytics'
|
||||
import { check_reachable } from '@/helpers/auth.js'
|
||||
import { debugAnalytics, initAnalytics, optOutAnalytics, trackEvent } from '@/helpers/analytics'
|
||||
import { get_user } from '@/helpers/cache.js'
|
||||
import { command_listener, warning_listener } from '@/helpers/events.js'
|
||||
import { useFetch } from '@/helpers/fetch.js'
|
||||
import { cancelLogin, get as getCreds, login, logout } from '@/helpers/mr_auth.ts'
|
||||
import { cancelLogin, get as getCreds, login, logout } from '@/helpers/mr_auth.js'
|
||||
import { list } from '@/helpers/profile.js'
|
||||
import { get as getSettings, set as setSettings } from '@/helpers/settings.ts'
|
||||
import { get } from '@/helpers/settings.ts'
|
||||
import { get_opening_command, initialize_state } from '@/helpers/state'
|
||||
import {
|
||||
areUpdatesEnabled,
|
||||
enqueueUpdateForInstallation,
|
||||
getOS,
|
||||
getUpdateSize,
|
||||
isDev,
|
||||
isNetworkMetered,
|
||||
} from '@/helpers/utils.js'
|
||||
import i18n from '@/i18n.config'
|
||||
import {
|
||||
provideAppUpdateDownloadProgress,
|
||||
subscribeToDownloadProgress,
|
||||
} from '@/providers/download-progress.ts'
|
||||
import { getOS, isDev, restartApp } from '@/helpers/utils.js'
|
||||
import { useError } from '@/store/error.js'
|
||||
import { useInstall } from '@/store/install.js'
|
||||
import { useLoading, useTheming } from '@/store/state'
|
||||
@@ -114,20 +85,6 @@ const notificationManager = new AppNotificationManager()
|
||||
provideNotificationManager(notificationManager)
|
||||
const { handleError, addNotification } = notificationManager
|
||||
|
||||
const tauriApiClient = new TauriModrinthClient({
|
||||
userAgent: `modrinth/theseus/${getVersion()} (support@modrinth.com)`,
|
||||
features: [
|
||||
new AuthFeature({
|
||||
token: async () => (await getCreds()).session,
|
||||
}),
|
||||
new PanelVersionFeature(),
|
||||
],
|
||||
})
|
||||
provideModrinthClient(tauriApiClient)
|
||||
providePageContext({
|
||||
hierarchicalSidebarAvailable: ref(true),
|
||||
showAds: ref(false),
|
||||
})
|
||||
const news = ref([])
|
||||
const availableSurvey = ref(false)
|
||||
|
||||
@@ -145,7 +102,6 @@ const showOnboarding = ref(false)
|
||||
const nativeDecorations = ref(false)
|
||||
|
||||
const os = ref('')
|
||||
const isDevEnvironment = ref(false)
|
||||
|
||||
const stateInitialized = ref(false)
|
||||
|
||||
@@ -153,81 +109,23 @@ const criticalErrorMessage = ref()
|
||||
|
||||
const isMaximized = ref(false)
|
||||
|
||||
const authUnreachableDebug = useDebugLogger('AuthReachableChecker')
|
||||
const authServerQuery = useQuery({
|
||||
queryKey: ['authServerReachability'],
|
||||
queryFn: async () => {
|
||||
await check_reachable()
|
||||
authUnreachableDebug('Auth servers are reachable')
|
||||
return true
|
||||
},
|
||||
refetchInterval: 5 * 60 * 1000, // 5 minutes
|
||||
retry: false,
|
||||
refetchOnWindowFocus: false,
|
||||
})
|
||||
|
||||
const authUnreachable = computed(() => {
|
||||
if (authServerQuery.isError.value && !authServerQuery.isLoading.value) {
|
||||
console.warn('Failed to reach auth servers', authServerQuery.error.value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
await useCheckDisableMouseover()
|
||||
|
||||
document.querySelector('body').addEventListener('click', handleClick)
|
||||
document.querySelector('body').addEventListener('auxclick', handleAuxClick)
|
||||
|
||||
checkUpdates()
|
||||
})
|
||||
|
||||
onUnmounted(async () => {
|
||||
onUnmounted(() => {
|
||||
document.querySelector('body').removeEventListener('click', handleClick)
|
||||
document.querySelector('body').removeEventListener('auxclick', handleAuxClick)
|
||||
|
||||
await unlistenUpdateDownload?.()
|
||||
})
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const messages = defineMessages({
|
||||
updateInstalledToastTitle: {
|
||||
id: 'app.update.complete-toast.title',
|
||||
defaultMessage: 'Version {version} was successfully installed!',
|
||||
},
|
||||
updateInstalledToastText: {
|
||||
id: 'app.update.complete-toast.text',
|
||||
defaultMessage: 'Click here to view the changelog.',
|
||||
},
|
||||
reloadToUpdate: {
|
||||
id: 'app.update.reload-to-update',
|
||||
defaultMessage: 'Reload to install update',
|
||||
},
|
||||
downloadUpdate: {
|
||||
id: 'app.update.download-update',
|
||||
defaultMessage: 'Download update',
|
||||
},
|
||||
downloadingUpdate: {
|
||||
id: 'app.update.downloading-update',
|
||||
defaultMessage: 'Downloading update ({percent}%)',
|
||||
},
|
||||
authUnreachableHeader: {
|
||||
id: 'app.auth-servers.unreachable.header',
|
||||
defaultMessage: 'Cannot reach authentication servers',
|
||||
},
|
||||
authUnreachableBody: {
|
||||
id: 'app.auth-servers.unreachable.body',
|
||||
defaultMessage:
|
||||
'Minecraft authentication servers may be down right now. Check your internet connection and try again later.',
|
||||
},
|
||||
})
|
||||
|
||||
async function setupApp() {
|
||||
stateInitialized.value = true
|
||||
const {
|
||||
native_decorations,
|
||||
theme,
|
||||
locale,
|
||||
telemetry,
|
||||
collapsed_navigation,
|
||||
advanced_rendering,
|
||||
@@ -236,13 +134,7 @@ async function setupApp() {
|
||||
toggle_sidebar,
|
||||
developer_mode,
|
||||
feature_flags,
|
||||
pending_update_toast_for_version,
|
||||
} = await getSettings()
|
||||
|
||||
// Initialize locale from saved settings
|
||||
if (locale) {
|
||||
i18n.global.locale.value = locale
|
||||
}
|
||||
} = await get()
|
||||
|
||||
if (default_page === 'Library') {
|
||||
await router.push('/library')
|
||||
@@ -250,7 +142,6 @@ async function setupApp() {
|
||||
|
||||
os.value = await getOS()
|
||||
const dev = await isDev()
|
||||
isDevEnvironment.value = dev
|
||||
const version = await getVersion()
|
||||
showOnboarding.value = !onboarded
|
||||
|
||||
@@ -263,7 +154,6 @@ async function setupApp() {
|
||||
themeStore.toggleSidebar = toggle_sidebar
|
||||
themeStore.devMode = developer_mode
|
||||
themeStore.featureFlags = feature_flags
|
||||
stateInitialized.value = true
|
||||
|
||||
isMaximized.value = await getCurrentWindow().isMaximized()
|
||||
|
||||
@@ -271,11 +161,12 @@ async function setupApp() {
|
||||
isMaximized.value = await getCurrentWindow().isMaximized()
|
||||
})
|
||||
|
||||
if (telemetry) {
|
||||
initAnalytics()
|
||||
if (dev) debugAnalytics()
|
||||
trackEvent('Launched', { version, dev, onboarded })
|
||||
initAnalytics()
|
||||
if (!telemetry) {
|
||||
optOutAnalytics()
|
||||
}
|
||||
if (dev) debugAnalytics()
|
||||
trackEvent('Launched', { version, dev, onboarded })
|
||||
|
||||
if (!dev) document.addEventListener('contextmenu', (event) => event.preventDefault())
|
||||
|
||||
@@ -330,6 +221,7 @@ async function setupApp() {
|
||||
})
|
||||
|
||||
get_opening_command().then(handleCommand)
|
||||
checkUpdates()
|
||||
fetchCredentials()
|
||||
|
||||
try {
|
||||
@@ -340,12 +232,6 @@ async function setupApp() {
|
||||
console.warn('Failed to generate skin previews in app setup.', error)
|
||||
}
|
||||
|
||||
if (pending_update_toast_for_version !== null) {
|
||||
const settings = await getSettings()
|
||||
settings.pending_update_toast_for_version = null
|
||||
await setSettings(settings)
|
||||
}
|
||||
|
||||
if (osType === 'windows') {
|
||||
await processPendingSurveys()
|
||||
} else {
|
||||
@@ -375,11 +261,7 @@ const handleClose = async () => {
|
||||
|
||||
const router = useRouter()
|
||||
router.afterEach((to, from, failure) => {
|
||||
trackEvent('PageView', {
|
||||
path: to.path,
|
||||
fromPath: from.path,
|
||||
failed: failure,
|
||||
})
|
||||
trackEvent('PageView', { path: to.path, fromPath: from.path, failed: failure })
|
||||
})
|
||||
const route = useRoute()
|
||||
|
||||
@@ -403,7 +285,7 @@ async function fetchCredentials() {
|
||||
if (creds && creds.user_id) {
|
||||
creds.user = await get_user(creds.user_id).catch(handleError)
|
||||
}
|
||||
credentials.value = creds ?? null
|
||||
credentials.value = creds
|
||||
}
|
||||
|
||||
async function signIn() {
|
||||
@@ -450,17 +332,19 @@ const forceSidebar = computed(
|
||||
() => route.path.startsWith('/browse') || route.path.startsWith('/project'),
|
||||
)
|
||||
const sidebarVisible = computed(() => sidebarToggled.value || forceSidebar.value)
|
||||
const showAd = computed(
|
||||
() => sidebarVisible.value && !hasPlus.value && credentials.value !== undefined,
|
||||
)
|
||||
const showAd = computed(() => !(!sidebarVisible.value || hasPlus.value))
|
||||
|
||||
watch(showAd, () => {
|
||||
if (!showAd.value) {
|
||||
hide_ads_window(true)
|
||||
} else {
|
||||
init_ads_window(true)
|
||||
}
|
||||
})
|
||||
watch(
|
||||
showAd,
|
||||
() => {
|
||||
if (!showAd.value) {
|
||||
hide_ads_window(true)
|
||||
} else {
|
||||
init_ads_window(true)
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
invoke('show_window')
|
||||
@@ -493,115 +377,19 @@ async function handleCommand(e) {
|
||||
}
|
||||
}
|
||||
|
||||
const appUpdateDownload = {
|
||||
progress: ref(0),
|
||||
version: ref(),
|
||||
}
|
||||
let unlistenUpdateDownload
|
||||
|
||||
const downloadProgress = computed(() => appUpdateDownload.progress.value)
|
||||
const downloadPercent = computed(() => Math.trunc(appUpdateDownload.progress.value * 100))
|
||||
|
||||
const metered = ref(true)
|
||||
const finishedDownloading = ref(false)
|
||||
const restarting = ref(false)
|
||||
const updateToastDismissed = ref(false)
|
||||
const availableUpdate = ref(null)
|
||||
const updateSize = ref(null)
|
||||
const updatesEnabled = ref(true)
|
||||
const updateAvailable = ref(false)
|
||||
async function checkUpdates() {
|
||||
if (!(await areUpdatesEnabled())) {
|
||||
console.log('Skipping update check as updates are disabled in this build or environment')
|
||||
updatesEnabled.value = false
|
||||
return
|
||||
}
|
||||
const update = await check()
|
||||
updateAvailable.value = !!update
|
||||
|
||||
async function performCheck() {
|
||||
const update = await invoke('plugin:updater|check')
|
||||
if (!update) {
|
||||
console.log('No update available')
|
||||
return
|
||||
}
|
||||
|
||||
const isExistingUpdate = update.version === availableUpdate.value?.version
|
||||
|
||||
if (isExistingUpdate) {
|
||||
console.log('Update is already known')
|
||||
return
|
||||
}
|
||||
|
||||
appUpdateDownload.progress.value = 0
|
||||
finishedDownloading.value = false
|
||||
updateToastDismissed.value = false
|
||||
|
||||
console.log(`Update ${update.version} is available.`)
|
||||
|
||||
metered.value = await isNetworkMetered()
|
||||
if (!metered.value) {
|
||||
console.log('Starting download of update')
|
||||
downloadUpdate(update)
|
||||
} else {
|
||||
console.log(`Metered connection detected, not auto-downloading update.`)
|
||||
}
|
||||
|
||||
getUpdateSize(update.rid).then((size) => (updateSize.value = size))
|
||||
|
||||
availableUpdate.value = update
|
||||
}
|
||||
|
||||
await performCheck()
|
||||
setTimeout(
|
||||
() => {
|
||||
checkUpdates()
|
||||
},
|
||||
5 /* min */ * 60 /* sec */ * 1000 /* ms */,
|
||||
5 * 1000 * 60,
|
||||
)
|
||||
}
|
||||
|
||||
async function showUpdateToast() {
|
||||
updateToastDismissed.value = false
|
||||
}
|
||||
|
||||
async function downloadAvailableUpdate() {
|
||||
return downloadUpdate(availableUpdate.value)
|
||||
}
|
||||
|
||||
async function downloadUpdate(versionToDownload) {
|
||||
if (!versionToDownload) {
|
||||
handleError(`Failed to download update: no version available`)
|
||||
}
|
||||
|
||||
if (appUpdateDownload.progress.value !== 0) {
|
||||
console.error(`Update ${versionToDownload.version} already downloading`)
|
||||
return
|
||||
}
|
||||
|
||||
console.log(`Downloading update ${versionToDownload.version}`)
|
||||
|
||||
try {
|
||||
enqueueUpdateForInstallation(versionToDownload.rid).then(() => {
|
||||
finishedDownloading.value = true
|
||||
unlistenUpdateDownload?.().then(() => {
|
||||
unlistenUpdateDownload = null
|
||||
})
|
||||
console.log('Finished downloading!')
|
||||
})
|
||||
unlistenUpdateDownload = await subscribeToDownloadProgress(
|
||||
appUpdateDownload,
|
||||
versionToDownload.version,
|
||||
)
|
||||
} catch (e) {
|
||||
handleError(e)
|
||||
}
|
||||
}
|
||||
|
||||
async function installUpdate() {
|
||||
restarting.value = true
|
||||
setTimeout(async () => {
|
||||
await handleClose()
|
||||
}, 250)
|
||||
}
|
||||
|
||||
function handleClick(e) {
|
||||
let target = e.target
|
||||
while (target != null) {
|
||||
@@ -746,52 +534,12 @@ async function processPendingSurveys() {
|
||||
console.info('No user survey to show')
|
||||
}
|
||||
}
|
||||
|
||||
provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SplashScreen v-if="!stateFailed" ref="splashScreen" data-tauri-drag-region />
|
||||
<div id="teleports"></div>
|
||||
<div
|
||||
v-if="stateInitialized"
|
||||
class="app-grid-layout experimental-styles-within relative"
|
||||
:class="{ 'disable-advanced-rendering': !themeStore.advancedRendering }"
|
||||
>
|
||||
<Suspense>
|
||||
<Transition name="toast">
|
||||
<UpdateToast
|
||||
v-if="
|
||||
!!availableUpdate &&
|
||||
!updateToastDismissed &&
|
||||
!restarting &&
|
||||
(finishedDownloading || metered)
|
||||
"
|
||||
:version="availableUpdate.version"
|
||||
:size="updateSize"
|
||||
:metered="metered"
|
||||
@close="updateToastDismissed = true"
|
||||
@restart="installUpdate"
|
||||
@download="downloadAvailableUpdate"
|
||||
/>
|
||||
<UpdateAvailableToast v-else-if="!updatesEnabled && os === 'Linux' && !isDevEnvironment" />
|
||||
</Transition>
|
||||
</Suspense>
|
||||
<Transition name="fade">
|
||||
<div
|
||||
v-if="restarting"
|
||||
data-tauri-drag-region
|
||||
class="inset-0 fixed bg-black/80 backdrop-blur z-[200] flex items-center justify-center"
|
||||
>
|
||||
<span
|
||||
data-tauri-drag-region
|
||||
class="flex items-center gap-4 text-contrast font-semibold text-xl select-none cursor-default"
|
||||
>
|
||||
<RefreshCwIcon data-tauri-drag-region class="animate-spin w-6 h-6" />
|
||||
Restarting...
|
||||
</span>
|
||||
</div>
|
||||
</Transition>
|
||||
<div v-if="stateInitialized" class="app-grid-layout experimental-styles-within relative">
|
||||
<Suspense>
|
||||
<AppSettingsModal ref="settingsModal" />
|
||||
</Suspense>
|
||||
@@ -810,13 +558,6 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
<NavButton v-if="themeStore.featureFlags.worlds_tab" v-tooltip.right="'Worlds'" to="/worlds">
|
||||
<WorldIcon />
|
||||
</NavButton>
|
||||
<NavButton
|
||||
v-if="themeStore.featureFlags.servers_in_app"
|
||||
v-tooltip.right="'Servers'"
|
||||
to="/hosting/manage"
|
||||
>
|
||||
<ServerIcon />
|
||||
</NavButton>
|
||||
<NavButton
|
||||
v-tooltip.right="'Discover content'"
|
||||
to="/browse/modpack"
|
||||
@@ -840,7 +581,7 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
>
|
||||
<LibraryIcon />
|
||||
</NavButton>
|
||||
<div class="h-px w-6 mx-auto my-2 bg-surface-5"></div>
|
||||
<div class="h-px w-6 mx-auto my-2 bg-button-bg"></div>
|
||||
<suspense>
|
||||
<QuickInstanceSwitcher />
|
||||
</suspense>
|
||||
@@ -852,85 +593,35 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
<PlusIcon />
|
||||
</NavButton>
|
||||
<div class="flex flex-grow"></div>
|
||||
<Transition name="nav-button-animated">
|
||||
<div
|
||||
v-if="
|
||||
availableUpdate &&
|
||||
updateToastDismissed &&
|
||||
!restarting &&
|
||||
(finishedDownloading || metered)
|
||||
"
|
||||
>
|
||||
<NavButton
|
||||
v-tooltip.right="
|
||||
formatMessage(
|
||||
finishedDownloading
|
||||
? messages.reloadToUpdate
|
||||
: downloadProgress === 0
|
||||
? messages.downloadUpdate
|
||||
: messages.downloadingUpdate,
|
||||
{
|
||||
percent: downloadPercent,
|
||||
},
|
||||
)
|
||||
"
|
||||
:to="
|
||||
finishedDownloading
|
||||
? installUpdate
|
||||
: downloadProgress > 0 && downloadProgress < 1
|
||||
? showUpdateToast
|
||||
: downloadAvailableUpdate
|
||||
"
|
||||
>
|
||||
<ProgressSpinner
|
||||
v-if="downloadProgress > 0 && downloadProgress < 1"
|
||||
class="text-brand"
|
||||
:progress="downloadProgress"
|
||||
/>
|
||||
<RefreshCwIcon v-else-if="finishedDownloading" class="text-brand" />
|
||||
<DownloadIcon v-else class="text-brand" />
|
||||
</NavButton>
|
||||
</div>
|
||||
</Transition>
|
||||
<NavButton
|
||||
v-tooltip.right="formatMessage(commonMessages.settingsLabel)"
|
||||
:to="() => $refs.settingsModal.show()"
|
||||
>
|
||||
<NavButton v-if="updateAvailable" v-tooltip.right="'Install update'" :to="() => restartApp()">
|
||||
<DownloadIcon />
|
||||
</NavButton>
|
||||
<NavButton v-tooltip.right="'Settings'" :to="() => $refs.settingsModal.show()">
|
||||
<SettingsIcon />
|
||||
</NavButton>
|
||||
<OverflowMenu
|
||||
v-if="credentials"
|
||||
v-tooltip.right="`Modrinth account`"
|
||||
class="w-12 h-12 text-primary rounded-full flex items-center justify-center text-2xl transition-all bg-transparent hover:bg-button-bg hover:text-contrast border-0 cursor-pointer"
|
||||
:options="[
|
||||
{
|
||||
id: 'view-profile',
|
||||
action: () => openUrl('https://modrinth.com/user/' + credentials.user.username),
|
||||
},
|
||||
{
|
||||
id: 'sign-out',
|
||||
action: () => logOut(),
|
||||
color: 'danger',
|
||||
},
|
||||
]"
|
||||
placement="right-end"
|
||||
>
|
||||
<Avatar :src="credentials.user.avatar_url" alt="" size="32px" circle />
|
||||
<template #view-profile>
|
||||
<UserIcon />
|
||||
<span class="inline-flex items-center gap-1">
|
||||
Signed in as
|
||||
<span class="inline-flex items-center gap-1 text-contrast font-semibold">
|
||||
<Avatar :src="credentials.user.avatar_url" alt="" size="20px" circle />
|
||||
{{ credentials.user.username }}
|
||||
</span>
|
||||
</span>
|
||||
<ExternalIcon />
|
||||
</template>
|
||||
<template #sign-out> <LogOutIcon /> Sign out </template>
|
||||
</OverflowMenu>
|
||||
<NavButton v-else v-tooltip.right="'Sign in to a Modrinth account'" :to="() => signIn()">
|
||||
<LogInIcon class="text-brand" />
|
||||
<ButtonStyled v-if="credentials" type="transparent" circular>
|
||||
<OverflowMenu
|
||||
:options="[
|
||||
{
|
||||
id: 'sign-out',
|
||||
action: () => logOut(),
|
||||
color: 'danger',
|
||||
},
|
||||
]"
|
||||
direction="left"
|
||||
>
|
||||
<Avatar
|
||||
:src="credentials.user.avatar_url"
|
||||
:alt="credentials.user.username"
|
||||
size="32px"
|
||||
circle
|
||||
/>
|
||||
<template #sign-out> <LogOutIcon /> Sign out </template>
|
||||
</OverflowMenu>
|
||||
</ButtonStyled>
|
||||
<NavButton v-else v-tooltip.right="'Sign in'" :to="() => signIn()">
|
||||
<LogInIcon />
|
||||
<template #label>Sign in</template>
|
||||
</NavButton>
|
||||
</div>
|
||||
<div data-tauri-drag-region class="app-grid-statusbar bg-bg-raised h-[--top-bar-height] flex">
|
||||
@@ -993,16 +684,13 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
<div
|
||||
v-if="stateInitialized"
|
||||
class="app-contents experimental-styles-within"
|
||||
:class="{
|
||||
'sidebar-enabled': sidebarVisible,
|
||||
'disable-advanced-rendering': !themeStore.advancedRendering,
|
||||
}"
|
||||
:class="{ 'sidebar-enabled': sidebarVisible }"
|
||||
>
|
||||
<div class="app-viewport flex-grow router-view">
|
||||
<transition name="popup-survey">
|
||||
<div
|
||||
v-if="availableSurvey"
|
||||
class="w-[400px] z-20 fixed -bottom-12 pb-16 right-[--right-bar-width] mr-4 rounded-t-2xl card-shadow bg-bg-raised border-surface-5 border-[1px] border-solid border-b-0 p-4"
|
||||
class="w-[400px] z-20 fixed -bottom-12 pb-16 right-[--right-bar-width] mr-4 rounded-t-2xl card-shadow bg-bg-raised border-divider border-[1px] border-solid border-b-0 p-4"
|
||||
>
|
||||
<h2 class="text-lg font-extrabold mt-0 mb-2">Hey there Modrinth user!</h2>
|
||||
<p class="m-0 leading-tight">
|
||||
@@ -1044,25 +732,16 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
width: 'calc(100% - var(--right-bar-width))',
|
||||
}"
|
||||
></div>
|
||||
<Admonition
|
||||
<div
|
||||
v-if="criticalErrorMessage"
|
||||
type="critical"
|
||||
:header="criticalErrorMessage.header"
|
||||
class="m-6 mb-0"
|
||||
class="m-6 mb-0 flex flex-col border-red bg-bg-red rounded-2xl border-2 border-solid p-4 gap-1 font-semibold text-contrast"
|
||||
>
|
||||
<h1 class="m-0 text-lg font-extrabold">{{ criticalErrorMessage.header }}</h1>
|
||||
<div
|
||||
class="markdown-body text-primary"
|
||||
v-html="renderString(criticalErrorMessage.body ?? '')"
|
||||
></div>
|
||||
</Admonition>
|
||||
<Admonition
|
||||
v-if="authUnreachable"
|
||||
type="warning"
|
||||
:header="formatMessage(messages.authUnreachableHeader)"
|
||||
class="m-6 mb-0"
|
||||
>
|
||||
{{ formatMessage(messages.authUnreachableBody) }}
|
||||
</Admonition>
|
||||
</div>
|
||||
<RouterView v-slot="{ Component }">
|
||||
<template v-if="Component">
|
||||
<Suspense @pending="loading.startLoading()" @resolve="loading.stopLoading()">
|
||||
@@ -1081,26 +760,20 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
>
|
||||
<div id="sidebar-teleport-target" class="sidebar-teleport-content"></div>
|
||||
<div class="sidebar-default-content" :class="{ 'sidebar-enabled': sidebarVisible }">
|
||||
<div
|
||||
class="p-4 pr-1 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid"
|
||||
>
|
||||
<h3 class="text-base text-primary font-medium m-0">Playing as</h3>
|
||||
<div class="p-4 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid">
|
||||
<h3 class="text-lg m-0">Playing as</h3>
|
||||
<suspense>
|
||||
<AccountsCard ref="accounts" mode="small" />
|
||||
</suspense>
|
||||
</div>
|
||||
<div class="py-4 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid">
|
||||
<div class="p-4 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid">
|
||||
<suspense>
|
||||
<FriendsList
|
||||
:credentials="credentials"
|
||||
:sign-in="() => signIn()"
|
||||
:refresh-credentials="fetchCredentials"
|
||||
/>
|
||||
<FriendsList :credentials="credentials" :sign-in="() => signIn()" />
|
||||
</suspense>
|
||||
</div>
|
||||
<div v-if="news && news.length > 0" class="p-4 pr-1 flex flex-col items-center">
|
||||
<h3 class="text-base mb-4 text-primary font-medium m-0 text-left w-full">News</h3>
|
||||
<div class="space-y-4 flex flex-col items-center w-full">
|
||||
<div v-if="news && news.length > 0" class="pt-4 flex flex-col items-center">
|
||||
<h3 class="px-4 text-lg m-0 text-left w-full">News</h3>
|
||||
<div class="px-4 pt-2 space-y-4 flex flex-col items-center w-full">
|
||||
<NewsArticleCard
|
||||
v-for="(item, index) in news"
|
||||
:key="`news-${index}`"
|
||||
@@ -1128,7 +801,6 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
</div>
|
||||
</div>
|
||||
<URLConfirmModal ref="urlModal" />
|
||||
<I18nDebugPanel />
|
||||
<NotificationPanel has-sidebar />
|
||||
<ErrorModal ref="errorModal" />
|
||||
<ModInstallModal ref="modInstallModal" />
|
||||
@@ -1286,19 +958,9 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
display: none;
|
||||
}
|
||||
|
||||
.disable-advanced-rendering {
|
||||
.app-sidebar::before {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&.app-contents::before {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.app-sidebar::before {
|
||||
content: '';
|
||||
box-shadow: -15px 0 15px -15px rgba(0, 0, 0, 0.1) inset;
|
||||
box-shadow: -15px 0 15px -15px rgba(0, 0, 0, 0.2) inset;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: -2rem;
|
||||
@@ -1323,10 +985,9 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
right: calc(-1 * var(--left-bar-width));
|
||||
bottom: calc(-1 * var(--left-bar-width));
|
||||
border-radius: var(--radius-xl);
|
||||
box-shadow: 1px 1px 15px rgba(0, 0, 0, 0.1) inset;
|
||||
border-color: var(--surface-5);
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
box-shadow:
|
||||
1px 1px 15px rgba(0, 0, 0, 0.2) inset,
|
||||
inset 1px 1px 1px rgba(255, 255, 255, 0.23);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -1361,84 +1022,6 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
opacity: 0;
|
||||
transform: translateY(10rem) scale(0.8) scaleY(1.6);
|
||||
}
|
||||
|
||||
.toast-enter-active {
|
||||
transition: opacity 0.25s linear;
|
||||
}
|
||||
|
||||
.toast-enter-from,
|
||||
.toast-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.toast-enter-active,
|
||||
.nav-button-animated-enter-active {
|
||||
transition: all 0.5s cubic-bezier(0.15, 1.4, 0.64, 0.96);
|
||||
}
|
||||
|
||||
.toast-leave-active,
|
||||
.nav-button-animated-leave-active {
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
.toast-enter-from {
|
||||
scale: 0.5;
|
||||
translate: 0 -10rem;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.toast-leave-to {
|
||||
scale: 0.96;
|
||||
translate: 20rem 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.nav-button-animated-enter-active {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-button-animated-enter-active::before {
|
||||
content: '';
|
||||
inset: 0;
|
||||
border-radius: 100vw;
|
||||
background-color: var(--color-brand-highlight);
|
||||
position: absolute;
|
||||
animation: pop 0.5s ease-in forwards;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@keyframes pop {
|
||||
0% {
|
||||
scale: 0.5;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
100% {
|
||||
scale: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-button-animated-enter-from {
|
||||
scale: 0.5;
|
||||
translate: -2rem 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.nav-button-animated-leave-to {
|
||||
scale: 0.75;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.fade-enter-active {
|
||||
transition: 0.25s ease-in-out;
|
||||
}
|
||||
|
||||
.fade-enter-from {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.mac {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:serif="http://www.serif.com/" version="1.1" viewBox="0 0 1793 199">
|
||||
<g>
|
||||
<g id="Layer_1">
|
||||
<g id="green" fill="var(--color-brand)">
|
||||
<path d="M1184.1,166.6c-8,0-15.6-1-22.9-3.1s-13.1-4.6-17.4-7.6l8.5-16.9c4.3,2.7,9.4,5,15.3,6.8,5.9,1.8,11.9,2.7,17.8,2.7s12.1-.9,15.2-2.8c3.1-1.9,4.7-4.5,4.7-7.7s-1.1-4.6-3.2-6c-2.1-1.4-4.9-2.4-8.4-3.1-3.4-.7-7.3-1.4-11.5-2-4.2-.6-8.4-1.4-12.6-2.4-4.2-1-8-2.5-11.5-4.5-3.4-2-6.2-4.6-8.4-7.9-2.1-3.3-3.2-7.7-3.2-13.2s1.7-11.3,5.2-15.8c3.4-4.5,8.3-7.9,14.5-10.3,6.2-2.4,13.6-3.7,22.2-3.7s12.9.7,19.4,2.1c6.5,1.4,11.9,3.4,16.2,6.1l-8.5,16.9c-4.5-2.7-9.1-4.6-13.6-5.6-4.6-1-9.1-1.5-13.6-1.5-6.8,0-11.8,1-15,3-3.3,2-4.9,4.6-4.9,7.7s1.1,5,3.2,6.4c2.1,1.4,4.9,2.6,8.4,3.4,3.4.8,7.3,1.5,11.5,2,4.2.5,8.4,1.3,12.6,2.4,4.2,1.1,8,2.5,11.5,4.4,3.5,1.8,6.3,4.4,8.5,7.7,2.1,3.3,3.2,7.7,3.2,13s-1.8,11.1-5.3,15.5c-3.5,4.4-8.5,7.8-14.9,10.2-6.4,2.4-14.1,3.7-23,3.7Z"/>
|
||||
<path d="M1291.1,166.6c-10.6,0-19.8-2.1-27.7-6.3-7.9-4.2-14-10-18.3-17.4-4.3-7.4-6.5-15.7-6.5-25.1s2.1-17.9,6.3-25.2c4.2-7.3,10-13,17.5-17.2,7.4-4.2,15.9-6.2,25.4-6.2s17.5,2,24.8,6.1c7.2,4,12.9,9.7,17.1,17.1,4.2,7.4,6.2,16,6.2,26s0,2,0,3.2c0,1.2-.2,2.3-.3,3.4h-79.3v-14.8h67.5l-8.7,4.6c.1-5.5-1-10.3-3.4-14.4-2.4-4.2-5.6-7.4-9.7-9.8-4.1-2.4-8.8-3.6-14.2-3.6s-10.2,1.2-14.3,3.6c-4.1,2.4-7.3,5.7-9.6,9.9-2.3,4.2-3.5,9.2-3.5,14.9v3.6c0,5.7,1.3,10.7,3.9,15.1,2.6,4.4,6.3,7.8,11,10.2,4.7,2.4,10.2,3.6,16.4,3.6s10.2-.8,14.4-2.5c4.3-1.7,8.1-4.3,11.4-7.8l11.9,13.7c-4.3,5-9.6,8.8-16.1,11.5-6.5,2.7-13.9,4-22.2,4Z"/>
|
||||
<path d="M1357.2,165.3v-95.1h21.2v26.2l-2.5-7.7c2.8-6.4,7.3-11.3,13.4-14.6,6.1-3.3,13.7-5,22.9-5v21.2c-1-.2-1.8-.4-2.7-.4-.8,0-1.7,0-2.5,0-8.4,0-15.1,2.5-20.1,7.4-5,4.9-7.5,12.3-7.5,22v46.1h-22.3Z"/>
|
||||
<path d="M1460,165.3l-40.8-95.1h23.2l35.1,83.9h-11.4l36.3-83.9h21.4l-40.8,95.1h-23Z"/>
|
||||
<path d="M1579.6,166.6c-10.6,0-19.8-2.1-27.7-6.3-7.9-4.2-14-10-18.3-17.4-4.3-7.4-6.5-15.7-6.5-25.1s2.1-17.9,6.3-25.2c4.2-7.3,10-13,17.5-17.2,7.4-4.2,15.9-6.2,25.4-6.2s17.5,2,24.8,6.1c7.2,4,12.9,9.7,17.1,17.1,4.2,7.4,6.2,16,6.2,26s0,2,0,3.2c0,1.2-.2,2.3-.3,3.4h-79.3v-14.8h67.5l-8.7,4.6c.1-5.5-1-10.3-3.4-14.4-2.4-4.2-5.6-7.4-9.7-9.8-4.1-2.4-8.8-3.6-14.2-3.6s-10.2,1.2-14.3,3.6c-4.1,2.4-7.3,5.7-9.6,9.9-2.3,4.2-3.5,9.2-3.5,14.9v3.6c0,5.7,1.3,10.7,3.9,15.1,2.6,4.4,6.3,7.8,11,10.2,4.7,2.4,10.2,3.6,16.4,3.6s10.2-.8,14.4-2.5c4.3-1.7,8.1-4.3,11.4-7.8l11.9,13.7c-4.3,5-9.6,8.8-16.1,11.5-6.5,2.7-13.9,4-22.2,4Z"/>
|
||||
<path d="M1645.7,165.3v-95.1h21.2v26.2l-2.5-7.7c2.8-6.4,7.3-11.3,13.4-14.6,6.1-3.3,13.7-5,22.9-5v21.2c-1-.2-1.8-.4-2.7-.4-.8,0-1.7,0-2.5,0-8.4,0-15.1,2.5-20.1,7.4-5,4.9-7.5,12.3-7.5,22v46.1h-22.3Z"/>
|
||||
<path d="M1749.9,166.6c-8,0-15.6-1-22.9-3.1s-13.1-4.6-17.4-7.6l8.5-16.9c4.3,2.7,9.4,5,15.3,6.8,5.9,1.8,11.9,2.7,17.8,2.7s12.1-.9,15.2-2.8c3.1-1.9,4.7-4.5,4.7-7.7s-1.1-4.6-3.2-6c-2.1-1.4-4.9-2.4-8.4-3.1-3.4-.7-7.3-1.4-11.5-2-4.2-.6-8.4-1.4-12.6-2.4-4.2-1-8-2.5-11.5-4.5-3.4-2-6.2-4.6-8.4-7.9-2.1-3.3-3.2-7.7-3.2-13.2s1.7-11.3,5.2-15.8c3.4-4.5,8.3-7.9,14.5-10.3,6.2-2.4,13.6-3.7,22.2-3.7s12.9.7,19.4,2.1c6.5,1.4,11.9,3.4,16.2,6.1l-8.5,16.9c-4.5-2.7-9.1-4.6-13.6-5.6-4.6-1-9.1-1.5-13.6-1.5-6.8,0-11.8,1-15,3-3.3,2-4.9,4.6-4.9,7.7s1.1,5,3.2,6.4c2.1,1.4,4.9,2.6,8.4,3.4,3.4.8,7.3,1.5,11.5,2,4.2.5,8.4,1.3,12.6,2.4,4.2,1.1,8,2.5,11.5,4.4,3.5,1.8,6.3,4.4,8.5,7.7,2.1,3.3,3.2,7.7,3.2,13s-1.8,11.1-5.3,15.5c-3.5,4.4-8.5,7.8-14.9,10.2-6.4,2.4-14.1,3.7-23,3.7Z"/>
|
||||
<g>
|
||||
<path d="M9.8,143l63.4-38.1-5.8-15.3,18.1-18.6,22.9-4.9,6.6,8.2-10.6,10.7-9.2,2.9-6.6,6.8,3.2,9,6.5,6.9,9.2-2.5,6.6-7.2,14.3-4.5,4.3,9.6-14.8,18.1-24.8,7.8-11.1-12.4-63.6,38.2c-3-3.9-6.5-9.4-8.8-14.7ZM192.8,65.4l-50.4,13.6c2.8,7.4,3.7,11.7,4.5,16.5l50.3-13.6c-.8-5.4-2.2-10.8-4.4-16.5Z" fill-rule="evenodd"/>
|
||||
<path d="M17.3,106.5c3.6,42.1,38.9,75.2,82,75.2s60.7-18.9,74-46.3l16.4,5.7c-15.8,34.1-50.3,57.9-90.4,57.9S3.6,158.2,0,106.5h17.3ZM.3,89.4C5.3,39.2,47.8,0,99.3,0s99.5,44.6,99.5,99.5-1.1,17.4-3.3,25.5l-16.3-5.7c1.6-6.5,2.4-13.1,2.4-19.8,0-45.4-36.9-82.3-82.3-82.3S22.6,48.7,17.6,89.4H.3Z" fill-rule="evenodd"/>
|
||||
<path d="M99,51.6c-26.4,0-47.9,21.5-47.9,48s21.5,48,48,48,2.7,0,4-.2l4.8,16.8c-2.9.4-5.8.6-8.8.6-36,0-65.2-29.2-65.2-65.2S63.1,34.4,99,34.4s1.8,0,2.7,0l-2.7,17.1ZM118.6,37.4c26.4,8.3,45.6,33,45.6,62.2s-16.4,50.2-39.8,60l-4.8-16.7c16.2-7.7,27.4-24.2,27.4-43.3s-13-38.1-31.1-44.9l2.7-17.2Z" fill-rule="evenodd"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="black" fill="currentColor">
|
||||
<path d="M354.8,69.2c12,0,21.7,3.4,28.6,10.4,7,7.2,10.6,17.5,10.6,31.5v54.8h-22.4v-51.9c0-8.4-1.8-14.7-5.5-19-3.8-4.1-8.9-6.3-15.9-6.3s-13.6,2.5-18.1,7.3c-4.5,5-6.8,12.2-6.8,21.3v48.5h-22.4v-51.9c0-8.4-1.8-14.7-5.5-19-3.8-4.1-8.9-6.3-15.9-6.3s-13.6,2.5-18.1,7.3c-4.5,4.8-6.8,12-6.8,21.3v48.5h-22.4v-95.6h21.3v12.2c3.6-4.3,8.1-7.5,13.4-9.8,5.4-2.3,11.3-3.4,17.9-3.4s13.6,1.3,19.2,3.9c5.5,2.9,9.8,6.8,13.1,12,3.9-5,8.9-8.9,15.2-11.8,6.3-2.7,13.1-4.1,20.6-4.1ZM466,167.2c-9.7,0-18.4-2.1-26.1-6.3-7.6-4-13.8-10.1-18.1-17.5-4.5-7.3-6.6-15.7-6.6-25.2s2.1-17.9,6.6-25.2c4.3-7.4,10.6-13.4,18.1-17.4,7.7-4.1,16.5-6.3,26.1-6.3s18.6,2.1,26.3,6.3c7.7,4.1,13.8,10,18.3,17.4,4.3,7.3,6.4,15.7,6.4,25.2s-2.1,17.9-6.4,25.2c-4.5,7.5-10.6,13.4-18.3,17.5-7.7,4.1-16.5,6.3-26.3,6.3h0ZM466,148c8.2,0,15-2.7,20.4-8.2,5.4-5.5,8.1-12.7,8.1-21.7s-2.7-16.1-8.1-21.7c-5.4-5.5-12.2-8.2-20.4-8.2s-15,2.7-20.2,8.2c-5.4,5.5-8.1,12.7-8.1,21.7s2.7,16.1,8.1,21.7c5.2,5.5,12,8.2,20.2,8.2ZM631.5,33.1v132.8h-21.5v-12.3c-3.7,4.4-8.3,7.9-13.6,10.2-5.5,2.3-11.5,3.4-18.1,3.4s-17.4-2-24.7-6.1c-7.3-4.1-13.2-9.8-17.4-17.4-4.1-7.3-6.3-15.9-6.3-25.6s2.1-18.3,6.3-25.6c4.1-7.3,10-13.1,17.4-17.2,7.3-4.1,15.6-6.1,24.7-6.1s12.2,1.1,17.4,3.2c5.2,2.1,9.8,5.4,13.4,9.7v-49h22.4ZM581.1,148c5.4,0,10.2-1.3,14.5-3.8,4.3-2.3,7.7-5.9,10.2-10.4,2.5-4.5,3.8-9.8,3.8-15.7s-1.3-11.3-3.8-15.7c-2.5-4.5-5.9-8.1-10.2-10.6-4.3-2.3-9.1-3.6-14.5-3.6s-10.2,1.3-14.5,3.6c-4.3,2.5-7.7,6.1-10.2,10.6-2.5,4.5-3.8,9.8-3.8,15.7s1.3,11.3,3.8,15.7c2.5,4.5,5.9,8.1,10.2,10.4,4.3,2.5,9.1,3.8,14.5,3.8ZM681.6,84.3c6.4-10,17.7-15,34-15v21.3c-1.7-.3-3.4-.5-5.2-.5-8.8,0-15.6,2.5-20.4,7.5-4.8,5.2-7.3,12.5-7.3,22v46.4h-22.4v-95.6h21.3v14h0ZM734.1,70.3h22.4v95.6h-22.4v-95.6ZM745.4,54.6c-4.1,0-7.5-1.3-10.2-3.9-2.7-2.4-4.2-5.9-4.1-9.5,0-3.8,1.4-7,4.1-9.7,2.7-2.5,6.1-3.8,10.2-3.8s7.5,1.3,10.2,3.6c2.7,2.5,4.1,5.5,4.1,9.3s-1.3,7.2-3.9,9.8c-2.7,2.7-6.3,4.1-10.4,4.1ZM839.5,69.2c12,0,21.7,3.6,29,10.6,7.3,7,10.9,17.5,10.9,31.3v54.8h-22.4v-51.9c0-8.4-2-14.7-5.9-19-3.9-4.1-9.5-6.3-16.8-6.3s-14.7,2.5-19.5,7.3c-4.8,5-7.2,12.2-7.2,21.5v48.3h-22.4v-95.6h21.3v12.3c3.8-4.5,8.4-7.7,14-10,5.5-2.3,12-3.4,19-3.4ZM964.8,160.7c-2.8,2.2-6,3.9-9.5,4.8-3.9,1.1-7.9,1.6-12,1.6-10.6,0-18.6-2.7-24.3-8.2-5.7-5.5-8.6-13.4-8.6-24v-46h-15.7v-17.9h15.7v-21.8h22.4v21.8h25.6v17.9h-25.6v45.5c0,4.7,1.1,8.2,3.4,10.6,2.3,2.5,5.5,3.8,9.8,3.8s9.1-1.3,12.5-3.9l6.3,15.9ZM1036.9,69.2c12,0,21.7,3.6,29,10.6,7.3,7,10.9,17.5,10.9,31.3v54.8h-22.4v-51.9c0-8.4-2-14.7-5.9-19-3.9-4.1-9.5-6.3-16.8-6.3s-14.7,2.5-19.5,7.3c-4.8,5-7.2,12.2-7.2,21.5v48.3h-22.4V33.1h22.4v48.3c3.8-3.9,8.2-7,13.8-9.1,5.4-2,11.5-3,18.1-3Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
@@ -2,8 +2,6 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@import '@modrinth/ui/src/styles/tailwind-utilities.css';
|
||||
|
||||
@font-face {
|
||||
font-family: 'bundled-minecraft-font-mrapp';
|
||||
font-style: normal;
|
||||
@@ -85,6 +83,10 @@ a {
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: flex;
|
||||
border-radius: var(--radius-md);
|
||||
|
||||
@@ -8,15 +8,10 @@ import {
|
||||
SearchIcon,
|
||||
StopCircleIcon,
|
||||
TrashIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
DropdownSelect,
|
||||
formatLoader,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import { Button, DropdownSelect, injectNotificationManager } from '@modrinth/ui'
|
||||
import { formatCategoryHeader } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
@@ -27,8 +22,6 @@ import { duplicate, remove } from '@/helpers/profile.js'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const props = defineProps({
|
||||
instances: {
|
||||
type: Array,
|
||||
@@ -128,50 +121,40 @@ const handleOptionsClick = async (args) => {
|
||||
}
|
||||
}
|
||||
|
||||
const state = useStorage(
|
||||
`${props.label}-grid-display-state`,
|
||||
{
|
||||
group: 'Group',
|
||||
sortBy: 'Name',
|
||||
},
|
||||
localStorage,
|
||||
{ mergeDefaults: true },
|
||||
)
|
||||
|
||||
const search = ref('')
|
||||
const group = ref('Group')
|
||||
const sortBy = ref('Name')
|
||||
|
||||
const filteredResults = computed(() => {
|
||||
const { group = 'Group', sortBy = 'Name' } = state.value
|
||||
|
||||
const instances = props.instances.filter((instance) => {
|
||||
return instance.name.toLowerCase().includes(search.value.toLowerCase())
|
||||
})
|
||||
|
||||
if (sortBy === 'Name') {
|
||||
if (sortBy.value === 'Name') {
|
||||
instances.sort((a, b) => {
|
||||
return a.name.localeCompare(b.name)
|
||||
})
|
||||
}
|
||||
|
||||
if (sortBy === 'Game version') {
|
||||
if (sortBy.value === 'Game version') {
|
||||
instances.sort((a, b) => {
|
||||
return a.game_version.localeCompare(b.game_version, undefined, { numeric: true })
|
||||
})
|
||||
}
|
||||
|
||||
if (sortBy === 'Last played') {
|
||||
if (sortBy.value === 'Last played') {
|
||||
instances.sort((a, b) => {
|
||||
return dayjs(b.last_played ?? 0).diff(dayjs(a.last_played ?? 0))
|
||||
})
|
||||
}
|
||||
|
||||
if (sortBy === 'Date created') {
|
||||
if (sortBy.value === 'Date created') {
|
||||
instances.sort((a, b) => {
|
||||
return dayjs(b.date_created).diff(dayjs(a.date_created))
|
||||
})
|
||||
}
|
||||
|
||||
if (sortBy === 'Date modified') {
|
||||
if (sortBy.value === 'Date modified') {
|
||||
instances.sort((a, b) => {
|
||||
return dayjs(b.date_modified).diff(dayjs(a.date_modified))
|
||||
})
|
||||
@@ -179,16 +162,16 @@ const filteredResults = computed(() => {
|
||||
|
||||
const instanceMap = new Map()
|
||||
|
||||
if (group === 'Loader') {
|
||||
if (group.value === 'Loader') {
|
||||
instances.forEach((instance) => {
|
||||
const loader = formatLoader(formatMessage, instance.loader)
|
||||
const loader = formatCategoryHeader(instance.loader)
|
||||
if (!instanceMap.has(loader)) {
|
||||
instanceMap.set(loader, [])
|
||||
}
|
||||
|
||||
instanceMap.get(loader).push(instance)
|
||||
})
|
||||
} else if (group === 'Game version') {
|
||||
} else if (group.value === 'Game version') {
|
||||
instances.forEach((instance) => {
|
||||
if (!instanceMap.has(instance.game_version)) {
|
||||
instanceMap.set(instance.game_version, [])
|
||||
@@ -196,7 +179,7 @@ const filteredResults = computed(() => {
|
||||
|
||||
instanceMap.get(instance.game_version).push(instance)
|
||||
})
|
||||
} else if (group === 'Group') {
|
||||
} else if (group.value === 'Group') {
|
||||
instances.forEach((instance) => {
|
||||
if (instance.groups.length === 0) {
|
||||
instance.groups.push('None')
|
||||
@@ -216,7 +199,7 @@ const filteredResults = computed(() => {
|
||||
|
||||
// For 'name', we intuitively expect the sorting to apply to the name of the group first, not just the name of the instance
|
||||
// ie: Category A should come before B, even if the first instance in B comes before the first instance in A
|
||||
if (sortBy === 'Name') {
|
||||
if (sortBy.value === 'Name') {
|
||||
const sortedEntries = [...instanceMap.entries()].sort((a, b) => {
|
||||
// None should always be first
|
||||
if (a[0] === 'None' && b[0] !== 'None') {
|
||||
@@ -234,7 +217,7 @@ const filteredResults = computed(() => {
|
||||
}
|
||||
// default sorting would do 1.20.4 < 1.8.9 because 2 < 8
|
||||
// localeCompare with numeric=true puts 1.8.9 < 1.20.4 because 8 < 20
|
||||
if (group === 'Game version') {
|
||||
if (group.value === 'Game version') {
|
||||
const sortedEntries = [...instanceMap.entries()].sort((a, b) => {
|
||||
return a[0].localeCompare(b[0], undefined, { numeric: true })
|
||||
})
|
||||
@@ -249,17 +232,16 @@ const filteredResults = computed(() => {
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex gap-2">
|
||||
<StyledInput
|
||||
v-model="search"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
clearable
|
||||
wrapper-class="flex-1"
|
||||
/>
|
||||
<div class="iconified-input flex-1">
|
||||
<SearchIcon />
|
||||
<input v-model="search" type="text" placeholder="Search" />
|
||||
<Button class="r-btn" @click="() => (search = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<DropdownSelect
|
||||
v-slot="{ selected }"
|
||||
v-model="state.sortBy"
|
||||
v-model="sortBy"
|
||||
name="Sort Dropdown"
|
||||
class="max-w-[16rem]"
|
||||
:options="['Name', 'Last played', 'Date created', 'Date modified', 'Game version']"
|
||||
@@ -270,7 +252,7 @@ const filteredResults = computed(() => {
|
||||
</DropdownSelect>
|
||||
<DropdownSelect
|
||||
v-slot="{ selected }"
|
||||
v-model="state.group"
|
||||
v-model="group"
|
||||
class="max-w-[16rem]"
|
||||
name="Group Dropdown"
|
||||
:options="['Group', 'Loader', 'Game version', 'None']"
|
||||
|
||||
@@ -18,8 +18,8 @@ import { useRouter } from 'vue-router'
|
||||
|
||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||
import Instance from '@/components/ui/Instance.vue'
|
||||
import LegacyProjectCard from '@/components/ui/LegacyProjectCard.vue'
|
||||
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
|
||||
import ProjectCard from '@/components/ui/ProjectCard.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { get_by_profile_path } from '@/helpers/process.js'
|
||||
import { duplicate, kill, remove, run } from '@/helpers/profile.js'
|
||||
@@ -270,7 +270,7 @@ onUnmounted(() => {
|
||||
/>
|
||||
</section>
|
||||
<section v-else ref="modsRow" class="projects">
|
||||
<LegacyProjectCard
|
||||
<ProjectCard
|
||||
v-for="project in row.instances.slice(0, maxProjectsPerRow)"
|
||||
:key="project?.project_id"
|
||||
ref="instanceComponents"
|
||||
|
||||
@@ -284,12 +284,12 @@ onUnmounted(() => {
|
||||
z-index: 11;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--color-divider);
|
||||
border: 1px solid var(--color-button-bg);
|
||||
width: max-content;
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
max-height: calc(100vh - 300px);
|
||||
max-height: 98vh;
|
||||
overflow-y: auto;
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
@@ -380,7 +380,7 @@ onUnmounted(() => {
|
||||
text-align: left;
|
||||
|
||||
&.expanded {
|
||||
border: 1px solid var(--color-divider);
|
||||
border: 1px solid var(--color-button-bg);
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
|
||||
const emit = defineEmits(['menu-closed', 'option-clicked'])
|
||||
|
||||
@@ -40,27 +40,22 @@ defineExpose({
|
||||
item.value = passedItem
|
||||
options.value = passedOptions
|
||||
|
||||
// show to get dimensions
|
||||
const menuWidth = contextMenu.value.clientWidth
|
||||
const menuHeight = contextMenu.value.clientHeight
|
||||
|
||||
if (menuWidth + event.pageX >= window.innerWidth) {
|
||||
left.value = event.pageX - menuWidth + 2 + 'px'
|
||||
} else {
|
||||
left.value = event.pageX - 2 + 'px'
|
||||
}
|
||||
|
||||
if (menuHeight + event.pageY >= window.innerHeight) {
|
||||
top.value = event.pageY - menuHeight + 2 + 'px'
|
||||
} else {
|
||||
top.value = event.pageY - 2 + 'px'
|
||||
}
|
||||
|
||||
shown.value = true
|
||||
|
||||
// then, adjust position if overflowing
|
||||
nextTick(() => {
|
||||
const menuWidth = contextMenu.value?.clientWidth || 200
|
||||
const menuHeight = contextMenu.value?.clientHeight || 100
|
||||
const minFromEdge = 10
|
||||
|
||||
if (event.pageX + menuWidth + minFromEdge >= window.innerWidth) {
|
||||
left.value = Math.max(minFromEdge, event.pageX - menuWidth - minFromEdge) + 'px'
|
||||
} else {
|
||||
left.value = event.pageX + minFromEdge + 'px'
|
||||
}
|
||||
|
||||
if (event.pageY + menuHeight + minFromEdge >= window.innerHeight) {
|
||||
top.value = Math.max(minFromEdge, event.pageY - menuHeight - minFromEdge) + 'px'
|
||||
} else {
|
||||
top.value = event.pageY + minFromEdge + 'px'
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
@@ -119,7 +114,7 @@ onBeforeUnmount(() => {
|
||||
background-color: var(--color-raised-bg);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-floating);
|
||||
border: 1px solid var(--color-divider);
|
||||
border: 1px solid var(--color-button-bg);
|
||||
margin: 0;
|
||||
position: fixed;
|
||||
z-index: 1000000;
|
||||
@@ -163,7 +158,7 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
|
||||
.divider {
|
||||
border: 1px solid var(--color-divider);
|
||||
border: 1px solid var(--color-button-bg);
|
||||
margin: var(--gap-sm);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { PlusIcon, XIcon } from '@modrinth/assets'
|
||||
import { Button, Checkbox, injectNotificationManager, StyledInput } from '@modrinth/ui'
|
||||
import { Button, Checkbox, injectNotificationManager } from '@modrinth/ui'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { ref } from 'vue'
|
||||
|
||||
@@ -110,33 +110,31 @@ const exportPack = async () => {
|
||||
<div class="modal-body">
|
||||
<div class="labeled_input">
|
||||
<p>Modpack Name</p>
|
||||
<StyledInput
|
||||
v-model="nameInput"
|
||||
:icon="PackageIcon"
|
||||
type="text"
|
||||
placeholder="Modpack name"
|
||||
clearable
|
||||
/>
|
||||
<div class="iconified-input">
|
||||
<PackageIcon />
|
||||
<input v-model="nameInput" type="text" placeholder="Modpack name" class="input" />
|
||||
<Button class="r-btn" @click="nameInput = ''">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="labeled_input">
|
||||
<p>Version number</p>
|
||||
<StyledInput
|
||||
v-model="versionInput"
|
||||
:icon="VersionIcon"
|
||||
type="text"
|
||||
placeholder="1.0.0"
|
||||
clearable
|
||||
/>
|
||||
<div class="iconified-input">
|
||||
<VersionIcon />
|
||||
<input v-model="versionInput" type="text" placeholder="1.0.0" class="input" />
|
||||
<Button class="r-btn" @click="versionInput = ''">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="adjacent-input">
|
||||
<div class="labeled_input">
|
||||
<p>Description</p>
|
||||
|
||||
<StyledInput
|
||||
v-model="exportDescription"
|
||||
multiline
|
||||
placeholder="Enter modpack description..."
|
||||
/>
|
||||
<div class="textarea-wrapper">
|
||||
<textarea v-model="exportDescription" placeholder="Enter modpack description..." />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -291,4 +289,17 @@ const exportPack = async () => {
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.textarea-wrapper {
|
||||
// margin-top: 1rem;
|
||||
height: 12rem;
|
||||
|
||||
textarea {
|
||||
max-height: 12rem;
|
||||
}
|
||||
|
||||
.preview {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -20,13 +20,12 @@
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<p class="input-label">Name</p>
|
||||
<StyledInput
|
||||
<input
|
||||
v-model="profile_name"
|
||||
autocomplete="off"
|
||||
class="text-input"
|
||||
type="text"
|
||||
placeholder="Enter a name for your instance..."
|
||||
:maxlength="100"
|
||||
wrapper-class="w-full"
|
||||
maxlength="100"
|
||||
/>
|
||||
</div>
|
||||
<div class="input-row">
|
||||
@@ -35,7 +34,7 @@
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<p class="input-label">Game version</p>
|
||||
<div class="flex gap-4 items-center">
|
||||
<div class="versions">
|
||||
<multiselect
|
||||
v-model="game_version"
|
||||
class="selector"
|
||||
@@ -46,7 +45,7 @@
|
||||
open-direction="top"
|
||||
:show-labels="false"
|
||||
/>
|
||||
<Checkbox v-model="showSnapshots" class="shrink-0" label="Show all versions" />
|
||||
<Checkbox v-model="showSnapshots" class="filter-checkbox" label="Show all versions" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="loader !== 'vanilla'" class="input-row">
|
||||
@@ -94,14 +93,18 @@
|
||||
<div class="path-selection">
|
||||
<h3>{{ selectedProfileType.name }} path</h3>
|
||||
<div class="path-input">
|
||||
<StyledInput
|
||||
v-model="selectedProfileType.path"
|
||||
:icon="FolderOpenIcon"
|
||||
type="text"
|
||||
placeholder="Path to launcher"
|
||||
clearable
|
||||
@change="setPath"
|
||||
/>
|
||||
<div class="iconified-input">
|
||||
<FolderOpenIcon />
|
||||
<input
|
||||
v-model="selectedProfileType.path"
|
||||
type="text"
|
||||
placeholder="Path to launcher"
|
||||
@change="setPath"
|
||||
/>
|
||||
<Button class="r-btn" @click="() => (selectedProfileType.path = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<Button icon-only @click="selectLauncherPath">
|
||||
<FolderSearchIcon />
|
||||
</Button>
|
||||
@@ -194,14 +197,7 @@ import {
|
||||
UploadIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Checkbox,
|
||||
Chips,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
import { Avatar, Button, Checkbox, Chips, injectNotificationManager } from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { getCurrentWebview } from '@tauri-apps/api/webview'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
@@ -345,7 +341,7 @@ const create_instance = async () => {
|
||||
creating.value = true
|
||||
const loader_version_value =
|
||||
loader_version.value === 'other' ? specified_loader_version.value : loader_version.value
|
||||
const loaderVersion = loader.value === 'vanilla' ? null : (loader_version_value ?? 'stable')
|
||||
const loaderVersion = loader.value === 'vanilla' ? null : loader_version_value ?? 'stable'
|
||||
|
||||
hide()
|
||||
creating.value = false
|
||||
@@ -354,7 +350,7 @@ const create_instance = async () => {
|
||||
profile_name.value,
|
||||
game_version.value,
|
||||
loader.value,
|
||||
loader.value === 'vanilla' ? null : (loader_version_value ?? 'stable'),
|
||||
loader.value === 'vanilla' ? null : loader_version_value ?? 'stable',
|
||||
icon.value,
|
||||
).catch(handleError)
|
||||
|
||||
@@ -550,6 +546,12 @@ const next = async () => {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.versions {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
:deep(button.checkbox) {
|
||||
border: none;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { GameIcon, LeftArrowIcon } from '@modrinth/assets'
|
||||
import { Avatar, ButtonStyled, FormattedTag } from '@modrinth/ui'
|
||||
import { Avatar, ButtonStyled } from '@modrinth/ui'
|
||||
import { formatCategory } from '@modrinth/utils'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
|
||||
type Instance = {
|
||||
@@ -36,8 +37,7 @@ defineProps<{
|
||||
</span>
|
||||
<span class="text-secondary flex items-center gap-2 font-semibold">
|
||||
<GameIcon class="h-5 w-5 text-secondary" />
|
||||
<FormattedTag :tag="instance.loader" enforce-type="loader" />
|
||||
{{ instance.game_version }}
|
||||
{{ formatCategory(instance.loader) }} {{ instance.game_version }}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
<template>
|
||||
<JavaDetectionModal ref="detectJavaModal" @submit="(val) => emit('update:modelValue', val)" />
|
||||
<div class="toggle-setting" :class="{ compact }">
|
||||
<StyledInput
|
||||
<input
|
||||
autocomplete="off"
|
||||
:disabled="props.disabled"
|
||||
:model-value="props.modelValue ? props.modelValue.path : ''"
|
||||
:value="props.modelValue ? props.modelValue.path : ''"
|
||||
type="text"
|
||||
class="installation-input"
|
||||
:placeholder="placeholder ?? '/path/to/java'"
|
||||
wrapper-class="installation-input"
|
||||
@update:model-value="
|
||||
@input="
|
||||
(val) => {
|
||||
emit('update:modelValue', {
|
||||
...props.modelValue,
|
||||
path: val,
|
||||
path: val.target.value,
|
||||
})
|
||||
}
|
||||
"
|
||||
@@ -59,7 +60,7 @@ import {
|
||||
SearchIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Button, injectNotificationManager, StyledInput } from '@modrinth/ui'
|
||||
import { Button, injectNotificationManager } from '@modrinth/ui'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { ref } from 'vue'
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
:class="{
|
||||
'router-link-active': isPrimary && isPrimary(route),
|
||||
'subpage-active': isSubpage && isSubpage(route),
|
||||
disabled: disabled,
|
||||
}"
|
||||
class="w-12 h-12 text-primary rounded-full flex items-center justify-center text-2xl transition-all bg-transparent hover:bg-button-bg hover:text-contrast"
|
||||
>
|
||||
@@ -16,7 +15,6 @@
|
||||
v-else
|
||||
v-bind="$attrs"
|
||||
class="button-animation border-none text-primary cursor-pointer w-12 h-12 rounded-full flex items-center justify-center text-2xl transition-all bg-transparent hover:bg-button-bg hover:text-contrast"
|
||||
:disabled="disabled"
|
||||
@click="to"
|
||||
>
|
||||
<slot />
|
||||
@@ -31,18 +29,12 @@ const route = useRoute()
|
||||
|
||||
type RouteFunction = (route: RouteLocationNormalizedLoaded) => boolean
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
to: (() => void) | string
|
||||
isPrimary?: RouteFunction
|
||||
isSubpage?: RouteFunction
|
||||
highlightOverride?: boolean
|
||||
disabled?: boolean
|
||||
}>(),
|
||||
{
|
||||
disabled: false,
|
||||
},
|
||||
)
|
||||
defineProps<{
|
||||
to: (() => void) | string
|
||||
isPrimary?: RouteFunction
|
||||
isSubpage?: RouteFunction
|
||||
highlightOverride?: boolean
|
||||
}>()
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
<template>
|
||||
<div class="progress-bar">
|
||||
<div
|
||||
class="progress-bar__fill"
|
||||
:style="{
|
||||
width: `${progress}%`,
|
||||
'background-color': error ? 'var(--color-red)' : 'var(--color-brand)',
|
||||
}"
|
||||
></div>
|
||||
<div class="progress-bar__fill" :style="{ width: `${progress}%` }"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -19,10 +13,6 @@ defineProps({
|
||||
return value >= 0 && value <= 100
|
||||
},
|
||||
},
|
||||
error: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -37,6 +27,7 @@ defineProps({
|
||||
|
||||
.progress-bar__fill {
|
||||
height: 100%;
|
||||
background-color: var(--color-brand);
|
||||
transition: width 0.3s;
|
||||
}
|
||||
</style>
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
<script setup>
|
||||
import { DownloadIcon, HeartIcon, TagIcon } from '@modrinth/assets'
|
||||
import { Avatar, FormattedTag, TagItem } from '@modrinth/ui'
|
||||
import { formatNumber } from '@modrinth/utils'
|
||||
import { Avatar, TagItem } from '@modrinth/ui'
|
||||
import { formatCategory, formatNumber } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { computed } from 'vue'
|
||||
@@ -63,7 +63,7 @@ const toTransparent = computed(() => {
|
||||
<div
|
||||
class="w-full aspect-[2/1] bg-cover bg-center bg-no-repeat"
|
||||
:style="{
|
||||
'background-color': (project.featured_gallery ?? project.gallery[0]) ? null : toColor,
|
||||
'background-color': project.featured_gallery ?? project.gallery[0] ? null : toColor,
|
||||
'background-image': `url(${
|
||||
project.featured_gallery ??
|
||||
project.gallery[0] ??
|
||||
@@ -107,7 +107,7 @@ const toTransparent = computed(() => {
|
||||
<div class="flex items-center gap-1 pr-2">
|
||||
<TagIcon />
|
||||
<TagItem>
|
||||
<FormattedTag :tag="featuredCategory" />
|
||||
{{ formatCategory(featuredCategory) }}
|
||||
</TagItem>
|
||||
</div>
|
||||
</div>
|
||||
@@ -34,18 +34,18 @@ function updateAdPosition() {
|
||||
<template>
|
||||
<div ref="adsWrapper" class="ad-parent relative flex w-full justify-center cursor-pointer bg-bg">
|
||||
<a
|
||||
href="https://modrinth.host/medal?from=app-placeholder"
|
||||
href="https://modrinth.gg/medal?from=app-placeholder"
|
||||
target="_blank"
|
||||
class="flex max-h-[250px] min-h-[250px] min-w-[300px] max-w-[300px] flex-col gap-4 rounded-[inherit]"
|
||||
>
|
||||
<img
|
||||
src="https://cdn-raw.modrinth.com/modrinth-hosting-medal-light.webp"
|
||||
alt="Host your next server with Modrinth Hosting"
|
||||
src="https://cdn-raw.modrinth.com/medal-modrinth-servers-light.webp"
|
||||
alt="Host your next server with Modrinth Servers"
|
||||
class="hidden light-image rounded-[inherit]"
|
||||
/>
|
||||
<img
|
||||
src="https://cdn-raw.modrinth.com/modrinth-hosting-medal-dark.webp"
|
||||
alt="Host your next server with Modrinth Hosting"
|
||||
src="https://cdn-raw.modrinth.com/medal-modrinth-servers-dark.webp"
|
||||
alt="Host your next server with Modrinth Servers"
|
||||
class="dark-image rounded-[inherit]"
|
||||
/>
|
||||
</a>
|
||||
|
||||
@@ -69,7 +69,7 @@ onUnmounted(() => {
|
||||
<SpinnerIcon class="animate-spin w-4 h-4" />
|
||||
</div>
|
||||
</NavButton>
|
||||
<div v-if="recentInstances.length > 0" class="h-px w-6 mx-auto my-2 bg-divider"></div>
|
||||
<div v-if="recentInstances.length > 0" class="h-px w-6 mx-auto my-2 bg-button-bg"></div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -177,8 +177,8 @@ const currentLoadingBars = ref([])
|
||||
|
||||
const refreshInfo = async () => {
|
||||
const currentLoadingBarCount = currentLoadingBars.value.length
|
||||
currentLoadingBars.value = Object.values(await progress_bars_list().catch(handleError))
|
||||
.map((x) => {
|
||||
currentLoadingBars.value = Object.values(await progress_bars_list().catch(handleError)).map(
|
||||
(x) => {
|
||||
if (x.bar_type.type === 'java_download') {
|
||||
x.title = 'Downloading Java ' + x.bar_type.version
|
||||
}
|
||||
@@ -190,8 +190,8 @@ const refreshInfo = async () => {
|
||||
}
|
||||
|
||||
return x
|
||||
})
|
||||
.filter((bar) => bar?.bar_type?.type !== 'launcher_update')
|
||||
},
|
||||
)
|
||||
|
||||
currentLoadingBars.value.sort((a, b) => {
|
||||
if (a.loading_bar_uuid < b.loading_bar_uuid) {
|
||||
@@ -293,7 +293,7 @@ onBeforeUnmount(() => {
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-divider);
|
||||
border: 1px solid var(--color-button-bg);
|
||||
padding: var(--gap-sm) var(--gap-lg);
|
||||
}
|
||||
|
||||
@@ -356,7 +356,7 @@ onBeforeUnmount(() => {
|
||||
gap: 1rem;
|
||||
overflow: auto;
|
||||
transition: all 0.2s ease-in-out;
|
||||
border: 1px solid var(--color-divider);
|
||||
border: 1px solid var(--color-button-bg);
|
||||
|
||||
&.hidden {
|
||||
transform: translateY(-100%);
|
||||
@@ -454,7 +454,7 @@ onBeforeUnmount(() => {
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
transition: all 0.2s ease-in-out;
|
||||
border: 1px solid var(--color-divider);
|
||||
border: 1px solid var(--color-button-bg);
|
||||
padding: var(--gap-md);
|
||||
|
||||
&.hidden {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ProjectCard
|
||||
:title="project.title"
|
||||
:link="
|
||||
<div
|
||||
class="card-shadow p-4 bg-bg-raised rounded-xl flex gap-3 group cursor-pointer hover:brightness-90 transition-all"
|
||||
@click="
|
||||
() => {
|
||||
emit('open')
|
||||
$router.push({
|
||||
@@ -10,58 +10,116 @@
|
||||
})
|
||||
}
|
||||
"
|
||||
:author="{ name: project.author, link: `https://modrinth.com/user/${project.author}` }"
|
||||
:icon-url="project.icon_url"
|
||||
:summary="project.description"
|
||||
:tags="project.display_categories"
|
||||
:all-tags="project.categories"
|
||||
:downloads="project.downloads"
|
||||
:followers="project.follows"
|
||||
:date-updated="project.date_modified"
|
||||
:banner="project.featured_gallery ?? undefined"
|
||||
:color="project.color ?? undefined"
|
||||
:environment="
|
||||
projectType
|
||||
? ['mod', 'modpack'].includes(projectType)
|
||||
? {
|
||||
clientSide: project.client_side,
|
||||
serverSide: project.server_side,
|
||||
}
|
||||
: undefined
|
||||
: undefined
|
||||
"
|
||||
layout="list"
|
||||
>
|
||||
<template #actions>
|
||||
<ButtonStyled color="brand" type="outlined">
|
||||
<button
|
||||
:disabled="installed || installing"
|
||||
class="shrink-0 no-wrap"
|
||||
@click.stop="install()"
|
||||
<div class="icon w-[96px] h-[96px] relative">
|
||||
<Avatar :src="project.icon_url" size="96px" class="search-icon origin-top transition-all" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 overflow-hidden">
|
||||
<div class="gap-2 overflow-hidden no-wrap text-ellipsis">
|
||||
<span class="text-lg font-extrabold text-contrast m-0 leading-none">
|
||||
{{ project.title }}
|
||||
</span>
|
||||
<span v-if="project.author" class="text-secondary"> by {{ project.author }}</span>
|
||||
</div>
|
||||
<div class="m-0 line-clamp-2">
|
||||
{{ project.description }}
|
||||
</div>
|
||||
<div v-if="categories.length > 0" class="mt-auto flex items-center gap-1 no-wrap">
|
||||
<TagsIcon class="h-4 w-4 shrink-0" />
|
||||
<div
|
||||
v-if="project.project_type === 'mod' || project.project_type === 'modpack'"
|
||||
class="text-sm font-semibold text-secondary flex gap-1 px-[0.375rem] py-0.5 bg-button-bg rounded-full"
|
||||
>
|
||||
<template v-if="!installed">
|
||||
<DownloadIcon v-if="modpack || instance" />
|
||||
<PlusIcon v-else />
|
||||
<template v-if="project.client_side === 'optional' && project.server_side === 'optional'">
|
||||
Client or server
|
||||
</template>
|
||||
<CheckIcon v-else />
|
||||
{{
|
||||
installing
|
||||
? 'Installing'
|
||||
: installed
|
||||
? 'Installed'
|
||||
: modpack || instance
|
||||
? 'Install'
|
||||
: 'Add to an instance'
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</template>
|
||||
</ProjectCard>
|
||||
<template
|
||||
v-else-if="
|
||||
(project.client_side === 'optional' || project.client_side === 'required') &&
|
||||
(project.server_side === 'optional' || project.server_side === 'unsupported')
|
||||
"
|
||||
>
|
||||
Client
|
||||
</template>
|
||||
<template
|
||||
v-else-if="
|
||||
(project.server_side === 'optional' || project.server_side === 'required') &&
|
||||
(project.client_side === 'optional' || project.client_side === 'unsupported')
|
||||
"
|
||||
>
|
||||
Server
|
||||
</template>
|
||||
<template
|
||||
v-else-if="
|
||||
project.client_side === 'unsupported' && project.server_side === 'unsupported'
|
||||
"
|
||||
>
|
||||
Unsupported
|
||||
</template>
|
||||
<template
|
||||
v-else-if="project.client_side === 'required' && project.server_side === 'required'"
|
||||
>
|
||||
Client and server
|
||||
</template>
|
||||
</div>
|
||||
<div
|
||||
v-for="tag in categories"
|
||||
:key="tag"
|
||||
class="text-sm font-semibold text-secondary flex gap-1 px-[0.375rem] py-0.5 bg-button-bg rounded-full"
|
||||
>
|
||||
{{ formatCategory(tag.name) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 items-end shrink-0 ml-auto">
|
||||
<div class="flex items-center gap-2">
|
||||
<DownloadIcon class="shrink-0" />
|
||||
<span>
|
||||
{{ formatNumber(project.downloads) }}
|
||||
<span class="text-secondary">downloads</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<HeartIcon class="shrink-0" />
|
||||
<span>
|
||||
{{ formatNumber(project.follows ?? project.followers) }}
|
||||
<span class="text-secondary">followers</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-auto relative">
|
||||
<div class="absolute bottom-0 right-0 w-fit">
|
||||
<ButtonStyled color="brand" type="outlined">
|
||||
<button
|
||||
:disabled="installed || installing"
|
||||
class="shrink-0 no-wrap"
|
||||
@click.stop="install()"
|
||||
>
|
||||
<template v-if="!installed">
|
||||
<DownloadIcon v-if="modpack || instance" />
|
||||
<PlusIcon v-else />
|
||||
</template>
|
||||
<CheckIcon v-else />
|
||||
{{
|
||||
installing
|
||||
? 'Installing'
|
||||
: installed
|
||||
? 'Installed'
|
||||
: modpack || instance
|
||||
? 'Install'
|
||||
: 'Add to an instance'
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { CheckIcon, DownloadIcon, PlusIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, injectNotificationManager, ProjectCard } from '@modrinth/ui'
|
||||
import { CheckIcon, DownloadIcon, HeartIcon, PlusIcon, TagsIcon } from '@modrinth/assets'
|
||||
import { Avatar, ButtonStyled, injectNotificationManager } from '@modrinth/ui'
|
||||
import { formatCategory, formatNumber } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { computed, ref } from 'vue'
|
||||
@@ -83,6 +141,10 @@ const props = defineProps({
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
categories: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
instance: {
|
||||
type: Object,
|
||||
default: null,
|
||||
@@ -95,10 +157,6 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
projectType: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['open', 'install'])
|
||||
|
||||
@@ -114,7 +114,7 @@ watch(loading, (newValue) => {
|
||||
setTimeout(() => {
|
||||
hidden.value = true
|
||||
loading.setEnabled(true)
|
||||
}, 50)
|
||||
}, 250)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -135,6 +135,9 @@ loading_listener(async (e) => {
|
||||
if (e.event.type === 'directory_move') {
|
||||
loadingProgress.value = 100 * (e.fraction ?? 1)
|
||||
message.value = 'Updating app directory...'
|
||||
} else if (e.event.type === 'launcher_update') {
|
||||
loadingProgress.value = 100 * (e.fraction ?? 1)
|
||||
message.value = 'Updating Modrinth App...'
|
||||
} else if (e.event.type === 'checking_for_updates') {
|
||||
loadingProgress.value = 100 * (e.fraction ?? 1)
|
||||
message.value = 'Checking for updates...'
|
||||
@@ -191,8 +194,7 @@ const handleClose = async () => {
|
||||
position: absolute;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(66, 131, 92, 0.275) 0%, rgba(17, 35, 43, 0.5) 97.29%),
|
||||
background: linear-gradient(180deg, rgba(66, 131, 92, 0.275) 0%, rgba(17, 35, 43, 0.5) 97.29%),
|
||||
linear-gradient(0deg, rgba(22, 24, 28, 0.64), rgba(22, 24, 28, 0.64));
|
||||
z-index: 9997;
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { XIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, commonMessages, defineMessages, useVIntl } from '@modrinth/ui'
|
||||
import { getVersion } from '@tauri-apps/api/app'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const dismissed = ref(false)
|
||||
const availableUpdate = ref<{ version: string } | null>(null)
|
||||
|
||||
let checkInterval: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
async function checkForUpdate() {
|
||||
try {
|
||||
const [response, currentVersion] = await Promise.all([
|
||||
fetch('https://launcher-files.modrinth.com/updates.json'),
|
||||
getVersion(),
|
||||
])
|
||||
const updates = await response.json()
|
||||
const latestVersion = updates?.version
|
||||
|
||||
if (latestVersion && latestVersion !== currentVersion) {
|
||||
if (latestVersion !== availableUpdate.value?.version) {
|
||||
availableUpdate.value = { version: latestVersion }
|
||||
dismissed.value = false
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to check for updates:', e)
|
||||
}
|
||||
}
|
||||
|
||||
function dismiss() {
|
||||
dismissed.value = true
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
checkForUpdate()
|
||||
checkInterval = setInterval(checkForUpdate, 5 * 60 * 1000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (checkInterval) {
|
||||
clearInterval(checkInterval)
|
||||
}
|
||||
})
|
||||
|
||||
const messages = defineMessages({
|
||||
title: {
|
||||
id: 'app.update-toast.title',
|
||||
defaultMessage: 'Update available',
|
||||
},
|
||||
body: {
|
||||
id: 'app.update-toast.body.linux',
|
||||
defaultMessage:
|
||||
'Modrinth App v{version} is available. Use your package manager to update for the latest features and fixes!',
|
||||
},
|
||||
download: {
|
||||
id: 'app.update-toast.download-page',
|
||||
defaultMessage: 'Download',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
v-if="availableUpdate && !dismissed"
|
||||
class="grid grid-cols-[min-content] fixed card-shadow rounded-2xl top-[--top-bar-height] mt-6 right-6 p-4 z-10 bg-bg-raised border-surface-5 border-solid border-[2px]"
|
||||
>
|
||||
<div class="flex min-w-[25rem] gap-4">
|
||||
<h2 class="whitespace-nowrap text-base text-contrast font-semibold m-0 grow">
|
||||
{{ formatMessage(messages.title) }}
|
||||
</h2>
|
||||
<ButtonStyled size="small" circular>
|
||||
<button v-tooltip="formatMessage(commonMessages.closeButton)" @click="dismiss">
|
||||
<XIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<p class="text-sm mt-2 mb-0">
|
||||
{{ formatMessage(messages.body, { version: availableUpdate.version }) }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,130 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { DownloadIcon, ExternalIcon, RefreshCwIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, commonMessages, defineMessages, ProgressBar, useVIntl } from '@modrinth/ui'
|
||||
import { formatBytes } from '@modrinth/utils'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { injectAppUpdateDownloadProgress } from '@/providers/download-progress.ts'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'close' | 'restart' | 'download'): void
|
||||
}>()
|
||||
|
||||
defineProps<{
|
||||
version: string
|
||||
size: number | null
|
||||
metered: boolean
|
||||
}>()
|
||||
|
||||
const downloading = ref(false)
|
||||
const { progress } = injectAppUpdateDownloadProgress()
|
||||
|
||||
function download() {
|
||||
emit('download')
|
||||
downloading.value = true
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
title: {
|
||||
id: 'app.update-toast.title',
|
||||
defaultMessage: 'Update available',
|
||||
},
|
||||
body: {
|
||||
id: 'app.update-toast.body',
|
||||
defaultMessage:
|
||||
'Modrinth App v{version} is ready to install! Reload to update now, or automatically when you close Modrinth App.',
|
||||
},
|
||||
reload: {
|
||||
id: 'app.update-toast.reload',
|
||||
defaultMessage: 'Reload',
|
||||
},
|
||||
download: {
|
||||
id: 'app.update-toast.download',
|
||||
defaultMessage: 'Download ({size})',
|
||||
},
|
||||
downloading: {
|
||||
id: 'app.update-toast.downloading',
|
||||
defaultMessage: 'Downloading...',
|
||||
},
|
||||
changelog: {
|
||||
id: 'app.update-toast.changelog',
|
||||
defaultMessage: 'Changelog',
|
||||
},
|
||||
meteredBody: {
|
||||
id: 'app.update-toast.body.metered',
|
||||
defaultMessage: `Modrinth App v{version} is available now! Since you're on a metered network, we didn't automatically download it.`,
|
||||
},
|
||||
downloadCompleteTitle: {
|
||||
id: 'app.update-toast.title.download-complete',
|
||||
defaultMessage: 'Download complete',
|
||||
},
|
||||
downloadedBody: {
|
||||
id: 'app.update-toast.body.download-complete',
|
||||
defaultMessage: `Modrinth App v{version} has finished downloading. Reload to update now, or automatically when you close Modrinth App.`,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="grid grid-cols-[min-content] fixed card-shadow rounded-2xl top-[--top-bar-height] mt-6 right-6 p-4 z-10 bg-bg-raised border-surface-5 border-solid border-[2px]"
|
||||
:class="{
|
||||
'download-complete': progress === 1,
|
||||
}"
|
||||
>
|
||||
<div class="flex min-w-[25rem] gap-4">
|
||||
<h2 class="whitespace-nowrap text-base text-contrast font-semibold m-0 grow">
|
||||
{{
|
||||
formatMessage(metered && progress === 1 ? messages.downloadCompleteTitle : messages.title)
|
||||
}}
|
||||
</h2>
|
||||
<ButtonStyled size="small" circular>
|
||||
<button v-tooltip="formatMessage(commonMessages.closeButton)" @click="emit('close')">
|
||||
<XIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<p class="text-sm mt-2 mb-0">
|
||||
{{
|
||||
formatMessage(
|
||||
metered
|
||||
? progress === 1
|
||||
? messages.downloadedBody
|
||||
: messages.meteredBody
|
||||
: messages.body,
|
||||
{ version },
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<p
|
||||
v-if="metered && progress < 1"
|
||||
class="text-sm text-secondary mt-2 mb-0 flex items-center gap-1"
|
||||
>
|
||||
<template v-if="progress > 0">
|
||||
<ProgressBar :progress="progress" class="max-w-[unset]" />
|
||||
</template>
|
||||
</p>
|
||||
<div class="flex gap-2 mt-4">
|
||||
<ButtonStyled color="brand">
|
||||
<button v-if="metered && progress < 1" :disabled="downloading" @click="download">
|
||||
<SpinnerIcon v-if="downloading" class="animate-spin" />
|
||||
<DownloadIcon v-else />
|
||||
{{
|
||||
formatMessage(downloading ? messages.downloading : messages.download, {
|
||||
size: formatBytes(size ?? 0),
|
||||
})
|
||||
}}
|
||||
</button>
|
||||
<button v-else @click="emit('restart')">
|
||||
<RefreshCwIcon /> {{ formatMessage(messages.reload) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<a href="https://modrinth.com/news/changelog?filter=app">
|
||||
{{ formatMessage(messages.changelog) }} <ExternalIcon />
|
||||
</a>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,42 +1,41 @@
|
||||
<script setup lang="ts">
|
||||
import { MailIcon, SendIcon, UserIcon, UserPlusIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
MailIcon,
|
||||
MoreVerticalIcon,
|
||||
SettingsIcon,
|
||||
TrashIcon,
|
||||
UserPlusIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
StyledInput,
|
||||
OverflowMenu,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, onUnmounted, ref, watch } from 'vue'
|
||||
|
||||
import FriendsSection from '@/components/ui/friends/FriendsSection.vue'
|
||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import { get_user_many } from '@/helpers/cache'
|
||||
import { friend_listener } from '@/helpers/events'
|
||||
import {
|
||||
add_friend,
|
||||
friends,
|
||||
type FriendWithUserData,
|
||||
remove_friend,
|
||||
transformFriends,
|
||||
} from '@/helpers/friends.ts'
|
||||
import type { ModrinthCredentials } from '@/helpers/mr_auth'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
import { add_friend, friend_statuses, friends, remove_friend } from '@/helpers/friends'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const formatRelativeTime = useRelativeTime()
|
||||
|
||||
const props = defineProps<{
|
||||
credentials: ModrinthCredentials | null
|
||||
credentials: unknown | null
|
||||
signIn: () => void
|
||||
}>()
|
||||
|
||||
const userCredentials = computed(() => props.credentials)
|
||||
|
||||
const search = ref('')
|
||||
const manageFriendsModal = ref()
|
||||
const friendInvitesModal = ref()
|
||||
|
||||
const username = ref('')
|
||||
@@ -48,64 +47,61 @@ async function addFriendFromModal() {
|
||||
await loadFriends()
|
||||
}
|
||||
|
||||
async function addFriend(friend: FriendWithUserData) {
|
||||
const id = friend.id === userCredentials.value?.user_id ? friend.friend_id : friend.id
|
||||
if (id) {
|
||||
await add_friend(id).catch(handleError)
|
||||
await loadFriends()
|
||||
const friendOptions = ref()
|
||||
async function handleFriendOptions(args) {
|
||||
switch (args.option) {
|
||||
case 'remove-friend':
|
||||
await removeFriend(args.item)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
async function removeFriend(friend: FriendWithUserData) {
|
||||
const id = friend.id === userCredentials.value?.user_id ? friend.friend_id : friend.id
|
||||
if (id) {
|
||||
await remove_friend(id).catch(handleError)
|
||||
await loadFriends()
|
||||
}
|
||||
async function addFriend(friend: Friend) {
|
||||
await add_friend(
|
||||
friend.id === userCredentials.value.user_id ? friend.friend_id : friend.id,
|
||||
).catch(handleError)
|
||||
await loadFriends()
|
||||
}
|
||||
|
||||
const userFriends = ref<FriendWithUserData[]>([])
|
||||
const sortedFriends = computed<FriendWithUserData[]>(() =>
|
||||
userFriends.value.slice().sort((a, b) => {
|
||||
if (a.last_updated === null && b.last_updated === null) {
|
||||
return 0 // Both are null, equal in sorting
|
||||
}
|
||||
if (a.last_updated === null) {
|
||||
return 1 // `a` is null, move it after `b`
|
||||
}
|
||||
if (b.last_updated === null) {
|
||||
return -1 // `b` is null, move it after `a`
|
||||
}
|
||||
// Both are non-null, sort by date
|
||||
return b.last_updated.diff(a.last_updated)
|
||||
}),
|
||||
)
|
||||
const filteredFriends = computed<FriendWithUserData[]>(() =>
|
||||
sortedFriends.value.filter((x) =>
|
||||
x.username.trim().toLowerCase().includes(search.value.trim().toLowerCase()),
|
||||
),
|
||||
)
|
||||
async function removeFriend(friend: Friend) {
|
||||
await remove_friend(
|
||||
friend.id === userCredentials.value.user_id ? friend.friend_id : friend.id,
|
||||
).catch(handleError)
|
||||
await loadFriends()
|
||||
}
|
||||
|
||||
const activeFriends = computed<FriendWithUserData[]>(() =>
|
||||
filteredFriends.value.filter((x) => !!x.status && x.online && x.accepted),
|
||||
)
|
||||
const onlineFriends = computed<FriendWithUserData[]>(() =>
|
||||
filteredFriends.value.filter((x) => x.online && !x.status && x.accepted),
|
||||
)
|
||||
const offlineFriends = computed<FriendWithUserData[]>(() =>
|
||||
filteredFriends.value.filter((x) => !x.online && x.accepted),
|
||||
type Friend = {
|
||||
id: string
|
||||
friend_id: string | null
|
||||
status: string | null
|
||||
last_updated: Dayjs | null
|
||||
created: Dayjs
|
||||
username: string
|
||||
accepted: boolean
|
||||
online: boolean
|
||||
avatar: string
|
||||
}
|
||||
|
||||
const userFriends = ref<Friend[]>([])
|
||||
const acceptedFriends = computed(() =>
|
||||
userFriends.value
|
||||
.filter((x) => x.accepted)
|
||||
.toSorted((a, b) => {
|
||||
if (a.last_updated === null && b.last_updated === null) {
|
||||
return 0 // Both are null, equal in sorting
|
||||
}
|
||||
if (a.last_updated === null) {
|
||||
return 1 // `a` is null, move it after `b`
|
||||
}
|
||||
if (b.last_updated === null) {
|
||||
return -1 // `b` is null, move it after `a`
|
||||
}
|
||||
// Both are non-null, sort by date
|
||||
return b.last_updated.diff(a.last_updated)
|
||||
}),
|
||||
)
|
||||
const pendingFriends = computed(() =>
|
||||
filteredFriends.value
|
||||
.filter((x) => !x.accepted && x.id !== userCredentials.value?.user_id)
|
||||
.slice()
|
||||
.sort((a, b) => b.created.diff(a.created)),
|
||||
)
|
||||
const incomingRequests = computed(() =>
|
||||
userFriends.value
|
||||
.filter((x) => !x.accepted && x.id === userCredentials.value?.user_id)
|
||||
.slice()
|
||||
.sort((a, b) => b.created.diff(a.created)),
|
||||
userFriends.value.filter((x) => !x.accepted).toSorted((a, b) => b.created.diff(a.created)),
|
||||
)
|
||||
|
||||
const loading = ref(true)
|
||||
@@ -114,7 +110,34 @@ async function loadFriends(timeout = false) {
|
||||
|
||||
try {
|
||||
const friendsList = await friends()
|
||||
userFriends.value = await transformFriends(friendsList, userCredentials.value)
|
||||
|
||||
if (friendsList.length === 0) {
|
||||
userFriends.value = []
|
||||
} else {
|
||||
const friendStatuses = await friend_statuses()
|
||||
const users = await get_user_many(
|
||||
friendsList.map((x) => (x.id === userCredentials.value.user_id ? x.friend_id : x.id)),
|
||||
)
|
||||
|
||||
userFriends.value = friendsList.map((friend) => {
|
||||
const user = users.find((x) => x.id === friend.id || x.id === friend.friend_id)
|
||||
const status = friendStatuses.find(
|
||||
(x) => x.user_id === friend.id || x.user_id === friend.friend_id,
|
||||
)
|
||||
return {
|
||||
id: friend.id,
|
||||
friend_id: friend.friend_id,
|
||||
status: status?.profile_name,
|
||||
last_updated: status && status.last_update ? dayjs(status.last_update) : null,
|
||||
created: dayjs(friend.created),
|
||||
avatar: user?.avatar_url,
|
||||
username: user?.username,
|
||||
online: !!status,
|
||||
accepted: friend.accepted,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
loading.value = false
|
||||
} catch (e) {
|
||||
console.error('Error loading friends', e)
|
||||
@@ -129,7 +152,6 @@ watch(
|
||||
() => {
|
||||
if (userCredentials.value === undefined) {
|
||||
userFriends.value = []
|
||||
loading.value = false
|
||||
} else if (userCredentials.value === null) {
|
||||
userFriends.value = []
|
||||
loading.value = false
|
||||
@@ -144,87 +166,49 @@ const unlisten = await friend_listener(() => loadFriends())
|
||||
onUnmounted(() => {
|
||||
unlisten()
|
||||
})
|
||||
|
||||
const messages = defineMessages({
|
||||
addFriend: {
|
||||
id: 'friends.action.add-friend',
|
||||
defaultMessage: 'Add a friend',
|
||||
},
|
||||
addingAFriend: {
|
||||
id: 'friends.add-friend.title',
|
||||
defaultMessage: 'Adding a friend',
|
||||
},
|
||||
usernameTitle: {
|
||||
id: 'friends.add-friend.username.title',
|
||||
defaultMessage: "What's your friend's Modrinth username?",
|
||||
},
|
||||
usernameDescription: {
|
||||
id: 'friends.add-friend.username.description',
|
||||
defaultMessage: 'It may be different from their Minecraft username!',
|
||||
},
|
||||
usernamePlaceholder: {
|
||||
id: 'friends.add-friend.username.placeholder',
|
||||
defaultMessage: 'Enter Modrinth username...',
|
||||
},
|
||||
sendFriendRequest: {
|
||||
id: 'friends.add-friend.submit',
|
||||
defaultMessage: 'Send friend request',
|
||||
},
|
||||
viewFriendRequests: {
|
||||
id: 'friends.action.view-friend-requests',
|
||||
defaultMessage: '{count} friend {count, plural, one {request} other {requests}}',
|
||||
},
|
||||
searchFriends: {
|
||||
id: 'friends.search-friends-placeholder',
|
||||
defaultMessage: 'Search friends...',
|
||||
},
|
||||
friends: {
|
||||
id: 'friends.heading',
|
||||
defaultMessage: 'Friends',
|
||||
},
|
||||
pending: {
|
||||
id: 'friends.heading.pending',
|
||||
defaultMessage: 'Pending',
|
||||
},
|
||||
active: {
|
||||
id: 'friends.heading.active',
|
||||
defaultMessage: 'Active',
|
||||
},
|
||||
online: {
|
||||
id: 'friends.heading.online',
|
||||
defaultMessage: 'Online',
|
||||
},
|
||||
offline: {
|
||||
id: 'friends.heading.offline',
|
||||
defaultMessage: 'Offline',
|
||||
},
|
||||
noFriendsMatch: {
|
||||
id: 'friends.no-friends-match',
|
||||
defaultMessage: `No friends matching ''{query}''`,
|
||||
},
|
||||
signInToAddFriends: {
|
||||
id: 'friends.sign-in-to-add-friends',
|
||||
defaultMessage:
|
||||
"<link>Sign in to a Modrinth account</link> to add friends and see what they're playing!",
|
||||
},
|
||||
addFriendsToShare: {
|
||||
id: 'friends.add-friends-to-share',
|
||||
defaultMessage: "<link>Add friends</link> to see what they're playing!",
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ModalWrapper ref="manageFriendsModal" header="Manage friends">
|
||||
<p v-if="acceptedFriends.length === 0">Add friends to share what you're playing!</p>
|
||||
<div v-else class="flex flex-col gap-4 min-w-[20rem]">
|
||||
<input v-model="search" type="text" placeholder="Search friends..." class="w-full" />
|
||||
<div
|
||||
v-for="friend in acceptedFriends.filter(
|
||||
(x) => !search || x.username.toLowerCase().includes(search),
|
||||
)"
|
||||
:key="friend.username"
|
||||
class="flex gap-2 items-center"
|
||||
>
|
||||
<div class="relative">
|
||||
<Avatar :src="friend.avatar" class="w-12 h-12 rounded-full" size="2.25rem" circle />
|
||||
<span
|
||||
v-if="friend.online"
|
||||
class="bottom-1 right-0 absolute w-3 h-3 bg-brand border-2 border-black border-solid rounded-full"
|
||||
/>
|
||||
</div>
|
||||
<div>{{ friend.username }}</div>
|
||||
<div class="ml-auto">
|
||||
<ButtonStyled>
|
||||
<button @click="removeFriend(friend)">
|
||||
<XIcon />
|
||||
Remove
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
<ModalWrapper ref="friendInvitesModal" header="View friend requests">
|
||||
<p v-if="incomingRequests.length === 0">You have no pending friend requests :C</p>
|
||||
<div v-else class="flex flex-col gap-4 min-w-[40rem]">
|
||||
<div v-for="friend in incomingRequests" :key="friend.username" class="flex gap-2">
|
||||
<p v-if="pendingFriends.length === 0">You have no pending friend requests :C</p>
|
||||
<div v-else class="flex flex-col gap-4">
|
||||
<div v-for="friend in pendingFriends" :key="friend.username" class="flex gap-2">
|
||||
<Avatar :src="friend.avatar" class="w-12 h-12 rounded-full" size="2.25rem" circle />
|
||||
<div class="grid grid-cols-[1fr_auto] w-full gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<div>
|
||||
<p class="m-0">
|
||||
<template v-if="friend.id === userCredentials?.user_id">
|
||||
<span class="text-contrast">{{ friend.username }}</span> sent you a friend request
|
||||
<template v-if="friend.id === userCredentials.user_id">
|
||||
<span class="font-bold">{{ friend.username }}</span> sent you a friend request
|
||||
</template>
|
||||
<template v-else>
|
||||
You sent <span class="font-bold">{{ friend.username }}</span> a friend request
|
||||
@@ -235,7 +219,7 @@ const messages = defineMessages({
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<template v-if="friend.id === userCredentials?.user_id">
|
||||
<template v-if="friend.id === userCredentials.user_id">
|
||||
<ButtonStyled color="brand">
|
||||
<button @click="addFriend(friend)">
|
||||
<UserPlusIcon />
|
||||
@@ -262,80 +246,78 @@ const messages = defineMessages({
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
<ModalWrapper ref="addFriendModal" :header="formatMessage(messages.addingAFriend)">
|
||||
<div class="min-w-[30rem]">
|
||||
<h2 class="m-0 text-base font-medium text-primary">
|
||||
{{ formatMessage(messages.usernameTitle) }}
|
||||
</h2>
|
||||
<p class="m-0 mt-1 text-sm text-secondary leading-tight">
|
||||
{{ formatMessage(messages.usernameDescription) }}
|
||||
</p>
|
||||
<div class="flex items-center gap-2 mt-4">
|
||||
<StyledInput
|
||||
v-model="username"
|
||||
:icon="UserIcon"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.usernamePlaceholder)"
|
||||
wrapper-class="flex-1"
|
||||
@keyup.enter="addFriendFromModal"
|
||||
/>
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="username.length === 0" @click="addFriendFromModal">
|
||||
<SendIcon />
|
||||
{{ formatMessage(messages.sendFriendRequest) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
<div v-if="userCredentials && !loading" class="flex gap-1 items-center mb-3 ml-2 mr-1">
|
||||
<template v-if="sortedFriends.length > 0">
|
||||
<ButtonStyled circular type="transparent">
|
||||
<button
|
||||
v-tooltip="formatMessage(messages.addFriend)"
|
||||
:aria-label="formatMessage(messages.addFriend)"
|
||||
@click="addFriendModal.show"
|
||||
>
|
||||
<UserPlusIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<StyledInput
|
||||
v-model="search"
|
||||
<ModalWrapper ref="addFriendModal" header="Add a friend">
|
||||
<div class="mb-4">
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Username</h2>
|
||||
<p class="m-0 mt-1 leading-tight">You can add friends with their Modrinth username.</p>
|
||||
<input
|
||||
v-model="username"
|
||||
class="mt-2 w-full"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.searchFriends)"
|
||||
clearable
|
||||
variant="outlined"
|
||||
wrapper-class="flex-1"
|
||||
@keyup.esc="search = ''"
|
||||
placeholder="Enter username..."
|
||||
@keyup.enter="addFriendFromModal"
|
||||
/>
|
||||
</template>
|
||||
<h3 v-else class="ml-2 w-full text-base text-primary font-medium m-0">
|
||||
{{ formatMessage(messages.friends) }}
|
||||
</h3>
|
||||
<ButtonStyled v-if="incomingRequests.length > 0" circular type="transparent">
|
||||
<button
|
||||
v-tooltip="formatMessage(messages.viewFriendRequests, { count: incomingRequests.length })"
|
||||
class="relative"
|
||||
:aria-label="formatMessage(messages.viewFriendRequests, { count: incomingRequests.length })"
|
||||
@click="friendInvitesModal.show"
|
||||
>
|
||||
<MailIcon />
|
||||
<span
|
||||
v-if="incomingRequests.length > 0"
|
||||
aria-hidden="true"
|
||||
class="absolute bg-brand text-brand-inverted text-[8px] top-0.5 px-1 right-0.5 min-w-3 h-3 rounded-full flex items-center justify-center font-bold"
|
||||
>
|
||||
{{ incomingRequests.length }}
|
||||
</span>
|
||||
</div>
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="username.length === 0" @click="addFriendFromModal">
|
||||
<UserPlusIcon />
|
||||
Add friend
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</ModalWrapper>
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="text-lg m-0">Friends</h3>
|
||||
<ButtonStyled v-if="userCredentials" type="transparent" circular>
|
||||
<OverflowMenu
|
||||
:options="[
|
||||
{
|
||||
id: 'add-friend',
|
||||
action: () => addFriendModal.show(),
|
||||
},
|
||||
{
|
||||
id: 'manage-friends',
|
||||
action: () => manageFriendsModal.show(),
|
||||
shown: acceptedFriends.length > 0,
|
||||
},
|
||||
{
|
||||
id: 'view-requests',
|
||||
action: () => friendInvitesModal.show(),
|
||||
shown: pendingFriends.length > 0,
|
||||
},
|
||||
]"
|
||||
aria-label="More options"
|
||||
>
|
||||
<MoreVerticalIcon aria-hidden="true" />
|
||||
<template #add-friend>
|
||||
<UserPlusIcon aria-hidden="true" />
|
||||
Add friend
|
||||
</template>
|
||||
<template #manage-friends>
|
||||
<SettingsIcon aria-hidden="true" />
|
||||
Manage friends
|
||||
<div
|
||||
v-if="acceptedFriends.length > 0"
|
||||
class="bg-button-bg w-6 h-6 rounded-full flex items-center justify-center"
|
||||
>
|
||||
{{ acceptedFriends.length }}
|
||||
</div>
|
||||
</template>
|
||||
<template #view-requests>
|
||||
<MailIcon aria-hidden="true" />
|
||||
View friend requests
|
||||
<div
|
||||
v-if="pendingFriends.length > 0"
|
||||
class="bg-button-bg w-6 h-6 rounded-full flex items-center justify-center"
|
||||
>
|
||||
{{ pendingFriends.length }}
|
||||
</div>
|
||||
</template>
|
||||
</OverflowMenu>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<div class="flex flex-col gap-3">
|
||||
<h3 v-if="loading" class="ml-4 mr-1 text-base text-primary font-medium m-0">
|
||||
{{ formatMessage(messages.friends) }}
|
||||
</h3>
|
||||
<div class="flex flex-col gap-2 mt-2">
|
||||
<template v-if="loading">
|
||||
<div v-for="n in 5" :key="n" class="flex gap-2 items-center animate-pulse ml-4 mr-1">
|
||||
<div v-for="n in 5" :key="n" class="flex gap-2 items-center animate-pulse">
|
||||
<div class="min-w-9 min-h-9 bg-button-bg rounded-full"></div>
|
||||
<div class="flex flex-col w-full">
|
||||
<div class="h-3 bg-button-bg rounded-full w-1/2 mb-1"></div>
|
||||
@@ -343,64 +325,50 @@ const messages = defineMessages({
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="sortedFriends.length === 0">
|
||||
<div class="text-sm ml-4 mr-1">
|
||||
<template v-else-if="acceptedFriends.length === 0">
|
||||
<div class="text-sm">
|
||||
<div v-if="!userCredentials">
|
||||
<IntlFormatted :message-id="messages.signInToAddFriends">
|
||||
<template #link="{ children }">
|
||||
<span class="font-semibold text-brand cursor-pointer" @click="signIn">
|
||||
<component :is="() => children" />
|
||||
</span>
|
||||
</template>
|
||||
</IntlFormatted>
|
||||
<span class="text-link cursor-pointer" @click="signIn">Sign in</span> to add friends!
|
||||
</div>
|
||||
<div v-else>
|
||||
<IntlFormatted :message-id="messages.addFriendsToShare">
|
||||
<template #link="{ children }">
|
||||
<span class="font-semibold text-brand cursor-pointer" @click="addFriendModal.show">
|
||||
<component :is="() => children" />
|
||||
</span>
|
||||
</template>
|
||||
</IntlFormatted>
|
||||
<span class="text-link cursor-pointer" @click="addFriendModal.show()">Add friends</span>
|
||||
to share what you're playing!
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<FriendsSection
|
||||
v-if="activeFriends.length > 0"
|
||||
:is-searching="!!search"
|
||||
open-by-default
|
||||
:friends="activeFriends"
|
||||
:heading="formatMessage(messages.active)"
|
||||
:remove-friend="removeFriend"
|
||||
/>
|
||||
<FriendsSection
|
||||
v-if="onlineFriends.length > 0"
|
||||
:is-searching="!!search"
|
||||
open-by-default
|
||||
:friends="onlineFriends"
|
||||
:heading="formatMessage(messages.online)"
|
||||
:remove-friend="removeFriend"
|
||||
/>
|
||||
<FriendsSection
|
||||
v-if="offlineFriends.length > 0"
|
||||
:is-searching="!!search"
|
||||
:open-by-default="activeFriends.length + onlineFriends.length < 3"
|
||||
:friends="offlineFriends"
|
||||
:heading="formatMessage(messages.offline)"
|
||||
:remove-friend="removeFriend"
|
||||
/>
|
||||
<FriendsSection
|
||||
v-if="pendingFriends.length > 0"
|
||||
:is-searching="!!search"
|
||||
open-by-default
|
||||
:friends="pendingFriends"
|
||||
:heading="formatMessage(messages.pending)"
|
||||
:remove-friend="removeFriend"
|
||||
/>
|
||||
<p v-if="filteredFriends.length === 0 && search" class="text-sm text-secondary my-1 mx-4">
|
||||
{{ formatMessage(messages.noFriendsMatch, { query: search }) }}
|
||||
</p>
|
||||
<ContextMenu ref="friendOptions" @option-clicked="handleFriendOptions">
|
||||
<template #remove-friend> <TrashIcon /> Remove friend </template>
|
||||
</ContextMenu>
|
||||
<div
|
||||
v-for="friend in acceptedFriends.slice(0, 5)"
|
||||
:key="friend.username"
|
||||
class="flex gap-2 items-center"
|
||||
:class="{ grayscale: !friend.online }"
|
||||
@contextmenu.prevent.stop="
|
||||
(event) =>
|
||||
friendOptions.showMenu(event, friend, [
|
||||
{
|
||||
name: 'remove-friend',
|
||||
color: 'danger',
|
||||
},
|
||||
])
|
||||
"
|
||||
>
|
||||
<div class="relative">
|
||||
<Avatar :src="friend.avatar" class="w-12 h-12 rounded-full" size="2.25rem" circle />
|
||||
<span
|
||||
v-if="friend.online"
|
||||
class="bottom-1 right-0 absolute w-3 h-3 bg-brand border-2 border-black border-solid rounded-full"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-md m-0 font-medium" :class="{ 'text-secondary': !friend.online }">
|
||||
{{ friend.username }}
|
||||
</span>
|
||||
<span v-if="friend.status" class="m-0 text-xs">{{ friend.status }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { MoreVerticalIcon, TrashIcon, UserIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Accordion,
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
defineMessages,
|
||||
OverflowMenu,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import { useTemplateRef } from 'vue'
|
||||
|
||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||
import type { FriendWithUserData } from '@/helpers/friends.ts'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
friends: FriendWithUserData[]
|
||||
heading: string
|
||||
removeFriend: (friend: FriendWithUserData) => Promise<void>
|
||||
isSearching?: boolean
|
||||
openByDefault?: boolean
|
||||
}>(),
|
||||
{
|
||||
isSearching: false,
|
||||
openByDefault: false,
|
||||
},
|
||||
)
|
||||
|
||||
function createContextMenuOptions(friend: FriendWithUserData) {
|
||||
if (friend.accepted) {
|
||||
return [
|
||||
{
|
||||
name: 'view-profile',
|
||||
},
|
||||
{
|
||||
name: 'remove-friend',
|
||||
color: 'danger',
|
||||
},
|
||||
]
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
name: 'view-profile',
|
||||
},
|
||||
{
|
||||
name: 'cancel-request',
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
function openProfile(username: string) {
|
||||
openUrl('https://modrinth.com/user/' + username)
|
||||
}
|
||||
|
||||
const friendOptions = useTemplateRef('friendOptions')
|
||||
async function handleFriendOptions(args: { item: FriendWithUserData; option: string }) {
|
||||
switch (args.option) {
|
||||
case 'remove-friend':
|
||||
case 'cancel-request':
|
||||
await props.removeFriend(args.item)
|
||||
break
|
||||
case 'view-profile':
|
||||
openProfile(args.item.username)
|
||||
}
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
removeFriend: {
|
||||
id: 'friends.friend.remove-friend',
|
||||
defaultMessage: 'Remove friend',
|
||||
},
|
||||
heading: {
|
||||
id: 'friends.section.heading',
|
||||
defaultMessage: '{title} - {count}',
|
||||
},
|
||||
friendRequestSent: {
|
||||
id: 'friends.friend.request-sent',
|
||||
defaultMessage: 'Friend request sent',
|
||||
},
|
||||
cancelRequest: {
|
||||
id: 'friends.friend.cancel-request',
|
||||
defaultMessage: 'Cancel request',
|
||||
},
|
||||
viewProfile: {
|
||||
id: 'friends.friend.view-profile',
|
||||
defaultMessage: 'View profile',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenu ref="friendOptions" @option-clicked="handleFriendOptions">
|
||||
<template #view-profile>
|
||||
<UserIcon />
|
||||
{{ formatMessage(messages.viewProfile) }}
|
||||
</template>
|
||||
<template #remove-friend> <TrashIcon /> {{ formatMessage(messages.removeFriend) }} </template>
|
||||
<template #cancel-request> <XIcon /> {{ formatMessage(messages.cancelRequest) }} </template>
|
||||
</ContextMenu>
|
||||
<Accordion
|
||||
:open-by-default="openByDefault"
|
||||
:force-open="isSearching"
|
||||
:button-class="
|
||||
'pl-4 pr-3 flex w-full items-center bg-transparent border-0 p-0' +
|
||||
(isSearching
|
||||
? ''
|
||||
: ' cursor-pointer hover:brightness-[--hover-brightness] active:scale-[0.98] transition-all')
|
||||
"
|
||||
>
|
||||
<template #title>
|
||||
<h3 class="text-base text-primary font-medium m-0">
|
||||
{{ formatMessage(messages.heading, { title: heading, count: friends.length }) }}
|
||||
</h3>
|
||||
</template>
|
||||
<template #default>
|
||||
<div class="pt-3 flex flex-col gap-1">
|
||||
<div
|
||||
v-for="friend in friends"
|
||||
:key="friend.username"
|
||||
class="group grid items-center grid-cols-[auto_1fr_auto] gap-2 hover:bg-button-bg transition-colors rounded-full ml-4 mr-1"
|
||||
@contextmenu.prevent.stop="
|
||||
(event) => friendOptions?.showMenu(event, friend, createContextMenuOptions(friend))
|
||||
"
|
||||
>
|
||||
<div class="relative">
|
||||
<Avatar
|
||||
:src="friend.avatar"
|
||||
:class="{ grayscale: !friend.online && friend.accepted }"
|
||||
class="w-12 h-12 rounded-full"
|
||||
size="32px"
|
||||
circle
|
||||
/>
|
||||
<span
|
||||
v-if="friend.online"
|
||||
aria-hidden="true"
|
||||
class="bottom-[2px] right-[-2px] absolute w-3 h-3 bg-brand border-2 border-black border-solid rounded-full"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span
|
||||
class="text-sm m-0"
|
||||
:class="friend.online || !friend.accepted ? 'text-contrast' : 'text-primary'"
|
||||
>
|
||||
{{ friend.username }}
|
||||
</span>
|
||||
<span v-if="!friend.accepted" class="m-0 text-xs">
|
||||
{{ formatMessage(messages.friendRequestSent) }}
|
||||
</span>
|
||||
<span v-else-if="friend.status" class="m-0 text-xs">{{ friend.status }}</span>
|
||||
</div>
|
||||
<ButtonStyled v-if="friend.accepted" circular type="transparent">
|
||||
<OverflowMenu
|
||||
class="opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
:options="[
|
||||
{
|
||||
id: 'view-profile',
|
||||
action: () => openProfile(friend.username),
|
||||
},
|
||||
{
|
||||
id: 'remove-friend',
|
||||
action: () => removeFriend(friend),
|
||||
color: 'red',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<MoreVerticalIcon />
|
||||
<template #view-profile>
|
||||
<UserIcon />
|
||||
{{ formatMessage(messages.viewProfile) }}
|
||||
</template>
|
||||
<template #remove-friend>
|
||||
<TrashIcon />
|
||||
{{ formatMessage(messages.removeFriend) }}
|
||||
</template>
|
||||
</OverflowMenu>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-else type="transparent" circular>
|
||||
<button v-tooltip="formatMessage(messages.cancelRequest)" @click="removeFriend(friend)">
|
||||
<XIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Accordion>
|
||||
</template>
|
||||
@@ -28,7 +28,7 @@
|
||||
:custom-label="
|
||||
(version) =>
|
||||
`${version?.name} (${version?.loaders
|
||||
.map((name) => formatLoader(formatMessage, name))
|
||||
.map((name) => formatCategory(name))
|
||||
.join(', ')} - ${version?.game_versions.join(', ')})`
|
||||
"
|
||||
:max-height="150"
|
||||
@@ -36,9 +36,7 @@
|
||||
<span v-else>
|
||||
<span>
|
||||
{{ selectedVersion?.name }} ({{
|
||||
selectedVersion?.loaders
|
||||
.map((name) => formatLoader(formatMessage, name))
|
||||
.join(', ')
|
||||
selectedVersion?.loaders.map((name) => formatCategory(name)).join(', ')
|
||||
}}
|
||||
- {{ selectedVersion?.game_versions.join(', ') }})
|
||||
</span>
|
||||
@@ -59,7 +57,8 @@
|
||||
|
||||
<script setup>
|
||||
import { DownloadIcon, XIcon } from '@modrinth/assets'
|
||||
import { Button, formatLoader, injectNotificationManager, useVIntl } from '@modrinth/ui'
|
||||
import { Button, injectNotificationManager } from '@modrinth/ui'
|
||||
import { formatCategory } from '@modrinth/utils'
|
||||
import { ref } from 'vue'
|
||||
import Multiselect from 'vue-multiselect'
|
||||
|
||||
@@ -68,7 +67,6 @@ import { trackEvent } from '@/helpers/analytics'
|
||||
import { add_project_from_version as installMod } from '@/helpers/profile'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const instance = ref(null)
|
||||
const project = ref(null)
|
||||
|
||||
@@ -4,11 +4,10 @@ import {
|
||||
DownloadIcon,
|
||||
PlusIcon,
|
||||
RightArrowIcon,
|
||||
SearchIcon,
|
||||
UploadIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Avatar, Button, Card, injectNotificationManager, StyledInput } from '@modrinth/ui'
|
||||
import { Avatar, Button, Card, injectNotificationManager } from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { computed, ref } from 'vue'
|
||||
@@ -49,14 +48,19 @@ const creatingInstance = ref(false)
|
||||
const profiles = ref([])
|
||||
|
||||
const shownProfiles = computed(() =>
|
||||
profiles.value.filter((profile) => {
|
||||
return profile.name.toLowerCase().includes(searchFilter.value.toLowerCase())
|
||||
}),
|
||||
profiles.value
|
||||
.filter((profile) => {
|
||||
return profile.name.toLowerCase().includes(searchFilter.value.toLowerCase())
|
||||
})
|
||||
.filter((profile) => {
|
||||
const version = {
|
||||
game_versions: versions.value.flatMap((v) => v.game_versions),
|
||||
loaders: versions.value.flatMap((v) => v.loaders),
|
||||
}
|
||||
return isVersionCompatible(version, project.value, profile)
|
||||
}),
|
||||
)
|
||||
|
||||
const isProfileCompatible = (profile) =>
|
||||
versions.value?.some((version) => isVersionCompatible(version, project.value, profile))
|
||||
|
||||
const onInstall = ref(() => {})
|
||||
|
||||
defineExpose({
|
||||
@@ -155,21 +159,20 @@ const reset_icon = () => {
|
||||
const createInstance = async () => {
|
||||
creatingInstance.value = true
|
||||
|
||||
const gameVersions = versions.value[0].game_versions
|
||||
const gameVersion = gameVersions[0]
|
||||
const loader =
|
||||
versions.value[0].loaders[0] !== 'forge' &&
|
||||
versions.value[0].loaders[0] !== 'fabric' &&
|
||||
versions.value[0].loaders[0] !== 'quilt'
|
||||
? 'vanilla'
|
||||
: versions.value[0].loaders[0]
|
||||
|
||||
const loaders = versions.value[0].loaders
|
||||
const loader = loaders.includes('fabric')
|
||||
? 'fabric'
|
||||
: loaders.includes('neoforge')
|
||||
? 'neoforge'
|
||||
: loaders.includes('forge')
|
||||
? 'forge'
|
||||
: loaders.includes('quilt')
|
||||
? 'quilt'
|
||||
: 'vanilla'
|
||||
|
||||
const id = await create(name.value, gameVersion, loader, 'latest', icon.value).catch(handleError)
|
||||
const id = await create(
|
||||
name.value,
|
||||
versions.value[0].game_versions[0],
|
||||
loader,
|
||||
'latest',
|
||||
icon.value,
|
||||
).catch(handleError)
|
||||
|
||||
await installMod(id, versions.value[0].id).catch(handleError)
|
||||
|
||||
@@ -207,12 +210,12 @@ const createInstance = async () => {
|
||||
<template>
|
||||
<ModalWrapper ref="installModal" header="Install project to instance" :on-hide="onInstall">
|
||||
<div class="modal-body">
|
||||
<StyledInput
|
||||
<input
|
||||
v-model="searchFilter"
|
||||
:icon="SearchIcon"
|
||||
type="search"
|
||||
placeholder="Search for an instance"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
class="search"
|
||||
placeholder="Search for an instance"
|
||||
/>
|
||||
<div class="profiles" :class="{ 'hide-creation': !showCreation }">
|
||||
<div v-for="profile in shownProfiles" :key="profile.name" class="option">
|
||||
@@ -235,23 +238,17 @@ const createInstance = async () => {
|
||||
"
|
||||
>
|
||||
<Button
|
||||
:disabled="
|
||||
!isProfileCompatible(profile) || profile.installedMod || profile.installing
|
||||
"
|
||||
:disabled="profile.installedMod || profile.installing"
|
||||
@click="install(profile)"
|
||||
>
|
||||
<DownloadIcon
|
||||
v-if="isProfileCompatible(profile) && !profile.installedMod && !profile.installing"
|
||||
/>
|
||||
<DownloadIcon v-if="!profile.installedMod && !profile.installing" />
|
||||
<CheckIcon v-else-if="profile.installedMod" />
|
||||
{{
|
||||
profile.installing
|
||||
? 'Installing...'
|
||||
: profile.installedMod
|
||||
? 'Installed'
|
||||
: !isProfileCompatible(profile)
|
||||
? 'Incompatible'
|
||||
: 'Install'
|
||||
: 'Install'
|
||||
}}
|
||||
</Button>
|
||||
</div>
|
||||
@@ -273,7 +270,7 @@ const createInstance = async () => {
|
||||
</div>
|
||||
</div>
|
||||
<div class="creation-settings">
|
||||
<StyledInput
|
||||
<input
|
||||
v-model="name"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
|
||||
@@ -4,14 +4,12 @@ import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
Checkbox,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
OverflowMenu,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import { computed, type Ref, ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
@@ -246,12 +244,13 @@ const messages = defineMessages({
|
||||
{{ formatMessage(messages.name) }}
|
||||
</label>
|
||||
<div class="flex">
|
||||
<StyledInput
|
||||
<input
|
||||
id="instance-name"
|
||||
v-model="title"
|
||||
autocomplete="off"
|
||||
:maxlength="80"
|
||||
wrapper-class="flex-grow"
|
||||
maxlength="80"
|
||||
class="flex-grow"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="instance.install_stage == 'installed'">
|
||||
@@ -292,8 +291,9 @@ const messages = defineMessages({
|
||||
@click="toggleGroup(group)"
|
||||
/>
|
||||
<div class="flex gap-2 items-center">
|
||||
<StyledInput
|
||||
<input
|
||||
v-model="newCategoryInput"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.libraryGroupsEnterName)"
|
||||
@submit="() => addCategory"
|
||||
/>
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Checkbox,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { Checkbox, injectNotificationManager } from '@modrinth/ui'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
import { edit } from '@/helpers/profile'
|
||||
@@ -114,13 +109,14 @@ const messages = defineMessages({
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.preLaunchDescription) }}
|
||||
</p>
|
||||
<StyledInput
|
||||
<input
|
||||
id="pre-launch"
|
||||
v-model="hooks.pre_launch"
|
||||
autocomplete="off"
|
||||
:disabled="!overrideHooks"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.preLaunchEnter)"
|
||||
wrapper-class="w-full mt-2"
|
||||
class="w-full mt-2"
|
||||
/>
|
||||
|
||||
<h2 class="mt-4 mb-1 text-lg font-extrabold text-contrast">
|
||||
@@ -129,13 +125,14 @@ const messages = defineMessages({
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.wrapperDescription) }}
|
||||
</p>
|
||||
<StyledInput
|
||||
<input
|
||||
id="wrapper"
|
||||
v-model="hooks.wrapper"
|
||||
autocomplete="off"
|
||||
:disabled="!overrideHooks"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.wrapperEnter)"
|
||||
wrapper-class="w-full mt-2"
|
||||
class="w-full mt-2"
|
||||
/>
|
||||
|
||||
<h2 class="mt-4 mb-1 text-lg font-extrabold text-contrast">
|
||||
@@ -144,13 +141,14 @@ const messages = defineMessages({
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.postExitDescription) }}
|
||||
</p>
|
||||
<StyledInput
|
||||
<input
|
||||
id="post-exit"
|
||||
v-model="hooks.post_exit"
|
||||
autocomplete="off"
|
||||
:disabled="!overrideHooks"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.postExitEnter)"
|
||||
wrapper-class="w-full mt-2"
|
||||
class="w-full mt-2"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
DownloadIcon,
|
||||
getLoaderIcon,
|
||||
HammerIcon,
|
||||
IssuesIcon,
|
||||
SpinnerIcon,
|
||||
@@ -16,13 +15,17 @@ import {
|
||||
ButtonStyled,
|
||||
Checkbox,
|
||||
Chips,
|
||||
Combobox,
|
||||
defineMessages,
|
||||
formatLoader,
|
||||
injectNotificationManager,
|
||||
useVIntl,
|
||||
TeleportDropdownMenu,
|
||||
} from '@modrinth/ui'
|
||||
import type { GameVersionTag, PlatformTag, Project, Version } from '@modrinth/utils'
|
||||
import {
|
||||
formatCategory,
|
||||
type GameVersionTag,
|
||||
type PlatformTag,
|
||||
type Project,
|
||||
type Version,
|
||||
} from '@modrinth/utils'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, type ComputedRef, type Ref, ref, shallowRef, watch } from 'vue'
|
||||
|
||||
@@ -125,7 +128,9 @@ if (props.instance.linked_data && props.instance.linked_data.project_id && !prop
|
||||
fetching.value = false
|
||||
}
|
||||
|
||||
const currentLoaderIcon = computed(() => getLoaderIcon(props.instance.loader))
|
||||
const currentLoaderIcon = computed(
|
||||
() => loaders?.value.find((x) => x.name === props.instance.loader)?.icon,
|
||||
)
|
||||
|
||||
const gameVersionsForLoader = computed(() => {
|
||||
return all_game_versions?.value.filter((item) => {
|
||||
@@ -153,21 +158,6 @@ const selectableGameVersionNumbers = computed(() => {
|
||||
.map((x) => x.version)
|
||||
})
|
||||
|
||||
const gameVersionOptions = computed(() =>
|
||||
(selectableGameVersionNumbers.value ?? []).map((v) => ({ value: v, label: v })),
|
||||
)
|
||||
|
||||
const loaderVersionOptions = computed(() =>
|
||||
(selectableLoaderVersions.value ?? []).map((opt, index) => ({ value: index, label: opt.id })),
|
||||
)
|
||||
|
||||
const loaderVersionLabel = computed(() => {
|
||||
const idx = loaderVersionIndex.value
|
||||
return idx >= 0 && selectableLoaderVersions.value
|
||||
? selectableLoaderVersions.value[idx]?.id
|
||||
: 'Select version'
|
||||
})
|
||||
|
||||
const selectableLoaderVersions: ComputedRef<ManifestLoaderVersion[] | undefined> = computed(() => {
|
||||
if (gameVersion.value) {
|
||||
if (loader.value === 'fabric') {
|
||||
@@ -544,7 +534,7 @@ const messages = defineMessages({
|
||||
v-else
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full bg-button-bg border-solid border-[1px] border-button-border p-2 [&_svg]:h-full [&_svg]:w-full"
|
||||
>
|
||||
<component :is="currentLoaderIcon" v-if="currentLoaderIcon" />
|
||||
<div v-if="!!currentLoaderIcon" class="contents" v-html="currentLoaderIcon" />
|
||||
<WrenchIcon v-else />
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 justify-center">
|
||||
@@ -563,7 +553,7 @@ const messages = defineMessages({
|
||||
? modpackVersion
|
||||
? modpackVersion?.version_number
|
||||
: 'Unknown version'
|
||||
: formatLoader(formatMessage, instance.loader)
|
||||
: formatCategory(instance.loader)
|
||||
}}
|
||||
<template v-if="instance.loader !== 'vanilla' && !modpackProject">
|
||||
{{ instance.loader_version || formatMessage(messages.unknownVersion) }}
|
||||
@@ -657,11 +647,11 @@ const messages = defineMessages({
|
||||
{{ formatMessage(messages.gameVersion) }}
|
||||
</h2>
|
||||
<div class="flex flex-wrap mt-2 gap-2">
|
||||
<Combobox
|
||||
<TeleportDropdownMenu
|
||||
v-if="selectableGameVersionNumbers !== undefined"
|
||||
v-model="gameVersion"
|
||||
:options="gameVersionOptions"
|
||||
:display-value="gameVersion || formatMessage(messages.unknownVersion)"
|
||||
:options="selectableGameVersionNumbers"
|
||||
name="Game Version Dropdown"
|
||||
/>
|
||||
<Checkbox
|
||||
v-if="hasSnapshots"
|
||||
@@ -671,19 +661,16 @@ const messages = defineMessages({
|
||||
</div>
|
||||
<template v-if="loader !== 'vanilla'">
|
||||
<h2 class="m-0 mt-4 text-lg font-extrabold text-contrast block">
|
||||
{{
|
||||
formatMessage(messages.loaderVersion, {
|
||||
loader: formatLoader(formatMessage, loader),
|
||||
})
|
||||
}}
|
||||
{{ formatMessage(messages.loaderVersion, { loader: formatCategory(loader) }) }}
|
||||
</h2>
|
||||
<Combobox
|
||||
<TeleportDropdownMenu
|
||||
v-if="selectableLoaderVersions"
|
||||
v-model="loaderVersionIndex"
|
||||
:options="loaderVersionOptions"
|
||||
:display-value="loaderVersionLabel"
|
||||
:model-value="selectableLoaderVersions[loaderVersionIndex]"
|
||||
:options="selectableLoaderVersions"
|
||||
:display-name="(option: ManifestLoaderVersion) => option?.id"
|
||||
name="Version selector"
|
||||
class="mt-2"
|
||||
@change="(value) => (loaderVersionIndex = value.index)"
|
||||
/>
|
||||
<div v-else class="mt-2 text-brand-red flex gap-2 items-center">
|
||||
<IssuesIcon />
|
||||
@@ -707,7 +694,7 @@ const messages = defineMessages({
|
||||
? messages.alreadyInstalledVanilla
|
||||
: messages.alreadyInstalledModded,
|
||||
{
|
||||
platform: formatLoader(formatMessage, loader),
|
||||
platform: formatCategory(loader),
|
||||
version: instance.loader_version,
|
||||
game_version: gameVersion,
|
||||
},
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { CheckCircleIcon, XCircleIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Checkbox,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
Slider,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { Checkbox, injectNotificationManager, Slider } from '@modrinth/ui'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import { computed, readonly, ref, watch } from 'vue'
|
||||
|
||||
import JavaSelector from '@/components/ui/JavaSelector.vue'
|
||||
@@ -15,7 +9,7 @@ import useMemorySlider from '@/composables/useMemorySlider'
|
||||
import { edit, get_optimal_jre_key } from '@/helpers/profile'
|
||||
import { get } from '@/helpers/settings.ts'
|
||||
|
||||
import type { AppSettings, InstanceSettingsTabProps } from '../../../helpers/types'
|
||||
import type { AppSettings, InstanceSettingsTabProps, MemorySettings } from '../../../helpers/types'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
@@ -28,12 +22,12 @@ const overrideJavaInstall = ref(!!props.instance.java_path)
|
||||
const optimalJava = readonly(await get_optimal_jre_key(props.instance.path).catch(handleError))
|
||||
const javaInstall = ref({ path: optimalJava.path ?? props.instance.java_path })
|
||||
|
||||
const overrideJavaArgs = ref((props.instance.extra_launch_args?.length ?? 0) > 0)
|
||||
const overrideJavaArgs = ref(props.instance.extra_launch_args?.length !== undefined)
|
||||
const javaArgs = ref(
|
||||
(props.instance.extra_launch_args ?? globalSettings.extra_launch_args).join(' '),
|
||||
)
|
||||
|
||||
const overrideEnvVars = ref((props.instance.custom_env_vars?.length ?? 0) > 0)
|
||||
const overrideEnvVars = ref(props.instance.custom_env_vars?.length !== undefined)
|
||||
const envVars = ref(
|
||||
(props.instance.custom_env_vars ?? globalSettings.custom_env_vars)
|
||||
.map((x) => x.join('='))
|
||||
@@ -48,23 +42,36 @@ const { maxMemory, snapPoints } = (await useMemorySlider().catch(handleError)) a
|
||||
}
|
||||
|
||||
const editProfileObject = computed(() => {
|
||||
return {
|
||||
java_path:
|
||||
overrideJavaInstall.value && javaInstall.value.path !== ''
|
||||
? javaInstall.value.path.replace('java.exe', 'javaw.exe')
|
||||
: null,
|
||||
extra_launch_args: overrideJavaArgs.value
|
||||
? javaArgs.value.trim().split(/\s+/).filter(Boolean)
|
||||
: null,
|
||||
custom_env_vars: overrideEnvVars.value
|
||||
? envVars.value
|
||||
.trim()
|
||||
.split(/\s+/)
|
||||
.filter(Boolean)
|
||||
.map((x) => x.split('=').filter(Boolean))
|
||||
: null,
|
||||
memory: overrideMemorySettings.value ? memory.value : null,
|
||||
const editProfile: {
|
||||
java_path?: string
|
||||
extra_launch_args?: string[]
|
||||
custom_env_vars?: string[][]
|
||||
memory?: MemorySettings
|
||||
} = {}
|
||||
|
||||
if (overrideJavaInstall.value) {
|
||||
if (javaInstall.value.path !== '') {
|
||||
editProfile.java_path = javaInstall.value.path.replace('java.exe', 'javaw.exe')
|
||||
}
|
||||
}
|
||||
|
||||
if (overrideJavaArgs.value) {
|
||||
editProfile.extra_launch_args = javaArgs.value.trim().split(/\s+/).filter(Boolean)
|
||||
}
|
||||
|
||||
if (overrideEnvVars.value) {
|
||||
editProfile.custom_env_vars = envVars.value
|
||||
.trim()
|
||||
.split(/\s+/)
|
||||
.filter(Boolean)
|
||||
.map((x) => x.split('=').filter(Boolean))
|
||||
}
|
||||
|
||||
if (overrideMemorySettings.value) {
|
||||
editProfile.memory = memory.value
|
||||
}
|
||||
|
||||
return editProfile
|
||||
})
|
||||
|
||||
watch(
|
||||
@@ -162,25 +169,27 @@ const messages = defineMessages({
|
||||
{{ formatMessage(messages.javaArguments) }}
|
||||
</h2>
|
||||
<Checkbox v-model="overrideJavaArgs" label="Custom java arguments" class="my-2" />
|
||||
<StyledInput
|
||||
<input
|
||||
id="java-args"
|
||||
v-model="javaArgs"
|
||||
autocomplete="off"
|
||||
:disabled="!overrideJavaArgs"
|
||||
type="text"
|
||||
class="w-full"
|
||||
placeholder="Enter java arguments..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<h2 id="project-name" class="mt-4 mb-1 text-lg font-extrabold text-contrast block">
|
||||
{{ formatMessage(messages.javaEnvironmentVariables) }}
|
||||
</h2>
|
||||
<Checkbox v-model="overrideEnvVars" label="Custom environment variables" class="mb-2" />
|
||||
<StyledInput
|
||||
<input
|
||||
id="env-vars"
|
||||
v-model="envVars"
|
||||
autocomplete="off"
|
||||
:disabled="!overrideEnvVars"
|
||||
type="text"
|
||||
class="w-full"
|
||||
placeholder="Enter environmental variables..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Checkbox,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
Toggle,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { Checkbox, injectNotificationManager, Toggle } from '@modrinth/ui'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import { computed, type Ref, ref, watch } from 'vue'
|
||||
|
||||
import { edit } from '@/helpers/profile'
|
||||
@@ -32,16 +26,20 @@ const fullscreenSetting: Ref<boolean> = ref(
|
||||
)
|
||||
|
||||
const editProfileObject = computed(() => {
|
||||
if (!overrideWindowSettings.value) {
|
||||
return {
|
||||
force_fullscreen: null,
|
||||
game_resolution: null,
|
||||
const editProfile: {
|
||||
force_fullscreen?: boolean
|
||||
game_resolution?: [number, number]
|
||||
} = {}
|
||||
|
||||
if (overrideWindowSettings.value) {
|
||||
editProfile.force_fullscreen = fullscreenSetting.value
|
||||
|
||||
if (!fullscreenSetting.value) {
|
||||
editProfile.game_resolution = resolution.value
|
||||
}
|
||||
}
|
||||
return {
|
||||
force_fullscreen: fullscreenSetting.value,
|
||||
game_resolution: fullscreenSetting.value ? null : resolution.value,
|
||||
}
|
||||
|
||||
return editProfile
|
||||
})
|
||||
|
||||
watch(
|
||||
@@ -97,6 +95,14 @@ const messages = defineMessages({
|
||||
<Checkbox
|
||||
v-model="overrideWindowSettings"
|
||||
:label="formatMessage(messages.customWindowSettings)"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
if (!value) {
|
||||
resolution = globalSettings.game_resolution
|
||||
fullscreenSetting = globalSettings.force_fullscreen
|
||||
}
|
||||
}
|
||||
"
|
||||
/>
|
||||
<div class="mt-2 flex items-center gap-4 justify-between">
|
||||
<div>
|
||||
@@ -128,7 +134,7 @@ const messages = defineMessages({
|
||||
{{ formatMessage(messages.widthDescription) }}
|
||||
</p>
|
||||
</div>
|
||||
<StyledInput
|
||||
<input
|
||||
id="width"
|
||||
v-model="resolution[0]"
|
||||
autocomplete="off"
|
||||
@@ -147,7 +153,7 @@ const messages = defineMessages({
|
||||
{{ formatMessage(messages.heightDescription) }}
|
||||
</p>
|
||||
</div>
|
||||
<StyledInput
|
||||
<input
|
||||
id="height"
|
||||
v-model="resolution[1]"
|
||||
autocomplete="off"
|
||||
|
||||
@@ -3,23 +3,16 @@ import {
|
||||
CoffeeIcon,
|
||||
GameIcon,
|
||||
GaugeIcon,
|
||||
LanguagesIcon,
|
||||
ModrinthIcon,
|
||||
PaintbrushIcon,
|
||||
ReportIcon,
|
||||
SettingsIcon,
|
||||
ShieldIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
commonMessages,
|
||||
defineMessage,
|
||||
defineMessages,
|
||||
ProgressBar,
|
||||
TabbedModal,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { TabbedModal } from '@modrinth/ui'
|
||||
import { getVersion } from '@tauri-apps/api/app'
|
||||
import { platform as getOsPlatform, version as getOsVersion } from '@tauri-apps/plugin-os'
|
||||
import { defineMessage, useVIntl } from '@vintl/vintl'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
@@ -27,11 +20,9 @@ import AppearanceSettings from '@/components/ui/settings/AppearanceSettings.vue'
|
||||
import DefaultInstanceSettings from '@/components/ui/settings/DefaultInstanceSettings.vue'
|
||||
import FeatureFlagSettings from '@/components/ui/settings/FeatureFlagSettings.vue'
|
||||
import JavaSettings from '@/components/ui/settings/JavaSettings.vue'
|
||||
import LanguageSettings from '@/components/ui/settings/LanguageSettings.vue'
|
||||
import PrivacySettings from '@/components/ui/settings/PrivacySettings.vue'
|
||||
import ResourceManagementSettings from '@/components/ui/settings/ResourceManagementSettings.vue'
|
||||
import { get, set } from '@/helpers/settings.ts'
|
||||
import { injectAppUpdateDownloadProgress } from '@/providers/download-progress.ts'
|
||||
import { useTheming } from '@/store/state'
|
||||
|
||||
const themeStore = useTheming()
|
||||
@@ -54,15 +45,6 @@ const tabs = [
|
||||
icon: PaintbrushIcon,
|
||||
content: AppearanceSettings,
|
||||
},
|
||||
{
|
||||
name: defineMessage({
|
||||
id: 'app.settings.tabs.language',
|
||||
defaultMessage: 'Language',
|
||||
}),
|
||||
icon: LanguagesIcon,
|
||||
content: LanguageSettings,
|
||||
badge: commonMessages.beta,
|
||||
},
|
||||
{
|
||||
name: defineMessage({
|
||||
id: 'app.settings.tabs.privacy',
|
||||
@@ -116,8 +98,6 @@ const isOpen = computed(() => modal.value?.isOpen)
|
||||
|
||||
defineExpose({ show, isOpen })
|
||||
|
||||
const { progress, version: downloadingVersion } = injectAppUpdateDownloadProgress()
|
||||
|
||||
const version = await getVersion()
|
||||
const osPlatform = getOsPlatform()
|
||||
const osVersion = getOsVersion()
|
||||
@@ -143,13 +123,6 @@ function devModeCount() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
downloading: {
|
||||
id: 'app.settings.downloading',
|
||||
defaultMessage: 'Downloading v{version}',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<ModalWrapper ref="modal">
|
||||
@@ -162,14 +135,6 @@ const messages = defineMessages({
|
||||
<TabbedModal :tabs="tabs.filter((t) => !t.developerOnly || themeStore.devMode)">
|
||||
<template #footer>
|
||||
<div class="mt-auto text-secondary text-sm">
|
||||
<div class="mb-3">
|
||||
<template v-if="progress > 0 && progress < 1">
|
||||
<p class="m-0 mb-2">
|
||||
{{ formatMessage(messages.downloading, { version: downloadingVersion }) }}
|
||||
</p>
|
||||
<ProgressBar :progress="progress" />
|
||||
</template>
|
||||
</div>
|
||||
<p v-if="themeStore.devMode" class="text-brand font-semibold m-0 mb-2">
|
||||
{{ formatMessage(developerModeEnabled) }}
|
||||
</p>
|
||||
@@ -187,7 +152,7 @@ const messages = defineMessages({
|
||||
<div>
|
||||
<p class="m-0">Modrinth App {{ version }}</p>
|
||||
<p class="m-0">
|
||||
<span v-if="osPlatform === 'macos'">macOS</span>
|
||||
<span v-if="osPlatform === 'macos'">MacOS</span>
|
||||
<span v-else class="capitalize">{{ osPlatform }}</span>
|
||||
{{ osVersion }}
|
||||
</p>
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
<template>
|
||||
<NewModal ref="modal" :header="formatMessage(messages.installToPlay)" :closable="true">
|
||||
<div class="flex flex-col gap-6 max-w-[500px]">
|
||||
<Admonition type="info" :header="formatMessage(messages.sharedServerInstance)">
|
||||
{{ formatMessage(messages.serverRequiresMods) }}
|
||||
</Admonition>
|
||||
|
||||
<div v-if="sharedBy?.name" class="flex items-center gap-2 text-sm text-secondary">
|
||||
<Avatar
|
||||
v-if="sharedBy?.icon_url"
|
||||
:src="sharedBy.icon_url"
|
||||
:alt="sharedBy.name"
|
||||
size="24px"
|
||||
/>
|
||||
<span>
|
||||
<IntlFormatted :message-id="messages.sharedByToday">
|
||||
<template #~name>
|
||||
<span class="font-semibold text-contrast">{{ sharedBy.name }}</span>
|
||||
</template>
|
||||
</IntlFormatted>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<span class="font-semibold text-contrast">
|
||||
{{ formatMessage(messages.sharedInstance) }}
|
||||
</span>
|
||||
<div class="flex items-center gap-3 rounded-xl bg-surface-4 p-3">
|
||||
<Avatar :src="project.icon_url" :alt="project.title" size="48px" />
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<span class="font-semibold text-contrast">{{ project.title }}</span>
|
||||
<span class="text-sm text-secondary">
|
||||
{{ loaderDisplay }} {{ project.game_versions?.[0] }}
|
||||
<template v-if="modCount">
|
||||
· {{ formatMessage(messages.modCount, { count: modCount }) }}
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #actions>
|
||||
<div class="flex justify-end gap-2">
|
||||
<ButtonStyled>
|
||||
<button @click="handleDecline">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button @click="handleAccept">
|
||||
<DownloadIcon />
|
||||
{{ formatMessage(messages.installButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { DownloadIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
formatLoader,
|
||||
IntlFormatted,
|
||||
NewModal,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { get_organization, get_team, get_version } from '@/helpers/cache.js'
|
||||
import { install } from '@/store/install.js'
|
||||
|
||||
const props = defineProps<{
|
||||
project: Labrinth.Projects.v2.Project
|
||||
}>()
|
||||
|
||||
const modal = ref<InstanceType<typeof NewModal>>()
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const { data: organization } = useQuery({
|
||||
queryKey: computed(() => ['organization', props.project.organization]),
|
||||
queryFn: () => get_organization(props.project.organization!, 'must_revalidate'),
|
||||
enabled: computed(() => !!props.project.organization),
|
||||
})
|
||||
|
||||
const { data: teamMembers } = useQuery({
|
||||
queryKey: computed(() => ['team', props.project.team]),
|
||||
queryFn: () => get_team(props.project.team, 'must_revalidate'),
|
||||
enabled: computed(() => !!props.project.team && !props.project.organization),
|
||||
})
|
||||
|
||||
const sharedBy = computed(() => {
|
||||
if (organization.value) {
|
||||
return {
|
||||
name: organization.value.name,
|
||||
icon_url: organization.value.icon_url,
|
||||
}
|
||||
}
|
||||
if (teamMembers.value) {
|
||||
const owner = teamMembers.value.find((member: { is_owner: boolean }) => member.is_owner)
|
||||
if (owner) {
|
||||
return {
|
||||
name: owner.user.username,
|
||||
icon_url: owner.user.avatar_url,
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
})
|
||||
|
||||
const loaderDisplay = computed(() => {
|
||||
const loader = props.project.loaders?.[0]
|
||||
if (!loader) return ''
|
||||
return formatLoader(formatMessage, loader)
|
||||
})
|
||||
|
||||
// Fetch the most recent version to get mod count from dependencies
|
||||
const latestVersionId = computed(() => props.project.versions?.[0] ?? null)
|
||||
const { data: latestVersion } = useQuery({
|
||||
queryKey: computed(() => ['version', latestVersionId.value]),
|
||||
queryFn: () => get_version(latestVersionId.value, 'must_revalidate'),
|
||||
enabled: computed(() => !!latestVersionId.value),
|
||||
})
|
||||
const modCount = computed(() => latestVersion.value?.dependencies?.length)
|
||||
|
||||
async function handleAccept() {
|
||||
hide()
|
||||
try {
|
||||
await install(props.project.id, null, null, 'ProjectPageInstallToPlayModal')
|
||||
} catch (error) {
|
||||
console.error('Failed to install project from InstallToPlayModal:', error)
|
||||
}
|
||||
}
|
||||
|
||||
function handleDecline() {
|
||||
hide()
|
||||
}
|
||||
|
||||
function show(e?: MouseEvent) {
|
||||
modal.value?.show(e)
|
||||
}
|
||||
|
||||
function hide() {
|
||||
modal.value?.hide()
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
installToPlay: {
|
||||
id: 'app.modal.install-to-play.header',
|
||||
defaultMessage: 'Install to play',
|
||||
},
|
||||
sharedServerInstance: {
|
||||
id: 'app.modal.install-to-play.shared-server-instance',
|
||||
defaultMessage: 'Shared server instance',
|
||||
},
|
||||
serverRequiresMods: {
|
||||
id: 'app.modal.install-to-play.server-requires-mods',
|
||||
defaultMessage:
|
||||
'This server requires mods to play. Click install to set up the required files from Modrinth.',
|
||||
},
|
||||
sharedByToday: {
|
||||
id: 'app.modal.install-to-play.shared-by-today',
|
||||
defaultMessage: '{name} shared this instance with you today.',
|
||||
},
|
||||
sharedInstance: {
|
||||
id: 'app.modal.install-to-play.shared-instance',
|
||||
defaultMessage: 'Shared instance',
|
||||
},
|
||||
modCount: {
|
||||
id: 'app.modal.install-to-play.mod-count',
|
||||
defaultMessage: '{count, plural, one {# mod} other {# mods}}',
|
||||
},
|
||||
installButton: {
|
||||
id: 'app.modal.install-to-play.install-button',
|
||||
defaultMessage: 'Install',
|
||||
},
|
||||
})
|
||||
|
||||
defineExpose({ show, hide })
|
||||
</script>
|
||||
@@ -7,15 +7,9 @@ import {
|
||||
MonitorIcon,
|
||||
WrenchIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Avatar,
|
||||
commonMessages,
|
||||
defineMessage,
|
||||
TabbedModal,
|
||||
type TabbedModalTab,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { Avatar, TabbedModal, type TabbedModalTab } from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { defineMessage, useVIntl } from '@vintl/vintl'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import GeneralSettings from '@/components/ui/instance_settings/GeneralSettings.vue'
|
||||
@@ -81,6 +75,11 @@ function show() {
|
||||
}
|
||||
|
||||
defineExpose({ show })
|
||||
|
||||
const titleMessage = defineMessage({
|
||||
id: 'instance.settings.title',
|
||||
defaultMessage: 'Settings',
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<ModalWrapper ref="modal">
|
||||
@@ -92,9 +91,7 @@ defineExpose({ show })
|
||||
:tint-by="props.instance.path"
|
||||
/>
|
||||
{{ instance.name }} <ChevronRightIcon />
|
||||
<span class="font-extrabold text-contrast">{{
|
||||
formatMessage(commonMessages.settingsLabel)
|
||||
}}</span>
|
||||
<span class="font-extrabold text-contrast">{{ formatMessage(titleMessage) }}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -12,10 +12,6 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
hideHeader: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
closable: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
@@ -53,14 +49,7 @@ function onModalHide() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
ref="modal"
|
||||
:header="header"
|
||||
:noblur="!themeStore.advancedRendering"
|
||||
:closable="closable"
|
||||
:hide-header="hideHeader"
|
||||
@hide="onModalHide"
|
||||
>
|
||||
<Modal ref="modal" :header="header" :noblur="!themeStore.advancedRendering" @hide="onModalHide">
|
||||
<template #title>
|
||||
<slot name="title" />
|
||||
</template>
|
||||
|
||||
@@ -1,382 +0,0 @@
|
||||
<template>
|
||||
<NewModal ref="modal" :header="formatMessage(messages.updateToPlay)" :closable="true" no-padding>
|
||||
<div class="max-w-[500px]">
|
||||
<div class="flex flex-col gap-4 p-4">
|
||||
<Admonition type="warning" :header="formatMessage(messages.updateRequired)">
|
||||
{{ formatMessage(messages.updateRequiredDescription, { name: instance.name }) }}
|
||||
</Admonition>
|
||||
|
||||
<div v-if="diffs.length" class="flex flex-col gap-2">
|
||||
<span v-if="publishedDate" class="text-contrast font-semibold">{{
|
||||
formatMessage(messages.publishedDate, { date: publishedDate })
|
||||
}}</span>
|
||||
<div class="flex gap-2">
|
||||
<div v-if="removedCount" class="flex gap-1 items-center">
|
||||
<MinusIcon />
|
||||
{{ formatMessage(messages.removedCount, { count: removedCount }) }}
|
||||
</div>
|
||||
<div v-if="addedCount" class="flex gap-1 items-center">
|
||||
<PlusIcon />
|
||||
{{ formatMessage(messages.addedCount, { count: addedCount }) }}
|
||||
</div>
|
||||
<div v-if="updatedCount" class="flex gap-1 items-center">
|
||||
<RefreshCwIcon />
|
||||
{{ formatMessage(messages.updatedCount, { count: updatedCount }) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="diffs.length" class="flex flex-col bg-surface-2 p-4 max-h-[272px] overflow-y-auto">
|
||||
<div
|
||||
v-for="diff in diffs"
|
||||
:key="diff.project_id"
|
||||
class="grid grid-cols-[auto_1fr_1fr_1fr] items-center min-h-10 h-10 gap-2"
|
||||
>
|
||||
<div class="flex flex-col justify-between items-center">
|
||||
<div class="w-[1px] h-2"></div>
|
||||
<PlusIcon v-if="diff.type === 'added'" />
|
||||
<MinusIcon v-else-if="diff.type === 'removed'" />
|
||||
<RefreshCwIcon v-else />
|
||||
<div class="bg-surface-5 w-[1px] h-2 relative top-1"></div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-1 col-span-2">
|
||||
<span class="text-sm">{{ formatMessage(diffTypeMessages[diff.type]) }}</span>
|
||||
<span
|
||||
v-if="diff.project"
|
||||
v-tooltip="diff.project.title"
|
||||
class="text-sm text-contrast font-medium truncate"
|
||||
>
|
||||
{{ diff.project.title }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span
|
||||
v-if="getFilename(diff.newVersion) || getFilename(diff.currentVersion)"
|
||||
v-tooltip="getFilename(diff.newVersion) || getFilename(diff.currentVersion)"
|
||||
class="text-xs truncate text-right"
|
||||
>
|
||||
{{ getFilename(diff.newVersion) || getFilename(diff.currentVersion) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #actions>
|
||||
<div class="flex justify-between gap-2">
|
||||
<ButtonStyled color="red" type="transparent">
|
||||
<button @click="handleReport">
|
||||
<ReportIcon />
|
||||
{{ formatMessage(commonMessages.reportButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<div class="flex gap-2">
|
||||
<ButtonStyled>
|
||||
<button @click="handleDecline">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button @click="handleUpdate">
|
||||
<DownloadIcon />
|
||||
{{ formatMessage(commonMessages.updateButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import {
|
||||
DownloadIcon,
|
||||
MinusIcon,
|
||||
PlusIcon,
|
||||
RefreshCwIcon,
|
||||
ReportIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
NewModal,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
import { get_project, get_project_many, get_version_many } from '@/helpers/cache.js'
|
||||
import { update_managed_modrinth_version } from '@/helpers/profile'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
|
||||
type Dependency = Labrinth.Versions.v3.Dependency
|
||||
type Version = Labrinth.Versions.v2.Version
|
||||
|
||||
interface BaseDiff {
|
||||
project_id: string
|
||||
project?: {
|
||||
title: string
|
||||
icon_url?: string
|
||||
slug: string
|
||||
}
|
||||
currentVersionId?: string
|
||||
newVersionId?: string
|
||||
currentVersion?: Version
|
||||
newVersion?: Version
|
||||
}
|
||||
interface AddedDiff extends BaseDiff {
|
||||
type: 'added'
|
||||
newVersionId: string
|
||||
}
|
||||
interface RemovedDiff extends BaseDiff {
|
||||
type: 'removed'
|
||||
}
|
||||
interface UpdatedDiff extends BaseDiff {
|
||||
type: 'updated'
|
||||
currentVersionId: string
|
||||
newVersionId: string
|
||||
}
|
||||
type DependencyDiff = AddedDiff | RemovedDiff | UpdatedDiff
|
||||
|
||||
type ProjectInfo = {
|
||||
id: string
|
||||
title: string
|
||||
icon_url?: string
|
||||
slug: string
|
||||
}
|
||||
|
||||
const { instance } = defineProps<{
|
||||
instance: GameInstance
|
||||
}>()
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const modal = ref<InstanceType<typeof NewModal>>()
|
||||
const diffs = ref<DependencyDiff[]>([])
|
||||
const latestVersionId = ref<string | null>(null)
|
||||
const latestVersion = ref<Version | null>(null)
|
||||
|
||||
const removedCount = computed(() => diffs.value.filter((d) => d.type === 'removed').length)
|
||||
const addedCount = computed(() => diffs.value.filter((d) => d.type === 'added').length)
|
||||
const updatedCount = computed(() => diffs.value.filter((d) => d.type === 'updated').length)
|
||||
const publishedDate = computed(() =>
|
||||
latestVersion.value?.date_published ? new Date(latestVersion.value.date_published) : null,
|
||||
)
|
||||
|
||||
function getFilename(version?: Version): string | undefined {
|
||||
return version?.files.find((f) => f.primary)?.filename
|
||||
}
|
||||
|
||||
async function computeDependencyDiffs(
|
||||
currentDeps: Dependency[],
|
||||
latestDeps: Dependency[],
|
||||
): Promise<DependencyDiff[]> {
|
||||
const currentByProject = new Map<string, Dependency>(
|
||||
currentDeps.map((d) => [d.project_id || '', d]),
|
||||
)
|
||||
const latestByProject = new Map<string, Dependency>(
|
||||
latestDeps.map((d) => [d.project_id || '', d]),
|
||||
)
|
||||
|
||||
const diffs: DependencyDiff[] = []
|
||||
|
||||
// Find added and updated dependencies
|
||||
latestByProject.forEach((latestDep, projectId) => {
|
||||
if (!projectId) return
|
||||
const currentDep = currentByProject.get(projectId)
|
||||
if (!currentDep && latestDep.version_id) {
|
||||
diffs.push({ type: 'added', project_id: projectId, newVersionId: latestDep.version_id })
|
||||
} else if (
|
||||
currentDep?.version_id &&
|
||||
latestDep?.version_id &&
|
||||
currentDep?.version_id !== latestDep.version_id
|
||||
) {
|
||||
diffs.push({
|
||||
type: 'updated',
|
||||
project_id: projectId,
|
||||
currentVersionId: currentDep.version_id,
|
||||
newVersionId: latestDep.version_id,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Find removed dependencies
|
||||
currentByProject.forEach((currentDep, projectId) => {
|
||||
if (!projectId) return
|
||||
if (!latestByProject.has(projectId)) {
|
||||
diffs.push({
|
||||
type: 'removed',
|
||||
project_id: projectId,
|
||||
currentVersionId: currentDep.version_id,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Fetch projects and versions of diffs
|
||||
const allProjectIds = [...new Set(diffs.map((d) => d.project_id).filter(Boolean))]
|
||||
const allVersionIds = [
|
||||
...new Set(
|
||||
[...diffs.map((d) => d.newVersionId), ...diffs.map((d) => d.currentVersionId)].filter(
|
||||
Boolean,
|
||||
),
|
||||
),
|
||||
] as string[]
|
||||
const [projects, versions] = await Promise.all([
|
||||
get_project_many(allProjectIds, 'must_revalidate'),
|
||||
get_version_many(allVersionIds, 'must_revalidate'),
|
||||
])
|
||||
|
||||
const projectMap = new Map<string, ProjectInfo>(projects.map((p: ProjectInfo) => [p.id, p]))
|
||||
const versionMap = new Map<string, Version>(versions.map((v: Version) => [v.id, v]))
|
||||
|
||||
return diffs
|
||||
.map((diff) => {
|
||||
const project = projectMap.get(diff.project_id)
|
||||
return {
|
||||
...diff,
|
||||
project: project
|
||||
? { title: project.title, icon_url: project.icon_url, slug: project.slug }
|
||||
: undefined,
|
||||
currentVersion: diff.currentVersionId ? versionMap.get(diff.currentVersionId) : undefined,
|
||||
newVersion: diff.newVersionId ? versionMap.get(diff.newVersionId) : undefined,
|
||||
}
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const typeOrder = { removed: 0, added: 1, updated: 2 }
|
||||
const typeCompare = typeOrder[a.type] - typeOrder[b.type]
|
||||
if (typeCompare !== 0) return typeCompare
|
||||
|
||||
const aDate = a.newVersion?.date_published || a.currentVersion?.date_published || ''
|
||||
const bDate = b.newVersion?.date_published || b.currentVersion?.date_published || ''
|
||||
return dayjs(bDate).valueOf() - dayjs(aDate).valueOf()
|
||||
})
|
||||
}
|
||||
|
||||
async function checkUpdateAvailable(instance: GameInstance): Promise<DependencyDiff[] | null> {
|
||||
if (!instance.linked_data) return null
|
||||
|
||||
try {
|
||||
const project = await get_project(instance.linked_data.project_id, 'must_revalidate')
|
||||
if (!project || !project.versions || project.versions.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const versions = await get_version_many(project.versions, 'must_revalidate')
|
||||
const sortedVersions = versions.sort(
|
||||
(a: { date_published: string }, b: { date_published: string }) =>
|
||||
dayjs(b.date_published).valueOf() - dayjs(a.date_published).valueOf(),
|
||||
)
|
||||
|
||||
latestVersion.value = sortedVersions[0]
|
||||
latestVersionId.value = latestVersion.value?.id || null
|
||||
|
||||
const currentVersionId = instance.linked_data.version_id
|
||||
const currentVersion = versions.find((v: { id: string }) => v.id === currentVersionId)
|
||||
|
||||
// Compute dependency diffs between current and latest version
|
||||
if (currentVersion && latestVersion.value) {
|
||||
return await computeDependencyDiffs(
|
||||
currentVersion.dependencies || [],
|
||||
latestVersion.value.dependencies || [],
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking for updates:', error)
|
||||
return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
watch(
|
||||
() => instance,
|
||||
async () => {
|
||||
const result = await checkUpdateAvailable(instance)
|
||||
diffs.value = result || []
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
|
||||
async function handleUpdate() {
|
||||
hide()
|
||||
try {
|
||||
if (latestVersionId.value) {
|
||||
await update_managed_modrinth_version(instance.path, latestVersionId.value)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error updating instance:', error)
|
||||
}
|
||||
}
|
||||
|
||||
function handleReport() {
|
||||
if (instance.linked_data?.project_id) {
|
||||
openUrl(`https://modrinth.com/report?item=project&itemID=${instance.linked_data.project_id}`)
|
||||
}
|
||||
}
|
||||
|
||||
function handleDecline() {
|
||||
hide()
|
||||
}
|
||||
|
||||
function show(e?: MouseEvent) {
|
||||
modal.value?.show(e)
|
||||
}
|
||||
|
||||
function hide() {
|
||||
modal.value?.hide()
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
updateToPlay: {
|
||||
id: 'app.modal.update-to-play.header',
|
||||
defaultMessage: 'Update to play',
|
||||
},
|
||||
updateRequired: {
|
||||
id: 'app.modal.update-to-play.update-required',
|
||||
defaultMessage: 'Update required',
|
||||
},
|
||||
updateRequiredDescription: {
|
||||
id: 'app.modal.update-to-play.update-required-description',
|
||||
defaultMessage:
|
||||
'An update is required to play {name}. Please update to the latest version to launch the game.',
|
||||
},
|
||||
publishedDate: {
|
||||
id: 'app.modal.update-to-play.published-date',
|
||||
defaultMessage: '{date, date, long}',
|
||||
},
|
||||
removedCount: {
|
||||
id: 'app.modal.update-to-play.removed-count',
|
||||
defaultMessage: '{count} removed',
|
||||
},
|
||||
addedCount: {
|
||||
id: 'app.modal.update-to-play.added-count',
|
||||
defaultMessage: '{count} added',
|
||||
},
|
||||
updatedCount: {
|
||||
id: 'app.modal.update-to-play.updated-count',
|
||||
defaultMessage: '{count} updated',
|
||||
},
|
||||
})
|
||||
|
||||
const diffTypeMessages = defineMessages({
|
||||
added: {
|
||||
id: 'app.modal.update-to-play.diff-type.added',
|
||||
defaultMessage: 'Added',
|
||||
},
|
||||
removed: {
|
||||
id: 'app.modal.update-to-play.diff-type.removed',
|
||||
defaultMessage: 'Removed',
|
||||
},
|
||||
updated: {
|
||||
id: 'app.modal.update-to-play.diff-type.updated',
|
||||
defaultMessage: 'Updated',
|
||||
},
|
||||
})
|
||||
|
||||
defineExpose({ show, hide })
|
||||
</script>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { Combobox, ThemeSelector, Toggle } from '@modrinth/ui'
|
||||
import { TeleportDropdownMenu, ThemeSelector, Toggle } from '@modrinth/ui'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import { get, set } from '@/helpers/settings.ts'
|
||||
@@ -50,7 +50,7 @@ watch(
|
||||
:model-value="themeStore.advancedRendering"
|
||||
@update:model-value="
|
||||
(e) => {
|
||||
themeStore.advancedRendering = !!e
|
||||
themeStore.advancedRendering = e
|
||||
settings.advanced_rendering = themeStore.advancedRendering
|
||||
}
|
||||
"
|
||||
@@ -86,13 +86,12 @@ watch(
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Default landing page</h2>
|
||||
<p class="m-0 mt-1">Change the page to which the launcher opens on.</p>
|
||||
</div>
|
||||
<Combobox
|
||||
<TeleportDropdownMenu
|
||||
id="opening-page"
|
||||
v-model="settings.default_page"
|
||||
name="Opening page dropdown"
|
||||
class="w-40"
|
||||
:options="['Home', 'Library'].map((v) => ({ value: v, label: v }))"
|
||||
:display-value="settings.default_page ?? 'Select an option'"
|
||||
:options="['Home', 'Library']"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -123,7 +122,7 @@ watch(
|
||||
:model-value="settings.toggle_sidebar"
|
||||
@update:model-value="
|
||||
(e) => {
|
||||
settings.toggle_sidebar = !!e
|
||||
settings.toggle_sidebar = e
|
||||
themeStore.toggleSidebar = settings.toggle_sidebar
|
||||
}
|
||||
"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { injectNotificationManager, Slider, StyledInput, Toggle } from '@modrinth/ui'
|
||||
import { injectNotificationManager, Slider, Toggle } from '@modrinth/ui'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import useMemorySlider from '@/composables/useMemorySlider'
|
||||
@@ -73,7 +73,7 @@ watch(
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<StyledInput
|
||||
<input
|
||||
id="width"
|
||||
v-model="settings.game_resolution[0]"
|
||||
:disabled="settings.force_fullscreen"
|
||||
@@ -91,12 +91,13 @@ watch(
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<StyledInput
|
||||
<input
|
||||
id="height"
|
||||
v-model="settings.game_resolution[1]"
|
||||
:disabled="settings.force_fullscreen"
|
||||
autocomplete="off"
|
||||
type="number"
|
||||
class="input"
|
||||
placeholder="Enter height..."
|
||||
/>
|
||||
</div>
|
||||
@@ -117,23 +118,23 @@ watch(
|
||||
/>
|
||||
|
||||
<h2 class="mt-4 mb-2 text-lg font-extrabold text-contrast">Java arguments</h2>
|
||||
<StyledInput
|
||||
<input
|
||||
id="java-args"
|
||||
v-model="settings.launchArgs"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter java arguments..."
|
||||
wrapper-class="w-full"
|
||||
class="w-full"
|
||||
/>
|
||||
|
||||
<h2 class="mt-4 mb-2 text-lg font-extrabold text-contrast">Environmental variables</h2>
|
||||
<StyledInput
|
||||
<input
|
||||
id="env-vars"
|
||||
v-model="settings.envVars"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter environmental variables..."
|
||||
wrapper-class="w-full"
|
||||
class="w-full"
|
||||
/>
|
||||
|
||||
<hr class="mt-4 bg-button-border border-none h-[1px]" />
|
||||
@@ -142,37 +143,37 @@ watch(
|
||||
|
||||
<h3 class="mt-2 m-0 text-base font-extrabold text-primary">Pre launch</h3>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">Ran before the instance is launched.</p>
|
||||
<StyledInput
|
||||
<input
|
||||
id="pre-launch"
|
||||
v-model="settings.hooks.pre_launch"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter pre-launch command..."
|
||||
wrapper-class="w-full"
|
||||
class="w-full"
|
||||
/>
|
||||
|
||||
<h3 class="mt-2 m-0 text-base font-extrabold text-primary">Wrapper</h3>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">
|
||||
Wrapper command for launching Minecraft.
|
||||
</p>
|
||||
<StyledInput
|
||||
<input
|
||||
id="wrapper"
|
||||
v-model="settings.hooks.wrapper"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter wrapper command..."
|
||||
wrapper-class="w-full"
|
||||
class="w-full"
|
||||
/>
|
||||
|
||||
<h3 class="mt-2 m-0 text-base font-extrabold text-primary">Post exit</h3>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">Ran after the game closes.</p>
|
||||
<StyledInput
|
||||
<input
|
||||
id="post-exit"
|
||||
v-model="settings.hooks.post_exit"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter post-exit command..."
|
||||
wrapper-class="w-full"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -21,7 +21,7 @@ async function updateJavaVersion(version) {
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div v-for="(javaVersion, index) in [25, 21, 17, 8]" :key="`java-${javaVersion}`">
|
||||
<div v-for="(javaVersion, index) in [21, 17, 8]" :key="`java-${javaVersion}`">
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast" :class="{ 'mt-4': index !== 0 }">
|
||||
Java {{ javaVersion }} location
|
||||
</h2>
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Admonition,
|
||||
AutoLink,
|
||||
IntlFormatted,
|
||||
LanguageSelector,
|
||||
languageSelectorMessages,
|
||||
LOCALES,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import { get, set } from '@/helpers/settings.ts'
|
||||
import i18n from '@/i18n.config'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const platform = formatMessage(languageSelectorMessages.platformApp)
|
||||
|
||||
const settings = ref(await get())
|
||||
|
||||
watch(
|
||||
settings,
|
||||
async () => {
|
||||
await set(settings.value)
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
const $isChanging = ref(false)
|
||||
|
||||
async function onLocaleChange(newLocale: string) {
|
||||
if (settings.value.locale === newLocale) return
|
||||
|
||||
$isChanging.value = true
|
||||
try {
|
||||
i18n.global.locale.value = newLocale
|
||||
settings.value.locale = newLocale
|
||||
} finally {
|
||||
$isChanging.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Language</h2>
|
||||
|
||||
<Admonition type="warning" class="mt-2 mb-4">
|
||||
{{ formatMessage(languageSelectorMessages.languageWarning, { platform }) }}
|
||||
</Admonition>
|
||||
|
||||
<p class="m-0 mb-4">
|
||||
<IntlFormatted
|
||||
:message-id="languageSelectorMessages.languagesDescription"
|
||||
:values="{ platform }"
|
||||
>
|
||||
<template #~crowdin-link="{ children }">
|
||||
<AutoLink to="https://translate.modrinth.com">
|
||||
<component :is="() => children" />
|
||||
</AutoLink>
|
||||
</template>
|
||||
</IntlFormatted>
|
||||
</p>
|
||||
|
||||
<LanguageSelector
|
||||
:current-locale="settings.locale"
|
||||
:locales="LOCALES"
|
||||
:on-locale-change="onLocaleChange"
|
||||
:is-changing="$isChanging"
|
||||
/>
|
||||
</template>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { BoxIcon, FolderSearchIcon, TrashIcon } from '@modrinth/assets'
|
||||
import { Button, injectNotificationManager, Slider, StyledInput } from '@modrinth/ui'
|
||||
import { Button, injectNotificationManager, Slider } from '@modrinth/ui'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
@@ -65,19 +65,13 @@ async function findLauncherDir() {
|
||||
</p>
|
||||
|
||||
<div class="m-1 my-2">
|
||||
<StyledInput
|
||||
id="appDir"
|
||||
v-model="settings.custom_dir"
|
||||
:icon="BoxIcon"
|
||||
type="text"
|
||||
wrapper-class="w-full"
|
||||
>
|
||||
<template #right>
|
||||
<Button class="r-btn" @click="findLauncherDir">
|
||||
<FolderSearchIcon />
|
||||
</Button>
|
||||
</template>
|
||||
</StyledInput>
|
||||
<div class="iconified-input w-full">
|
||||
<BoxIcon />
|
||||
<input id="appDir" v-model="settings.custom_dir" type="text" class="input" />
|
||||
<Button class="r-btn" @click="findLauncherDir">
|
||||
<FolderSearchIcon />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
@@ -130,7 +130,6 @@ import {
|
||||
remove_custom_skin,
|
||||
type Skin,
|
||||
type SkinModel,
|
||||
type SkinTextureUrl,
|
||||
unequip_skin,
|
||||
} from '@/helpers/skins.ts'
|
||||
|
||||
@@ -143,7 +142,7 @@ const currentSkin = ref<Skin | null>(null)
|
||||
const shouldRestoreModal = ref(false)
|
||||
const isSaving = ref(false)
|
||||
|
||||
const uploadedTextureUrl = ref<SkinTextureUrl | null>(null)
|
||||
const uploadedTextureUrl = ref<string | null>(null)
|
||||
const previewSkin = ref<string>('')
|
||||
|
||||
const variant = ref<SkinModel>('CLASSIC')
|
||||
@@ -189,7 +188,7 @@ function getSortedCapeExcluding(excludeId: string): Cape | undefined {
|
||||
|
||||
async function loadPreviewSkin() {
|
||||
if (uploadedTextureUrl.value) {
|
||||
previewSkin.value = uploadedTextureUrl.value.normalized
|
||||
previewSkin.value = uploadedTextureUrl.value
|
||||
} else if (currentSkin.value) {
|
||||
try {
|
||||
previewSkin.value = await get_normalized_skin_texture(currentSkin.value)
|
||||
@@ -254,11 +253,11 @@ async function show(e: MouseEvent, skin?: Skin) {
|
||||
modal.value?.show(e)
|
||||
}
|
||||
|
||||
async function showNew(e: MouseEvent, skinTextureUrl: SkinTextureUrl) {
|
||||
async function showNew(e: MouseEvent, skinTextureUrl: string) {
|
||||
mode.value = 'new'
|
||||
currentSkin.value = null
|
||||
uploadedTextureUrl.value = skinTextureUrl
|
||||
variant.value = await determineModelType(skinTextureUrl.original)
|
||||
variant.value = await determineModelType(skinTextureUrl)
|
||||
selectedCape.value = undefined
|
||||
visibleCapeList.value = []
|
||||
initVisibleCapeList()
|
||||
@@ -268,7 +267,7 @@ async function showNew(e: MouseEvent, skinTextureUrl: SkinTextureUrl) {
|
||||
modal.value?.show(e)
|
||||
}
|
||||
|
||||
async function restoreWithNewTexture(skinTextureUrl: SkinTextureUrl) {
|
||||
async function restoreWithNewTexture(skinTextureUrl: string) {
|
||||
uploadedTextureUrl.value = skinTextureUrl
|
||||
await loadPreviewSkin()
|
||||
|
||||
@@ -362,7 +361,7 @@ async function save() {
|
||||
let textureUrl: string
|
||||
|
||||
if (uploadedTextureUrl.value) {
|
||||
textureUrl = uploadedTextureUrl.value.original
|
||||
textureUrl = uploadedTextureUrl.value
|
||||
} else {
|
||||
textureUrl = currentSkin.value!.texture
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ import {
|
||||
OverflowMenu,
|
||||
SmartClickable,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { capitalizeString } from '@modrinth/utils'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { useVIntl } from '@vintl/vintl'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||
@@ -130,7 +130,7 @@ onUnmounted(() => {
|
||||
/>
|
||||
</template>
|
||||
<div
|
||||
class="grid grid-cols-[auto_minmax(0,3fr)_minmax(0,4fr)_auto] items-center gap-2 p-3 bg-bg-raised card-shadow rounded-xl smart-clickable:highlight-on-hover"
|
||||
class="grid grid-cols-[auto_minmax(0,3fr)_minmax(0,4fr)_auto] items-center gap-2 p-3 bg-bg-raised rounded-xl smart-clickable:highlight-on-hover"
|
||||
>
|
||||
<Avatar
|
||||
:src="instanceIcon ? convertFileSrc(instanceIcon) : undefined"
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { LoaderCircleIcon } from '@modrinth/assets'
|
||||
import type { GameVersion } from '@modrinth/ui'
|
||||
import { GAME_MODES, HeadingLink, injectNotificationManager } from '@modrinth/ui'
|
||||
import { platform } from '@tauri-apps/plugin-os'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
@@ -41,7 +39,6 @@ const props = defineProps<{
|
||||
const theme = useTheming()
|
||||
|
||||
const jumpBackInItems = ref<JumpBackInItem[]>([])
|
||||
const loading = ref(true)
|
||||
const serverData = ref<Record<string, ServerData>>({})
|
||||
const protocolVersions = ref<Record<string, ProtocolVersion | null>>({})
|
||||
const gameVersions = ref<GameVersion[]>(await get_game_versions().catch(() => []))
|
||||
@@ -49,11 +46,6 @@ const gameVersions = ref<GameVersion[]>(await get_game_versions().catch(() => []
|
||||
const MIN_JUMP_BACK_IN = 3
|
||||
const MAX_JUMP_BACK_IN = 6
|
||||
const TWO_WEEKS_AGO = dayjs().subtract(14, 'day')
|
||||
const MAX_LINUX_POPULATES = 3
|
||||
|
||||
// Track populate calls on Linux to prevent server ping spam
|
||||
const isLinux = platform() === 'linux'
|
||||
const linuxPopulateCount = ref(0)
|
||||
|
||||
type BaseJumpBackInItem = {
|
||||
last_played: Dayjs
|
||||
@@ -79,19 +71,11 @@ watch([() => props.recentInstances, () => showWorlds.value], async () => {
|
||||
})
|
||||
})
|
||||
|
||||
populateJumpBackIn()
|
||||
.catch(() => {
|
||||
console.error('Failed to populate jump back in')
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
await populateJumpBackIn().catch(() => {
|
||||
console.error('Failed to populate jump back in')
|
||||
})
|
||||
|
||||
async function populateJumpBackIn() {
|
||||
// On Linux, limit automatic populates to prevent server ping spam
|
||||
if (isLinux && linuxPopulateCount.value >= MAX_LINUX_POPULATES) return
|
||||
if (isLinux) linuxPopulateCount.value++
|
||||
|
||||
console.info('Repopulating jump back in...')
|
||||
|
||||
const worldItems: WorldJumpBackInItem[] = []
|
||||
@@ -240,7 +224,6 @@ const checkProcesses = async () => {
|
||||
|
||||
onMounted(() => {
|
||||
checkProcesses()
|
||||
linuxPopulateCount.value = 0
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -250,15 +233,7 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="loading" class="flex flex-col gap-2">
|
||||
<span class="flex mt-1 mb-3 leading-none items-center gap-1 text-primary text-lg font-bold">
|
||||
Jump back in
|
||||
</span>
|
||||
<div class="text-center py-4">
|
||||
<LoaderCircleIcon class="mx-auto size-8 animate-spin text-contrast" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="jumpBackInItems.length > 0" class="flex flex-col gap-2">
|
||||
<div v-if="jumpBackInItems.length > 0" class="flex flex-col gap-2">
|
||||
<HeadingLink v-if="theme.getFeatureFlag('worlds_tab')" to="/worlds" class="mt-1">
|
||||
Jump back in
|
||||
</HeadingLink>
|
||||
|
||||
@@ -17,19 +17,18 @@ import {
|
||||
UserIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import type { MessageDescriptor } from '@modrinth/ui'
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
OverflowMenu,
|
||||
SmartClickable,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { formatNumber, getPingLevel } from '@modrinth/utils'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import type { MessageDescriptor } from '@vintl/vintl'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import dayjs from 'dayjs'
|
||||
import { Tooltip } from 'floating-vue'
|
||||
import type { Component } from 'vue'
|
||||
@@ -182,16 +181,14 @@ const messages = defineMessages({
|
||||
/>
|
||||
</template>
|
||||
<div
|
||||
class="grid grid-cols-[auto_minmax(0,3fr)_minmax(0,4fr)_auto] items-center gap-2 p-3 bg-bg-raised card-shadow smart-clickable:highlight-on-hover rounded-xl"
|
||||
class="grid grid-cols-[auto_minmax(0,3fr)_minmax(0,4fr)_auto] items-center gap-2 p-3 bg-bg-raised smart-clickable:highlight-on-hover rounded-xl"
|
||||
:class="{
|
||||
'world-item-highlighted': highlighted,
|
||||
}"
|
||||
>
|
||||
<Avatar
|
||||
:src="
|
||||
world.type === 'server' && serverStatus
|
||||
? (serverStatus.favicon ?? world.icon)
|
||||
: world.icon
|
||||
world.type === 'server' && serverStatus ? serverStatus.favicon ?? world.icon : world.icon
|
||||
"
|
||||
size="48px"
|
||||
/>
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { PlayIcon, PlusIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { ButtonStyled, commonMessages, injectNotificationManager } from '@modrinth/ui'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import InstanceModalTitlePrefix from '@/components/ui/modal/InstanceModalTitlePrefix.vue'
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { SaveIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessage,
|
||||
injectNotificationManager,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { ButtonStyled, commonMessages, injectNotificationManager } from '@modrinth/ui'
|
||||
import { defineMessage, useVIntl } from '@vintl/vintl'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ChevronRightIcon, SaveIcon, UndoIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { Avatar, ButtonStyled, commonMessages, injectNotificationManager } from '@modrinth/ui'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
@@ -104,11 +97,12 @@ const messages = defineMessages({
|
||||
<h2 class="text-lg font-extrabold text-contrast mt-0 mb-1">
|
||||
{{ formatMessage(messages.name) }}
|
||||
</h2>
|
||||
<StyledInput
|
||||
<input
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.placeholderName)"
|
||||
class="w-full"
|
||||
autocomplete="off"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<HideFromHomeOption v-model="hideFromHome" class="mt-3" />
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { Checkbox, defineMessage, useVIntl } from '@modrinth/ui'
|
||||
import { Checkbox } from '@modrinth/ui'
|
||||
import { defineMessage, useVIntl } from '@vintl/vintl'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Combobox,
|
||||
defineMessages,
|
||||
type MessageDescriptor,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { TeleportDropdownMenu } from '@modrinth/ui'
|
||||
import { defineMessages, type MessageDescriptor, useVIntl } from '@vintl/vintl'
|
||||
|
||||
import type { ServerPackStatus } from '@/helpers/worlds.ts'
|
||||
|
||||
@@ -58,38 +53,33 @@ defineExpose({ resourcePackOptions })
|
||||
<h2 class="text-lg font-extrabold text-contrast mt-0 mb-1">
|
||||
{{ formatMessage(messages.name) }}
|
||||
</h2>
|
||||
<StyledInput
|
||||
<input
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.placeholderName)"
|
||||
class="w-full"
|
||||
autocomplete="off"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<h2 class="text-lg font-extrabold text-contrast mt-3 mb-1">
|
||||
{{ formatMessage(messages.address) }}
|
||||
</h2>
|
||||
<StyledInput
|
||||
<input
|
||||
v-model="address"
|
||||
type="text"
|
||||
placeholder="example.modrinth.gg"
|
||||
class="w-full"
|
||||
autocomplete="off"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<h2 class="text-lg font-extrabold text-contrast mt-3 mb-1">
|
||||
{{ formatMessage(messages.resourcePack) }}
|
||||
</h2>
|
||||
<div>
|
||||
<Combobox
|
||||
<TeleportDropdownMenu
|
||||
v-model="resourcePack"
|
||||
:options="
|
||||
resourcePackOptions.map((o) => ({
|
||||
value: o,
|
||||
label: formatMessage(resourcePackOptionMessages[o]),
|
||||
}))
|
||||
"
|
||||
:options="resourcePackOptions"
|
||||
name="Server resource pack"
|
||||
:display-value="
|
||||
resourcePack
|
||||
? formatMessage(resourcePackOptionMessages[resourcePack])
|
||||
: 'Select an option'
|
||||
:display-name="
|
||||
(option: ServerPackStatus) => formatMessage(resourcePackOptionMessages[option])
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { posthog } from 'posthog-js'
|
||||
|
||||
export const initAnalytics = () => {
|
||||
posthog.init('phc_9Iqi6lFs9sr5BSqh9RRNRSJ0mATS9PSgirDiX3iOYJ', {
|
||||
persistence: 'localStorage',
|
||||
api_host: 'https://posthog.modrinth.com',
|
||||
})
|
||||
}
|
||||
|
||||
export const debugAnalytics = () => {
|
||||
posthog.debug()
|
||||
}
|
||||
|
||||
export const optOutAnalytics = () => {
|
||||
posthog.opt_out_capturing()
|
||||
}
|
||||
|
||||
export const optInAnalytics = () => {
|
||||
posthog.opt_in_capturing()
|
||||
}
|
||||
|
||||
export const trackEvent = (eventName, properties) => {
|
||||
posthog.capture(eventName, properties)
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
import { posthog } from 'posthog-js'
|
||||
|
||||
interface InstanceProperties {
|
||||
loader: string
|
||||
game_version: string
|
||||
}
|
||||
|
||||
interface ProjectProperties extends InstanceProperties {
|
||||
id: string
|
||||
project_type: string
|
||||
}
|
||||
|
||||
type AnalyticsEventMap = {
|
||||
Launched: { version: string; dev: boolean; onboarded: boolean }
|
||||
PageView: { path: string; fromPath: string; failed: unknown }
|
||||
InstanceCreate: { source: string }
|
||||
InstanceCreateStart: { source: string }
|
||||
InstancePlay: InstanceProperties & { source: string }
|
||||
InstanceStop: Partial<InstanceProperties> & { source?: string }
|
||||
InstanceDuplicate: InstanceProperties
|
||||
InstanceRepair: InstanceProperties
|
||||
InstanceSetIcon: Record<string, never>
|
||||
InstanceRemoveIcon: Record<string, never>
|
||||
InstanceUpdateAll: InstanceProperties & { count: number; selected: boolean }
|
||||
InstanceProjectUpdate: InstanceProperties & { id: string; name: string; project_type: string }
|
||||
InstanceProjectDisable: InstanceProperties & {
|
||||
id: string
|
||||
name: string
|
||||
project_type: string
|
||||
disabled: boolean
|
||||
}
|
||||
InstanceProjectRemove: InstanceProperties & { id: string; name: string; project_type: string }
|
||||
ProjectInstall: ProjectProperties & { version_id: string; title: string; source: string }
|
||||
ProjectInstallStart: { source: string }
|
||||
PackInstall: { id: string; version_id: string; title: string; source: string }
|
||||
PackInstallStart: Record<string, never>
|
||||
AccountLogIn: { source?: string }
|
||||
AccountLogOut: Record<string, never>
|
||||
JavaTest: { path: string; success: boolean }
|
||||
JavaManualSelect: { version: string }
|
||||
JavaAutoDetect: { path: string; version: string }
|
||||
}
|
||||
|
||||
export type AnalyticsEvent = keyof AnalyticsEventMap
|
||||
|
||||
let initialized = false
|
||||
|
||||
export const initAnalytics = () => {
|
||||
if (initialized) return
|
||||
posthog.init('phc_9Iqi6lFs9sr5BSqh9RRNRSJ0mATS9PSgirDiX3iOYJ', {
|
||||
persistence: 'localStorage',
|
||||
api_host: 'https://posthog.modrinth.com',
|
||||
})
|
||||
initialized = true
|
||||
}
|
||||
|
||||
export const debugAnalytics = () => {
|
||||
if (!initialized) return
|
||||
posthog.debug()
|
||||
}
|
||||
|
||||
export const optOutAnalytics = () => {
|
||||
if (!initialized) return
|
||||
posthog.opt_out_capturing()
|
||||
}
|
||||
|
||||
export const optInAnalytics = () => {
|
||||
initAnalytics()
|
||||
posthog.opt_in_capturing()
|
||||
}
|
||||
|
||||
type OptionalArgs<T> = Record<string, never> extends T ? [properties?: T] : [properties: T]
|
||||
|
||||
export const trackEvent = <E extends AnalyticsEvent>(
|
||||
eventName: E,
|
||||
...args: OptionalArgs<AnalyticsEventMap[E]>
|
||||
) => {
|
||||
if (!initialized) return
|
||||
posthog.capture(eventName, args[0])
|
||||
}
|
||||
@@ -13,14 +13,6 @@ import { invoke } from '@tauri-apps/api/core'
|
||||
// await authenticate_await_completion()
|
||||
// }
|
||||
|
||||
/**
|
||||
* Check if the authentication servers are reachable, throwing an exception if
|
||||
* not reachable.
|
||||
*/
|
||||
export async function check_reachable() {
|
||||
await invoke('plugin:auth|check_reachable')
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a user with Hydra - part 1.
|
||||
* This begins the authentication flow quasi-synchronously.
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
export async function friends() {
|
||||
return await invoke('plugin:friends|friends')
|
||||
}
|
||||
|
||||
export async function friend_statuses() {
|
||||
return await invoke('plugin:friends|friend_statuses')
|
||||
}
|
||||
|
||||
export async function add_friend(userId) {
|
||||
return await invoke('plugin:friends|add_friend', { userId })
|
||||
}
|
||||
|
||||
export async function remove_friend(userId) {
|
||||
return await invoke('plugin:friends|remove_friend', { userId })
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import type { User } from '@modrinth/utils'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
import { get_user_many } from '@/helpers/cache'
|
||||
import type { ModrinthCredentials } from '@/helpers/mr_auth'
|
||||
|
||||
export type UserStatus = {
|
||||
user_id: string
|
||||
profile_name: string | null
|
||||
last_update: string
|
||||
}
|
||||
|
||||
export type UserFriend = {
|
||||
id: string
|
||||
friend_id: string
|
||||
accepted: boolean
|
||||
created: string
|
||||
}
|
||||
|
||||
export async function friends(): Promise<UserFriend[]> {
|
||||
return await invoke('plugin:friends|friends')
|
||||
}
|
||||
|
||||
export async function friend_statuses(): Promise<UserStatus[]> {
|
||||
return await invoke('plugin:friends|friend_statuses')
|
||||
}
|
||||
|
||||
export async function add_friend(userId: string): Promise<void> {
|
||||
return await invoke('plugin:friends|add_friend', { userId })
|
||||
}
|
||||
|
||||
export async function remove_friend(userId: string): Promise<void> {
|
||||
return await invoke('plugin:friends|remove_friend', { userId })
|
||||
}
|
||||
|
||||
export type FriendWithUserData = {
|
||||
id: string
|
||||
friend_id: string | null
|
||||
status: string | null
|
||||
last_updated: Dayjs | null
|
||||
created: Dayjs
|
||||
username: string
|
||||
accepted: boolean
|
||||
online: boolean
|
||||
avatar: string
|
||||
}
|
||||
export async function transformFriends(
|
||||
friends: UserFriend[],
|
||||
credentials: ModrinthCredentials | null,
|
||||
): Promise<FriendWithUserData[]> {
|
||||
if (friends.length === 0 || !credentials) {
|
||||
return []
|
||||
}
|
||||
|
||||
const friendStatuses = await friend_statuses()
|
||||
const users = await get_user_many(
|
||||
friends.map((x) => (x.id === credentials.user_id ? x.friend_id : x.id)),
|
||||
)
|
||||
|
||||
return friends.map((friend) => {
|
||||
const user = users.find((x: User) => x.id === friend.id || x.id === friend.friend_id)
|
||||
const status = friendStatuses.find(
|
||||
(x) => x.user_id === friend.id || x.user_id === friend.friend_id,
|
||||
)
|
||||
return {
|
||||
id: friend.id,
|
||||
friend_id: friend.friend_id,
|
||||
status: status?.profile_name ?? null,
|
||||
last_updated: status && status.last_update ? dayjs(status.last_update) : null,
|
||||
created: dayjs(friend.created),
|
||||
avatar: user?.avatar_url ?? '',
|
||||
username: user?.username ?? '',
|
||||
online: !!status,
|
||||
accepted: friend.accepted,
|
||||
}
|
||||
})
|
||||
}
|
||||
+4
-11
@@ -5,25 +5,18 @@
|
||||
*/
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
export type ModrinthCredentials = {
|
||||
session: string
|
||||
expires: string
|
||||
user_id: string
|
||||
active: boolean
|
||||
}
|
||||
|
||||
export async function login(): Promise<ModrinthCredentials> {
|
||||
export async function login() {
|
||||
return await invoke('plugin:mr-auth|modrinth_login')
|
||||
}
|
||||
|
||||
export async function logout(): Promise<void> {
|
||||
export async function logout() {
|
||||
return await invoke('plugin:mr-auth|logout')
|
||||
}
|
||||
|
||||
export async function get(): Promise<ModrinthCredentials | null> {
|
||||
export async function get() {
|
||||
return await invoke('plugin:mr-auth|get')
|
||||
}
|
||||
|
||||
export async function cancelLogin(): Promise<void> {
|
||||
export async function cancelLogin() {
|
||||
return await invoke('plugin:mr-auth|cancel_modrinth_login')
|
||||
}
|
||||
@@ -18,7 +18,7 @@ import { install_to_existing_profile } from '@/helpers/pack.js'
|
||||
- icon is a path to an image file, which will be copied into the profile directory
|
||||
*/
|
||||
|
||||
export async function create(name, gameVersion, modloader, loaderVersion, icon, skipInstall) {
|
||||
export async function create(name, gameVersion, modloader, loaderVersion, iconPath, skipInstall) {
|
||||
//Trim string name to avoid "Unable to find directory"
|
||||
name = name.trim()
|
||||
return await invoke('plugin:profile-create|profile_create', {
|
||||
@@ -26,7 +26,7 @@ export async function create(name, gameVersion, modloader, loaderVersion, icon,
|
||||
gameVersion,
|
||||
modloader,
|
||||
loaderVersion,
|
||||
icon,
|
||||
iconPath,
|
||||
skipInstall,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ export type AppSettings = {
|
||||
max_concurrent_writes: number
|
||||
|
||||
theme: ColorTheme
|
||||
locale: string
|
||||
default_page: 'home' | 'library'
|
||||
collapsed_navigation: boolean
|
||||
hide_nametag_skins_page: boolean
|
||||
@@ -64,12 +63,6 @@ export type AppSettings = {
|
||||
|
||||
developer_mode: boolean
|
||||
feature_flags: Record<FeatureFlag, boolean>
|
||||
|
||||
skipped_update: string | null
|
||||
pending_update_toast_for_version: string | null
|
||||
auto_download_updates: boolean | null
|
||||
|
||||
version: number
|
||||
}
|
||||
|
||||
// Get full settings object
|
||||
|
||||
@@ -22,11 +22,6 @@ export interface Skin {
|
||||
is_equipped: boolean
|
||||
}
|
||||
|
||||
export interface SkinTextureUrl {
|
||||
original: string
|
||||
normalized: string
|
||||
}
|
||||
|
||||
export const DEFAULT_MODEL_SORTING = ['Steve', 'Alex'] as string[]
|
||||
|
||||
export const DEFAULT_MODELS: Record<string, SkinModel> = {
|
||||
|
||||
@@ -6,31 +6,11 @@ export async function isDev() {
|
||||
return await invoke('is_dev')
|
||||
}
|
||||
|
||||
export async function areUpdatesEnabled() {
|
||||
return await invoke('are_updates_enabled')
|
||||
}
|
||||
|
||||
export async function getUpdateSize(updateRid) {
|
||||
return await invoke('get_update_size', { rid: updateRid })
|
||||
}
|
||||
|
||||
export async function enqueueUpdateForInstallation(updateRid) {
|
||||
return await invoke('enqueue_update_for_installation', { rid: updateRid })
|
||||
}
|
||||
|
||||
export async function removeEnqueuedUpdate() {
|
||||
return await invoke('remove_enqueued_update')
|
||||
}
|
||||
|
||||
// One of 'Windows', 'Linux', 'MacOS'
|
||||
export async function getOS() {
|
||||
return await invoke('plugin:utils|get_os')
|
||||
}
|
||||
|
||||
export async function isNetworkMetered() {
|
||||
return await invoke('plugin:utils|is_network_metered')
|
||||
}
|
||||
|
||||
export async function openPath(path) {
|
||||
return await invoke('plugin:utils|open_path', { path })
|
||||
}
|
||||
@@ -58,6 +38,13 @@ export async function restartApp() {
|
||||
return await invoke('restart_app')
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method is no longer needed, and just returns its parameter
|
||||
*/
|
||||
export function sanitizePotentialFileUrl(url) {
|
||||
return url
|
||||
}
|
||||
|
||||
export const releaseColor = (releaseType) => {
|
||||
switch (releaseType) {
|
||||
case 'release':
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { autoToHTML } from '@geometrically/minecraft-motd-parser'
|
||||
import type { GameVersion } from '@modrinth/ui'
|
||||
import { autoToHTML } from '@sfirew/minecraft-motd-parser'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { buildLocaleMessages, createMessageCompiler, type CrowdinMessages } from '@modrinth/ui'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
|
||||
const localeModules = import.meta.glob<{ default: CrowdinMessages }>('./locales/*/index.json', {
|
||||
eager: true,
|
||||
})
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'en-US',
|
||||
fallbackLocale: 'en-US',
|
||||
messageCompiler: createMessageCompiler(),
|
||||
missingWarn: false,
|
||||
fallbackWarn: false,
|
||||
messages: buildLocaleMessages(localeModules),
|
||||
})
|
||||
|
||||
export default i18n
|
||||
@@ -1,557 +0,0 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "قد تكون خوادم مصادقة ماينكرافت معطلة حاليًا. تحقق من اتصالك بالإنترنت وحاول مرة أخرى لاحقًا."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "تعذر الوصول إلى خوادم المصادقة"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "نزل للعب"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "تثبيت"
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": ""
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "تم إضافة"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "تم إزالة"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "تم تحديث"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "حدث للعب"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "يلزم التحديث"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "تم تفعيل وضع المطوّر."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "جار تنزيل الإصدار {version}"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "المظهر"
|
||||
},
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "خيارات النسخة الافتراضية"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "أعلام الميزات"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "تثبيتات جافا"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "اللغة"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "الخصوصية"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "إدارة الموارد"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "تطبيق Modrinth الإصدار {version} جاهز للتثبيت!\nأعد التحميل لتحديث التطبيق الآن، أو سيتم التحديث تلقائيًا عند إغلاق تطبيق Modrinth."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "تطبيق Modrinth الإصدار {version} جاهز للتثبيت!\nأعد التحميل لتحديث التطبيق الآن، أو سيتم التحديث تلقائيًا عند إغلاق تطبيق Modrinth."
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "تطبيق Modrinth الإصدار {version} متاح الآن!\nنظرًا لأنك تستخدم شبكة محدودة البيانات، لم نقم بتنزيل التحديث تلقائيًا.\n"
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "سجلّ التغييرات"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "تنزيل ({size})"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "جار التنزيل..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "إعادة تحميل"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "تحديث متاح"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "اكتمل التنزيل"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "انقر هنا لعرض سجلّ التغييرات."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "تم تثبيت الإصدار {version} بنجاح!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "تنزيل التحديث"
|
||||
},
|
||||
"app.update.downloading-update": {
|
||||
"message": "جار تنزيل التحديث ({percent}٪)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "أعد التحميل لتثبيت التحديث"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "إضافة صديق"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} {count, plural, one {طلب صداقة} other {طلبات صداقة}}"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "إرسال طلب صداقة"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "جار إضافة صديق"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "قد يختلف عن اسم المستخدم الخاص بهم في ماينكرافت!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "أدخل اسم مستخدم Modrinth..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "ما اسم مستخدم صديقك في Modrinth؟"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>أضف أصدقاء</link> لمعرفة ما الذي يلعبونه!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "إلغاء الطلب"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "إزالة صديق"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "إرسال طلب الصداقة"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "عرض الملف الشخصي"
|
||||
},
|
||||
"friends.heading": {
|
||||
"message": "أصدقاء"
|
||||
},
|
||||
"friends.heading.active": {
|
||||
"message": "نشط"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "غير متصل"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "متصل"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "قيد الانتظار"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "لا يوجد أصدقاء يطابقون ''{query}''"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "ابحث عن الأصدقاء..."
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>سجّل الدخول إلى حساب Modrinth</link> لإضافة الأصدقاء ومعرفة ما الذي يلعبونه!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "إضافة واللعب"
|
||||
},
|
||||
"instance.add-server.add-server": {
|
||||
"message": "إضافة خادم"
|
||||
},
|
||||
"instance.add-server.resource-pack.disabled": {
|
||||
"message": "معطَّل"
|
||||
},
|
||||
"instance.add-server.resource-pack.enabled": {
|
||||
"message": "مفعَّل"
|
||||
},
|
||||
"instance.add-server.resource-pack.prompt": {
|
||||
"message": "موجه الأوامر"
|
||||
},
|
||||
"instance.add-server.title": {
|
||||
"message": "إضافة خادم"
|
||||
},
|
||||
"instance.edit-server.title": {
|
||||
"message": "تعديل خادم"
|
||||
},
|
||||
"instance.edit-world.hide-from-home": {
|
||||
"message": "إخفاء من الصفحة الرئيسية"
|
||||
},
|
||||
"instance.edit-world.name": {
|
||||
"message": "الاسم"
|
||||
},
|
||||
"instance.edit-world.placeholder-name": {
|
||||
"message": "عالم ماينكرافت"
|
||||
},
|
||||
"instance.edit-world.reset-icon": {
|
||||
"message": "إعادة تعيين الأيقونة"
|
||||
},
|
||||
"instance.edit-world.title": {
|
||||
"message": "تعديل العالم"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "المشاريع المعطَّلة"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "توجد تحديثات متاحة"
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "العنوان"
|
||||
},
|
||||
"instance.server-modal.name": {
|
||||
"message": "الاسم"
|
||||
},
|
||||
"instance.server-modal.placeholder-name": {
|
||||
"message": "خادم ماينكرافت"
|
||||
},
|
||||
"instance.server-modal.resource-pack": {
|
||||
"message": "حزمة الموارد"
|
||||
},
|
||||
"instance.settings.tabs.general": {
|
||||
"message": "عام"
|
||||
},
|
||||
"instance.settings.tabs.general.delete": {
|
||||
"message": "حذف النسخة"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.button": {
|
||||
"message": "حذف النسخة"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "يحذف النسخة نهائيًا من جهازك، بما في ذلك عوالمك، إعداداتك، وجميع المحتويات المثبّتة. كن حذرًا، فبمجرد حذف النسخة لن تكون هناك أي طريقة لاستعادتها."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "جاري الحذف..."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button": {
|
||||
"message": "نسخ"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button.tooltip.installing": {
|
||||
"message": "لا يمكن النسخ أثناء التثبيت."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "نسخة النسخة"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "إنشاء."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "تعديل الأيقونة"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.remove": {
|
||||
"message": "أزل الأيقونة"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.replace": {
|
||||
"message": "استبدل الأيقونة"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.select": {
|
||||
"message": "اختر الأيقونة"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups": {
|
||||
"message": "مجموعات المكتبة"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.create": {
|
||||
"message": "إنشاء مجموعة جديدة"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.description": {
|
||||
"message": "مجموعات المكتبة تساعدك على ترتيب حالاتك على أقسام مختلفة في مكتبتك."
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.enter-name": {
|
||||
"message": "إدخال اسم المجموعة"
|
||||
},
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "الاسم"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "إجراءات تشغيل إضافية"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "إجراءات تشغيل إضافية مخصصة"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "إجراءات التشغيل المضافة تسمح للمستخدمين المتقدمين بإنشاء أوامر نظامية محددة قبل و عند تشغيل اللعبة."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "ما بعد الخروج"
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.description": {
|
||||
"message": "يتم تشغيله بعد إغلاق اللعبة."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.enter": {
|
||||
"message": "أدخل أمر ما بعد الخروج..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch": {
|
||||
"message": "ما قبل الإطلاق"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.description": {
|
||||
"message": "يتم تشغيله قبل بَدْء تشغيل النسخة."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "أدخل أمر ما قبل الإطلاق..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "خطافات تشغيل اللعبة"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "مُغلِّف"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "أمر غلاف لتشغيل ماينكرافت."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "أدخل أمر الغلاف..."
|
||||
},
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "تثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} لماينكرافت {game_version} مثبت بالفعل"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "فانيلا {game_version} مُثبّتة بالفعل"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "تغيير الإصدار"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "تثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "جاري التثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "جاري جلب إصدارات حزمة المودات"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "جاري تثبيت الإصدار الجديد"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "المثبت حاليًا"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "معلومات التصحيح:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "جاري جلب تفاصيل حزمة المودات"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "إصدار اللعبة"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "تثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "التثبيت قيد التنفيذ"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "إصدار {loader}"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "ماين كرافت {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "تعذّر جلب تفاصيل حزمة المودات المرتبطة. يرجى التحقق من اتصالك بالإنترنت."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} غير متاح لماين كرافت {version}. جرّب محمّل مودات آخر."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "هذه النسخة مرتبطة بحزمة مودات، لكن لم يتم العثور على الحزمة على مودرنث."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "منصّة"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "إعادة تثبيت حزمة المودات"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "جاري إعادة تثبيت حزمة المودات"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "إعادة التثبيت ستُعيد جميع الملفات المثبتة أو المعدلة إلى ما توفره حُزْمة المودات، مع إزالة أي مودات أو محتوى أضفته بعد التثبيت الأصلي. قد يساعد ذلك في حل السلوك غير المتوقع إذا تم تعديل النسخة، لكن إذا كانت عوالمك تعتمد على محتويات إضافية، فقد يتسبب ذلك في تعطلها."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "هل أنت متأكد أنك تريد إعادة تثبيت هذه النسخة؟"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "يعيد محتوى النسخة إلى حالته الأصلية، مع إزالة جميع المودات أو المحتوى الذي أُضيف فوق حزمة المودات الأصلية."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "إعادة تثبيت حزمة المودات"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "إصلاح"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "جاري الإصلاح"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "الإصلاح يعيد تثبيت مكوّنات ماين كرافت ويتحقق من التلف. قد يساعد ذلك في حل المشكلات إذا كانت لعبتك لا تعمل بسبب أخطاء متعلقة ببرنامج التشغيل، لكنه لن يحل المشكلات أو الأعطال الناتجة عن المودات المثبّتة."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "إصلاح النسخة؟"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "الإصلاح قيد التنفيذ"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "إعادة التعيين إلى الحالة الحالية"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "عرض جميع الإصدارات"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "تغيير الإصدار"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "تثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "إعادة التثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "إصلاح"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "لا يمكن {action} أثناء التثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "لا يمكن {action} أثناء عدم الاتصال بالإنترنت"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "لا يمكن {action} أثناء الإصلاح"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(إصدار غير معروف)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "إلغاء ربط النسخة"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "إذا تابعت، فلن تتمكّن من إعادة ربطها إلا بإنشاء نسخة جديدة بالكامل. لن تتلقى بعد ذلك تحديثات حزمة المودات، وستصبح نسخة عادية."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "هل أنت متأكد أنك تريد إلغاء ربط هذه النسخة؟"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "هذه النسخة مرتبطة بحزمة مودات، مما يعني أنه لا يمكن تحديث المودات أو تغيير محمّل المودات أو إصدار ماين كرافت. سيؤدي إلغاء الربط إلى فصل هذه النسخة نهائيًا عن حزمة المودات."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "إلغاء الربط من حزمة المودات"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "جافا والذاكرة"
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "المتغيرات البيئية"
|
||||
},
|
||||
"instance.settings.tabs.java.hooks": {
|
||||
"message": "الخطافات"
|
||||
},
|
||||
"instance.settings.tabs.java.java-arguments": {
|
||||
"message": "وسائط جافا"
|
||||
},
|
||||
"instance.settings.tabs.java.java-installation": {
|
||||
"message": "تثبيت جافا"
|
||||
},
|
||||
"instance.settings.tabs.java.java-memory": {
|
||||
"message": "الذاكرة المخصَّصة"
|
||||
},
|
||||
"instance.settings.tabs.window": {
|
||||
"message": "النافذة"
|
||||
},
|
||||
"instance.settings.tabs.window.custom-window-settings": {
|
||||
"message": "إعدادات نافذة مخصّصة"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen": {
|
||||
"message": "ملء الشاشة"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen.description": {
|
||||
"message": "جعل اللعبة تبدأ في وضع ملء الشاشة عند التشغيل (باستخدام options.txt)."
|
||||
},
|
||||
"instance.settings.tabs.window.height": {
|
||||
"message": "الارتفاع"
|
||||
},
|
||||
"instance.settings.tabs.window.height.description": {
|
||||
"message": "ارتفاع نافذة اللعبة عند التشغيل."
|
||||
},
|
||||
"instance.settings.tabs.window.height.enter": {
|
||||
"message": "أدخل الارتفاع..."
|
||||
},
|
||||
"instance.settings.tabs.window.width": {
|
||||
"message": "العرض"
|
||||
},
|
||||
"instance.settings.tabs.window.width.description": {
|
||||
"message": "عرض نافذة اللعبة عند التشغيل."
|
||||
},
|
||||
"instance.settings.tabs.window.width.enter": {
|
||||
"message": "أدخل العرض..."
|
||||
},
|
||||
"instance.worlds.a_minecraft_server": {
|
||||
"message": "خادم ماين كرافت"
|
||||
},
|
||||
"instance.worlds.cant_connect": {
|
||||
"message": "لا يمكن الاتصال بالخادم"
|
||||
},
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "نسخ العنوان"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "عدم العرض في الصفحة الرئيسية"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "متاح"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "النسخة مفتوحة بالفعل"
|
||||
},
|
||||
"instance.worlds.hardcore": {
|
||||
"message": "وضع الهاردكور"
|
||||
},
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "الخادم غير متوافق"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "تعذّر الاتصال بالخادم"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "يمكنك الدخول مباشرة إلى الخوادم فقط على ماين كرافت Alpha 1.0.5+"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "يمكنك الدخول مباشرة إلى عوالم اللعب الفردي فقط على ماين كرافت 1.20+"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "تشغيل النسخة"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "الخادم"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "لعب فردي"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "عرض النسخة"
|
||||
},
|
||||
"instance.worlds.world_in_use": {
|
||||
"message": "العالم قيد الاستخدام"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "مقدَّم من النسخة"
|
||||
},
|
||||
"search.filter.locked.instance-game-version.title": {
|
||||
"message": "إصدار اللعبة مقدَّم من النسخة"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "المحمّل مقدَّم من النسخة"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "مزامنة مع النسخة"
|
||||
}
|
||||
}
|
||||
@@ -1,590 +0,0 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Autořizační servery Minecraftu aktuálně nejsou k dispozici. Zkontrolujte si své připojení k internetu a zkuste to znovu později."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Připojení k autorizačním serverům se nezdařilo"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Nainstaluj ke hraní"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Instalovat"
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural,one {#mód} other {#módy}}"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Tento server k hraní vyžaduje módy. Klikni na instalovat pro získání potřebných módů z Modrinth."
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} dnes s vámi sdílel tuto instanci."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Sdílená instance"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Sdílená serverová instance"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} přidáno"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Přidáno"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Odebráno"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Aktualizováno"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Updatuj ke hraní"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} odstraněno"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Je vyžadována aktualizace"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Je nutná aktualizace ke hraní {name}. Prosím updatuj na nejnovější verzi k spuštění hry."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} aktualizováno"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Vývojářský režim povolen."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "Stahování v{version}"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "Vzhled"
|
||||
},
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Výchozí možnosti instance"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Vlajky funkcí"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Instalace Javy"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Jazyk"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Soukromí"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Správa zdrojů"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Aplikace Modrinth v{version} je připravena k instalaci! Nainstalujte aktualizaci nyní nebo automaticky po zavření aplikace Modrinth."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Stahování aplikace Modrinth v{version} bylo dokončeno. Nainstalujte aktualizaci nyní nebo automaticky po zavření aplikace Modrinth."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "Modrinth App v{version} je k dispozici. Aktualizujte pomocí svého správce balíčků, abyste získali nejnovější funkce a opravy!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Aplikace Modrinth v{version} je nyní k dispozici! Protože jste v měřené síti, nebyla stažena automaticky."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Seznam změn"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "Stahování ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Stáhnout"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Stahování..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Načíst znovu"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Aktualizace je k dispozici"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Stahování bylo dokončeno"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Kliknutím sem zobrazíte seznam změn."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "Verze {version} byla úspěšně nainstalována!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "Stáhnout aktualizaci"
|
||||
},
|
||||
"app.update.downloading-update": {
|
||||
"message": "Stahování aktualizace ({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Restartovat aplikaci pro nainstalování aktualizace"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Přidat přítele"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} {count, plural, one {žádost} few {žádosti} other {žádostí}} o přátelství"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Poslat žádost o přátelství"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Přidávání kamaráda"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "Může být jiné než jejich Minecraft jméno!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Zadejte uživatelské jméno Modrinth..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Jak se váš kamarád jmenuje na Modrinthu?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Přidejte si přátelé</link> a podívejte se, co hrají!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Zrušit žádost"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "Odebrat přítele"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Žádost o přátelství odeslána"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "Zobrazit profil"
|
||||
},
|
||||
"friends.heading": {
|
||||
"message": "Kamarádi"
|
||||
},
|
||||
"friends.heading.active": {
|
||||
"message": "Aktivní"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "Čeká na vyřízení"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "Žádní přátelé neodpovídají '{query}''"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Hledat přátele..."
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Přihlašte se ke svému Modrinth účtu</link>, abyste jsi přidali přátele a uviděli co hrají!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Přidat a hrát"
|
||||
},
|
||||
"instance.add-server.add-server": {
|
||||
"message": "Přidat server"
|
||||
},
|
||||
"instance.add-server.resource-pack.disabled": {
|
||||
"message": "Vypnuto"
|
||||
},
|
||||
"instance.add-server.resource-pack.enabled": {
|
||||
"message": "Zapnuto"
|
||||
},
|
||||
"instance.add-server.resource-pack.prompt": {
|
||||
"message": "Ptát se"
|
||||
},
|
||||
"instance.add-server.title": {
|
||||
"message": "Přidat server"
|
||||
},
|
||||
"instance.edit-server.title": {
|
||||
"message": "Upravit server"
|
||||
},
|
||||
"instance.edit-world.hide-from-home": {
|
||||
"message": "Skrýt z domovské obrazovky"
|
||||
},
|
||||
"instance.edit-world.name": {
|
||||
"message": "Název"
|
||||
},
|
||||
"instance.edit-world.placeholder-name": {
|
||||
"message": "Minecraft svět"
|
||||
},
|
||||
"instance.edit-world.reset-icon": {
|
||||
"message": "Resetovat ikonu"
|
||||
},
|
||||
"instance.edit-world.title": {
|
||||
"message": "Upravit svět"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Vypnuté projekty"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "K dispozice jsou aktualizace"
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Adresa"
|
||||
},
|
||||
"instance.server-modal.name": {
|
||||
"message": "Název"
|
||||
},
|
||||
"instance.server-modal.placeholder-name": {
|
||||
"message": "Minecraft Server"
|
||||
},
|
||||
"instance.server-modal.resource-pack": {
|
||||
"message": "Balíčky textur"
|
||||
},
|
||||
"instance.settings.tabs.general": {
|
||||
"message": "Obecné"
|
||||
},
|
||||
"instance.settings.tabs.general.delete": {
|
||||
"message": "Odstranit instalaci"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.button": {
|
||||
"message": "Odstranit instalaci"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Trvale smaže instalaci z vašeho zařízení, včetně vašich světů, konfigurací a veškerého nainstalovaného obsahu. Buďte opatrní, protože jakmile instalaci smažete, nebude možné ji obnovit."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Mazání..."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button": {
|
||||
"message": "Duplikovat"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button.tooltip.installing": {
|
||||
"message": "Nelze duplikovat při instalaci."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "Duplikovat instalaci"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "Vytvoří kopii této instalace, včetně světů, konfigurací, modů atd."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "Upravit ikonu"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.remove": {
|
||||
"message": "Odstranit ikonu"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.replace": {
|
||||
"message": "Změnit ikonu"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.select": {
|
||||
"message": "Vybrat ikonu"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups": {
|
||||
"message": "Skupina knihoven"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.create": {
|
||||
"message": "Vytvořit novou skupinu"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.description": {
|
||||
"message": "Skupiny knihoven vám umožňují uspořádat instalace do různých sekcí."
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.enter-name": {
|
||||
"message": "Zadejte název skupiny"
|
||||
},
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "Název"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Spouštěcí hooky"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Vlastní spouštěcí hooky"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Hooky umožňují pokročilým uživatelům spouštět určité systémové příkazy před a po spuštění hry."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "Po ukončení"
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.description": {
|
||||
"message": "Spušteno po vypnutí hry."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.enter": {
|
||||
"message": "Zadejte příkaz k provedení po ukončení..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch": {
|
||||
"message": "Před spuštěním"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.description": {
|
||||
"message": "Spouštějí se před spuštěním instalace."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Zadejte příkaz k provedení před spuštěním..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Spouštěcí hooky hry"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "Wrapper"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "Příkaz wrapperu pro spuštění Minecraftu."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "Zadejte příkaz wrapperu..."
|
||||
},
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Instalace"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} pro Minecraft {game_version} již je nainstalována"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} již je nainstalována"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Změnit verzi"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Instalovat"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Instalování"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Načítání verzí modpacku"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Instalace nové verze"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Aktuálně nainstalováno"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Debugové informace:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Načítání detailů modpacku"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Verze hry"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Instalovat"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Probíhá instalace"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} verze"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Nelze načíst podrobnosti o modpacku. Prosím, zkontrolujte své připojení k internetu."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} není dostupný pro Minecraft {version}. Zkuste jiný mod loader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Tato instalace je připojená k modpacku, který ake nebyl najit na Modrinthu."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Platforma"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Přeinstalovat modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Přeinstalovávání modpacku"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Přeinstalace resetuje veškerý nainstalovaný nebo upravený obsah kromě toho, co poskytuje modpack, a odstraní všechny módy nebo obsah, které jste přidali do původní instalace. To může opravit neočekávané chyby, ale pokud vaše světy závisejí na doinstalovaném obsahu, možná budou poškozeny."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Opravdu si přejete přeinstalovat tuto instalaci?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Obnoví obsah instance do původního stavu a odstraní všechny mody nebo obsah, které jste přidali nad původní modpack."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Přeinstalovat modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Opravit"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Opravováno"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Oprava přeinstaluje závislosti Minecraftu a zkontroluje poškození. To může vyřešit problémy, pokud se hra nespustí kvůli chybám souvisejícím s launcherem, ale nevyřeší to problémy nebo pády související s nainstalovanými mody."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Opravit instanci?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Probíhá oprava"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Resetovat na aktuální"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Ukázat všechny verze"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "změnit verzi"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "Instalovat"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "přeinstalovat"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "opravit"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "Nelze {action} při instalaci"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "Nelze {action} když offline"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "Nelze {action} při opravě"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(neznámá verze)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Odpojit instanci"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Pokud budete pokračovat, nebudete ji moci znovu propojit bez vytvoření zcela nové instance. Již nebudete dostávat aktualizace modpacku a stane se z něj běžná instance."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Opravdu si přejete odpojit tuto instanci?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Tato instance je připojena k modpacku, což znamená, že módy nemohou být aktualizované a nelze změnit mod loader ani verze minecraftu. Odpojení permanentně rozváže tuto instanci od modpacku."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Odpojit od modpacku"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java a pamět"
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "Proměnné prostředí"
|
||||
},
|
||||
"instance.settings.tabs.java.hooks": {
|
||||
"message": "Hooky"
|
||||
},
|
||||
"instance.settings.tabs.java.java-arguments": {
|
||||
"message": "Java argumenty"
|
||||
},
|
||||
"instance.settings.tabs.java.java-installation": {
|
||||
"message": "Instalace Javy"
|
||||
},
|
||||
"instance.settings.tabs.java.java-memory": {
|
||||
"message": "Paměti přiřazeno"
|
||||
},
|
||||
"instance.settings.tabs.window": {
|
||||
"message": "Okno"
|
||||
},
|
||||
"instance.settings.tabs.window.custom-window-settings": {
|
||||
"message": "Vlastní nastavení okna"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen": {
|
||||
"message": "Celá obrazovka"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen.description": {
|
||||
"message": "Spustit hru v plné obrazovce pokud spuštěno (použitím options.txt)."
|
||||
},
|
||||
"instance.settings.tabs.window.height": {
|
||||
"message": "Výška"
|
||||
},
|
||||
"instance.settings.tabs.window.height.description": {
|
||||
"message": "Výška herního okna při spuštění."
|
||||
},
|
||||
"instance.settings.tabs.window.height.enter": {
|
||||
"message": "Zadejte výšku..."
|
||||
},
|
||||
"instance.settings.tabs.window.width": {
|
||||
"message": "Šířka"
|
||||
},
|
||||
"instance.settings.tabs.window.width.description": {
|
||||
"message": "Šířka herního okna při spuštění."
|
||||
},
|
||||
"instance.settings.tabs.window.width.enter": {
|
||||
"message": "Zadejte šířku..."
|
||||
},
|
||||
"instance.worlds.a_minecraft_server": {
|
||||
"message": "Minecraft Server"
|
||||
},
|
||||
"instance.worlds.cant_connect": {
|
||||
"message": "Nelze připojit k serveru"
|
||||
},
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Kopírovat adresu"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Nezobrazuje na domovské stránce"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Dostupné"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Instance je již otevřená"
|
||||
},
|
||||
"instance.worlds.hardcore": {
|
||||
"message": "Hardcore režim"
|
||||
},
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Server je nekompatibilní"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Server se nepodařilo spojit"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "Můžeš rovnou skočit na server pouze v Minecraftu Alpha 1.0.5+"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Můžeš se rovnou připojit do světa jednoho hráče pouze v Minecraftu 1.20+"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Hrát instanci"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Server"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Hra pro jednoho hráče"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Zobrazit instanci"
|
||||
},
|
||||
"instance.worlds.world_in_use": {
|
||||
"message": "Svět je použit"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "Poskytováno instancí"
|
||||
},
|
||||
"search.filter.locked.instance-game-version.title": {
|
||||
"message": "Verze hry je poskytnut instanci"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "Spouštěč je poskytnut instanci"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synchronizováno z instancí"
|
||||
}
|
||||
}
|
||||
@@ -1,578 +0,0 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Minecraft authentication servere kan måske være nede lige nu. Tjek din internet forbindelse og prøv igen senere."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Kan ikke nå autentificeringsservere"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Installer for at spille"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Installer"
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Denne server kræver mods for at spille. Klik installer for at sætte op filerne som er krævet fra Modrinth."
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} tilføjet"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Tilføjet"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Fjernet"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Opdateret"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Opdater for at spille"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} fjernet"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Opdatering krævet"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "En opdatering er krævet for at spille {name}. Venligst opdater til den seneste version for at køre spillet."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} opdateret"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Udvikler-tilstand aktiveret."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "Downloader v{version}"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "Udseende"
|
||||
},
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Standardindstillinger for instans"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Funktionsflags"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Javainstallationer"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Sprog"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Privatliv"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Ressourcestyring"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth App v{version} er allerede installeret! Genindlæs for at opdatere nu, eller automatisk når du lukker Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth App v{version} er færdig med at download. Genindlæs for at opdatere nu, eller automatisk når du lukker Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "Modrinth App v{version} er nu tilgængelig. Brug din pakke-manager til at opdatere for de nyeste features og fejlrettelser!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version} er nu tilgængelig! Siden du er på et begrænset netværk, vi downloadede den ikke automatisk."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Ændringslog"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "Download ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Download"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Downloader..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Geninlæs"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Opdatering tilgængelig"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Download færdiggjort"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Klik her for at vise ændringslog."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "Version {version} var installeret med succes!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "Download opdatering"
|
||||
},
|
||||
"app.update.downloading-update": {
|
||||
"message": "Downloader opdatering ({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Genindlæs for at installere opdatering"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Tilføj en ven"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} venne{count, plural, one {anmodning} other {anmodninger}}"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Send en venneanmodning"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Tilføjer en ven"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "Det er muligvis anderledes end deres Minecraft brugernavn!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Indskriv Modrinth brugernavn..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Hvad er din vens Modrinth brugernavn?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Tilføj venner</link> for at se hvad de spiller!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Annuller anmodning"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "Fjern ven"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Venneanmodning sendt"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "Vis profil"
|
||||
},
|
||||
"friends.heading": {
|
||||
"message": "Venner"
|
||||
},
|
||||
"friends.heading.active": {
|
||||
"message": "Aktiv"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "Afventer"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "Ingen venner som matcher \"{query}\""
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Søg venner..."
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Log ind på en Modrinth konto</link> for at tilføje venner og se hvad de spiller!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Tilføj og spil"
|
||||
},
|
||||
"instance.add-server.add-server": {
|
||||
"message": "Tilføj server"
|
||||
},
|
||||
"instance.add-server.resource-pack.disabled": {
|
||||
"message": "Deaktiveret"
|
||||
},
|
||||
"instance.add-server.resource-pack.enabled": {
|
||||
"message": "Aktiveret"
|
||||
},
|
||||
"instance.add-server.resource-pack.prompt": {
|
||||
"message": "Spørg"
|
||||
},
|
||||
"instance.add-server.title": {
|
||||
"message": "Tilføj en server"
|
||||
},
|
||||
"instance.edit-server.title": {
|
||||
"message": "Rediger server"
|
||||
},
|
||||
"instance.edit-world.hide-from-home": {
|
||||
"message": "Skjul fra forside"
|
||||
},
|
||||
"instance.edit-world.name": {
|
||||
"message": "Navn"
|
||||
},
|
||||
"instance.edit-world.placeholder-name": {
|
||||
"message": "Minecraft verden"
|
||||
},
|
||||
"instance.edit-world.reset-icon": {
|
||||
"message": "Nulstil ikon"
|
||||
},
|
||||
"instance.edit-world.title": {
|
||||
"message": "Rediger verden"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Deaktiverede projekter"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Tilgængelige opdateringer"
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Adresse"
|
||||
},
|
||||
"instance.server-modal.name": {
|
||||
"message": "Navn"
|
||||
},
|
||||
"instance.server-modal.placeholder-name": {
|
||||
"message": "Minecraft server"
|
||||
},
|
||||
"instance.server-modal.resource-pack": {
|
||||
"message": "Ressourcepakke"
|
||||
},
|
||||
"instance.settings.tabs.general": {
|
||||
"message": "Generelt"
|
||||
},
|
||||
"instance.settings.tabs.general.delete": {
|
||||
"message": "Slet instans"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.button": {
|
||||
"message": "Slet instans"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Permanent slet en instans fra din enhed, inkluderer dine verdener, konfigurationer, og alt installeret indhold. Vær forsigtig, for så snart du sletter en instans der er ingen at gendanne det."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Sletter..."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button": {
|
||||
"message": "Kopiér"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button.tooltip.installing": {
|
||||
"message": "Kan ikke kopiere under installation."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "Kopiér instans"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "Opret en kopi af denne instans, inkluderer verdener, konfigurationer, mods, osv."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "Rediger ikon"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.remove": {
|
||||
"message": "Fjern ikon"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.replace": {
|
||||
"message": "Udskift ikon"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.select": {
|
||||
"message": "Vælg ikon"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups": {
|
||||
"message": "Biblioteks grupper"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.create": {
|
||||
"message": "Opret ny gruppe"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.description": {
|
||||
"message": "Biblioteksgrupper lader dig organisere dine instanser i forskellige sektioner i dit bibliotek."
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.enter-name": {
|
||||
"message": "Indtast gruppenavn"
|
||||
},
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "Navn"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Startkommandoer"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Brugerfinansieret startkommandoer"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Startkommandoer giver avancerede brugere mulighed for at køre bestemte systemkommandoer før og efter spillet startes."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "Post-exit"
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.description": {
|
||||
"message": "Kørte efter spillet lukkes."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.enter": {
|
||||
"message": "Indtast post-exit kommando..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch": {
|
||||
"message": "Pre-launch"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.description": {
|
||||
"message": "Kørt før en instance bliver kørt."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Indtast pre-launch kommando..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Spille lunch hooks"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "Wrapper"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "Wrapper kommando for at køre Minecraft."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "Indtast wrapper kommando..."
|
||||
},
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Installation"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} for Minecraft {game_version} er allerede installeret"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} er allerede installeret"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Skift version"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Installer"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Installer"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Får modpack versioner"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Installere ny version"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Lige nu installeret"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Debug information:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Får modpack detaljer"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Spil version"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Installer"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Installation igangværende"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} version"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Kan ikke få forbundet modpack detaljer. Venligst tjek din internet forbindelse."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} er ikke mulig at bruge for Minecraft {version}. Prøv en anden mod loader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Denne instance er koblet til en modpack, men modpacken kunne ikke blive fundet på Modrinth."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Platform"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Geninstaller modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Geninstallere modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Geninstallering vil nulstille alt installeret eller modificeret indhold givet af modpacken, fjerne alle mods eller indhold du har tilføjet ovenpå den originale installation. Dette vil måske fikse uforventet adfærd hvis ændringer er blevet lavet til den instance, men hvis din verdener nu afhænger af ektra tilføjet indhold, dette vil måske ødelægge eksisterende verdener."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Er du sikker på du vil geninstallere denne instance?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Nulstiller instanceens indhold til dens oprindelige tilstand, fjerne alle mods eller indhold du har tilføjet ovenpå den oprindelige modpack."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Geninstaller modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Reparer"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Reparere"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Reparering geninstaller Minecraft afhængigheder og tjekker for korruption. Dette vil måske fikse fejl hvis dit spil ikke køre på grund af launcher relateret fejl, men vil ikke fikse fejl eller crashes relateret til installerede mods."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Reparer instance?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Reparation i gang"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Nulstil til nuværende"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Vis alle versioner"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "Ændre version"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "Installer"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "Geninstaller"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "Reparer"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "Kan ikke {action} under installation"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "Kan ikke {action} uden internet"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "Kan ikke {action} under reparation"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(Ukendt version)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Frakoble instance"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Hvis du forsætter, du vil ikke have mulighed for at koble sammen igen uden at lave en helt ny instance. Du vil ikke længere modtage modpack opdateringer og vil blive en normal."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Er du sikker på du vil frakoble denne instance?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Denne instance er forbundet til en modpack, hvilket betyder mods kan ikke blive opdateret og du kan ikke ændre mod loaderen eller Minecraft version. Frakobling vil permanent frakoble denne instance fra modpacken."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Frakoble fra modpack"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java og hukommelse"
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "Omgivelses variabler"
|
||||
},
|
||||
"instance.settings.tabs.java.hooks": {
|
||||
"message": "Hooks"
|
||||
},
|
||||
"instance.settings.tabs.java.java-arguments": {
|
||||
"message": "Java argumenter"
|
||||
},
|
||||
"instance.settings.tabs.java.java-installation": {
|
||||
"message": "Java installation"
|
||||
},
|
||||
"instance.settings.tabs.java.java-memory": {
|
||||
"message": "Allokeret hukommelse"
|
||||
},
|
||||
"instance.settings.tabs.window": {
|
||||
"message": "Vindue"
|
||||
},
|
||||
"instance.settings.tabs.window.custom-window-settings": {
|
||||
"message": "Brugerdefineret vindue indstillinger"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen": {
|
||||
"message": "Fuld skærm"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen.description": {
|
||||
"message": "Gør så spillet starter i fuld skærm når du køre spillet (Med brug af options.txt)."
|
||||
},
|
||||
"instance.settings.tabs.window.height": {
|
||||
"message": "Højde"
|
||||
},
|
||||
"instance.settings.tabs.window.height.description": {
|
||||
"message": "Højden af spillevinduet når kørt."
|
||||
},
|
||||
"instance.settings.tabs.window.height.enter": {
|
||||
"message": "Indtast højde..."
|
||||
},
|
||||
"instance.settings.tabs.window.width": {
|
||||
"message": "Bredde"
|
||||
},
|
||||
"instance.settings.tabs.window.width.description": {
|
||||
"message": "Bredden på spille vinduet når kørt."
|
||||
},
|
||||
"instance.settings.tabs.window.width.enter": {
|
||||
"message": "Indtast bredde..."
|
||||
},
|
||||
"instance.worlds.a_minecraft_server": {
|
||||
"message": "En Minecraft server"
|
||||
},
|
||||
"instance.worlds.cant_connect": {
|
||||
"message": "Kan ikke forbinde til serveren"
|
||||
},
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Kopier adresse"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Vis ikke på forsiden"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Tilgængelig"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Instance allerede åben"
|
||||
},
|
||||
"instance.worlds.hardcore": {
|
||||
"message": "Hardcore mode"
|
||||
},
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Serveren er uforenelig"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Serveren kunne ikke blive kontaktet"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "Du kan kun hoppe lige ind i servere på Minecraft Alpha 1.0.5+"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Du kan kun hoppe lige ind i singleplayer verdener på Minecraft 1.20+"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Spil instance"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Server"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Singleplayer"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Se instance"
|
||||
},
|
||||
"instance.worlds.world_in_use": {
|
||||
"message": "Verden er i brug"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "Givet af instanceen"
|
||||
},
|
||||
"search.filter.locked.instance-game-version.title": {
|
||||
"message": "Spille version er givet af instanceen"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "Loader er givet af instanceen"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synkroniser med instance"
|
||||
}
|
||||
}
|
||||
@@ -1,590 +0,0 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Die Authentifizierungsserver von Minecraft sind eventuell momentan nicht erreichbar. Überprüfe deine Internetverbindung und versuche es später erneut."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Authentifizierungsserver sind nicht erreichbar"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Installieren zum Spielen"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# Mod} other {# Mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Dieser Server benötigt Mods zum spielen. Klicke auf Installieren um die nötigen Dateien von Modrinth einzurichten."
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} hat diese Instanz heute mit dir geteilt."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Geteilte Instanz"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Geteilte Server Instanz"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} hinzugefügt"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Hinzugefügt"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Entfernt"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Aktualisiert"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Aktualisieren zum Spielen"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} entfernt"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Aktualisierung benötigt"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Eine aktualisierung zum spielen von {name} ist benötigt. Bitte aktualisiere auf die neuste Version um das Spiel zu starten."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} aktualisiert"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Entwicklermodus aktiviert."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "Lade v{version} herunter"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "Erscheinungsbild"
|
||||
},
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Standard Instanz-Einstellungen"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Funktionsflaggen"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java Installationen"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Sprache"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Datenschutz"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Ressourcenmanagement"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth App v{version} ist bereit zur Installation! Lade die App neu, oder schliesse sie, um zu aktualisieren."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth App v{version} wurde heruntergeladen. Lade die App neu, oder schliesse sie, um zu aktualisieren."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "Modrinth App v{version} ist verfügbar. Benutze deinen Paketmanager zum aktualisieren um die neusten Features und Bugfixes zu erhalten!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version} ist jetzt verfügbar! Da du in einem begrenzten Netzwerk bist, haben wir es nicht automatisch heruntergeladen."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Änderungen"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "Herunterladen ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Herunterladen"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Lade herunter..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Neu Laden"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Aktualisierung verfügbar"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Download abgeschlossen"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Klicke Hier um die Änderungen zu sehen."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "Version {version} wurde erfolgreich installiert!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "Aktualisierung herunterladen"
|
||||
},
|
||||
"app.update.downloading-update": {
|
||||
"message": "Lade Aktualisierung herunter ({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Lade neu um Aktualisierung zu installieren"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Freund hinzufügen"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} Freundschaftsanfrage{count, plural, one {} other {n}}"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Freundschaftsanfrage senden"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Einen Freund hinzufügen"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "Es könnte anders als ihr Minecraft Nutzername sein!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Modrinth Nutzernamen eingeben..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Was ist der Modrinth Nutzername deines Freundes?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Füge Freunde hinzu</link> um zu sehen, was sie spielen!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Anfrage abbrechen"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "Freund entfernen"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Freundschaftsanfrage gesendet"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "Profil anzeigen"
|
||||
},
|
||||
"friends.heading": {
|
||||
"message": "Freunde"
|
||||
},
|
||||
"friends.heading.active": {
|
||||
"message": "Aktiv"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "Ausstehend"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "Keine Freunde, die mit \"{query}\" übereinstimmen"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Freunde suchen..."
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Logge dich in ein Modrinth Konto ein</link> um Freunde hinzuzufügen und zu sehen, was sie spielen!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Ersteue u starte"
|
||||
},
|
||||
"instance.add-server.add-server": {
|
||||
"message": "Server hinzufügen"
|
||||
},
|
||||
"instance.add-server.resource-pack.disabled": {
|
||||
"message": "Deaktiviert"
|
||||
},
|
||||
"instance.add-server.resource-pack.enabled": {
|
||||
"message": "Aktiviert"
|
||||
},
|
||||
"instance.add-server.resource-pack.prompt": {
|
||||
"message": "Fragä"
|
||||
},
|
||||
"instance.add-server.title": {
|
||||
"message": "Einen Server hinzufügen"
|
||||
},
|
||||
"instance.edit-server.title": {
|
||||
"message": "Server bearbeiten"
|
||||
},
|
||||
"instance.edit-world.hide-from-home": {
|
||||
"message": "Von Startseite ausblenden"
|
||||
},
|
||||
"instance.edit-world.name": {
|
||||
"message": "Name"
|
||||
},
|
||||
"instance.edit-world.placeholder-name": {
|
||||
"message": "Minecraft Welt"
|
||||
},
|
||||
"instance.edit-world.reset-icon": {
|
||||
"message": "Icon zurücksetzen"
|
||||
},
|
||||
"instance.edit-world.title": {
|
||||
"message": "Welt bearbeiten"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Deaktivierte Projekte"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Updates verfügbar"
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Adresse"
|
||||
},
|
||||
"instance.server-modal.name": {
|
||||
"message": "Name"
|
||||
},
|
||||
"instance.server-modal.placeholder-name": {
|
||||
"message": "Minecraft Server"
|
||||
},
|
||||
"instance.server-modal.resource-pack": {
|
||||
"message": "Ressourcenpaket"
|
||||
},
|
||||
"instance.settings.tabs.general": {
|
||||
"message": "Allgemein"
|
||||
},
|
||||
"instance.settings.tabs.general.delete": {
|
||||
"message": "Instanz löschen"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.button": {
|
||||
"message": "Instanz löschen"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Löscht eine Instanz dauerhaft von deinem Gerät, inklusive deiner Welten, Einstellungen und allen installierten Inhalten. Sei vorsichtig, da eine gelöschte Instanz nicht mehr wiederherstellbar ist."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Lösche..."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button": {
|
||||
"message": "Duplizieren"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button.tooltip.installing": {
|
||||
"message": "Kann während dem installieren nicht duplizieren."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "Instanz duplizieren"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "Erstellt eine Kopie dieser Instanz, inklusive aller Welten, Einstellungen, Modifikationen, etc."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "Icon bearbeiten"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.remove": {
|
||||
"message": "Icon entfernen"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.replace": {
|
||||
"message": "Icon ersetzen"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.select": {
|
||||
"message": "Icon auswählen"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups": {
|
||||
"message": "Bibliotheksgruppen"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.create": {
|
||||
"message": "Neue Gruppe erstellen"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.description": {
|
||||
"message": "Bibliotheksgruppen ermöglichen es dir, deine Instanzen in unterschiedliche Bereiche deiner Bibliothek aufzuteilen."
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.enter-name": {
|
||||
"message": "Gruppenname eingeben"
|
||||
},
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "Name"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Start Hooks"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Benutzerdefinierte Start Hooks"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Hooks ermöglichen es erfahrenen Benutzern, bestimmte Systembefehle vor und nach dem Start des Spiels auszuführen."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "Nach dem Schliessen des Spiels"
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.description": {
|
||||
"message": "Wird nach dem Beenden des Spiels ausgeführt."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.enter": {
|
||||
"message": "Ausgeführter Befehl nach dem Beenden des Spiels eingeben..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch": {
|
||||
"message": "Vor Start des Spiels"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.description": {
|
||||
"message": "Wird vor dem Starten des Spiels ausgeführt."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Ausgeführter Befehl nach dem Starten des Spiels eingeben..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Spielstart Hooks"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "Wrapper"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "Wrapperbefehl zum Starten von Minecraft."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "Wrapperbefehl eingeben..."
|
||||
},
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Installation"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} für Minecraft {game_version} ist bereits installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} ist bereits installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Version ändern"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Wird installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Sammle Modpack-Versionen"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Neue Version wird installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Aktuell installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Informationen zur Fehlerbehebung:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Sammle Modpack-Details"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Spielversion"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Wird installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} Version"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Kann Details für verknüpftes Modpack nicht abrufen. Bitte überprüfe deine Internerverbindung."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} ist nicht verfügbar für Minecraft {version}. Versuch einen anderen Modloader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Diese Instanz ist mit einem Modpack verknüpft, aber das Modpack konnte nicht auf Modrinth gefunden werden."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Platform"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Modpack neu installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Modpack wird neu installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Durch die Neuinstallation werden alle installierten oder geänderten Inhalte auf die vom Modpack bereitgestellten Inhalte zurückgesetzt, wobei alle Mods oder Inhalte entfernt werden, die zusätzlich zur ursprünglichen Installation hinzugefügt wurden. Dies kann unerwartetes Verhalten beheben, wenn Änderungen an der Instanz vorgenommen wurden. Wenn deine Welten jedoch von zusätzlich installierten Inhalten abhängig sind, kann dies zu Fehlern in bestehenden Welten führen."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Bist du sicher, dass du diese Instanz neu installieren willst?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Setzt den Inhalt der Instanz auf seinen ursprünglichen Zustand zurück und entfernt all Mods oder Inhalte, welche zusätzlich zum ursprünglichen Modpack hinzugefügt wurden."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Modpack neu installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Reparieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Wird repariert"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Das reparieren installier Minecraft-Abhängigkeiten neu und überprüft für Beschädigungen. Dies kann Probleme beheben, sofern dein Spiel aufgrund von Launcher-relevanten Problemen nicht startet, aber es kann nicht Fehler und Abstpürze in Zusammenhang mit installierten Mods beheben."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Instanz reparieren?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Wird repariert"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Auf aktuellen Wert zurücksetzen"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Alle Versionen anzeigen"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "Version ändern"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "Neuinstallieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "Reparieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "{action} während der Installation nicht möglich"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "{action} nicht möglich ohne Internetverbindung"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "{action} während reparatur nicht möglich"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(unbekannte Version)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Verlinking der Instanz trennen"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Wenn du fortfährst, kann die Instanz nicht erneut verknüpft werden, ohne eine komplett neue Instanz zu ersztellen. Du erhälst keine Modpack-Updates mehr und es wird zu einer normalen Instanz."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Bist du sicher, dass du die Verknüpfung dieser Instanz trennen willst?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Diese Instanz ist mit einem Modpack verknüpft. Dies bedeutet, dass Mods nicht aktualisiert werden können, und dass du den Modloader oder die Minecraft Versionen nicht ändern kannst. Durch das trennen der Verknüpfung wird die Instanz permanent vom Modpack getrennt."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Verknüpfung vom Modpack trennen"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java und Arbeitsspeicher"
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "Umgebungsvariablen"
|
||||
},
|
||||
"instance.settings.tabs.java.hooks": {
|
||||
"message": "Hooks"
|
||||
},
|
||||
"instance.settings.tabs.java.java-arguments": {
|
||||
"message": "Java-Argumente"
|
||||
},
|
||||
"instance.settings.tabs.java.java-installation": {
|
||||
"message": "Java Installationen"
|
||||
},
|
||||
"instance.settings.tabs.java.java-memory": {
|
||||
"message": "Zugewiesener Arbeitsspeicher"
|
||||
},
|
||||
"instance.settings.tabs.window": {
|
||||
"message": "Spielfenster"
|
||||
},
|
||||
"instance.settings.tabs.window.custom-window-settings": {
|
||||
"message": "Benutzerdefinierte Spielfenstereinstellungen"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen": {
|
||||
"message": "Vollbild"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen.description": {
|
||||
"message": "Startet das Spiel im Vollbildmodus (durch verwenden von options.txt)."
|
||||
},
|
||||
"instance.settings.tabs.window.height": {
|
||||
"message": "Höhe"
|
||||
},
|
||||
"instance.settings.tabs.window.height.description": {
|
||||
"message": "Die höhe des Spielfensters beim Start."
|
||||
},
|
||||
"instance.settings.tabs.window.height.enter": {
|
||||
"message": "Höhe eingeben..."
|
||||
},
|
||||
"instance.settings.tabs.window.width": {
|
||||
"message": "Breite"
|
||||
},
|
||||
"instance.settings.tabs.window.width.description": {
|
||||
"message": "Die Breite des Spielfensters beim Start."
|
||||
},
|
||||
"instance.settings.tabs.window.width.enter": {
|
||||
"message": "Breite eingeben..."
|
||||
},
|
||||
"instance.worlds.a_minecraft_server": {
|
||||
"message": "Ä Minecraft-Server"
|
||||
},
|
||||
"instance.worlds.cant_connect": {
|
||||
"message": "Verbindung mit Server nicht möglich"
|
||||
},
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Adresse kopieren"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Nicht auf Startseite anzeigen"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Verfügbar"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Instanz ist bereits geöffnet"
|
||||
},
|
||||
"instance.worlds.hardcore": {
|
||||
"message": "Hardcore-Modus"
|
||||
},
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Server ist inkompatibel"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Server konnte nicht erreicht werden"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "Du kannst nur in Minecraft Alpha 1.0.5 und neuer direkt einem Server beitreten"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Du kannst nur in Minecraft 1.20 und neuer einer Einzelspieler-Welt beitreten"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Instanz Spielen"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Server"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Einzelspieler"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Instanz anzeigen"
|
||||
},
|
||||
"instance.worlds.world_in_use": {
|
||||
"message": "Welt bereits in benutzung"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "Von der Instanz bereitgestellt"
|
||||
},
|
||||
"search.filter.locked.instance-game-version.title": {
|
||||
"message": "Spielversion ist von der Instanz bereitgestellt"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "Loader ist von der Instanz bereitgestellt"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Mit Instanz synchronisieren"
|
||||
}
|
||||
}
|
||||
@@ -1,590 +0,0 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Die Authentifizierungsserver von Minecraft sind eventuell momentan nicht erreichbar. Überprüfe deine Internetverbindung und versuche es später erneut."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Authentifizierungsserver sind nicht erreichbar"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Installieren zum Spielen"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# Mod} other {# Mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Dieser Server benötigt Mods zum Spielen. Klick auf „Installieren“ um die erforderlichen Dateien von Modrinth zu installieren."
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} hat diese Instanz heute mit dir geteilt."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Geteilte Instanz"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Geteilte Serverinstanz"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} hinzugefügt"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Hinzugefügt"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Entfernt"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Aktualisiert"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Aktualisieren zum Spielen"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} entfernt"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Aktualisierung erforderlich"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Zum Spielen von {name} ist eine Aktualisierung erforderlich. Bitte aktualisiere auf die neueste Version, um das Spiel zu starten."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} aktualisiert"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Entwicklermodus aktiviert."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "Lade v{version} herunter"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "Erscheinungsbild"
|
||||
},
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Standard Instanz-Einstellungen"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Funktionsflags"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java-Installationen"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Sprache"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Datenschutz"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Ressourcenmanagement"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth App v{version} ist bereit zur Installation! Neu laden, um jetzt zu aktualisieren, oder automatisch, wenn du die Modrinth App schließt."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth App v{version} wurde heruntergeladen. Neu laden, um jetzt zu aktualisieren, oder automatisch, wenn du die Modrinth App schließt."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "Modrinth App v{version} ist verfügbar. Verwende deinen Paketmanager, um die neuesten Funktionen und Fehlerbehebungen zu installieren!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version} ist jetzt verfügbar! Da du ein getaktetes Netzwerk nutzt, haben wir den Download nicht automatisch gestartet."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Änderungsverlauf"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "Herunterladen ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Herunterladen"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Wird Heruntergeladen..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Neu laden"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Update verfügbar"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Download abgeschlossen"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Hier klicken, um das Änderungsprotokoll anzuzeigen."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "Version {version} wurde erfolgreich installiert!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "Update herunterladen"
|
||||
},
|
||||
"app.update.downloading-update": {
|
||||
"message": "Update wird heruntergeladen ({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Neu laden, um das Update zu installieren"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Freund hinzufügen"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} {count, plural, one {Freundesanfrage} other {Freundesanfragen}}"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Freundschaftsanfrage senden"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Einen Freund hinzufügen"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "Er kann vom Minecraft-Nutzernamen abweichen!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Modrinth-Benutzernamen eingeben..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Wie lautet der Modrinth-Benutzername deines Freundes?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Freunde hinzufügen</link>, um zu sehen, was sie spielen!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Anfrage abbrechen"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "Freund entfernen"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Freundschaftsanfrage gesendet"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "Profil anzeigen"
|
||||
},
|
||||
"friends.heading": {
|
||||
"message": "Freunde"
|
||||
},
|
||||
"friends.heading.active": {
|
||||
"message": "Aktiv"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "Ausstehend"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "Keine Freunde die \"{query}\" entsprechen"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Freunde durchsuchen..."
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Melde dich bei einem Modrinth-Konto an</link>, um Freunde hinzuzufügen und zu sehen, was sie gerade spielen!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Hinzufügen und spielen"
|
||||
},
|
||||
"instance.add-server.add-server": {
|
||||
"message": "Server hinzufügen"
|
||||
},
|
||||
"instance.add-server.resource-pack.disabled": {
|
||||
"message": "Deaktiviert"
|
||||
},
|
||||
"instance.add-server.resource-pack.enabled": {
|
||||
"message": "Aktiviert"
|
||||
},
|
||||
"instance.add-server.resource-pack.prompt": {
|
||||
"message": "Nachfragen"
|
||||
},
|
||||
"instance.add-server.title": {
|
||||
"message": "Server hinzufügen"
|
||||
},
|
||||
"instance.edit-server.title": {
|
||||
"message": "Server bearbeiten"
|
||||
},
|
||||
"instance.edit-world.hide-from-home": {
|
||||
"message": "Von der Startseite verbergen"
|
||||
},
|
||||
"instance.edit-world.name": {
|
||||
"message": "Name"
|
||||
},
|
||||
"instance.edit-world.placeholder-name": {
|
||||
"message": "Minecraft-Welt"
|
||||
},
|
||||
"instance.edit-world.reset-icon": {
|
||||
"message": "Icon zurücksetzen"
|
||||
},
|
||||
"instance.edit-world.title": {
|
||||
"message": "Welt bearbeiten"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Deaktivierte Projekte"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Updates verfügbar"
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Adresse"
|
||||
},
|
||||
"instance.server-modal.name": {
|
||||
"message": "Name"
|
||||
},
|
||||
"instance.server-modal.placeholder-name": {
|
||||
"message": "Minecraft-Server"
|
||||
},
|
||||
"instance.server-modal.resource-pack": {
|
||||
"message": "Ressourcenpaket"
|
||||
},
|
||||
"instance.settings.tabs.general": {
|
||||
"message": "Allgemein"
|
||||
},
|
||||
"instance.settings.tabs.general.delete": {
|
||||
"message": "Instanz löschen"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.button": {
|
||||
"message": "Instanz löschen"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Löscht eine Instanz dauerhaft von deinem Gerät, einschließlich deiner Welten, Einstellungen und aller installierten Inhalte. Sei vorsichtig, eine gelöschte Instanz ist nicht wiederherstellbar."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Wird gelöscht..."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button": {
|
||||
"message": "Kopieren"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button.tooltip.installing": {
|
||||
"message": "Kann während der Installation nicht dupliziert werden."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "Instanz duplizieren"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "Erstellt eine Kopie dieser Instanz, inklusive aller Welten, Einstellungen, Mods, usw."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "Icon bearbeiten"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.remove": {
|
||||
"message": "Icon entfernen"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.replace": {
|
||||
"message": "Icon ersetzen"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.select": {
|
||||
"message": "Icon auswählen"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups": {
|
||||
"message": "Bibliotheksgruppen"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.create": {
|
||||
"message": "Neue Gruppe erstellen"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.description": {
|
||||
"message": "Bibliotheksgruppen ermöglichen es dir, deine Instanzen in verschiedene Abschnitte deiner Bibliothek zu organisieren."
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.enter-name": {
|
||||
"message": "Gruppenname eingeben"
|
||||
},
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "Name"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Startargumente"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Benutzerdefinierte Startargumente"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Hooks ermöglichen es fortgeschrittenen Benutzern, bestimmte Systembefehle vor und nach dem Spielstart auszuführen."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "Nach dem Beenden"
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.description": {
|
||||
"message": "Wird nach dem Beenden des Spiels ausgeführt."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.enter": {
|
||||
"message": "Nach Spielbeendigung auszuführender Befehl eingeben..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch": {
|
||||
"message": "Vor dem Start"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.description": {
|
||||
"message": "Wird vor dem Starten der Instanz ausgeführt."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Vor Spielstart auszuführenden Befehl eingeben..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Start-Hooks"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "Wrapper"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "Wrapperbefehl für den Start von Minecraft."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "Wrapperbefehl eingeben..."
|
||||
},
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Installation"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} für Minecraft {game_version} bereits installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} ist bereits installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Version ändern"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Wird installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Modpack-Versionen werden abgerufen"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Neue Version wird installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Derzeit installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Informationen für die Fehlerbehebung:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Modpack-Details werden abgerufen"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Spielversion"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Installation im Gange"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} Version"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Die Details des verknüpften Modpacks können nicht abgerufen werden. Bitte überprüfe deine Internetverbindung."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} ist nicht für Minecraft {version} verfügbar. Versuche einen anderen Modloader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Diese Instanz ist mit einem Modpack verknüpft, aber das Modpack konnte auf Modrinth nicht gefunden werden."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Plattform"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Modpack neu installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Modpack wird neu installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Eine Neuinstallation setzt alle installierten oder geänderten Inhalte auf den Zustand zurück, der vom Modpack bereitgestellt wird, und entfernt alle Mods oder Inhalte, die du zusätzlich zur ursprünglichen Installation hinzugefügt hast.\nDies kann unerwartetes Verhalten beheben, falls Änderungen an der Instanz vorgenommen wurden. Wenn deine Welten jedoch von zusätzlich installierten Inhalten abhängen, kann dies bestehende Welten beschädigen."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Bist du dir sicher, dass du diese Instanz neu installieren willst?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Setzt den Inhalt der Instanz auf den ursprünglichen Zustand zurück und entfernt alle Mods oder Inhalte, die du zusätzlich zum ursprünglichen Modpack hinzugefügt hast."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Modpack neu installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Reparieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Wird repariert"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Durch die Reparatur werden die Abhängigkeiten von Minecraft neu installiert und auf Beschädigungen überprüft. Dies kann Probleme beheben, wenn Minecraft aufgrund von Fehlern im Launcher nicht startet, löst jedoch keine Probleme oder Abstürze im Zusammenhang mit installierten Mods."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Instanz reparieren?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Reparatur im Gange"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Auf aktuellen Stand zurücksetzen"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Alle Versionen anzeigen"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "Version ändern"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "Neuinstallieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "Reparieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "{action} während der Installation nicht möglich"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "{action} offline nicht möglich"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "{action} während der Reparation nicht möglich"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(unbekannte Version)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Verknüpfung der Instanz trennen"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Wenn du fortfährst, kannst du sie nicht erneut verknüpfen, ohne eine völlig neue Instanz zu erstellen. Du wirst keine Modpack-Updates mehr erhalten, und sie wird zu einer normalen Instanz."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Möchtest du die Verknüpfungen dieser Instanz wirklich trennen?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Diese Instanz ist mit einem Modpack verknüpft. Das bedeutet, dass Mods nicht aktualisiert werden können und der Mod-Loader oder die Minecraft-Version nicht geändert werden können. Durch das Aufheben der Verknüpfung wird die Instanz dauerhaft vom Modpack getrennt."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Verknüpfung vom Modpack trennen"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java und Arbeitsspeicher"
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "Umgebungsvariablen"
|
||||
},
|
||||
"instance.settings.tabs.java.hooks": {
|
||||
"message": "Hooks"
|
||||
},
|
||||
"instance.settings.tabs.java.java-arguments": {
|
||||
"message": "Java-Argumente"
|
||||
},
|
||||
"instance.settings.tabs.java.java-installation": {
|
||||
"message": "Java-Installation"
|
||||
},
|
||||
"instance.settings.tabs.java.java-memory": {
|
||||
"message": "Zugewiesener Arbeitsspeicher"
|
||||
},
|
||||
"instance.settings.tabs.window": {
|
||||
"message": "Fenster"
|
||||
},
|
||||
"instance.settings.tabs.window.custom-window-settings": {
|
||||
"message": "Benutzerdefinierte Fenstereinstellungen"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen": {
|
||||
"message": "Vollbild"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen.description": {
|
||||
"message": "Lässt das Spiel im Vollbildmodus starten (mit Verwendung von options.txt)."
|
||||
},
|
||||
"instance.settings.tabs.window.height": {
|
||||
"message": "Höhe"
|
||||
},
|
||||
"instance.settings.tabs.window.height.description": {
|
||||
"message": "Die Höhe des Spielfensters beim Start."
|
||||
},
|
||||
"instance.settings.tabs.window.height.enter": {
|
||||
"message": "Höhe eingeben..."
|
||||
},
|
||||
"instance.settings.tabs.window.width": {
|
||||
"message": "Breite"
|
||||
},
|
||||
"instance.settings.tabs.window.width.description": {
|
||||
"message": "Die Breite des Spielfensters beim Start."
|
||||
},
|
||||
"instance.settings.tabs.window.width.enter": {
|
||||
"message": "Breite eingeben..."
|
||||
},
|
||||
"instance.worlds.a_minecraft_server": {
|
||||
"message": "Ein Minecraft-Server"
|
||||
},
|
||||
"instance.worlds.cant_connect": {
|
||||
"message": "Verbindung mit Server nicht möglich"
|
||||
},
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Adresse kopieren"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Nicht auf der Startseite anzeigen"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Verfügbar"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Instanz ist bereits geöffnet"
|
||||
},
|
||||
"instance.worlds.hardcore": {
|
||||
"message": "Hardcore-Modus"
|
||||
},
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Server ist nicht kompatibel"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Server konnte nicht erreicht werden"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "Du kannst erst ab Minecraft Alpha 1.0.5+ direkt einem Server beitreten"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Du kannst erst ab Minecraft 1.20+ direkt in Einzelspieler-Welten springen"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Instanz spielen"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Server"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Einzelspieler"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Instanz anzeigen"
|
||||
},
|
||||
"instance.worlds.world_in_use": {
|
||||
"message": "Welt wird aktuell benutzt"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "Von der Instanz vorgegeben"
|
||||
},
|
||||
"search.filter.locked.instance-game-version.title": {
|
||||
"message": "Spielversion ist von der Instanz vorgegeben"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "Der Loader ist von der Instanz vorgegeben"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Mit Instanz synchronisieren"
|
||||
}
|
||||
}
|
||||
@@ -1,67 +1,7 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Minecraft authentication servers may be down right now. Check your internet connection and try again later."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Cannot reach authentication servers"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Install to play"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Install"
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "This server requires mods to play. Click install to set up the required files from Modrinth."
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} shared this instance with you today."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Shared instance"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Shared server instance"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} added"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Added"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Removed"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Updated"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Update to play"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} removed"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Update required"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "An update is required to play {name}. Please update to the latest version to launch the game."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} updated"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Developer mode enabled."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "Downloading v{version}"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "Appearance"
|
||||
},
|
||||
@@ -74,126 +14,12 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java installations"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Language"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Privacy"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Resource management"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth App v{version} is ready to install! Reload to update now, or automatically when you close Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth App v{version} has finished downloading. Reload to update now, or automatically when you close Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "Modrinth App v{version} is available. Use your package manager to update for the latest features and fixes!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version} is available now! Since you're on a metered network, we didn't automatically download it."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Changelog"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "Download ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Download"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Downloading..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Reload"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Update available"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Download complete"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Click here to view the changelog."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "Version {version} was successfully installed!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "Download update"
|
||||
},
|
||||
"app.update.downloading-update": {
|
||||
"message": "Downloading update ({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Reload to install update"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Add a friend"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} friend {count, plural, one {request} other {requests}}"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Send friend request"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Adding a friend"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "It may be different from their Minecraft username!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Enter Modrinth username..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "What's your friend's Modrinth username?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Add friends</link> to see what they're playing!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Cancel request"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "Remove friend"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Friend request sent"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "View profile"
|
||||
},
|
||||
"friends.heading": {
|
||||
"message": "Friends"
|
||||
},
|
||||
"friends.heading.active": {
|
||||
"message": "Active"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "Pending"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "No friends matching ''{query}''"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Search friends..."
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Sign in to a Modrinth account</link> to add friends and see what they're playing!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Add and play"
|
||||
},
|
||||
@@ -527,6 +353,9 @@
|
||||
"instance.settings.tabs.window.width.enter": {
|
||||
"message": "Enter width..."
|
||||
},
|
||||
"instance.settings.title": {
|
||||
"message": "Settings"
|
||||
},
|
||||
"instance.worlds.a_minecraft_server": {
|
||||
"message": "A Minecraft Server"
|
||||
},
|
||||
|
||||
@@ -1,590 +0,0 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Los servidores de autenticación de Minecraft pueden no estar funcionando en este momento. Verifica tu conexión a internet e inténtalo de nuevo más tarde."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "No se puede acceder a los servidores de autenticación"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Instala para jugar"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Instalar"
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Este servidor requiere mods para jugar. Haz clic en instalar para configurar los archivos necesarios desde Modrinth."
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} compartió esta instancia contigo hoy."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Instancia compartida"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Instancia de servidor compartida"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} agregados"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Se agregó"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Se eliminó"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Actualizado"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Actualiza para jugar"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} eliminados"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Actualización requerida"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Se requiere una actualización para jugar {name}. Por favor, actualiza a la versión más reciente para iniciar el juego."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} actualizados"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Modo desarrollador activado."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "Descargando v{version}"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "Apariencia"
|
||||
},
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Opciones predeterminadas de la instancia"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Funciones experimentales"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Instalaciones de Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Idioma"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Privacidad"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Gestión de recursos"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "¡Modrinth App v{version} lista para instalar! Actualiza ahora o automáticamente al cerrar la aplicación."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "La descarga de la Modrinth App v{version} ha finalizado. Actualiza ahora o automáticamente al cerrar la aplicación Modrinth."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "La aplicación Modrinth v{version} ya está disponible. ¡Utiliza tu gestor de paquetes para actualizarla y disfrutar de las últimas funciones y correcciones!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "¡Modrinth App v{version} ya está disponible! Como estás en una red con límite de datos, no se descargó automáticamente."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Registro de cambios"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "Descargar ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Descargar"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Descargando..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Recargar"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Actualización disponible"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Descarga completada"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Haz clic aquí para ver el registro de cambios."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "¡La versión {version} se ha instalado correctamente!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "Descargar actualización"
|
||||
},
|
||||
"app.update.downloading-update": {
|
||||
"message": "Descargando actualización ({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Recarga para instalar la actualización"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Añadir un amigo"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} {count, plural, one {solicitud} other {solicitudes}} de amistad"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Enviar solicitud de amistad"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Añadiendo un amigo"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "¡Podría ser distinto a su nombre de usuario de Minecraft!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Ingresa tu nombre de usuario de Modrinth..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "¿Cuál es el nombre de usuario de Modrinth de tu amigo?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>¡Añade amigos</link> para ver qué están jugando!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Cancelar solicitud"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "Eliminar amigo"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Solicitud de amistad enviada"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "Ver perfil"
|
||||
},
|
||||
"friends.heading": {
|
||||
"message": "Amigos"
|
||||
},
|
||||
"friends.heading.active": {
|
||||
"message": "Activos"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "Desconectados"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "Conectados"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "Pendiente"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "Ningún amigo coincide con \"{query}\""
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Buscar amigos..."
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>¡Inicia sesión en una cuenta de Modrinth</link> para añadir amigos y ver qué están jugando!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Añadir y jugar"
|
||||
},
|
||||
"instance.add-server.add-server": {
|
||||
"message": "Añadir servidor"
|
||||
},
|
||||
"instance.add-server.resource-pack.disabled": {
|
||||
"message": "Desactivado"
|
||||
},
|
||||
"instance.add-server.resource-pack.enabled": {
|
||||
"message": "Activado"
|
||||
},
|
||||
"instance.add-server.resource-pack.prompt": {
|
||||
"message": "Preguntar"
|
||||
},
|
||||
"instance.add-server.title": {
|
||||
"message": "Añadir un servidor"
|
||||
},
|
||||
"instance.edit-server.title": {
|
||||
"message": "Editar servidor"
|
||||
},
|
||||
"instance.edit-world.hide-from-home": {
|
||||
"message": "Ocultar de la página de Inicio"
|
||||
},
|
||||
"instance.edit-world.name": {
|
||||
"message": "Nombre"
|
||||
},
|
||||
"instance.edit-world.placeholder-name": {
|
||||
"message": "Mundo de Minecraft"
|
||||
},
|
||||
"instance.edit-world.reset-icon": {
|
||||
"message": "Restablecer ícono"
|
||||
},
|
||||
"instance.edit-world.title": {
|
||||
"message": "Editar mundo"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Proyectos desactivados"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Actualizaciones disponibles"
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Dirección IP"
|
||||
},
|
||||
"instance.server-modal.name": {
|
||||
"message": "Nombre"
|
||||
},
|
||||
"instance.server-modal.placeholder-name": {
|
||||
"message": "Servidor de Minecraft"
|
||||
},
|
||||
"instance.server-modal.resource-pack": {
|
||||
"message": "Paquete de recursos"
|
||||
},
|
||||
"instance.settings.tabs.general": {
|
||||
"message": "General"
|
||||
},
|
||||
"instance.settings.tabs.general.delete": {
|
||||
"message": "Eliminar instancia"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.button": {
|
||||
"message": "Eliminar instancia"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Elimina permanentemente una instancia de tu dispositivo, incluidos tus mundos, configuraciones y todo el contenido instalado. Ten cuidado, una vez eliminada, no hay forma de recuperarla."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Eliminando..."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button": {
|
||||
"message": "Duplicar"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button.tooltip.installing": {
|
||||
"message": "No se puede duplicar durante la instalación."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "Duplicar la instancia"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "Crea una copia de esta instancia, incluyendo mundos, configuración, mods, etc."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "Editar ícono"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.remove": {
|
||||
"message": "Eliminar ícono"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.replace": {
|
||||
"message": "Reemplazar ícono"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.select": {
|
||||
"message": "Selecionar ícono"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups": {
|
||||
"message": "Grupos de la librería"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.create": {
|
||||
"message": "Crear nuevo grupo"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.description": {
|
||||
"message": "Los grupos de la librería te ayudan a organizar tus instancias en diferentes secciones en tu librería."
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.enter-name": {
|
||||
"message": "Ingresa el nombre del grupo"
|
||||
},
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "Nombre"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Hooks de inicio"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Hooks de inicio personalizados"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Los hooks permiten que usuarios avanzados ejecuten comandos del sistema antes y despues de lanzar el juego."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "Post-cierre"
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.description": {
|
||||
"message": "Ejecutados después de que el juego se cierre."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.enter": {
|
||||
"message": "Introduce el comando post-cierre..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch": {
|
||||
"message": "Pre-inicio"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.description": {
|
||||
"message": "Ejecutados antes de que la instancia inicie."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Introduce el comando pre-inicio..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Hooks de inicio del juego"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "Wrapper"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "Comando Wrapper para iniciar Minecraft."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "Introduce el comando Wrapper..."
|
||||
},
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Instalación"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} ya está instalado para Minecraft {game_version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} ya está instalada"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Cambiar versión"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Instalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Instalando"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Obteniendo versiones del modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Instalando nueva versión"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Actualmente instalado"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Información de depuración:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Obteniendo detalles del modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Versión del juego"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Instalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Instalación en progreso"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "Versión de {loader}"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "No se pueden obtener los detalles del modpack vinculado. Por favor, verifica tu conexión a internet."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} no está disponible para Minecraft {version}. Prueba con otro mod loader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Esta instancia está vinculada a un modpack, pero no se pudo encontrar el modpack en Modrinth."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Plataforma"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Reinstalar modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Reinstalando modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "La reinstalación restablecerá todo el contenido instalado o modificado a lo que proporciona el modpack, eliminando cualquier mod o contenido que hayas agregado sobre la instalación original. Esto puede solucionar comportamientos inesperados si se han hecho cambios en la instancia, pero si tus mundos dependen de contenido adicional instalado, podría romper los mundos existentes."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "¿Estás seguro de que quieres reinstalar esta instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Restablece el contenido de la instancia a su estado original, eliminando cualquier mod o contenido que hayas agregado sobre el modpack original."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Reinstalar modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Reparar"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Reparando"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Reparar reinstala las dependencias de Minecraft y verifica la integridad de los archivos. Esto puede solucionar problemas si tu juego no se inicia por errores relacionados con el launcher, pero no resolverá problemas debidos a mods instalados."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "¿Reparar instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Reparación en proceso..."
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Restablecer al actual"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Mostrar todas las versiones"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "cambiar versión"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "instalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "reinstalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "reparar"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "No se puede {action} mientras se está instalando"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "No se puede {action} mientras estés desconectado"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "No se puede {action} mientras se está reparando"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(versión desconocida)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Desvincular instancia"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Si continúas, no podrás volver a vincularla sin crear una nueva instancia. Ya no recibirás actualizaciones del modpack y pasará a ser una instancia normal."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "¿Estás seguro de que quieres desvincular esta instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Esta instancia está vinculada a un modpack, lo que significa que los mods no pueden actualizarse y no puedes cambiar el mod loader ni la versión de Minecraft. Desvincularla la desconectará permanentemente del modpack."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Desvincular del modpack"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java y memoria"
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "Variables de entorno"
|
||||
},
|
||||
"instance.settings.tabs.java.hooks": {
|
||||
"message": "Hooks"
|
||||
},
|
||||
"instance.settings.tabs.java.java-arguments": {
|
||||
"message": "Argumentos de Java"
|
||||
},
|
||||
"instance.settings.tabs.java.java-installation": {
|
||||
"message": "Instalación de Java"
|
||||
},
|
||||
"instance.settings.tabs.java.java-memory": {
|
||||
"message": "Memoria asignada"
|
||||
},
|
||||
"instance.settings.tabs.window": {
|
||||
"message": "Ventana"
|
||||
},
|
||||
"instance.settings.tabs.window.custom-window-settings": {
|
||||
"message": "Configuración de ventana personalizada"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen": {
|
||||
"message": "Pantalla completa"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen.description": {
|
||||
"message": "Inicia el juego en pantalla completa al iniciarlo (usando options.txt)."
|
||||
},
|
||||
"instance.settings.tabs.window.height": {
|
||||
"message": "Altura"
|
||||
},
|
||||
"instance.settings.tabs.window.height.description": {
|
||||
"message": "Altura de la ventana del juego al iniciar."
|
||||
},
|
||||
"instance.settings.tabs.window.height.enter": {
|
||||
"message": "Ingresa la altura..."
|
||||
},
|
||||
"instance.settings.tabs.window.width": {
|
||||
"message": "Ancho"
|
||||
},
|
||||
"instance.settings.tabs.window.width.description": {
|
||||
"message": "Ancho de la ventana del juego al iniciar."
|
||||
},
|
||||
"instance.settings.tabs.window.width.enter": {
|
||||
"message": "Ingresa el ancho..."
|
||||
},
|
||||
"instance.worlds.a_minecraft_server": {
|
||||
"message": "Un servidor de Minecraft"
|
||||
},
|
||||
"instance.worlds.cant_connect": {
|
||||
"message": "No se puede conectar al servidor"
|
||||
},
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Copiar dirección"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "No mostrar en la página de inicio"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Disponible"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "La instancia ya está abierta"
|
||||
},
|
||||
"instance.worlds.hardcore": {
|
||||
"message": "Modo hardcore"
|
||||
},
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "El servidor es incompatible"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "No se pudo conectar al servidor"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "Solo puedes conectarte directamente a servidores en Minecraft Alpha 1.0.5+"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Solo puedes conectarte directamente a mundos para un jugador en Minecraft 1.20+"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Iniciar instancia"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Servidor"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Un jugador"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Ver instancia"
|
||||
},
|
||||
"instance.worlds.world_in_use": {
|
||||
"message": "El mundo ya está en uso"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "Proporcionado por la instancia"
|
||||
},
|
||||
"search.filter.locked.instance-game-version.title": {
|
||||
"message": "La versión del juego es proporcionada por la instancia"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "El loader es proporcionado por la instancia"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sincronizar con la instancia"
|
||||
}
|
||||
}
|
||||
@@ -1,590 +0,0 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Los servidores de autenticación de Minecraft pueden no estar funcionando en este momento. Verifica tu conexión a internet e inténtalo de nuevo más tarde."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "No se puede conectar con los servidores de autenticación"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Instala para jugar"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Instalar"
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Este servidor requiere mods para jugar. Haz clic en instalar para configurar los archivos necesarios de Modrinth."
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} ha compartido contigo hoy esta instancia."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Instancia compartida"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Instancia de servidor compartida"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} añadidos"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Añadido"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Eliminado"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Actualizado"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Actualiza para jugar"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} eliminados"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Actualización requerida"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Una actualización es requerida para jugar {name}. Por favor actualízala a la versión más reciente para ejecutar el juego."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} actualizados"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Modo desarrollador activado."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "Descargando v{version}"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "Apariencia"
|
||||
},
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Opciones predeterminadas de la instancia"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Funciones experimentales"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Instalaciones de Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Idioma"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Privacidad"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Gestión de recursos"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "¡La versión v{version} de Modrinth está lista para instalarse! Actualiza ahora o automáticamente al cerrar la aplicación."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "La descarga de la versión v{version} de Modrinth ha finalizado. Actualice ahora o automáticamente al cerrar la aplicación."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "Modrinth App v{version} está disponible. ¡Usa tu gestor de paquetes para actualizar a la última versión con nuevas funciones y correcciones!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "¡La versión v{version} de Modrinth App ya está disponible! Como estás conectado a una red con límite de datos, no la hemos descargado automáticamente."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Registro de cambios"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "Descarga ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Descargar"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Descargando..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Recarga"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Actualización disponible"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Descarga completada"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Haga clic aquí para ver el registro de cambios."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "¡La versión {version} se ha instalado correctamente!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "Descarga actualización"
|
||||
},
|
||||
"app.update.downloading-update": {
|
||||
"message": "Descargando actualización ({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Recarga para instalar la actualización"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Agrega a un amigo"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} {count, plural, one {petición} other {peticiones}} de amistad"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Envía una petición de amistad"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Agrega a un amigo"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "¡Puede ser diferente de su apodo en Minecraft!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Escribe su apodo en Modrinth..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "¿Cuál es el apodo de tu amigo en Modrinth?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Añade amigos</link> para ver a qué están jugando!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Cancelar petición"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "Eliminar amigo"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Petición de amistad enviada"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "Ver perfil"
|
||||
},
|
||||
"friends.heading": {
|
||||
"message": "Amigos"
|
||||
},
|
||||
"friends.heading.active": {
|
||||
"message": "Activos"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "Desconectados"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "Conectados"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "Pendientes"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "Ningún apodo concuerda con ''{query}''"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Buscando amigos..."
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title}: {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Inicia sesión en una cuenta Modrinth</link> para añadir amigos y ver a qué están jugando!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Añadir y jugar"
|
||||
},
|
||||
"instance.add-server.add-server": {
|
||||
"message": "Añadir servidor"
|
||||
},
|
||||
"instance.add-server.resource-pack.disabled": {
|
||||
"message": "Desactivado"
|
||||
},
|
||||
"instance.add-server.resource-pack.enabled": {
|
||||
"message": "Activado"
|
||||
},
|
||||
"instance.add-server.resource-pack.prompt": {
|
||||
"message": "Preguntar"
|
||||
},
|
||||
"instance.add-server.title": {
|
||||
"message": "Añadir un servidor"
|
||||
},
|
||||
"instance.edit-server.title": {
|
||||
"message": "Editar servidor"
|
||||
},
|
||||
"instance.edit-world.hide-from-home": {
|
||||
"message": "Ocultar de la página de Inicio"
|
||||
},
|
||||
"instance.edit-world.name": {
|
||||
"message": "Nombre"
|
||||
},
|
||||
"instance.edit-world.placeholder-name": {
|
||||
"message": "Mundo de Minecraft"
|
||||
},
|
||||
"instance.edit-world.reset-icon": {
|
||||
"message": "Resetear icono"
|
||||
},
|
||||
"instance.edit-world.title": {
|
||||
"message": "Editar mundo"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Desactivar proyectos"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Actualizaciones disponibles"
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Dirección IP"
|
||||
},
|
||||
"instance.server-modal.name": {
|
||||
"message": "Nombre"
|
||||
},
|
||||
"instance.server-modal.placeholder-name": {
|
||||
"message": "Servidor de Minecraft"
|
||||
},
|
||||
"instance.server-modal.resource-pack": {
|
||||
"message": "Paquete de recursos"
|
||||
},
|
||||
"instance.settings.tabs.general": {
|
||||
"message": "General"
|
||||
},
|
||||
"instance.settings.tabs.general.delete": {
|
||||
"message": "Eliminar instancia"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.button": {
|
||||
"message": "Eliminar instancia"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Elimina permanentemente una instancia de tu dispositivo, incluyendo tus mundos, configuraciones y todo el contenido instalado. Ten cuidado, ya que una vez que elimines una instancia no habrá forma de recuperarla."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Eliminando..."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button": {
|
||||
"message": "Duplicar"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button.tooltip.installing": {
|
||||
"message": "No puedes duplicar mientras se instala."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "Duplicar instancia"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "Crea una copia de esta instancia, incluyendo mundos, configuraciones, mods, etc."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "Editar icono"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.remove": {
|
||||
"message": "Eliminar icono"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.replace": {
|
||||
"message": "Reemplazar icono"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.select": {
|
||||
"message": "Seleccionar icono"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups": {
|
||||
"message": "Grupos de librerías"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.create": {
|
||||
"message": "Crear un nuevo grupo"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.description": {
|
||||
"message": "Los grupos de librerías te permiten organizar tus instancias en diferentes secciones en tu librería."
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.enter-name": {
|
||||
"message": "Inserta nombre de grupo"
|
||||
},
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "Nombre"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Hooks de lanzamiento"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Hooks de lanzamiento personalizados"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Los hooks permiten a los usuarios avanzados ejecutar ciertas funciones del sistema antes y después de lanzar el juego."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "Post-salida"
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.description": {
|
||||
"message": "Iniciar tras cerrar el juego."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.enter": {
|
||||
"message": "Introduzca el comando post-salida..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch": {
|
||||
"message": "Pre-lanzar"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.description": {
|
||||
"message": "Se ejecutó antes de iniciar la instancia."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Introducir comando previo al lanzamiento..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Hooks de lanzamiento del juego"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "Wrapper"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "comando Wrapper para lanzar Minecraft."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "Introducir comando para el wrapper..."
|
||||
},
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Instancia"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} para Minecraft {game_version} ya está instalada"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "La versión vanilla {game_version} ya está instalada"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Cambiar versión"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Instalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Instalando"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Buscando versiones del modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Instalando versión nueva"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Instalado actualmente"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Información de debug:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Buscando detalles del modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Versión del juego"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Instalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Instalación en progreso"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} versión"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "No se puede buscar los detalles del modpack enlazado. Por favor revise su conexión a internet."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} no está disponible para Minecraft {version}. Prueba con otro cargador."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "La instancia está enlazada a un modpack, pero el modpack no se ha podido encontrar en Modrinth."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Plataforma"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Reinstalar modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Reinstalando modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Reinstalar reiniciará todo el contenido instalado o modificado a lo que el modpack proporcione, quitando cualquier mod o contenido que hayas añadido por encima de la instalación original. Esto puede arreglar actividad inesperada, pero si los mundos dependen del contendio adicional instalado, puede romperlos. "
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "¿Estás seguro de que quieres reinstalar esta instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Reinicia el contenido de la instancia a su estado original, quitando cualquier mod o contenido que hayas añadido por encima del modpack original."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Reinstalar modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Reparar"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Reparando"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Reparando reinstalaciones Minecraft dependencias y buscando corrupciones. Esto podría solucionar problemas si tu juego no se está abriendo debido a errores relacionados con el launcher, pero no solucionará problemas o crashes relacionados con mods instalados."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "¿Reparar instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Reparación en progreso"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Reiniciar a actual"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Mostrar todas las versiones"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "cambiar versión"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "instalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "reinstalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "reparar"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "No se puede {action} mientras se está instalando."
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "No se puede {action} sin conexión"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "No se puede {action} reparando"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(versión desconocida)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Desvincular instancia"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Si procedes, no podrás re-vincular sin crear una nueva instancia. No recibirás actualizaciones del modpack y se convertira en uno normal."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "¿Estás seguro de que quieres desvincular esta instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "La instancia está vinculada a un modpack, lo que significa que los mods no pueden ser actualizados y no puedes cambiar el mod loader o la versión de Minecraft. Desvincular desconectará permanentemente esta instancia del modpack."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Desvincular del modpack"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java y memoria"
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "Variables de entorno"
|
||||
},
|
||||
"instance.settings.tabs.java.hooks": {
|
||||
"message": "Hooks"
|
||||
},
|
||||
"instance.settings.tabs.java.java-arguments": {
|
||||
"message": "Argumentos de Java"
|
||||
},
|
||||
"instance.settings.tabs.java.java-installation": {
|
||||
"message": "Instalación de Java"
|
||||
},
|
||||
"instance.settings.tabs.java.java-memory": {
|
||||
"message": "Memoria asignada"
|
||||
},
|
||||
"instance.settings.tabs.window": {
|
||||
"message": "Ventana"
|
||||
},
|
||||
"instance.settings.tabs.window.custom-window-settings": {
|
||||
"message": "Configuración de ventana personalizada"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen": {
|
||||
"message": "Pantalla completa"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen.description": {
|
||||
"message": "Iniciar juego en pantalla completa al iniciarse (usando options.txt)."
|
||||
},
|
||||
"instance.settings.tabs.window.height": {
|
||||
"message": "Alto"
|
||||
},
|
||||
"instance.settings.tabs.window.height.description": {
|
||||
"message": "La altura de la ventana del juego cuando se inicia."
|
||||
},
|
||||
"instance.settings.tabs.window.height.enter": {
|
||||
"message": "Introducir alto..."
|
||||
},
|
||||
"instance.settings.tabs.window.width": {
|
||||
"message": "Ancho"
|
||||
},
|
||||
"instance.settings.tabs.window.width.description": {
|
||||
"message": "El ancho de la ventana del juego cuando se inicia."
|
||||
},
|
||||
"instance.settings.tabs.window.width.enter": {
|
||||
"message": "Introduzca el ancho..."
|
||||
},
|
||||
"instance.worlds.a_minecraft_server": {
|
||||
"message": "Un Servidor de Minecraft"
|
||||
},
|
||||
"instance.worlds.cant_connect": {
|
||||
"message": "No se puede conectar al servidor"
|
||||
},
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Copiar dirección"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "No mostrar en Inicio"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Disponible"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "La instancia ya está abierta"
|
||||
},
|
||||
"instance.worlds.hardcore": {
|
||||
"message": "Modo hardcore"
|
||||
},
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Servidor es incompatible"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "No se pudo contactar con el servidor"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "Solo puedes acceder directamente a los servidores en Minecraft Alpha 1.0.5+"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Solo puedes saltar directamente a los mundos de un jugador en Minecraft 1.20+"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Jugar instancia"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Servidor"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Un jugador"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Ver instancia"
|
||||
},
|
||||
"instance.worlds.world_in_use": {
|
||||
"message": "El mundo está en uso"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "Proporcionado por la instancia"
|
||||
},
|
||||
"search.filter.locked.instance-game-version.title": {
|
||||
"message": "Versión del juego proporciona por la instancia"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "Cargador proporcionado por la instancia"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sincronizar con la instancia"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user