├── .editorconfig ├── .gitattributes ├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ ├── config.yml │ └── feature-request.yml └── workflows │ ├── build.yml │ ├── crowdin-sync.yml │ ├── release.yml │ ├── set-server-version.yml │ └── set-version.yml ├── .gitignore ├── .husky └── pre-commit ├── .idea └── icon.svg ├── .npmrc ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── com.soulfiremc.soulfire.metainfo.xml ├── components.json ├── crowdin.yml ├── eslint.config.mjs ├── generate-proto.ts ├── images ├── controls.png └── instances.png ├── index.html ├── locales ├── az-AZ │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json ├── cs-CZ │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json ├── de-DE │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json ├── en-US │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json ├── es-ES │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json ├── fr-FR │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json ├── lol-US │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json ├── pl-PL │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json ├── pt-BR │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json ├── ru-RU │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json ├── sk-SK │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json ├── tr-TR │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json ├── uk-UA │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json └── zh-CN │ ├── admin.json │ ├── common.json │ ├── instance.json │ └── login.json ├── package.json ├── pnpm-lock.yaml ├── postcss.config.mjs ├── protos ├── google │ └── protobuf │ │ ├── any.proto │ │ ├── api.proto │ │ ├── descriptor.proto │ │ ├── duration.proto │ │ ├── empty.proto │ │ ├── field_mask.proto │ │ ├── source_context.proto │ │ ├── struct.proto │ │ ├── timestamp.proto │ │ ├── type.proto │ │ └── wrappers.proto ├── grpc │ ├── binlog │ │ └── v1 │ │ │ └── binarylog.proto │ ├── channelz │ │ └── v1 │ │ │ └── channelz.proto │ ├── health │ │ └── v1 │ │ │ └── health.proto │ └── reflection │ │ └── v1 │ │ └── reflection.proto └── soulfire │ ├── client.proto │ ├── command.proto │ ├── common.proto │ ├── download.proto │ ├── instance.proto │ ├── login.proto │ ├── logs.proto │ ├── mc-auth.proto │ ├── proxy-check.proto │ ├── script.proto │ ├── server.proto │ └── user.proto ├── public ├── favicon.ico ├── icons │ ├── web-app-manifest-192x192.png │ └── web-app-manifest-512x512.png ├── logo.png ├── logo.svg ├── manifest.json └── robots.txt ├── renovate.json ├── rsbuild.config.ts ├── scripts └── termux_setup.sh ├── src-tauri ├── .cargo │ └── config.toml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── capabilities │ ├── default.json │ ├── desktop.json │ └── mobile.json ├── gen │ └── android │ │ ├── .editorconfig │ │ ├── .gitignore │ │ ├── app │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── soulfiremc │ │ │ │ └── soulfire │ │ │ │ ├── MainActivity.kt │ │ │ │ └── generated │ │ │ │ ├── Ipc.kt │ │ │ │ ├── Logger.kt │ │ │ │ ├── PermissionHelper.kt │ │ │ │ ├── RustWebChromeClient.kt │ │ │ │ ├── RustWebView.kt │ │ │ │ ├── RustWebViewClient.kt │ │ │ │ ├── TauriActivity.kt │ │ │ │ ├── WryActivity.kt │ │ │ │ └── proguard-wry.pro │ │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ └── ic_launcher_background.xml │ │ │ ├── layout │ │ │ └── activity_main.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── values-night │ │ │ └── themes.xml │ │ │ ├── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── themes.xml │ │ │ └── xml │ │ │ └── file_paths.xml │ │ ├── build.gradle.kts │ │ ├── buildSrc │ │ ├── build.gradle.kts │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── soulfiremc │ │ │ └── app │ │ │ └── kotlin │ │ │ ├── BuildTask.kt │ │ │ └── RustPlugin.kt │ │ ├── gradle.properties │ │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── settings.gradle ├── icons │ ├── 128x128.png │ ├── 128x128@2x.png │ ├── 32x32.png │ ├── Square107x107Logo.png │ ├── Square142x142Logo.png │ ├── Square150x150Logo.png │ ├── Square284x284Logo.png │ ├── Square30x30Logo.png │ ├── Square310x310Logo.png │ ├── Square44x44Logo.png │ ├── Square71x71Logo.png │ ├── Square89x89Logo.png │ ├── StoreLogo.png │ ├── android │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ └── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ ├── icon.icns │ ├── icon.ico │ ├── icon.png │ └── ios │ │ ├── AppIcon-20x20@1x.png │ │ ├── AppIcon-20x20@2x-1.png │ │ ├── AppIcon-20x20@2x.png │ │ ├── AppIcon-20x20@3x.png │ │ ├── AppIcon-29x29@1x.png │ │ ├── AppIcon-29x29@2x-1.png │ │ ├── AppIcon-29x29@2x.png │ │ ├── AppIcon-29x29@3x.png │ │ ├── AppIcon-40x40@1x.png │ │ ├── AppIcon-40x40@2x-1.png │ │ ├── AppIcon-40x40@2x.png │ │ ├── AppIcon-40x40@3x.png │ │ ├── AppIcon-512@2x.png │ │ ├── AppIcon-60x60@2x.png │ │ ├── AppIcon-60x60@3x.png │ │ ├── AppIcon-76x76@1x.png │ │ ├── AppIcon-76x76@2x.png │ │ └── AppIcon-83.5x83.5@2x.png ├── src │ ├── cast.rs │ ├── discord.rs │ ├── lib.rs │ ├── main.rs │ ├── sf_loader.rs │ ├── sf_version_constant.rs │ ├── tray.rs │ ├── updater.rs │ └── utils.rs ├── tauri.conf.json ├── tauri.linux.conf.json └── tauri.microsoftstore.conf.json ├── src ├── App.css ├── components │ ├── command-input.tsx │ ├── controls-menu.tsx │ ├── data-table-pagination.tsx │ ├── data-table-selects.tsx │ ├── data-table.tsx │ ├── dialog │ │ ├── about-dialog.tsx │ │ ├── create-instance-dialog.tsx │ │ ├── import-dialog.tsx │ │ ├── manage-script-dialog.tsx │ │ └── manage-user-dialog.tsx │ ├── dynamic-icon.tsx │ ├── error-component.tsx │ ├── external-link.tsx │ ├── generic-scripts-page.tsx │ ├── info-buttons.tsx │ ├── loading-component.tsx │ ├── nav │ │ ├── cast-menu-entry.tsx │ │ ├── instance-page-layout.tsx │ │ ├── instance-sidebar.tsx │ │ ├── instance-switcher.tsx │ │ ├── nav-account.tsx │ │ ├── nav-controls.tsx │ │ ├── nav-default-skeleton.tsx │ │ ├── nav-plugins.tsx │ │ ├── nav-secondary.tsx │ │ ├── nav-settings.tsx │ │ ├── nav-user-admin.tsx │ │ ├── nav-user-options.tsx │ │ ├── user-page-layout.tsx │ │ └── user-sidebar.tsx │ ├── not-found-component.tsx │ ├── plugin-info-card.tsx │ ├── providers │ │ ├── system-info-context.tsx │ │ ├── terminal-theme-context.tsx │ │ ├── theme-provider.tsx │ │ └── transport-context.tsx │ ├── settings-page.tsx │ ├── sf-timeago.tsx │ ├── tailwind-indicator.tsx │ ├── terminal.tsx │ ├── ui │ │ ├── avatar.tsx │ │ ├── badge.tsx │ │ ├── breadcrumb.tsx │ │ ├── button.tsx │ │ ├── calendar.tsx │ │ ├── card.tsx │ │ ├── chart.tsx │ │ ├── checkbox.tsx │ │ ├── collapsible.tsx │ │ ├── command.tsx │ │ ├── credenza.tsx │ │ ├── dialog.tsx │ │ ├── drawer.tsx │ │ ├── dropdown-menu.tsx │ │ ├── form.tsx │ │ ├── input-otp.tsx │ │ ├── input.tsx │ │ ├── label.tsx │ │ ├── menubar.tsx │ │ ├── popover.tsx │ │ ├── scroll-area.tsx │ │ ├── select.tsx │ │ ├── separator.tsx │ │ ├── sheet.tsx │ │ ├── sidebar.tsx │ │ ├── skeleton.tsx │ │ ├── sonner.tsx │ │ ├── switch.tsx │ │ ├── table.tsx │ │ ├── textarea.tsx │ │ └── tooltip.tsx │ └── user-avatar.tsx ├── demo-data.ts ├── env.d.ts ├── generated │ ├── google │ │ └── protobuf │ │ │ ├── any.ts │ │ │ ├── api.ts │ │ │ ├── descriptor.ts │ │ │ ├── duration.ts │ │ │ ├── empty.ts │ │ │ ├── field_mask.ts │ │ │ ├── source_context.ts │ │ │ ├── struct.ts │ │ │ ├── timestamp.ts │ │ │ ├── type.ts │ │ │ └── wrappers.ts │ ├── grpc │ │ ├── binlog │ │ │ └── v1 │ │ │ │ └── binarylog.ts │ │ ├── channelz │ │ │ └── v1 │ │ │ │ ├── channelz.client.ts │ │ │ │ └── channelz.ts │ │ ├── health │ │ │ └── v1 │ │ │ │ ├── health.client.ts │ │ │ │ └── health.ts │ │ └── reflection │ │ │ └── v1 │ │ │ ├── reflection.client.ts │ │ │ └── reflection.ts │ └── soulfire │ │ ├── client.client.ts │ │ ├── client.ts │ │ ├── command.client.ts │ │ ├── command.ts │ │ ├── common.ts │ │ ├── download.client.ts │ │ ├── download.ts │ │ ├── instance.client.ts │ │ ├── instance.ts │ │ ├── login.client.ts │ │ ├── login.ts │ │ ├── logs.client.ts │ │ ├── logs.ts │ │ ├── mc-auth.client.ts │ │ ├── mc-auth.ts │ │ ├── proxy-check.client.ts │ │ ├── proxy-check.ts │ │ ├── script.client.ts │ │ ├── script.ts │ │ ├── server.client.ts │ │ ├── server.ts │ │ ├── user.client.ts │ │ └── user.ts ├── hooks │ ├── use-changing-value.ts │ ├── use-date-fns-locale.ts │ ├── use-locale-number-format.tsx │ ├── use-media-query.tsx │ └── use-mobile.ts ├── index.tsx ├── lib │ ├── i18n.ts │ ├── types.ts │ ├── utils.tsx │ └── web-rpc.ts ├── routeTree.gen.ts └── routes │ ├── __root.tsx │ ├── _dashboard.tsx │ ├── _dashboard │ ├── instance │ │ ├── $instance.tsx │ │ └── $instance │ │ │ ├── accounts.tsx │ │ │ ├── audit-log.tsx │ │ │ ├── discover.tsx │ │ │ ├── index.tsx │ │ │ ├── meta.tsx │ │ │ ├── proxies.tsx │ │ │ ├── scripts.tsx │ │ │ └── settings │ │ │ └── $namespace.tsx │ ├── user.tsx │ └── user │ │ ├── access.tsx │ │ ├── admin.tsx │ │ ├── admin │ │ ├── console.tsx │ │ ├── index.tsx │ │ ├── scripts.tsx │ │ ├── settings │ │ │ └── $namespace.tsx │ │ └── users.tsx │ │ ├── index.tsx │ │ └── settings.tsx │ └── index.tsx ├── tsconfig.json ├── tsr.config.json └── vercel.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | tab_width = 2 10 | trim_trailing_whitespace = true 11 | ij_continuation_indent_size = 2 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.rs text eol=lf 2 | src-tauri/Cargo.toml text eol=lf 3 | src-tauri/Cargo.lock text eol=lf 4 | .gitignore text eol=lf 5 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @AlexProgrammerDE 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: alexprogrammerde 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | name: 🐞 Bug 2 | description: File a bug/issue report 3 | labels: ['type: :bug: bug'] 4 | 5 | body: 6 | - type: checkboxes 7 | attributes: 8 | label: Is there an existing issue for this? 9 | description: | 10 | Please search to see if an issue already exists for the bug you encountered. 11 | 12 | Tip: You can go to the [GitHub issue tab](https://github.com/AlexProgrammerDE/SoulFire/issues?q=is%3Aopen+is%3Aissue+label%3A%22type%3A+%3Abug%3A+bug%22) for a list of open issues 13 | options: 14 | - label: I have searched the existing issues 15 | required: true 16 | - type: textarea 17 | attributes: 18 | label: Describe your issue 19 | description: What is the issue? 20 | placeholder: "After the update x feature broke. It gives me this message: '...'" 21 | validations: 22 | required: true 23 | - type: textarea 24 | attributes: 25 | label: How can we reproduce what you got? 26 | description: Please describe the steps for us to reproduce the issue. Screenshots are also very welcomed. 27 | placeholder: | 28 | 1. Go to '...' 29 | 2. Click on '...' 30 | 3. Scroll down to '...' 31 | 4. See error 32 | validations: 33 | required: false 34 | - type: input 35 | id: logs 36 | attributes: 37 | label: SoulFire/Error Logs 38 | description: | 39 | Replace the links below by a paste of your console logs. 40 | - https://gist.github.com 41 | - https://bin.birdflop.com 42 | placeholder: '' 43 | validations: 44 | required: false 45 | - type: markdown 46 | attributes: 47 | value: '----' 48 | - type: markdown 49 | attributes: 50 | value: '## Helpful info' 51 | - type: input 52 | id: swversion 53 | attributes: 54 | label: SoulFire Version 55 | description: 'SoulFire says its version at startup.' 56 | placeholder: '1.0.0' 57 | validations: 58 | required: true 59 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: AlexProgrammerDE Discord 4 | url: https://pistonmaster.net/discord 5 | about: For support & help 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: 💡 Feature Request 2 | description: Request a feature/enhancement 3 | labels: ['type: :bulb: enhancement'] 4 | 5 | body: 6 | - type: checkboxes 7 | attributes: 8 | label: Is there an existing feature request for this? 9 | description: | 10 | Please search to see if an feature request like this already exists. 11 | 12 | Tip: You can go to the [GitHub issue tab](https://github.com/AlexProgrammerDE/SoulFire/labels/type%3A%20%3Abulb%3A%20enhancement) for a list of open feature requests 13 | options: 14 | - label: I have searched the existing feature requests 15 | required: true 16 | - type: textarea 17 | attributes: 18 | label: Describe your feature request 19 | description: What do you want added to SoulFire? 20 | placeholder: 'I want x feature added to SoulFire' 21 | validations: 22 | required: true 23 | -------------------------------------------------------------------------------- /.github/workflows/crowdin-sync.yml: -------------------------------------------------------------------------------- 1 | name: crowdin-sync 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | 7 | jobs: 8 | synchronize-with-crowdin: 9 | runs-on: ubuntu-24.04 10 | steps: 11 | - name: Checkout Repository 12 | uses: actions/checkout@v4 13 | with: 14 | persist-credentials: false 15 | - name: Crowdin Sync 16 | id: crowdin-download 17 | uses: crowdin/github-action@v2 18 | with: 19 | config: crowdin.yml 20 | upload_sources: true 21 | download_translations: true 22 | localization_branch_name: l10n_crowdin_translations 23 | create_pull_request: true 24 | pull_request_base_branch_name: main 25 | pull_request_title: 'chore(i18n): new crowdin translations' 26 | pull_request_body: 'New translations from [SoulFireClient Crowdin](https://crowdin.com/project/soulfireclient)' 27 | pull_request_labels: crowdin 28 | commit_message: 'chore(i18n): updated translations from crowdin' 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} 32 | CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} 33 | 34 | - name: Enable auto-merge for the PR 35 | if: steps.crowdin-download.outputs.pull_request_url 36 | run: gh pr --repo $GITHUB_REPOSITORY merge ${{ steps.crowdin-download.outputs.pull_request_url }} --auto --merge 37 | env: 38 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 39 | -------------------------------------------------------------------------------- /.github/workflows/set-server-version.yml: -------------------------------------------------------------------------------- 1 | name: set-server-version 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: 'Server version to set' 8 | required: true 9 | workflow_call: 10 | inputs: 11 | version: 12 | required: true 13 | type: string 14 | 15 | jobs: 16 | set-server-version: 17 | name: Set Server Version 18 | 19 | permissions: 20 | contents: write 21 | 22 | runs-on: ubuntu-24.04 23 | steps: 24 | - name: 'Shared: Checkout repository' 25 | uses: actions/checkout@v4 26 | with: 27 | ref: ${{ github.ref }} 28 | 29 | - name: 'Set Server Version' 30 | run: | 31 | echo "pub const SOULFIRE_VERSION: &str = \"${{ inputs.version }}\";" > src-tauri/src/sf_version_constant.rs 32 | 33 | - name: 'Commit Version' 34 | uses: stefanzweifel/git-auto-commit-action@v5 35 | with: 36 | commit_message: 'chore: bump server version to ${{ inputs.version }}' 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | .eslintcache 26 | .vercel 27 | 28 | .flatpak-builder/ 29 | builddir/ 30 | repo/ 31 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | pnpm run pre-commit 2 | -------------------------------------------------------------------------------- /.idea/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | SF 12 | 13 | 14 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | enable-pre-post-scripts=true 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | src/generated 27 | src/routeTree.gen.ts 28 | protobuf 29 | src-tauri 30 | pnpm-lock.yaml 31 | shared-modules 32 | locales 33 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "all", 4 | "singleQuote": true, 5 | "plugins": ["prettier-plugin-tailwindcss"] 6 | } 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [![discord](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/social/discord-singular_vector.svg)](https://discord.gg/vHgRd6YZmH) [![kofi](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/donate/kofi-singular_vector.svg)](https://ko-fi.com/alexprogrammerde) 4 | 5 | # SoulFireClient 6 | 7 | This is a frontend for the [SoulFire server](https://github.com/AlexProgrammerDE/SoulFire). 8 | It mainly targets the web, but uses native APIs using Tauri. 9 | 10 | > [!NOTE] 11 | > For more info about SoulFire, take a look at the main [SoulFire repository](https://github.com/AlexProgrammerDE/SoulFire). 12 | 13 | ## About the client 14 | 15 | Built using latest web tech to consistently work on both web, desktop and mobile. 16 | The client is the GUI for the SoulFire server, but it uses the official SoulFire gRPC API. 17 | Anything that can be done using the SF client can also be done using gRPC HTTP API calls directly. 18 | 19 | ## Installation 20 | 21 | > [!TIP] 22 | > Want to check out how SoulFire looks before installing it? Take a look at the official [demo page](https://demo.soulfiremc.com). 23 | 24 | For installing SoulFire, please refer to the [installation guide](https://soulfiremc.com/docs/installation). 25 | 26 | 27 | Get it on Flathub 28 | 29 | 30 | ## Deployments 31 | 32 | See which branches are at which URLs: 33 | 34 | - [`release`](https://app.soulfiremc.com) -> app.soulfiremc.com 35 | - [`main`](https://preview.soulfiremc.com) -> preview.soulfiremc.com 36 | - [`demo`](https://demo.soulfiremc.com) -> demo.soulfiremc.com 37 | 38 | ## Building 39 | 40 | The client has a lot of dependencies. You'll need pnpm, latest node and a nightly rust toolchain installed. 41 | Take a look at the scripts in `package.json` to see how to run a dev env locally. 42 | You can also refer to the GitHub actions workflows to see how production builds are made. 43 | 44 | ## Sponsors 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 |
[SignPath]Free code signing on Windows provided by SignPath.io, certificate by SignPath Foundation
54 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "src/App.css", 9 | "baseColor": "zinc", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | }, 20 | "iconLibrary": "lucide" 21 | } 22 | -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: /locales/en-US/*.json 3 | translation: /locales/%locale%/%original_file_name% 4 | type: i18next_json 5 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import eslint from '@eslint/js'; 2 | import tseslint from 'typescript-eslint'; 3 | import reactHooks from 'eslint-plugin-react-hooks'; 4 | import react from 'eslint-plugin-react'; 5 | import globals from 'globals'; 6 | 7 | // noinspection JSCheckFunctionSignatures 8 | export default tseslint.config( 9 | { 10 | ignores: [ 11 | 'src/generated', 12 | 'src/routeTree.gen.ts', 13 | '**/protobuf', 14 | 'node_modules', 15 | 'src-tauri', 16 | 'src/components/ui/chart.tsx', 17 | ], 18 | }, 19 | { 20 | languageOptions: { 21 | ecmaVersion: 2022, 22 | sourceType: 'module', 23 | globals: globals.browser, 24 | }, 25 | }, 26 | eslint.configs.recommended, 27 | tseslint.configs.recommendedTypeChecked, 28 | { 29 | plugins: { 30 | reactHooks, 31 | react, 32 | }, 33 | rules: { 34 | '@typescript-eslint/no-empty-object-type': 'off', 35 | }, 36 | languageOptions: { 37 | parserOptions: { 38 | projectService: true, 39 | tsconfigRootDir: import.meta.dirname, 40 | }, 41 | }, 42 | }, 43 | ); 44 | -------------------------------------------------------------------------------- /generate-proto.ts: -------------------------------------------------------------------------------- 1 | import { execSync } from 'child_process'; 2 | import { readdirSync, statSync } from 'fs'; 3 | import { join } from 'path'; 4 | 5 | function findProtoFiles(dir: string): string[] { 6 | let files: string[] = []; 7 | const entries = readdirSync(dir); 8 | for (const entry of entries) { 9 | const fullPath = join(dir, entry); 10 | if (statSync(fullPath).isDirectory()) { 11 | files = files.concat(findProtoFiles(fullPath)); 12 | } else if (entry.endsWith('.proto')) { 13 | files.push(fullPath); 14 | } 15 | } 16 | return files; 17 | } 18 | 19 | function compileProtos(): void { 20 | const protoFiles = findProtoFiles('protos'); 21 | if (protoFiles.length === 0) { 22 | console.log('No .proto files found.'); 23 | return; 24 | } 25 | 26 | const command = `protoc --ts_out src/generated --ts_opt long_type_string --ts_opt optimize_code_size --ts_opt eslint_disable --ts_opt ts_nocheck --proto_path protos ${protoFiles.join(' ')}`; 27 | console.log(`Running: ${command}`); 28 | execSync(command, { stdio: 'inherit' }); 29 | } 30 | 31 | compileProtos(); 32 | -------------------------------------------------------------------------------- /images/controls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/images/controls.png -------------------------------------------------------------------------------- /images/instances.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/images/instances.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | SoulFire 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 68 | 69 | 70 |
71 | 72 | 73 | -------------------------------------------------------------------------------- /locales/az-AZ/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "overview": { 3 | "welcome": "", 4 | "instancesChart": { 5 | "title": "", 6 | "instances": "", 7 | "label": { 8 | "state": "", 9 | "active": "", 10 | "stopped": "", 11 | "other": "" 12 | } 13 | }, 14 | "usersChart": { 15 | "title": "", 16 | "users": "", 17 | "label": { 18 | "role": "", 19 | "user": "", 20 | "admin": "", 21 | "other": "" 22 | } 23 | } 24 | }, 25 | "users": { 26 | "filterPlaceholder": "", 27 | "baseUserDialog": { 28 | "form": { 29 | "username": { 30 | "min": "", 31 | "max": "", 32 | "regex": "", 33 | "label": "", 34 | "placeholder": "", 35 | "description": "" 36 | }, 37 | "email": { 38 | "label": "", 39 | "placeholder": "", 40 | "description": "" 41 | }, 42 | "role": { 43 | "label": "", 44 | "description": "", 45 | "user": "", 46 | "admin": "" 47 | } 48 | } 49 | }, 50 | "addUserDialog": { 51 | "title": "", 52 | "description": "", 53 | "form": { 54 | "cancel": "", 55 | "add": "" 56 | } 57 | }, 58 | "updateUserDialog": { 59 | "title": "", 60 | "description": "", 61 | "form": { 62 | "cancel": "", 63 | "update": "" 64 | } 65 | }, 66 | "addToast": { 67 | "loading": "", 68 | "success": "", 69 | "error": "" 70 | }, 71 | "updateToast": { 72 | "loading": "", 73 | "success": "", 74 | "error": "" 75 | }, 76 | "removeToast": { 77 | "loading": "", 78 | "success": "", 79 | "error": "" 80 | }, 81 | "invalidateToast": { 82 | "loading": "", 83 | "success": "", 84 | "error": "" 85 | }, 86 | "table": { 87 | "username": "", 88 | "email": "", 89 | "role": "", 90 | "createdAt": "", 91 | "minIssuedAt": "", 92 | "actions": "" 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /locales/az-AZ/instance.json: -------------------------------------------------------------------------------- 1 | { 2 | "proxy": { 3 | "filterPlaceholder": "", 4 | "listImportToast": { 5 | "loading": "", 6 | "success": "", 7 | "error": "", 8 | "noProxies": "" 9 | }, 10 | "import": { 11 | "proxyType": "", 12 | "http": "", 13 | "socks4": "", 14 | "socks5": "", 15 | "uri": "", 16 | "dialog": { 17 | "title": "", 18 | "description": "" 19 | } 20 | }, 21 | "removeToast": { 22 | "loading": "", 23 | "success": "", 24 | "error": "" 25 | }, 26 | "checkToast": { 27 | "loading": "", 28 | "success": "", 29 | "error": "" 30 | }, 31 | "invalidFormat": "", 32 | "table": { 33 | "type": "", 34 | "address": "", 35 | "username": "", 36 | "password": "" 37 | } 38 | }, 39 | "account": { 40 | "filterPlaceholder": "", 41 | "listImportToast": { 42 | "loading": "", 43 | "allFailed": "", 44 | "someFailed": "", 45 | "noneFailed": "", 46 | "error": "", 47 | "noAccounts": "" 48 | }, 49 | "unknownError": "", 50 | "deviceCodeImportToast": { 51 | "loading": "", 52 | "success": "", 53 | "error": "" 54 | }, 55 | "import": { 56 | "javaEdition": "", 57 | "bedrockEdition": "", 58 | "offline": "", 59 | "microsoftCredentials": "", 60 | "microsoftDeviceCode": "", 61 | "microsoftRefreshToken": "", 62 | "theAltening": "", 63 | "dialog": { 64 | "title": "", 65 | "description": "" 66 | } 67 | }, 68 | "removeToast": { 69 | "loading": "", 70 | "success": "", 71 | "error": "" 72 | }, 73 | "table": { 74 | "type": "", 75 | "profileId": "", 76 | "lastKnownName": "" 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /locales/az-AZ/login.json: -------------------------------------------------------------------------------- 1 | { 2 | "header": { 3 | "image": { 4 | "alt": "" 5 | }, 6 | "title": "" 7 | }, 8 | "connect": { 9 | "title": "", 10 | "description": "", 11 | "integrated": { 12 | "title": "", 13 | "description": "" 14 | }, 15 | "dedicated": { 16 | "title": "", 17 | "description": "" 18 | }, 19 | "demo": { 20 | "title": "", 21 | "description": "" 22 | } 23 | }, 24 | "integrated": { 25 | "preparing": "", 26 | "toast": { 27 | "loading": "", 28 | "success": "", 29 | "error": "" 30 | }, 31 | "description": "", 32 | "form": { 33 | "jvmArgs": { 34 | "title": "", 35 | "description": "", 36 | "placeholder": "" 37 | }, 38 | "back": "", 39 | "start": "" 40 | }, 41 | "mobile": { 42 | "description": "", 43 | "form": { 44 | "termuxCommand": { 45 | "title": "", 46 | "description": "" 47 | }, 48 | "token": { 49 | "title": "", 50 | "description": "", 51 | "placeholder": "" 52 | }, 53 | "back": "", 54 | "connect": "" 55 | } 56 | } 57 | }, 58 | "dedicated": { 59 | "description": "", 60 | "toast": { 61 | "loading": "", 62 | "success": "", 63 | "error": "" 64 | }, 65 | "form": { 66 | "address": { 67 | "title": "", 68 | "description": "", 69 | "placeholder": "" 70 | }, 71 | "token": { 72 | "title": "", 73 | "placeholder": "", 74 | "description": "" 75 | }, 76 | "email": { 77 | "title": "", 78 | "placeholder": "", 79 | "description": "" 80 | }, 81 | "back": "", 82 | "useToken": "", 83 | "useEmail": "", 84 | "login": "" 85 | } 86 | }, 87 | "emailCode": { 88 | "description": "", 89 | "toast": { 90 | "loading": "", 91 | "success": "", 92 | "error": "" 93 | }, 94 | "back": "" 95 | }, 96 | "footer": { 97 | "version": "", 98 | "preview": "", 99 | "production": "", 100 | "helpTranslate": "" 101 | } 102 | } -------------------------------------------------------------------------------- /locales/cs-CZ/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "overview": { 3 | "welcome": "", 4 | "instancesChart": { 5 | "title": "", 6 | "instances": "", 7 | "label": { 8 | "state": "", 9 | "active": "", 10 | "stopped": "", 11 | "other": "" 12 | } 13 | }, 14 | "usersChart": { 15 | "title": "", 16 | "users": "", 17 | "label": { 18 | "role": "", 19 | "user": "", 20 | "admin": "", 21 | "other": "" 22 | } 23 | } 24 | }, 25 | "users": { 26 | "filterPlaceholder": "", 27 | "baseUserDialog": { 28 | "form": { 29 | "username": { 30 | "min": "", 31 | "max": "", 32 | "regex": "", 33 | "label": "", 34 | "placeholder": "", 35 | "description": "" 36 | }, 37 | "email": { 38 | "label": "", 39 | "placeholder": "", 40 | "description": "" 41 | }, 42 | "role": { 43 | "label": "", 44 | "description": "", 45 | "user": "", 46 | "admin": "" 47 | } 48 | } 49 | }, 50 | "addUserDialog": { 51 | "title": "", 52 | "description": "", 53 | "form": { 54 | "cancel": "", 55 | "add": "" 56 | } 57 | }, 58 | "updateUserDialog": { 59 | "title": "", 60 | "description": "", 61 | "form": { 62 | "cancel": "", 63 | "update": "" 64 | } 65 | }, 66 | "addToast": { 67 | "loading": "", 68 | "success": "", 69 | "error": "" 70 | }, 71 | "updateToast": { 72 | "loading": "", 73 | "success": "", 74 | "error": "" 75 | }, 76 | "removeToast": { 77 | "loading": "", 78 | "success": "", 79 | "error": "" 80 | }, 81 | "invalidateToast": { 82 | "loading": "", 83 | "success": "", 84 | "error": "" 85 | }, 86 | "table": { 87 | "username": "", 88 | "email": "", 89 | "role": "", 90 | "createdAt": "", 91 | "minIssuedAt": "", 92 | "actions": "" 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /locales/cs-CZ/instance.json: -------------------------------------------------------------------------------- 1 | { 2 | "proxy": { 3 | "filterPlaceholder": "", 4 | "listImportToast": { 5 | "loading": "", 6 | "success": "", 7 | "error": "", 8 | "noProxies": "" 9 | }, 10 | "import": { 11 | "proxyType": "", 12 | "http": "", 13 | "socks4": "", 14 | "socks5": "", 15 | "uri": "", 16 | "dialog": { 17 | "title": "", 18 | "description": "" 19 | } 20 | }, 21 | "removeToast": { 22 | "loading": "", 23 | "success": "", 24 | "error": "" 25 | }, 26 | "checkToast": { 27 | "loading": "", 28 | "success": "", 29 | "error": "" 30 | }, 31 | "invalidFormat": "", 32 | "table": { 33 | "type": "", 34 | "address": "", 35 | "username": "", 36 | "password": "" 37 | } 38 | }, 39 | "account": { 40 | "filterPlaceholder": "", 41 | "listImportToast": { 42 | "loading": "", 43 | "allFailed": "", 44 | "someFailed": "", 45 | "noneFailed": "", 46 | "error": "", 47 | "noAccounts": "" 48 | }, 49 | "unknownError": "", 50 | "deviceCodeImportToast": { 51 | "loading": "", 52 | "success": "", 53 | "error": "" 54 | }, 55 | "import": { 56 | "javaEdition": "", 57 | "bedrockEdition": "", 58 | "offline": "", 59 | "microsoftCredentials": "", 60 | "microsoftDeviceCode": "", 61 | "microsoftRefreshToken": "", 62 | "theAltening": "", 63 | "dialog": { 64 | "title": "", 65 | "description": "" 66 | } 67 | }, 68 | "removeToast": { 69 | "loading": "", 70 | "success": "", 71 | "error": "" 72 | }, 73 | "table": { 74 | "type": "", 75 | "profileId": "", 76 | "lastKnownName": "" 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /locales/cs-CZ/login.json: -------------------------------------------------------------------------------- 1 | { 2 | "header": { 3 | "image": { 4 | "alt": "" 5 | }, 6 | "title": "" 7 | }, 8 | "connect": { 9 | "title": "", 10 | "description": "", 11 | "integrated": { 12 | "title": "", 13 | "description": "" 14 | }, 15 | "dedicated": { 16 | "title": "", 17 | "description": "" 18 | }, 19 | "demo": { 20 | "title": "", 21 | "description": "" 22 | } 23 | }, 24 | "integrated": { 25 | "preparing": "", 26 | "toast": { 27 | "loading": "", 28 | "success": "", 29 | "error": "" 30 | }, 31 | "description": "", 32 | "form": { 33 | "jvmArgs": { 34 | "title": "", 35 | "description": "", 36 | "placeholder": "" 37 | }, 38 | "back": "", 39 | "start": "" 40 | }, 41 | "mobile": { 42 | "description": "", 43 | "form": { 44 | "termuxCommand": { 45 | "title": "", 46 | "description": "" 47 | }, 48 | "token": { 49 | "title": "", 50 | "description": "", 51 | "placeholder": "" 52 | }, 53 | "back": "", 54 | "connect": "" 55 | } 56 | } 57 | }, 58 | "dedicated": { 59 | "description": "", 60 | "toast": { 61 | "loading": "", 62 | "success": "", 63 | "error": "" 64 | }, 65 | "form": { 66 | "address": { 67 | "title": "", 68 | "description": "", 69 | "placeholder": "" 70 | }, 71 | "token": { 72 | "title": "", 73 | "placeholder": "", 74 | "description": "" 75 | }, 76 | "email": { 77 | "title": "", 78 | "placeholder": "", 79 | "description": "" 80 | }, 81 | "back": "", 82 | "useToken": "", 83 | "useEmail": "", 84 | "login": "" 85 | } 86 | }, 87 | "emailCode": { 88 | "description": "", 89 | "toast": { 90 | "loading": "", 91 | "success": "", 92 | "error": "" 93 | }, 94 | "back": "" 95 | }, 96 | "footer": { 97 | "version": "", 98 | "preview": "", 99 | "production": "", 100 | "helpTranslate": "" 101 | } 102 | } -------------------------------------------------------------------------------- /locales/de-DE/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "overview": { 3 | "welcome": "Willkommen zurück, {{name}} 🧙", 4 | "instancesChart": { 5 | "title": "Gesamte Instanzen auf diesem Server", 6 | "instances": "Instanzen", 7 | "label": { 8 | "state": "Zustand", 9 | "active": "Aktiv", 10 | "stopped": "Gestoppt", 11 | "other": "Andere" 12 | } 13 | }, 14 | "usersChart": { 15 | "title": "Gesamte Nutzer auf diesem Server", 16 | "users": "Nutzer", 17 | "label": { 18 | "role": "Rolle", 19 | "user": "Nutzer", 20 | "admin": "Admin", 21 | "other": "Andere" 22 | } 23 | } 24 | }, 25 | "users": { 26 | "filterPlaceholder": "", 27 | "baseUserDialog": { 28 | "form": { 29 | "username": { 30 | "min": "", 31 | "max": "", 32 | "regex": "", 33 | "label": "Benutzername", 34 | "placeholder": "", 35 | "description": "" 36 | }, 37 | "email": { 38 | "label": "", 39 | "placeholder": "", 40 | "description": "" 41 | }, 42 | "role": { 43 | "label": "Rolle", 44 | "description": "", 45 | "user": "Nutzer", 46 | "admin": "Admin" 47 | } 48 | } 49 | }, 50 | "addUserDialog": { 51 | "title": "", 52 | "description": "", 53 | "form": { 54 | "cancel": "Abbrechen", 55 | "add": "" 56 | } 57 | }, 58 | "updateUserDialog": { 59 | "title": "", 60 | "description": "", 61 | "form": { 62 | "cancel": "Abbrechen", 63 | "update": "" 64 | } 65 | }, 66 | "addToast": { 67 | "loading": "", 68 | "success": "", 69 | "error": "" 70 | }, 71 | "updateToast": { 72 | "loading": "", 73 | "success": "", 74 | "error": "" 75 | }, 76 | "removeToast": { 77 | "loading": "", 78 | "success": "", 79 | "error": "" 80 | }, 81 | "invalidateToast": { 82 | "loading": "", 83 | "success": "", 84 | "error": "" 85 | }, 86 | "table": { 87 | "username": "Benutzername", 88 | "email": "", 89 | "role": "Rolle", 90 | "createdAt": "Erstellt", 91 | "minIssuedAt": "Min. Login", 92 | "actions": "Aktionen" 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /locales/es-ES/instance.json: -------------------------------------------------------------------------------- 1 | { 2 | "proxy": { 3 | "filterPlaceholder": "", 4 | "listImportToast": { 5 | "loading": "", 6 | "success": "", 7 | "error": "", 8 | "noProxies": "" 9 | }, 10 | "import": { 11 | "proxyType": "", 12 | "http": "", 13 | "socks4": "", 14 | "socks5": "", 15 | "uri": "", 16 | "dialog": { 17 | "title": "", 18 | "description": "" 19 | } 20 | }, 21 | "removeToast": { 22 | "loading": "", 23 | "success": "", 24 | "error": "" 25 | }, 26 | "checkToast": { 27 | "loading": "", 28 | "success": "", 29 | "error": "" 30 | }, 31 | "invalidFormat": "", 32 | "table": { 33 | "type": "Tipo", 34 | "address": "Dirección de conexión", 35 | "username": "", 36 | "password": "" 37 | } 38 | }, 39 | "account": { 40 | "filterPlaceholder": "", 41 | "listImportToast": { 42 | "loading": "", 43 | "allFailed": "", 44 | "someFailed": "", 45 | "noneFailed": "", 46 | "error": "", 47 | "noAccounts": "" 48 | }, 49 | "unknownError": "", 50 | "deviceCodeImportToast": { 51 | "loading": "", 52 | "success": "", 53 | "error": "" 54 | }, 55 | "import": { 56 | "javaEdition": "", 57 | "bedrockEdition": "", 58 | "offline": "", 59 | "microsoftCredentials": "", 60 | "microsoftDeviceCode": "", 61 | "microsoftRefreshToken": "", 62 | "theAltening": "", 63 | "dialog": { 64 | "title": "", 65 | "description": "" 66 | } 67 | }, 68 | "removeToast": { 69 | "loading": "", 70 | "success": "", 71 | "error": "" 72 | }, 73 | "table": { 74 | "type": "Tipo", 75 | "profileId": "", 76 | "lastKnownName": "" 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /locales/lol-US/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "overview": { 3 | "welcome": "", 4 | "instancesChart": { 5 | "title": "", 6 | "instances": "", 7 | "label": { 8 | "state": "", 9 | "active": "", 10 | "stopped": "", 11 | "other": "" 12 | } 13 | }, 14 | "usersChart": { 15 | "title": "", 16 | "users": "", 17 | "label": { 18 | "role": "", 19 | "user": "", 20 | "admin": "", 21 | "other": "" 22 | } 23 | } 24 | }, 25 | "users": { 26 | "filterPlaceholder": "", 27 | "baseUserDialog": { 28 | "form": { 29 | "username": { 30 | "min": "", 31 | "max": "", 32 | "regex": "", 33 | "label": "", 34 | "placeholder": "", 35 | "description": "" 36 | }, 37 | "email": { 38 | "label": "", 39 | "placeholder": "", 40 | "description": "" 41 | }, 42 | "role": { 43 | "label": "", 44 | "description": "", 45 | "user": "", 46 | "admin": "" 47 | } 48 | } 49 | }, 50 | "addUserDialog": { 51 | "title": "", 52 | "description": "", 53 | "form": { 54 | "cancel": "cancel k?", 55 | "add": "" 56 | } 57 | }, 58 | "updateUserDialog": { 59 | "title": "", 60 | "description": "", 61 | "form": { 62 | "cancel": "cancel k?", 63 | "update": "" 64 | } 65 | }, 66 | "addToast": { 67 | "loading": "", 68 | "success": "", 69 | "error": "" 70 | }, 71 | "updateToast": { 72 | "loading": "", 73 | "success": "", 74 | "error": "" 75 | }, 76 | "removeToast": { 77 | "loading": "", 78 | "success": "", 79 | "error": "" 80 | }, 81 | "invalidateToast": { 82 | "loading": "", 83 | "success": "", 84 | "error": "" 85 | }, 86 | "table": { 87 | "username": "", 88 | "email": "", 89 | "role": "", 90 | "createdAt": "", 91 | "minIssuedAt": "", 92 | "actions": "" 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /locales/lol-US/instance.json: -------------------------------------------------------------------------------- 1 | { 2 | "proxy": { 3 | "filterPlaceholder": "", 4 | "listImportToast": { 5 | "loading": "", 6 | "success": "", 7 | "error": "", 8 | "noProxies": "" 9 | }, 10 | "import": { 11 | "proxyType": "", 12 | "http": "", 13 | "socks4": "", 14 | "socks5": "", 15 | "uri": "", 16 | "dialog": { 17 | "title": "", 18 | "description": "" 19 | } 20 | }, 21 | "removeToast": { 22 | "loading": "", 23 | "success": "", 24 | "error": "" 25 | }, 26 | "checkToast": { 27 | "loading": "", 28 | "success": "", 29 | "error": "" 30 | }, 31 | "invalidFormat": "", 32 | "table": { 33 | "type": "Tyep", 34 | "address": "Addres", 35 | "username": "", 36 | "password": "" 37 | } 38 | }, 39 | "account": { 40 | "filterPlaceholder": "", 41 | "listImportToast": { 42 | "loading": "", 43 | "allFailed": "", 44 | "someFailed": "", 45 | "noneFailed": "", 46 | "error": "", 47 | "noAccounts": "" 48 | }, 49 | "unknownError": "", 50 | "deviceCodeImportToast": { 51 | "loading": "", 52 | "success": "", 53 | "error": "" 54 | }, 55 | "import": { 56 | "javaEdition": "", 57 | "bedrockEdition": "", 58 | "offline": "", 59 | "microsoftCredentials": "", 60 | "microsoftDeviceCode": "", 61 | "microsoftRefreshToken": "", 62 | "theAltening": "", 63 | "dialog": { 64 | "title": "", 65 | "description": "" 66 | } 67 | }, 68 | "removeToast": { 69 | "loading": "", 70 | "success": "", 71 | "error": "" 72 | }, 73 | "table": { 74 | "type": "Tyep", 75 | "profileId": "", 76 | "lastKnownName": "" 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /locales/pl-PL/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "overview": { 3 | "welcome": "Witamy ponownie, {{name}}🧙", 4 | "instancesChart": { 5 | "title": "Wszystkie instancje na tym serwerze", 6 | "instances": "Instancje", 7 | "label": { 8 | "state": "Stan", 9 | "active": "Aktywny", 10 | "stopped": "Zatrzymana", 11 | "other": "Inne" 12 | } 13 | }, 14 | "usersChart": { 15 | "title": "Wszyscy użytkownicy na tym serwerze", 16 | "users": "Użytkownicy", 17 | "label": { 18 | "role": "Role", 19 | "user": "Użytkownik", 20 | "admin": "Administrator", 21 | "other": "Inne" 22 | } 23 | } 24 | }, 25 | "users": { 26 | "filterPlaceholder": "", 27 | "baseUserDialog": { 28 | "form": { 29 | "username": { 30 | "min": "", 31 | "max": "", 32 | "regex": "", 33 | "label": "Nazwa użytkownika", 34 | "placeholder": "", 35 | "description": "" 36 | }, 37 | "email": { 38 | "label": "E-mail", 39 | "placeholder": "", 40 | "description": "" 41 | }, 42 | "role": { 43 | "label": "Role", 44 | "description": "", 45 | "user": "Użytkownik", 46 | "admin": "Administrator" 47 | } 48 | } 49 | }, 50 | "addUserDialog": { 51 | "title": "", 52 | "description": "", 53 | "form": { 54 | "cancel": "Anuluj", 55 | "add": "" 56 | } 57 | }, 58 | "updateUserDialog": { 59 | "title": "", 60 | "description": "", 61 | "form": { 62 | "cancel": "Anuluj", 63 | "update": "" 64 | } 65 | }, 66 | "addToast": { 67 | "loading": "", 68 | "success": "", 69 | "error": "" 70 | }, 71 | "updateToast": { 72 | "loading": "", 73 | "success": "", 74 | "error": "" 75 | }, 76 | "removeToast": { 77 | "loading": "", 78 | "success": "", 79 | "error": "" 80 | }, 81 | "invalidateToast": { 82 | "loading": "", 83 | "success": "", 84 | "error": "" 85 | }, 86 | "table": { 87 | "username": "Nazwa użytkownika", 88 | "email": "E-mail", 89 | "role": "Role", 90 | "createdAt": "", 91 | "minIssuedAt": "", 92 | "actions": "" 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /locales/pt-BR/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "overview": { 3 | "welcome": "Bem-vindo de volta, {{name}} 🧙", 4 | "instancesChart": { 5 | "title": "Total de instâncias neste servidor", 6 | "instances": "Instâncias", 7 | "label": { 8 | "state": "Estado", 9 | "active": "Ativo", 10 | "stopped": "Interrompido", 11 | "other": "Outro" 12 | } 13 | }, 14 | "usersChart": { 15 | "title": "Total de usuários neste servidor", 16 | "users": "Usuários", 17 | "label": { 18 | "role": "Função", 19 | "user": "Usuário", 20 | "admin": "Administrador", 21 | "other": "Outro" 22 | } 23 | } 24 | }, 25 | "users": { 26 | "filterPlaceholder": "Filtrar usuários...", 27 | "baseUserDialog": { 28 | "form": { 29 | "username": { 30 | "min": "O nome de usuário deve ter pelo menos 3 caracteres", 31 | "max": "Nomes de usuário devem ter no máximo 32 caracteres", 32 | "regex": "Nomes de usuário devem ter letras minúsculas, começar com um caractere alfanumérico, seguido de caracteres alfanuméricos ou hifens e terminar com um caractere alfanumérico.", 33 | "label": "", 34 | "placeholder": "Digite seu usuário", 35 | "description": "Um nome de usuário exclusivo que identifica o usuário" 36 | }, 37 | "email": { 38 | "label": "", 39 | "placeholder": "", 40 | "description": "" 41 | }, 42 | "role": { 43 | "label": "Função", 44 | "description": "", 45 | "user": "Usuário", 46 | "admin": "Administrador" 47 | } 48 | } 49 | }, 50 | "addUserDialog": { 51 | "title": "", 52 | "description": "", 53 | "form": { 54 | "cancel": "Cancelar", 55 | "add": "" 56 | } 57 | }, 58 | "updateUserDialog": { 59 | "title": "", 60 | "description": "", 61 | "form": { 62 | "cancel": "Cancelar", 63 | "update": "" 64 | } 65 | }, 66 | "addToast": { 67 | "loading": "", 68 | "success": "", 69 | "error": "" 70 | }, 71 | "updateToast": { 72 | "loading": "", 73 | "success": "", 74 | "error": "" 75 | }, 76 | "removeToast": { 77 | "loading": "", 78 | "success": "", 79 | "error": "" 80 | }, 81 | "invalidateToast": { 82 | "loading": "", 83 | "success": "", 84 | "error": "" 85 | }, 86 | "table": { 87 | "username": "", 88 | "email": "", 89 | "role": "Função", 90 | "createdAt": "", 91 | "minIssuedAt": "", 92 | "actions": "Ações" 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /locales/pt-BR/instance.json: -------------------------------------------------------------------------------- 1 | { 2 | "proxy": { 3 | "filterPlaceholder": "", 4 | "listImportToast": { 5 | "loading": "", 6 | "success": "", 7 | "error": "", 8 | "noProxies": "" 9 | }, 10 | "import": { 11 | "proxyType": "", 12 | "http": "", 13 | "socks4": "", 14 | "socks5": "", 15 | "uri": "", 16 | "dialog": { 17 | "title": "", 18 | "description": "" 19 | } 20 | }, 21 | "removeToast": { 22 | "loading": "", 23 | "success": "", 24 | "error": "" 25 | }, 26 | "checkToast": { 27 | "loading": "", 28 | "success": "", 29 | "error": "" 30 | }, 31 | "invalidFormat": "", 32 | "table": { 33 | "type": "Tipo", 34 | "address": "Endereço", 35 | "username": "", 36 | "password": "" 37 | } 38 | }, 39 | "account": { 40 | "filterPlaceholder": "", 41 | "listImportToast": { 42 | "loading": "", 43 | "allFailed": "Falha ao importar contas", 44 | "someFailed": "{{count}} Contas importadas, falha ao importar {{failed}} contas", 45 | "noneFailed": "{{count}} Contas importadas!", 46 | "error": "Falha ao importar contas", 47 | "noAccounts": "" 48 | }, 49 | "unknownError": "Erro desconhecido", 50 | "deviceCodeImportToast": { 51 | "loading": "", 52 | "success": "", 53 | "error": "" 54 | }, 55 | "import": { 56 | "javaEdition": "", 57 | "bedrockEdition": "", 58 | "offline": "", 59 | "microsoftCredentials": "", 60 | "microsoftDeviceCode": "", 61 | "microsoftRefreshToken": "", 62 | "theAltening": "", 63 | "dialog": { 64 | "title": "", 65 | "description": "" 66 | } 67 | }, 68 | "removeToast": { 69 | "loading": "", 70 | "success": "", 71 | "error": "" 72 | }, 73 | "table": { 74 | "type": "Tipo", 75 | "profileId": "", 76 | "lastKnownName": "" 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /locales/sk-SK/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "overview": { 3 | "welcome": "", 4 | "instancesChart": { 5 | "title": "", 6 | "instances": "", 7 | "label": { 8 | "state": "", 9 | "active": "", 10 | "stopped": "", 11 | "other": "" 12 | } 13 | }, 14 | "usersChart": { 15 | "title": "", 16 | "users": "", 17 | "label": { 18 | "role": "", 19 | "user": "", 20 | "admin": "", 21 | "other": "" 22 | } 23 | } 24 | }, 25 | "users": { 26 | "filterPlaceholder": "", 27 | "baseUserDialog": { 28 | "form": { 29 | "username": { 30 | "min": "", 31 | "max": "", 32 | "regex": "", 33 | "label": "", 34 | "placeholder": "", 35 | "description": "" 36 | }, 37 | "email": { 38 | "label": "E-mail", 39 | "placeholder": "", 40 | "description": "" 41 | }, 42 | "role": { 43 | "label": "", 44 | "description": "", 45 | "user": "", 46 | "admin": "" 47 | } 48 | } 49 | }, 50 | "addUserDialog": { 51 | "title": "", 52 | "description": "", 53 | "form": { 54 | "cancel": "", 55 | "add": "" 56 | } 57 | }, 58 | "updateUserDialog": { 59 | "title": "", 60 | "description": "", 61 | "form": { 62 | "cancel": "", 63 | "update": "" 64 | } 65 | }, 66 | "addToast": { 67 | "loading": "", 68 | "success": "", 69 | "error": "" 70 | }, 71 | "updateToast": { 72 | "loading": "", 73 | "success": "", 74 | "error": "" 75 | }, 76 | "removeToast": { 77 | "loading": "", 78 | "success": "", 79 | "error": "" 80 | }, 81 | "invalidateToast": { 82 | "loading": "", 83 | "success": "", 84 | "error": "" 85 | }, 86 | "table": { 87 | "username": "", 88 | "email": "E-mail", 89 | "role": "", 90 | "createdAt": "", 91 | "minIssuedAt": "", 92 | "actions": "" 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /locales/sk-SK/instance.json: -------------------------------------------------------------------------------- 1 | { 2 | "proxy": { 3 | "filterPlaceholder": "", 4 | "listImportToast": { 5 | "loading": "", 6 | "success": "", 7 | "error": "", 8 | "noProxies": "" 9 | }, 10 | "import": { 11 | "proxyType": "", 12 | "http": "", 13 | "socks4": "", 14 | "socks5": "", 15 | "uri": "", 16 | "dialog": { 17 | "title": "", 18 | "description": "" 19 | } 20 | }, 21 | "removeToast": { 22 | "loading": "", 23 | "success": "", 24 | "error": "" 25 | }, 26 | "checkToast": { 27 | "loading": "", 28 | "success": "", 29 | "error": "" 30 | }, 31 | "invalidFormat": "", 32 | "table": { 33 | "type": "", 34 | "address": "Adresa", 35 | "username": "", 36 | "password": "" 37 | } 38 | }, 39 | "account": { 40 | "filterPlaceholder": "", 41 | "listImportToast": { 42 | "loading": "", 43 | "allFailed": "", 44 | "someFailed": "", 45 | "noneFailed": "", 46 | "error": "", 47 | "noAccounts": "" 48 | }, 49 | "unknownError": "", 50 | "deviceCodeImportToast": { 51 | "loading": "", 52 | "success": "", 53 | "error": "" 54 | }, 55 | "import": { 56 | "javaEdition": "", 57 | "bedrockEdition": "", 58 | "offline": "", 59 | "microsoftCredentials": "", 60 | "microsoftDeviceCode": "", 61 | "microsoftRefreshToken": "", 62 | "theAltening": "", 63 | "dialog": { 64 | "title": "", 65 | "description": "" 66 | } 67 | }, 68 | "removeToast": { 69 | "loading": "", 70 | "success": "", 71 | "error": "" 72 | }, 73 | "table": { 74 | "type": "", 75 | "profileId": "", 76 | "lastKnownName": "" 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /locales/tr-TR/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "overview": { 3 | "welcome": "Hoş geldiniz, {{name}} 🧙", 4 | "instancesChart": { 5 | "title": "Bu sunucudaki toplam Olay sayısı", 6 | "instances": "", 7 | "label": { 8 | "state": "Durum", 9 | "active": "Aktif", 10 | "stopped": "", 11 | "other": "Diğer" 12 | } 13 | }, 14 | "usersChart": { 15 | "title": "Bu sunucudaki toplam kullanıcı sayısı", 16 | "users": "Kullanıcılar", 17 | "label": { 18 | "role": "Rol", 19 | "user": "", 20 | "admin": "", 21 | "other": "Diğer" 22 | } 23 | } 24 | }, 25 | "users": { 26 | "filterPlaceholder": "", 27 | "baseUserDialog": { 28 | "form": { 29 | "username": { 30 | "min": "", 31 | "max": "", 32 | "regex": "", 33 | "label": "", 34 | "placeholder": "", 35 | "description": "" 36 | }, 37 | "email": { 38 | "label": "Mail Adresi", 39 | "placeholder": "", 40 | "description": "" 41 | }, 42 | "role": { 43 | "label": "Rol", 44 | "description": "", 45 | "user": "", 46 | "admin": "" 47 | } 48 | } 49 | }, 50 | "addUserDialog": { 51 | "title": "", 52 | "description": "", 53 | "form": { 54 | "cancel": "", 55 | "add": "" 56 | } 57 | }, 58 | "updateUserDialog": { 59 | "title": "", 60 | "description": "", 61 | "form": { 62 | "cancel": "", 63 | "update": "" 64 | } 65 | }, 66 | "addToast": { 67 | "loading": "", 68 | "success": "", 69 | "error": "" 70 | }, 71 | "updateToast": { 72 | "loading": "", 73 | "success": "", 74 | "error": "" 75 | }, 76 | "removeToast": { 77 | "loading": "", 78 | "success": "", 79 | "error": "" 80 | }, 81 | "invalidateToast": { 82 | "loading": "", 83 | "success": "", 84 | "error": "" 85 | }, 86 | "table": { 87 | "username": "", 88 | "email": "Mail Adresi", 89 | "role": "Rol", 90 | "createdAt": "", 91 | "minIssuedAt": "", 92 | "actions": "" 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /locales/tr-TR/instance.json: -------------------------------------------------------------------------------- 1 | { 2 | "proxy": { 3 | "filterPlaceholder": "", 4 | "listImportToast": { 5 | "loading": "", 6 | "success": "", 7 | "error": "", 8 | "noProxies": "" 9 | }, 10 | "import": { 11 | "proxyType": "", 12 | "http": "", 13 | "socks4": "", 14 | "socks5": "", 15 | "uri": "", 16 | "dialog": { 17 | "title": "", 18 | "description": "" 19 | } 20 | }, 21 | "removeToast": { 22 | "loading": "", 23 | "success": "", 24 | "error": "" 25 | }, 26 | "checkToast": { 27 | "loading": "", 28 | "success": "", 29 | "error": "" 30 | }, 31 | "invalidFormat": "", 32 | "table": { 33 | "type": "Tip", 34 | "address": "Adres", 35 | "username": "", 36 | "password": "" 37 | } 38 | }, 39 | "account": { 40 | "filterPlaceholder": "", 41 | "listImportToast": { 42 | "loading": "", 43 | "allFailed": "", 44 | "someFailed": "", 45 | "noneFailed": "", 46 | "error": "", 47 | "noAccounts": "" 48 | }, 49 | "unknownError": "", 50 | "deviceCodeImportToast": { 51 | "loading": "", 52 | "success": "", 53 | "error": "" 54 | }, 55 | "import": { 56 | "javaEdition": "", 57 | "bedrockEdition": "", 58 | "offline": "", 59 | "microsoftCredentials": "", 60 | "microsoftDeviceCode": "", 61 | "microsoftRefreshToken": "", 62 | "theAltening": "", 63 | "dialog": { 64 | "title": "", 65 | "description": "" 66 | } 67 | }, 68 | "removeToast": { 69 | "loading": "", 70 | "success": "", 71 | "error": "" 72 | }, 73 | "table": { 74 | "type": "Tip", 75 | "profileId": "", 76 | "lastKnownName": "" 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /locales/uk-UA/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "overview": { 3 | "welcome": "", 4 | "instancesChart": { 5 | "title": "", 6 | "instances": "", 7 | "label": { 8 | "state": "", 9 | "active": "", 10 | "stopped": "", 11 | "other": "" 12 | } 13 | }, 14 | "usersChart": { 15 | "title": "", 16 | "users": "", 17 | "label": { 18 | "role": "", 19 | "user": "", 20 | "admin": "", 21 | "other": "" 22 | } 23 | } 24 | }, 25 | "users": { 26 | "filterPlaceholder": "", 27 | "baseUserDialog": { 28 | "form": { 29 | "username": { 30 | "min": "", 31 | "max": "", 32 | "regex": "", 33 | "label": "", 34 | "placeholder": "", 35 | "description": "" 36 | }, 37 | "email": { 38 | "label": "", 39 | "placeholder": "", 40 | "description": "" 41 | }, 42 | "role": { 43 | "label": "", 44 | "description": "", 45 | "user": "", 46 | "admin": "" 47 | } 48 | } 49 | }, 50 | "addUserDialog": { 51 | "title": "", 52 | "description": "", 53 | "form": { 54 | "cancel": "", 55 | "add": "" 56 | } 57 | }, 58 | "updateUserDialog": { 59 | "title": "", 60 | "description": "", 61 | "form": { 62 | "cancel": "", 63 | "update": "" 64 | } 65 | }, 66 | "addToast": { 67 | "loading": "", 68 | "success": "", 69 | "error": "" 70 | }, 71 | "updateToast": { 72 | "loading": "", 73 | "success": "", 74 | "error": "" 75 | }, 76 | "removeToast": { 77 | "loading": "", 78 | "success": "", 79 | "error": "" 80 | }, 81 | "invalidateToast": { 82 | "loading": "", 83 | "success": "", 84 | "error": "" 85 | }, 86 | "table": { 87 | "username": "", 88 | "email": "", 89 | "role": "", 90 | "createdAt": "", 91 | "minIssuedAt": "", 92 | "actions": "" 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /locales/uk-UA/instance.json: -------------------------------------------------------------------------------- 1 | { 2 | "proxy": { 3 | "filterPlaceholder": "", 4 | "listImportToast": { 5 | "loading": "", 6 | "success": "", 7 | "error": "", 8 | "noProxies": "" 9 | }, 10 | "import": { 11 | "proxyType": "", 12 | "http": "", 13 | "socks4": "", 14 | "socks5": "", 15 | "uri": "", 16 | "dialog": { 17 | "title": "", 18 | "description": "" 19 | } 20 | }, 21 | "removeToast": { 22 | "loading": "", 23 | "success": "", 24 | "error": "" 25 | }, 26 | "checkToast": { 27 | "loading": "", 28 | "success": "", 29 | "error": "" 30 | }, 31 | "invalidFormat": "", 32 | "table": { 33 | "type": "", 34 | "address": "", 35 | "username": "", 36 | "password": "" 37 | } 38 | }, 39 | "account": { 40 | "filterPlaceholder": "", 41 | "listImportToast": { 42 | "loading": "", 43 | "allFailed": "", 44 | "someFailed": "", 45 | "noneFailed": "", 46 | "error": "", 47 | "noAccounts": "" 48 | }, 49 | "unknownError": "", 50 | "deviceCodeImportToast": { 51 | "loading": "", 52 | "success": "", 53 | "error": "" 54 | }, 55 | "import": { 56 | "javaEdition": "", 57 | "bedrockEdition": "", 58 | "offline": "", 59 | "microsoftCredentials": "", 60 | "microsoftDeviceCode": "", 61 | "microsoftRefreshToken": "", 62 | "theAltening": "", 63 | "dialog": { 64 | "title": "", 65 | "description": "" 66 | } 67 | }, 68 | "removeToast": { 69 | "loading": "", 70 | "success": "", 71 | "error": "" 72 | }, 73 | "table": { 74 | "type": "", 75 | "profileId": "", 76 | "lastKnownName": "" 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /locales/uk-UA/login.json: -------------------------------------------------------------------------------- 1 | { 2 | "header": { 3 | "image": { 4 | "alt": "" 5 | }, 6 | "title": "" 7 | }, 8 | "connect": { 9 | "title": "", 10 | "description": "", 11 | "integrated": { 12 | "title": "", 13 | "description": "" 14 | }, 15 | "dedicated": { 16 | "title": "", 17 | "description": "" 18 | }, 19 | "demo": { 20 | "title": "", 21 | "description": "" 22 | } 23 | }, 24 | "integrated": { 25 | "preparing": "", 26 | "toast": { 27 | "loading": "", 28 | "success": "", 29 | "error": "" 30 | }, 31 | "description": "", 32 | "form": { 33 | "jvmArgs": { 34 | "title": "", 35 | "description": "", 36 | "placeholder": "" 37 | }, 38 | "back": "", 39 | "start": "" 40 | }, 41 | "mobile": { 42 | "description": "", 43 | "form": { 44 | "termuxCommand": { 45 | "title": "", 46 | "description": "" 47 | }, 48 | "token": { 49 | "title": "", 50 | "description": "", 51 | "placeholder": "" 52 | }, 53 | "back": "", 54 | "connect": "" 55 | } 56 | } 57 | }, 58 | "dedicated": { 59 | "description": "", 60 | "toast": { 61 | "loading": "", 62 | "success": "", 63 | "error": "" 64 | }, 65 | "form": { 66 | "address": { 67 | "title": "", 68 | "description": "", 69 | "placeholder": "" 70 | }, 71 | "token": { 72 | "title": "", 73 | "placeholder": "", 74 | "description": "" 75 | }, 76 | "email": { 77 | "title": "", 78 | "placeholder": "", 79 | "description": "" 80 | }, 81 | "back": "", 82 | "useToken": "", 83 | "useEmail": "", 84 | "login": "" 85 | } 86 | }, 87 | "emailCode": { 88 | "description": "", 89 | "toast": { 90 | "loading": "", 91 | "success": "", 92 | "error": "" 93 | }, 94 | "back": "" 95 | }, 96 | "footer": { 97 | "version": "", 98 | "preview": "", 99 | "production": "", 100 | "helpTranslate": "" 101 | } 102 | } -------------------------------------------------------------------------------- /locales/zh-CN/admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "overview": { 3 | "welcome": "欢迎回来, {{name}} 🧙", 4 | "instancesChart": { 5 | "title": "服务器上的实例总数", 6 | "instances": "实例", 7 | "label": { 8 | "state": "状态", 9 | "active": "活跃", 10 | "stopped": "已停止", 11 | "other": "其他" 12 | } 13 | }, 14 | "usersChart": { 15 | "title": "服务器上的用户总数", 16 | "users": "用户", 17 | "label": { 18 | "role": "用户类型", 19 | "user": "用户", 20 | "admin": "管理员", 21 | "other": "其他" 22 | } 23 | } 24 | }, 25 | "users": { 26 | "filterPlaceholder": "", 27 | "baseUserDialog": { 28 | "form": { 29 | "username": { 30 | "min": "", 31 | "max": "", 32 | "regex": "", 33 | "label": "用户名", 34 | "placeholder": "", 35 | "description": "" 36 | }, 37 | "email": { 38 | "label": "电子邮箱", 39 | "placeholder": "", 40 | "description": "" 41 | }, 42 | "role": { 43 | "label": "用户类型", 44 | "description": "", 45 | "user": "用户", 46 | "admin": "管理员" 47 | } 48 | } 49 | }, 50 | "addUserDialog": { 51 | "title": "", 52 | "description": "", 53 | "form": { 54 | "cancel": "取消", 55 | "add": "" 56 | } 57 | }, 58 | "updateUserDialog": { 59 | "title": "", 60 | "description": "", 61 | "form": { 62 | "cancel": "取消", 63 | "update": "" 64 | } 65 | }, 66 | "addToast": { 67 | "loading": "", 68 | "success": "", 69 | "error": "" 70 | }, 71 | "updateToast": { 72 | "loading": "", 73 | "success": "", 74 | "error": "" 75 | }, 76 | "removeToast": { 77 | "loading": "", 78 | "success": "", 79 | "error": "" 80 | }, 81 | "invalidateToast": { 82 | "loading": "", 83 | "success": "", 84 | "error": "" 85 | }, 86 | "table": { 87 | "username": "用户名", 88 | "email": "电子邮箱", 89 | "role": "用户类型", 90 | "createdAt": "", 91 | "minIssuedAt": "", 92 | "actions": "" 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /locales/zh-CN/instance.json: -------------------------------------------------------------------------------- 1 | { 2 | "proxy": { 3 | "filterPlaceholder": "过滤代理服务器...", 4 | "listImportToast": { 5 | "loading": "正在导入代理...", 6 | "success": "成功导入 {{count}} 个代理!", 7 | "error": "导入代理失败", 8 | "noProxies": "没有代理可导入" 9 | }, 10 | "import": { 11 | "proxyType": "代理连接类型", 12 | "http": "HTTP", 13 | "socks4": "SOCKS4", 14 | "socks5": "SOCKS5", 15 | "uri": "URI", 16 | "dialog": { 17 | "title": "导入 {{type}} 个代理", 18 | "description": "在这里粘贴您的代理,每行一个" 19 | } 20 | }, 21 | "removeToast": { 22 | "loading": "正在删除代理...", 23 | "success": "删除了 {{count}} 个代理!", 24 | "error": "删除代理失败" 25 | }, 26 | "checkToast": { 27 | "loading": "检查代理中… {{checked}}/{{total}}(成功:{{success}} 失败:{{failed}})", 28 | "success": "删除了 {{count}} 个无效的代理!", 29 | "error": "无法检查代理" 30 | }, 31 | "invalidFormat": "无效的代理格式", 32 | "table": { 33 | "type": "类型", 34 | "address": "地址", 35 | "username": "用户名", 36 | "password": "密码" 37 | } 38 | }, 39 | "account": { 40 | "filterPlaceholder": "筛选账户...", 41 | "listImportToast": { 42 | "loading": "导入账户中… {{checked}}/{{total}}(成功:{{success}} 失败:{{failed}})", 43 | "allFailed": "导入账户失败", 44 | "someFailed": "成功导入 {{count}} 个账户, {{failed}} 个账户导入失败", 45 | "noneFailed": "已导入 {{count}} 个账户", 46 | "error": "导入帐户失败", 47 | "noAccounts": "没有账户可导入" 48 | }, 49 | "unknownError": "未知错误", 50 | "deviceCodeImportToast": { 51 | "loading": "导入帐户...", 52 | "success": "帐户已导入!", 53 | "error": "导入帐户失败" 54 | }, 55 | "import": { 56 | "javaEdition": "Java 版", 57 | "bedrockEdition": "基岩版", 58 | "offline": "离线", 59 | "microsoftCredentials": "Microsoft 账户", 60 | "microsoftDeviceCode": "Microsoft 设备代码", 61 | "microsoftRefreshToken": "Microsoft 刷新令牌", 62 | "theAltening": "交替", 63 | "dialog": { 64 | "title": "导入 {{type}} 个账户", 65 | "description": "在这里粘贴您的帐户,每行一个" 66 | } 67 | }, 68 | "removeToast": { 69 | "loading": "正在删除帐户...", 70 | "success": "删除了 {{count}} 个账户!", 71 | "error": "删除帐户失败" 72 | }, 73 | "table": { 74 | "type": "类型", 75 | "profileId": "UUID", 76 | "lastKnownName": "用户名" 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | '@tailwindcss/postcss': {}, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /protos/google/protobuf/empty.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option go_package = "google.golang.org/protobuf/types/known/emptypb"; 36 | option java_package = "com.google.protobuf"; 37 | option java_outer_classname = "EmptyProto"; 38 | option java_multiple_files = true; 39 | option objc_class_prefix = "GPB"; 40 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 41 | option cc_enable_arenas = true; 42 | 43 | // A generic empty message that you can re-use to avoid defining duplicated 44 | // empty messages in your APIs. A typical example is to use it as the request 45 | // or the response type of an API method. For instance: 46 | // 47 | // service Foo { 48 | // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); 49 | // } 50 | // 51 | message Empty {} 52 | -------------------------------------------------------------------------------- /protos/google/protobuf/source_context.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option java_package = "com.google.protobuf"; 36 | option java_outer_classname = "SourceContextProto"; 37 | option java_multiple_files = true; 38 | option objc_class_prefix = "GPB"; 39 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 40 | option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; 41 | 42 | // `SourceContext` represents information about the source of a 43 | // protobuf element, like the file in which it is defined. 44 | message SourceContext { 45 | // The path-qualified name of the .proto file that contained the associated 46 | // protobuf element. For example: `"google/protobuf/source_context.proto"`. 47 | string file_name = 1; 48 | } 49 | -------------------------------------------------------------------------------- /protos/grpc/health/v1/health.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The gRPC Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // The canonical version of this proto can be found at 16 | // https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto 17 | 18 | syntax = "proto3"; 19 | 20 | package grpc.health.v1; 21 | 22 | option csharp_namespace = "Grpc.Health.V1"; 23 | option go_package = "google.golang.org/grpc/health/grpc_health_v1"; 24 | option java_multiple_files = true; 25 | option java_outer_classname = "HealthProto"; 26 | option java_package = "io.grpc.health.v1"; 27 | 28 | message HealthCheckRequest { 29 | string service = 1; 30 | } 31 | 32 | message HealthCheckResponse { 33 | enum ServingStatus { 34 | UNKNOWN = 0; 35 | SERVING = 1; 36 | NOT_SERVING = 2; 37 | SERVICE_UNKNOWN = 3; // Used only by the Watch method. 38 | } 39 | ServingStatus status = 1; 40 | } 41 | 42 | service Health { 43 | // If the requested service is unknown, the call will fail with status 44 | // NOT_FOUND. 45 | rpc Check(HealthCheckRequest) returns (HealthCheckResponse); 46 | 47 | // Performs a watch for the serving status of the requested service. 48 | // The server will immediately send back a message indicating the current 49 | // serving status. It will then subsequently send a new message whenever 50 | // the service's serving status changes. 51 | // 52 | // If the requested service is unknown when the call is received, the 53 | // server will send a message setting the serving status to 54 | // SERVICE_UNKNOWN but will *not* terminate the call. If at some 55 | // future point, the serving status of the service becomes known, the 56 | // server will send a new message with the service's serving status. 57 | // 58 | // If the call terminates with status UNIMPLEMENTED, then clients 59 | // should assume this method is not supported and should not retry the 60 | // call. If the call terminates with any other status (including OK), 61 | // clients should retry the call with appropriate exponential backoff. 62 | rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse); 63 | } 64 | -------------------------------------------------------------------------------- /protos/soulfire/client.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.soulfiremc.grpc.generated"; 4 | option java_multiple_files = true; 5 | 6 | package soulfire.v1; 7 | 8 | import "soulfire/common.proto"; 9 | 10 | message ClientDataRequest { 11 | } 12 | 13 | message GlobalPermissionState { 14 | GlobalPermission global_permission = 1; 15 | bool granted = 2; 16 | } 17 | 18 | message ServerInfo { 19 | string version = 1; 20 | string commit_hash = 2; 21 | string branch_name = 3; 22 | string public_api_address = 4; 23 | string public_webdav_address = 5; 24 | string public_docs_address = 6; 25 | } 26 | 27 | message ClientDataResponse { 28 | string id = 6; 29 | string username = 1; 30 | UserRole role = 7; 31 | string email = 8; 32 | repeated GlobalPermissionState server_permissions = 2; 33 | ServerInfo server_info = 11; 34 | } 35 | 36 | message GenerateWebDAVTokenRequest { 37 | } 38 | 39 | message GenerateWebDAVTokenResponse { 40 | string token = 1; 41 | } 42 | 43 | message GenerateAPITokenRequest { 44 | } 45 | 46 | message GenerateAPITokenResponse { 47 | string token = 1; 48 | } 49 | 50 | message UpdateSelfUsernameRequest { 51 | string username = 1; 52 | } 53 | 54 | message UpdateSelfUsernameResponse { 55 | } 56 | 57 | message UpdateSelfEmailRequest { 58 | string email = 1; 59 | } 60 | 61 | message UpdateSelfEmailResponse { 62 | } 63 | 64 | message InvalidateSelfSessionsRequest { 65 | } 66 | 67 | message InvalidateSelfSessionsResponse { 68 | } 69 | 70 | service ClientService { 71 | rpc GetClientData (ClientDataRequest) returns (ClientDataResponse) {} 72 | rpc GenerateWebDAVToken (GenerateWebDAVTokenRequest) returns (GenerateWebDAVTokenResponse) {} 73 | rpc GenerateAPIToken (GenerateAPITokenRequest) returns (GenerateAPITokenResponse) {} 74 | rpc UpdateSelfUsername (UpdateSelfUsernameRequest) returns (UpdateSelfUsernameResponse) {} 75 | rpc UpdateSelfEmail (UpdateSelfEmailRequest) returns (UpdateSelfEmailResponse) {} 76 | rpc InvalidateSelfSessions (InvalidateSelfSessionsRequest) returns (InvalidateSelfSessionsResponse) {} 77 | } 78 | -------------------------------------------------------------------------------- /protos/soulfire/command.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.soulfiremc.grpc.generated"; 4 | option java_multiple_files = true; 5 | 6 | package soulfire.v1; 7 | 8 | message GlobalCommandScope { 9 | } 10 | 11 | message InstanceCommandScope { 12 | string instance_id = 1; 13 | } 14 | 15 | message CommandScope { 16 | oneof scope { 17 | GlobalCommandScope global = 1; 18 | InstanceCommandScope instance = 2; 19 | } 20 | } 21 | 22 | message CommandRequest { 23 | CommandScope scope = 4; 24 | string command = 3; 25 | } 26 | 27 | message CommandResponse { 28 | int32 code = 1; 29 | } 30 | 31 | message CommandCompletionRequest { 32 | CommandScope scope = 5; 33 | string command = 3; 34 | int32 cursor = 4; 35 | } 36 | 37 | message CommandCompletion { 38 | string suggestion = 1; 39 | optional string tooltip = 2; 40 | } 41 | 42 | message CommandCompletionResponse { 43 | repeated CommandCompletion suggestions = 1; 44 | } 45 | 46 | service CommandService { 47 | rpc ExecuteCommand (CommandRequest) returns (CommandResponse) {} 48 | rpc TabCompleteCommand (CommandCompletionRequest) returns (CommandCompletionResponse) {} 49 | } 50 | -------------------------------------------------------------------------------- /protos/soulfire/download.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.soulfiremc.grpc.generated"; 4 | option java_multiple_files = true; 5 | 6 | package soulfire.v1; 7 | 8 | import "soulfire/common.proto"; 9 | 10 | message HeaderPair { 11 | string key = 1; 12 | string value = 2; 13 | } 14 | 15 | message DownloadRequest { 16 | string instance_id = 1; 17 | string uri = 2; 18 | repeated HeaderPair headers = 3; 19 | optional ProxyProto proxy = 4; 20 | } 21 | 22 | message DownloadResponse { 23 | bytes data = 1; 24 | repeated HeaderPair headers = 2; 25 | int32 status_code = 3; 26 | } 27 | 28 | service DownloadService { 29 | rpc Download (DownloadRequest) returns (DownloadResponse) {} 30 | } 31 | -------------------------------------------------------------------------------- /protos/soulfire/login.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.soulfiremc.grpc.generated"; 4 | option java_multiple_files = true; 5 | 6 | package soulfire.v1; 7 | 8 | message LoginRequest { 9 | string email = 1; 10 | } 11 | 12 | message NextAuthFlowResponse { 13 | message EmailCode { 14 | } 15 | 16 | message Success { 17 | string token = 1; 18 | } 19 | 20 | message Failure { 21 | enum Reason { 22 | INVALID_CODE = 0; 23 | } 24 | 25 | Reason reason = 1; 26 | } 27 | 28 | string auth_flow_token = 1; 29 | oneof next { 30 | EmailCode email_code = 2; 31 | Success success = 3; 32 | Failure failure = 4; 33 | } 34 | } 35 | 36 | message EmailCodeRequest { 37 | string auth_flow_token = 1; 38 | string code = 2; 39 | } 40 | 41 | service LoginService { 42 | rpc Login (LoginRequest) returns (NextAuthFlowResponse) {} 43 | rpc EmailCode (EmailCodeRequest) returns (NextAuthFlowResponse) {} 44 | } 45 | -------------------------------------------------------------------------------- /protos/soulfire/logs.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.soulfiremc.grpc.generated"; 4 | option java_multiple_files = true; 5 | 6 | package soulfire.v1; 7 | 8 | message LogString { 9 | string id = 1; 10 | string message = 2; 11 | optional string instance_id = 3; 12 | optional string bot_id = 4; 13 | optional string script_id = 5; 14 | } 15 | 16 | message GlobalLogScope { 17 | } 18 | 19 | message InstanceLogScope { 20 | string instance_id = 1; 21 | } 22 | 23 | message BotLogScope { 24 | string instance_id = 1; 25 | string bot_id = 2; 26 | } 27 | 28 | message GlobalScriptLogScope { 29 | string script_id = 1; 30 | } 31 | 32 | message InstanceScriptLogScope { 33 | string instance_id = 1; 34 | string script_id = 2; 35 | } 36 | 37 | message LogScope { 38 | oneof scope { 39 | GlobalLogScope global = 1; 40 | InstanceLogScope instance = 2; 41 | BotLogScope bot = 3; 42 | GlobalScriptLogScope global_script = 4; 43 | InstanceScriptLogScope instance_script = 5; 44 | } 45 | } 46 | 47 | message PreviousLogRequest { 48 | LogScope scope = 4; 49 | int32 count = 3; 50 | } 51 | 52 | message PreviousLogResponse { 53 | repeated LogString messages = 1; 54 | } 55 | 56 | message LogRequest { 57 | LogScope scope = 3; 58 | } 59 | 60 | message LogResponse { 61 | LogString message = 1; 62 | } 63 | 64 | service LogsService { 65 | rpc GetPrevious (PreviousLogRequest) returns (PreviousLogResponse) {} 66 | rpc Subscribe (LogRequest) returns (stream LogResponse) {} 67 | } 68 | -------------------------------------------------------------------------------- /protos/soulfire/mc-auth.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.soulfiremc.grpc.generated"; 4 | option java_multiple_files = true; 5 | 6 | package soulfire.v1; 7 | 8 | import "soulfire/common.proto"; 9 | 10 | message CredentialsAuthRequest { 11 | string instance_id = 1; 12 | AccountTypeCredentials service = 2; 13 | repeated string payload = 3; 14 | } 15 | 16 | // Full response of all accounts that were authenticated 17 | message CredentialsAuthFullList { 18 | repeated MinecraftAccountProto account = 1; 19 | } 20 | 21 | // Used when an account is successfully authenticated 22 | message CredentialsAuthOneSuccess { 23 | } 24 | 25 | // Used when an account is not successfully authenticated 26 | message CredentialsAuthOneFailure { 27 | } 28 | 29 | message CredentialsAuthResponse { 30 | oneof data { 31 | CredentialsAuthFullList full_list = 1; 32 | CredentialsAuthOneSuccess one_success = 2; 33 | CredentialsAuthOneFailure one_failure = 3; 34 | } 35 | } 36 | 37 | message DeviceCodeAuthRequest { 38 | string instance_id = 1; 39 | AccountTypeDeviceCode service = 2; 40 | } 41 | 42 | message DeviceCode { 43 | string device_code = 1; 44 | string user_code = 2; 45 | string verification_uri = 3; 46 | string direct_verification_uri = 4; 47 | } 48 | 49 | message DeviceCodeAuthResponse { 50 | oneof data { 51 | MinecraftAccountProto account = 1; 52 | DeviceCode device_code = 2; 53 | } 54 | } 55 | 56 | message RefreshRequest { 57 | string instance_id = 1; 58 | MinecraftAccountProto account = 2; 59 | } 60 | 61 | message RefreshResponse { 62 | MinecraftAccountProto account = 1; 63 | } 64 | 65 | service MCAuthService { 66 | rpc LoginCredentials (CredentialsAuthRequest) returns (stream CredentialsAuthResponse) {} 67 | rpc LoginDeviceCode (DeviceCodeAuthRequest) returns (stream DeviceCodeAuthResponse) {} 68 | rpc Refresh (RefreshRequest) returns (RefreshResponse) {} 69 | } 70 | -------------------------------------------------------------------------------- /protos/soulfire/proxy-check.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.soulfiremc.grpc.generated"; 4 | option java_multiple_files = true; 5 | 6 | package soulfire.v1; 7 | 8 | import "soulfire/common.proto"; 9 | 10 | message ProxyCheckRequest { 11 | string instance_id = 1; 12 | repeated ProxyProto proxy = 2; 13 | } 14 | 15 | message ProxyCheckResponseSingle { 16 | ProxyProto proxy = 1; 17 | bool valid = 2; 18 | int32 latency = 3; 19 | string real_ip = 4; 20 | } 21 | 22 | // Full response of all proxies that were checked 23 | message ProxyCheckFullList { 24 | repeated ProxyCheckResponseSingle response = 1; 25 | } 26 | 27 | // Used when a proxy is successfully checked 28 | message ProxyCheckOneSuccess { 29 | } 30 | 31 | // Used when a proxy is not successfully checked 32 | message ProxyCheckOneFailure { 33 | } 34 | 35 | message ProxyCheckResponse { 36 | oneof data { 37 | ProxyCheckFullList full_list = 1; 38 | ProxyCheckOneSuccess one_success = 2; 39 | ProxyCheckOneFailure one_failure = 3; 40 | } 41 | } 42 | 43 | service ProxyCheckService { 44 | rpc Check (ProxyCheckRequest) returns (stream ProxyCheckResponse) {} 45 | } 46 | -------------------------------------------------------------------------------- /protos/soulfire/script.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.soulfiremc.grpc.generated"; 4 | option java_multiple_files = true; 5 | 6 | package soulfire.v1; 7 | 8 | import "soulfire/common.proto"; 9 | import "google/protobuf/timestamp.proto"; 10 | 11 | message GlobalScriptScope { 12 | } 13 | 14 | message InstanceScriptScope { 15 | string id = 1; 16 | } 17 | 18 | message ScriptScope { 19 | oneof scope { 20 | GlobalScriptScope global_script = 1; 21 | InstanceScriptScope instance_script = 2; 22 | } 23 | } 24 | 25 | message CreateScriptRequest { 26 | ScriptScope scope = 1; 27 | string script_name = 2; 28 | bool elevated_permissions = 3; 29 | } 30 | 31 | message CreateScriptResponse { 32 | string id = 1; 33 | } 34 | 35 | message DeleteScriptRequest { 36 | string id = 1; 37 | } 38 | 39 | message DeleteScriptResponse { 40 | } 41 | 42 | message RestartScriptRequest { 43 | string id = 1; 44 | } 45 | 46 | message RestartScriptResponse { 47 | } 48 | 49 | message UpdateScriptRequest { 50 | string id = 1; 51 | string script_name = 2; 52 | bool elevated_permissions = 3; 53 | } 54 | 55 | message UpdateScriptResponse { 56 | } 57 | 58 | message ScriptListRequest { 59 | ScriptScope scope = 1; 60 | } 61 | 62 | enum ScriptLanguage { 63 | JAVASCRIPT = 0; 64 | PYTHON = 1; 65 | TYPESCRIPT = 2; 66 | } 67 | 68 | message ScriptListResponse { 69 | message Script { 70 | string id = 1; 71 | string script_name = 2; 72 | bool elevated_permissions = 3; 73 | ScriptLanguage language = 4; 74 | google.protobuf.Timestamp created_at = 5; 75 | google.protobuf.Timestamp updated_at = 6; 76 | ScriptScope script_scope = 7; 77 | } 78 | 79 | repeated Script scripts = 1; 80 | } 81 | 82 | service ScriptService { 83 | rpc CreateScript (CreateScriptRequest) returns (CreateScriptResponse) {} 84 | rpc DeleteScript (DeleteScriptRequest) returns (DeleteScriptResponse) {} 85 | rpc RestartScript (RestartScriptRequest) returns (RestartScriptResponse) {} 86 | rpc UpdateScript (UpdateScriptRequest) returns (UpdateScriptResponse) {} 87 | rpc ListScripts (ScriptListRequest) returns (ScriptListResponse) {} 88 | } 89 | -------------------------------------------------------------------------------- /protos/soulfire/server.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.soulfiremc.grpc.generated"; 4 | option java_multiple_files = true; 5 | 6 | package soulfire.v1; 7 | 8 | import "soulfire/common.proto"; 9 | 10 | message ServerConfig { 11 | repeated SettingsNamespace settings = 1; 12 | } 13 | 14 | message ServerInfoRequest { 15 | } 16 | 17 | message ServerInfoResponse { 18 | ServerConfig config = 1; 19 | repeated SettingsPage server_settings = 2; 20 | } 21 | 22 | message ServerUpdateConfigRequest { 23 | ServerConfig config = 1; 24 | } 25 | 26 | message ServerUpdateConfigResponse { 27 | } 28 | 29 | service ServerService { 30 | rpc GetServerInfo (ServerInfoRequest) returns (ServerInfoResponse) {} 31 | rpc UpdateServerConfig (ServerUpdateConfigRequest) returns (ServerUpdateConfigResponse) {} 32 | } 33 | -------------------------------------------------------------------------------- /protos/soulfire/user.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.soulfiremc.grpc.generated"; 4 | option java_multiple_files = true; 5 | 6 | package soulfire.v1; 7 | 8 | import "soulfire/common.proto"; 9 | import "google/protobuf/timestamp.proto"; 10 | 11 | message UserCreateRequest { 12 | string username = 1; 13 | UserRole role = 2; 14 | string email = 3; 15 | } 16 | 17 | message UserCreateResponse { 18 | string id = 1; 19 | } 20 | 21 | message UserDeleteRequest { 22 | string id = 1; 23 | } 24 | 25 | message UserDeleteResponse { 26 | } 27 | 28 | message UserListRequest { 29 | } 30 | 31 | message UserListResponse { 32 | message User { 33 | string id = 1; 34 | string username = 2; 35 | UserRole role = 3; 36 | string email = 4; 37 | google.protobuf.Timestamp created_at = 5; 38 | google.protobuf.Timestamp updated_at = 6; 39 | optional google.protobuf.Timestamp last_login_at = 7; 40 | google.protobuf.Timestamp min_issued_at = 8; 41 | } 42 | 43 | repeated User users = 1; 44 | } 45 | 46 | message UserInfoRequest { 47 | string id = 1; 48 | } 49 | 50 | message UserInfoResponse { 51 | string username = 1; 52 | UserRole role = 2; 53 | string email = 3; 54 | google.protobuf.Timestamp created_at = 4; 55 | google.protobuf.Timestamp updated_at = 5; 56 | optional google.protobuf.Timestamp last_login_at = 6; 57 | google.protobuf.Timestamp min_issued_at = 7; 58 | } 59 | 60 | // Invalidate all sessions for a user, effectively logging them out of all devices. 61 | message InvalidateSessionsRequest { 62 | string id = 1; 63 | } 64 | 65 | message InvalidateSessionsResponse { 66 | } 67 | 68 | message UpdateUserRequest { 69 | string id = 1; 70 | string username = 2; 71 | UserRole role = 3; 72 | string email = 4; 73 | } 74 | 75 | message UpdateUserResponse { 76 | } 77 | 78 | message GenerateUserAPITokenRequest { 79 | string id = 1; 80 | } 81 | 82 | message GenerateUserAPITokenResponse { 83 | string token = 1; 84 | } 85 | 86 | service UserService { 87 | rpc CreateUser (UserCreateRequest) returns (UserCreateResponse) {} 88 | rpc DeleteUser (UserDeleteRequest) returns (UserDeleteResponse) {} 89 | rpc ListUsers (UserListRequest) returns (UserListResponse) {} 90 | rpc GetUserInfo (UserInfoRequest) returns (UserInfoResponse) {} 91 | rpc InvalidateSessions (InvalidateSessionsRequest) returns (InvalidateSessionsResponse) {} 92 | rpc UpdateUser (UpdateUserRequest) returns (UpdateUserResponse) {} 93 | rpc GenerateUserAPIToken (GenerateUserAPITokenRequest) returns (GenerateUserAPITokenResponse) {} 94 | } 95 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/public/favicon.ico -------------------------------------------------------------------------------- /public/icons/web-app-manifest-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/public/icons/web-app-manifest-192x192.png -------------------------------------------------------------------------------- /public/icons/web-app-manifest-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/public/icons/web-app-manifest-512x512.png -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/public/logo.png -------------------------------------------------------------------------------- /public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | SF 12 | 13 | 14 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SoulFire", 3 | "short_name": "SoulFire", 4 | "icons": [ 5 | { 6 | "src": "/icons/web-app-manifest-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/icons/web-app-manifest-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#3289BF", 17 | "background_color": "#3289BF", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Allow: /$ 3 | Disallow: / 4 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["config:recommended", "group:allNonMajor", ":semanticCommits"], 3 | "packageRules": [ 4 | { 5 | "matchUpdateTypes": ["minor", "patch", "pin", "digest"], 6 | "automerge": true 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /rsbuild.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@rsbuild/core'; 2 | import { pluginReact } from '@rsbuild/plugin-react'; 3 | import { TanStackRouterRspack } from '@tanstack/router-plugin/rspack'; 4 | import { pluginTypeCheck } from '@rsbuild/plugin-type-check'; 5 | import { pluginSvgr } from '@rsbuild/plugin-svgr'; 6 | import tauriConf from './src-tauri/tauri.conf.json'; 7 | import * as fs from 'node:fs'; 8 | 9 | const dev = process.env.NODE_ENV !== 'production'; 10 | 11 | const baseEnv = process.env.VERCEL_ENV ?? process.env.NODE_ENV; 12 | let appEnv: string; 13 | if (baseEnv === 'production') { 14 | appEnv = 'production'; 15 | } else if (baseEnv === 'preview') { 16 | appEnv = 'preview'; 17 | } else { 18 | appEnv = 'development'; 19 | } 20 | 21 | const locales = fs 22 | .readdirSync('./locales', { withFileTypes: true }) 23 | .filter((dirent) => dirent.isDirectory()) 24 | .map((dirent) => dirent.name) 25 | .join(','); 26 | 27 | const namespaces = fs 28 | .readdirSync('./locales/en-US', { withFileTypes: true }) 29 | .filter((dirent) => dirent.isFile()) 30 | .map((dirent) => dirent.name.split('.')[0]) 31 | .join(','); 32 | 33 | export default defineConfig({ 34 | plugins: [pluginReact(), pluginTypeCheck(), pluginSvgr()], 35 | tools: { 36 | rspack: { 37 | plugins: [ 38 | TanStackRouterRspack({ 39 | autoCodeSplitting: true, 40 | }), 41 | ], 42 | output: { 43 | asyncChunks: false, 44 | }, 45 | module: { 46 | rules: [ 47 | { 48 | test: /\.png$/, 49 | type: 'asset/inline', 50 | }, 51 | ], 52 | }, 53 | watchOptions: { 54 | ignored: /\.git|node_mobules|src-tauri/, 55 | }, 56 | }, 57 | }, 58 | html: { 59 | template: './index.html', 60 | }, 61 | source: { 62 | define: { 63 | APP_VERSION: JSON.stringify(process.env.npm_package_version), 64 | APP_ENVIRONMENT: JSON.stringify(appEnv), 65 | APP_LOCALES: JSON.stringify(locales), 66 | APP_NAMESPACES: JSON.stringify(namespaces), 67 | }, 68 | }, 69 | output: { 70 | target: 'web', 71 | sourceMap: { 72 | js: dev ? 'cheap-module-source-map' : 'source-map', 73 | css: true, 74 | }, 75 | }, 76 | performance: { 77 | chunkSplit: { 78 | strategy: 'split-by-size', 79 | minSize: 300000, 80 | maxSize: 500000, 81 | }, 82 | }, 83 | server: { 84 | strictPort: true, 85 | host: process.env.TAURI_DEV_HOST ?? undefined, 86 | headers: { 87 | 'X-DNS-Prefetch-Control': 'on', 88 | 'X-XSS-Protection': '1; mode=block', 89 | 'X-Frame-Options': 'SAMEORIGIN', 90 | 'X-Content-Type-Options': 'nosniff', 91 | 'Content-Security-Policy': tauriConf.app.security.csp, 92 | }, 93 | }, 94 | }); 95 | -------------------------------------------------------------------------------- /scripts/termux_setup.sh: -------------------------------------------------------------------------------- 1 | #!/data/data/com.termux/files/usr/bin/bash 2 | 3 | # Exit on error and print commands 4 | set -e 5 | set -x 6 | 7 | # Update and install required repo 8 | pkg update -y && pkg upgrade -y 9 | pkg install -y x11-repo 10 | 11 | # Install OpenJDK 21 12 | pkg install -y openjdk-21 13 | 14 | # Create soulfire dir and set as pwd 15 | mkdir -p ~/soulfire 16 | cd ~/soulfire 17 | 18 | # Prepare jars 19 | mkdir -p ~/soulfire/jars 20 | cd ~/soulfire/jars 21 | 22 | # Define the jar file name 23 | JAR_NAME="SoulFireDedicated-$1.jar" 24 | 25 | # Only download if the jar does not exist 26 | if [ ! -f ~/soulfire/jars/$JAR_NAME ]; then 27 | curl -L -o ~/soulfire/jars/$JAR_NAME "https://github.com/AlexProgrammerDE/SoulFire/releases/download/$1/$JAR_NAME" 28 | else 29 | echo "$JAR_NAME already exists, skipping download." 30 | fi 31 | 32 | # Prepare rundir 33 | mkdir -p ~/soulfire/rundir 34 | cd ~/soulfire/rundir 35 | 36 | # Run SoulFire 37 | java $2 -jar ~/soulfire/jars/$JAR_NAME 38 | -------------------------------------------------------------------------------- /src-tauri/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["-Z", "threads=8"] 3 | -------------------------------------------------------------------------------- /src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Generated by Tauri 6 | # will have schema files for capabilities auto-completion 7 | /gen/schemas 8 | 9 | *.salive 10 | -------------------------------------------------------------------------------- /src-tauri/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "soulfire" 3 | version = "1.10.7" 4 | description = "Frontend client for SoulFire." 5 | authors = ["Pistonmaster"] 6 | license = "GPL-3.0" 7 | repository = "https://github.com/AlexProgrammerDE/SoulFireClient" 8 | edition = "2024" 9 | rust-version = "1.85" 10 | 11 | [lib] 12 | name = "soulfire_lib" 13 | crate-type = ["staticlib", "cdylib", "rlib"] 14 | 15 | [build-dependencies] 16 | tauri-build = { version = "2.0.2", features = [] } 17 | 18 | [dependencies] 19 | serde_json = "1.0" 20 | serde = { version = "1.0", features = ["derive"] } 21 | tauri = { version = "2.0.6", features = ["macos-private-api", "devtools", "tray-icon"] } 22 | reqwest = { version = "0.12.8", features = ["json"] } 23 | tar = "0.4.42" 24 | flate2 = "1.0.34" 25 | strip-ansi-escapes = "0.2.0" 26 | zip = "4.0.0" 27 | rust_cast = "0.19.0" 28 | mdns-sd = "0.13.0" 29 | log = "0.4.22" 30 | discord-presence = "1.3.1" 31 | tauri-plugin-dialog = "2.0.3" 32 | tauri-plugin-fs = { version = "2.0.3", features = ["watch"] } 33 | tauri-plugin-os = "2.0.1" 34 | tauri-plugin-shell = "2.0.2" 35 | tauri-plugin-clipboard-manager = "2.1.0-beta.7" 36 | tauri-plugin-process = "2.0.1" 37 | tauri-plugin-log = { version = "2.0.1", features = ["colored"] } 38 | async-std = "1.13.0" 39 | sha2 = "0.11.0-pre.4" 40 | thiserror = "2.0.0" 41 | hex = "0.4.3" 42 | tauri-plugin-deep-link = "2" 43 | tauri-plugin-opener = "2" 44 | 45 | [target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\"))".dependencies] 46 | tauri-plugin-updater = "2.0.2" 47 | tauri-plugin-single-instance = { version = "2.0.1", features = ["semver", "deep-link"] } 48 | 49 | [target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies] 50 | openssl = { version = "*", features = ["vendored"] } 51 | 52 | [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] 53 | tauri-plugin-window-state = "2" 54 | 55 | [profile.dev] 56 | incremental = true 57 | strip = false 58 | lto = false 59 | opt-level = 0 60 | 61 | [profile.dev.package."*"] 62 | opt-level = 0 63 | incremental = true 64 | 65 | [profile.dev.build-override] 66 | opt-level = 0 67 | incremental = true 68 | -------------------------------------------------------------------------------- /src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tauri_build::build() 3 | } 4 | -------------------------------------------------------------------------------- /src-tauri/capabilities/desktop.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../gen/schemas/desktop-schema.json", 3 | "identifier": "desktop-capability", 4 | "windows": ["main"], 5 | "platforms": ["linux", "macOS", "windows"], 6 | "permissions": ["updater:default", "window-state:default"] 7 | } 8 | -------------------------------------------------------------------------------- /src-tauri/capabilities/mobile.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../gen/schemas/mobile-schema.json", 3 | "identifier": "mobile-capability", 4 | "windows": ["main"], 5 | "platforms": ["iOS", "android"], 6 | "permissions": [] 7 | } 8 | -------------------------------------------------------------------------------- /src-tauri/gen/android/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = false 12 | insert_final_newline = false -------------------------------------------------------------------------------- /src-tauri/gen/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | key.properties 17 | 18 | /.tauri 19 | /tauri.settings.gradle 20 | keystore.properties 21 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /src/main/java/com/soulfiremc/app/generated 2 | /src/main/jniLibs/**/*.so 3 | /src/main/assets/tauri.conf.json 4 | /tauri.build.gradle.kts 5 | /proguard-tauri.pro 6 | /tauri.properties -------------------------------------------------------------------------------- /src-tauri/gen/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 43 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/java/com/soulfiremc/soulfire/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.soulfiremc.soulfire 2 | 3 | class MainActivity : TauriActivity() -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/java/com/soulfiremc/soulfire/generated/Ipc.kt: -------------------------------------------------------------------------------- 1 | /* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */ 2 | 3 | // Copyright 2020-2023 Tauri Programme within The Commons Conservancy 4 | // SPDX-License-Identifier: Apache-2.0 5 | // SPDX-License-Identifier: MIT 6 | 7 | @file:Suppress("unused") 8 | 9 | package com.soulfiremc.soulfire 10 | 11 | import android.webkit.* 12 | 13 | class Ipc(val webViewClient: RustWebViewClient) { 14 | @JavascriptInterface 15 | fun postMessage(message: String?) { 16 | message?.let {m -> 17 | // we're not using WebView::getUrl() here because it needs to be executed on the main thread 18 | // and it would slow down the Ipc 19 | // so instead we track the current URL on the webview client 20 | this.ipc(webViewClient.currentUrl, m) 21 | } 22 | } 23 | 24 | companion object { 25 | init { 26 | System.loadLibrary("soulfire_lib") 27 | } 28 | } 29 | 30 | private external fun ipc(url: String, message: String) 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/java/com/soulfiremc/soulfire/generated/Logger.kt: -------------------------------------------------------------------------------- 1 | /* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */ 2 | 3 | // Copyright 2020-2023 Tauri Programme within The Commons Conservancy 4 | // SPDX-License-Identifier: Apache-2.0 5 | // SPDX-License-Identifier: MIT 6 | 7 | @file:Suppress("unused", "MemberVisibilityCanBePrivate") 8 | 9 | package com.soulfiremc.soulfire 10 | 11 | // taken from https://github.com/ionic-team/capacitor/blob/6658bca41e78239347e458175b14ca8bd5c1d6e8/android/capacitor/src/main/java/com/getcapacitor/Logger.java 12 | 13 | import android.text.TextUtils 14 | import android.util.Log 15 | 16 | class Logger { 17 | companion object { 18 | private const val LOG_TAG_CORE = "Tauri" 19 | 20 | fun tags(vararg subtags: String): String { 21 | return if (subtags.isNotEmpty()) { 22 | LOG_TAG_CORE + "/" + TextUtils.join("/", subtags) 23 | } else LOG_TAG_CORE 24 | } 25 | 26 | fun verbose(message: String) { 27 | verbose(LOG_TAG_CORE, message) 28 | } 29 | 30 | private fun verbose(tag: String, message: String) { 31 | if (!shouldLog()) { 32 | return 33 | } 34 | Log.v(tag, message) 35 | } 36 | 37 | fun debug(message: String) { 38 | debug(LOG_TAG_CORE, message) 39 | } 40 | 41 | fun debug(tag: String, message: String) { 42 | if (!shouldLog()) { 43 | return 44 | } 45 | Log.d(tag, message) 46 | } 47 | 48 | fun info(message: String) { 49 | info(LOG_TAG_CORE, message) 50 | } 51 | 52 | fun info(tag: String, message: String) { 53 | if (!shouldLog()) { 54 | return 55 | } 56 | Log.i(tag, message) 57 | } 58 | 59 | fun warn(message: String) { 60 | warn(LOG_TAG_CORE, message) 61 | } 62 | 63 | fun warn(tag: String, message: String) { 64 | if (!shouldLog()) { 65 | return 66 | } 67 | Log.w(tag, message) 68 | } 69 | 70 | fun error(message: String) { 71 | error(LOG_TAG_CORE, message, null) 72 | } 73 | 74 | fun error(message: String, e: Throwable?) { 75 | error(LOG_TAG_CORE, message, e) 76 | } 77 | 78 | fun error(tag: String, message: String, e: Throwable?) { 79 | if (!shouldLog()) { 80 | return 81 | } 82 | Log.e(tag, message, e) 83 | } 84 | 85 | private fun shouldLog(): Boolean { 86 | return BuildConfig.DEBUG 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/java/com/soulfiremc/soulfire/generated/TauriActivity.kt: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2024 Tauri Programme within The Commons Conservancy 2 | // SPDX-License-Identifier: Apache-2.0 3 | // SPDX-License-Identifier: MIT 4 | 5 | /* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */ 6 | 7 | package com.soulfiremc.soulfire 8 | 9 | import android.os.Bundle 10 | import android.content.Intent 11 | import app.tauri.plugin.PluginManager 12 | 13 | abstract class TauriActivity : WryActivity() { 14 | var pluginManager: PluginManager = PluginManager(this) 15 | 16 | override fun onNewIntent(intent: Intent) { 17 | super.onNewIntent(intent) 18 | pluginManager.onNewIntent(intent) 19 | } 20 | 21 | override fun onResume() { 22 | super.onResume() 23 | pluginManager.onResume() 24 | } 25 | 26 | override fun onPause() { 27 | super.onPause() 28 | pluginManager.onPause() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/java/com/soulfiremc/soulfire/generated/proguard-wry.pro: -------------------------------------------------------------------------------- 1 | # THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! 2 | 3 | # Copyright 2020-2023 Tauri Programme within The Commons Conservancy 4 | # SPDX-License-Identifier: Apache-2.0 5 | # SPDX-License-Identifier: MIT 6 | 7 | -keep class com.soulfiremc.soulfire.* { 8 | native ; 9 | } 10 | 11 | -keep class com.soulfiremc.soulfire.WryActivity { 12 | public (...); 13 | 14 | void setWebView(com.soulfiremc.soulfire.RustWebView); 15 | java.lang.Class getAppClass(...); 16 | java.lang.String getVersion(); 17 | } 18 | 19 | -keep class com.soulfiremc.soulfire.Ipc { 20 | public (...); 21 | 22 | @android.webkit.JavascriptInterface public ; 23 | } 24 | 25 | -keep class com.soulfiremc.soulfire.RustWebView { 26 | public (...); 27 | 28 | void loadUrlMainThread(...); 29 | void loadHTMLMainThread(...); 30 | void setAutoPlay(...); 31 | void setUserAgent(...); 32 | void evalScript(...); 33 | } 34 | 35 | -keep class com.soulfiremc.soulfire.RustWebChromeClient,com.soulfiremc.soulfire.RustWebViewClient { 36 | public (...); 37 | } -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SoulFire 3 | SoulFire 4 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/xml/file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src-tauri/gen/android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | dependencies { 7 | classpath("com.android.tools.build:gradle:8.10.1") 8 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.21") 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | mavenCentral() 16 | } 17 | } 18 | 19 | tasks.register("clean").configure { 20 | delete("build") 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src-tauri/gen/android/buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | gradlePlugin { 6 | plugins { 7 | create("pluginsForCoolKids") { 8 | id = "rust" 9 | implementationClass = "RustPlugin" 10 | } 11 | } 12 | } 13 | 14 | repositories { 15 | google() 16 | mavenCentral() 17 | } 18 | 19 | dependencies { 20 | compileOnly(gradleApi()) 21 | implementation("com.android.tools.build:gradle:8.10.1") 22 | } 23 | -------------------------------------------------------------------------------- /src-tauri/gen/android/buildSrc/src/main/java/com/soulfiremc/app/kotlin/BuildTask.kt: -------------------------------------------------------------------------------- 1 | import java.io.File 2 | import org.apache.tools.ant.taskdefs.condition.Os 3 | import org.gradle.api.DefaultTask 4 | import org.gradle.api.GradleException 5 | import org.gradle.api.logging.LogLevel 6 | import org.gradle.api.tasks.Input 7 | import org.gradle.api.tasks.TaskAction 8 | 9 | open class BuildTask : DefaultTask() { 10 | @Input 11 | var rootDirRel: String? = null 12 | @Input 13 | var target: String? = null 14 | @Input 15 | var release: Boolean? = null 16 | 17 | @TaskAction 18 | fun assemble() { 19 | val executable = """cargo"""; 20 | try { 21 | runTauriCli(executable) 22 | } catch (e: Exception) { 23 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 24 | runTauriCli("$executable.cmd") 25 | } else { 26 | throw e; 27 | } 28 | } 29 | } 30 | 31 | fun runTauriCli(executable: String) { 32 | val rootDirRel = rootDirRel ?: throw GradleException("rootDirRel cannot be null") 33 | val target = target ?: throw GradleException("target cannot be null") 34 | val release = release ?: throw GradleException("release cannot be null") 35 | val args = listOf("tauri", "android", "android-studio-script"); 36 | 37 | project.exec { 38 | workingDir(File(project.projectDir, rootDirRel)) 39 | executable(executable) 40 | args(args) 41 | if (project.logger.isEnabled(LogLevel.DEBUG)) { 42 | args("-vv") 43 | } else if (project.logger.isEnabled(LogLevel.INFO)) { 44 | args("-v") 45 | } 46 | if (release) { 47 | args("--release") 48 | } 49 | args(listOf("--target", target)) 50 | }.assertNormalExitValue() 51 | } 52 | } -------------------------------------------------------------------------------- /src-tauri/gen/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true 24 | android.nonFinalResIds=false -------------------------------------------------------------------------------- /src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue May 10 19:22:52 CST 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /src-tauri/gen/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | apply from: 'tauri.settings.gradle' 4 | -------------------------------------------------------------------------------- /src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-20x20@1x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-20x20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-20x20@2x-1.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-20x20@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-20x20@3x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-29x29@1x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-29x29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-29x29@2x-1.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-29x29@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-29x29@3x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-40x40@1x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-40x40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-40x40@2x-1.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-40x40@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-40x40@3x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-512@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-60x60@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-60x60@3x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-76x76@1x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-76x76@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexProgrammerDE/SoulFireClient/62e29fdc4bf5a31ac6835f84e40491e84f08dc8a/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png -------------------------------------------------------------------------------- /src-tauri/src/discord.rs: -------------------------------------------------------------------------------- 1 | use std::time::{SystemTime, UNIX_EPOCH}; 2 | 3 | use crate::utils::SFAnyError; 4 | use discord_presence::{Client, Event}; 5 | use log::{debug, error, info}; 6 | 7 | const CLIENT_ID: u64 = 1248603974475583608; 8 | pub fn load_discord_rpc() -> Result<(), SFAnyError> { 9 | let mut discord_rpc = Client::new(CLIENT_ID); 10 | 11 | let _ready = discord_rpc.on_ready(|_ctx| { 12 | info!("Discord RPC ready!"); 13 | }); 14 | 15 | let _error = discord_rpc.on_error(|error| { 16 | debug!("Discord RPC error: {:?}", error); 17 | }); 18 | 19 | discord_rpc.start(); 20 | 21 | let start = SystemTime::now(); 22 | let epoch_secs = start.duration_since(UNIX_EPOCH)?.as_secs(); 23 | discord_rpc.block_until_event(Event::Ready)?; 24 | if let Err(why) = discord_rpc.set_activity(|a| { 25 | a.state("Idling") 26 | .details("Professional bot tool") 27 | .timestamps(|timestamps| timestamps.start(epoch_secs)) 28 | .assets(|assets| assets.large_image("logo").large_text("SoulFire 🧙")) 29 | .append_buttons(|button| button.label("Learn more").url("https://soulfiremc.com")) 30 | }) { 31 | error!("Failed to set presence: {}", why); 32 | } 33 | 34 | discord_rpc.block_on()?; 35 | 36 | Ok(()) 37 | } 38 | -------------------------------------------------------------------------------- /src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | // Prevents an additional console window on Windows in release, DO NOT REMOVE!! 2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 3 | 4 | fn main() { 5 | soulfire_lib::run(); 6 | } 7 | -------------------------------------------------------------------------------- /src-tauri/src/sf_version_constant.rs: -------------------------------------------------------------------------------- 1 | pub const SOULFIRE_VERSION: &str = "1.20.4"; 2 | -------------------------------------------------------------------------------- /src-tauri/src/tray.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::{SFAnyError, SFError}; 2 | use log::error; 3 | use tauri::menu::MenuEvent; 4 | use tauri::tray::TrayIcon; 5 | use tauri::{ 6 | AppHandle, Manager, Runtime, 7 | menu::{Menu, MenuItem}, 8 | tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent}, 9 | }; 10 | 11 | fn handle_menu_event( 12 | app_handle: AppHandle, 13 | event: MenuEvent, 14 | ) -> Result<(), SFAnyError> { 15 | match event.id.as_ref() { 16 | "open" => { 17 | let _ = app_handle 18 | .get_webview_window("main") 19 | .ok_or(SFError::NoMainWindow)? 20 | .show(); 21 | } 22 | "quit" => { 23 | app_handle.exit(0); 24 | } 25 | _ => {} 26 | } 27 | 28 | Ok(()) 29 | } 30 | 31 | fn handle_tray_event( 32 | tray: TrayIcon, 33 | event: TrayIconEvent, 34 | ) -> Result<(), SFAnyError> { 35 | if let TrayIconEvent::Click { 36 | button: MouseButton::Left, 37 | button_state: MouseButtonState::Up, 38 | .. 39 | } = event 40 | { 41 | let app = tray.app_handle(); 42 | let main_window = app 43 | .get_webview_window("main") 44 | .ok_or(SFError::NoMainWindow)?; 45 | main_window.show()?; 46 | main_window.set_focus()?; 47 | } 48 | 49 | Ok(()) 50 | } 51 | 52 | pub fn create_tray(app: &AppHandle) -> Result<(), SFAnyError> { 53 | let open_i = MenuItem::with_id(app, "open", "Open SoulFire", true, None::<&str>)?; 54 | let quit_i = MenuItem::with_id(app, "quit", "Quit SoulFire", true, None::<&str>)?; 55 | let menu = Menu::with_items(app, &[&open_i, &quit_i])?; 56 | 57 | let _ = TrayIconBuilder::with_id("tray") 58 | .icon( 59 | app.default_window_icon() 60 | .ok_or(SFError::NoDefaultWindowIcon)? 61 | .clone(), 62 | ) 63 | .menu(&menu) 64 | .show_menu_on_left_click(false) 65 | .on_menu_event( 66 | move |app, event| match handle_menu_event(app.clone(), event) { 67 | Ok(_) => {} 68 | Err(e) => error!("Error during menu event: {e}"), 69 | }, 70 | ) 71 | .on_tray_icon_event(|tray, event| match handle_tray_event(tray.clone(), event) { 72 | Ok(_) => {} 73 | Err(e) => error!("Error during tray event: {e}"), 74 | }) 75 | .build(app); 76 | 77 | Ok(()) 78 | } 79 | -------------------------------------------------------------------------------- /src-tauri/src/updater.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::SFAnyError; 2 | use log::info; 3 | use tauri_plugin_updater::UpdaterExt; 4 | 5 | pub(crate) async fn update(app: tauri::AppHandle) -> Result<(), SFAnyError> { 6 | info!("Checking for updates"); 7 | if let Some(update) = app.updater()?.check().await? { 8 | let mut downloaded = 0; 9 | 10 | update 11 | .download_and_install( 12 | |chunk_length, content_length| { 13 | downloaded += chunk_length; 14 | info!("Downloaded {downloaded} from {content_length:?}"); 15 | }, 16 | || { 17 | info!("Download finished"); 18 | }, 19 | ) 20 | .await?; 21 | 22 | info!("Update installed"); 23 | app.restart(); 24 | } else { 25 | info!("No update found"); 26 | } 27 | 28 | Ok(()) 29 | } 30 | -------------------------------------------------------------------------------- /src-tauri/tauri.linux.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "productName": "soulfire" 3 | } 4 | -------------------------------------------------------------------------------- /src-tauri/tauri.microsoftstore.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "bundle": { 3 | "windows": { 4 | "webviewInstallMode": { 5 | "type": "offlineInstaller" 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/components/data-table-selects.tsx: -------------------------------------------------------------------------------- 1 | import { CellContext, HeaderContext } from '@tanstack/react-table'; 2 | import { Checkbox } from '@/components/ui/checkbox.tsx'; 3 | import { useTranslation } from 'react-i18next'; 4 | 5 | export function SelectAllHeader({ table }: HeaderContext) { 6 | const { t } = useTranslation('common'); 7 | return ( 8 |
9 | table.toggleAllRowsSelected(!!value)} 16 | aria-label={t('dataTable.selectAll')} 17 | /> 18 |
19 | ); 20 | } 21 | 22 | export function SelectRowHeader({ row }: CellContext) { 23 | const { t } = useTranslation('common'); 24 | return ( 25 |
26 | row.toggleSelected(!!value)} 31 | aria-label={t('dataTable.selectRow')} 32 | /> 33 |
34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /src/components/dynamic-icon.tsx: -------------------------------------------------------------------------------- 1 | import React, { Suspense } from 'react'; 2 | import { LucideProps } from 'lucide-react'; 3 | import dynamicIconImports from 'lucide-react/dynamicIconImports'; 4 | import i18n from '@/lib/i18n'; 5 | import tags from 'lucide-static/tags.json'; 6 | 7 | export function getAllIconTags() { 8 | return Object.entries(tags); 9 | } 10 | 11 | export type LucideIconName = keyof typeof dynamicIconImports; 12 | 13 | export interface IconProps extends Omit { 14 | name: string; 15 | } 16 | 17 | const cache = new Map< 18 | string, 19 | React.LazyExoticComponent> 20 | >(); 21 | 22 | function convertUnsafeIconName(name: string): LucideIconName { 23 | if (name in dynamicIconImports) { 24 | return name as LucideIconName; 25 | } 26 | 27 | throw new Error( 28 | i18n.t('icon.invalidName', { 29 | name, 30 | }), 31 | ); 32 | } 33 | 34 | function loadCachedIcon(name: LucideIconName) { 35 | const value = cache.get(name); 36 | if (value !== undefined) { 37 | return value; 38 | } 39 | 40 | const lazyValue = React.lazy(dynamicIconImports[name]); 41 | cache.set(name, lazyValue); 42 | return lazyValue; 43 | } 44 | 45 | const DynamicIcon = React.memo(({ name, ...props }: IconProps) => { 46 | const LazyIcon = loadCachedIcon(convertUnsafeIconName(name)); 47 | 48 | return ( 49 | }> 50 | 51 | 52 | ); 53 | }); 54 | 55 | export default DynamicIcon; 56 | -------------------------------------------------------------------------------- /src/components/external-link.tsx: -------------------------------------------------------------------------------- 1 | import { AnchorHTMLAttributes, DetailedHTMLProps } from 'react'; 2 | import { isTauri, runAsync } from '@/lib/utils.tsx'; 3 | import { openUrl } from '@tauri-apps/plugin-opener'; 4 | 5 | export function ExternalLink( 6 | props: Omit< 7 | DetailedHTMLProps< 8 | AnchorHTMLAttributes, 9 | HTMLAnchorElement 10 | >, 11 | 'target' 12 | > & { 13 | href: string; 14 | }, 15 | ) { 16 | return ( 17 | { 19 | e.stopPropagation(); 20 | e.preventDefault(); 21 | 22 | if (isTauri()) { 23 | runAsync(async () => { 24 | await openUrl(props.href); 25 | }); 26 | } else { 27 | window.open(props.href, '_blank'); 28 | } 29 | }} 30 | target="_blank" 31 | {...props} 32 | /> 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /src/components/info-buttons.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode, useState } from 'react'; 2 | import { 3 | Popover, 4 | PopoverContent, 5 | PopoverTrigger, 6 | } from '@/components/ui/popover.tsx'; 7 | import { ClipboardIcon, InfoIcon } from 'lucide-react'; 8 | import { copyToClipboard, isTauri } from '@/lib/utils.tsx'; 9 | import * as clipboard from '@tauri-apps/plugin-clipboard-manager'; 10 | import { useTranslation } from 'react-i18next'; 11 | import { toast } from 'sonner'; 12 | import { Button } from '@/components/ui/button.tsx'; 13 | 14 | export function TextInfoButton(props: { value: ReactNode }) { 15 | return ( 16 |

{props.value}

} 18 | /> 19 | ); 20 | } 21 | 22 | export function CopyInfoButton(props: { value: string }) { 23 | const { t } = useTranslation('common'); 24 | return ( 25 | ( 27 |
28 |

{props.value}

29 | 41 |
42 | )} 43 | /> 44 | ); 45 | } 46 | 47 | function GenericInfoButton(props: { 48 | value: (closer: () => void) => ReactNode; 49 | }) { 50 | const [open, setOpen] = useState(false); 51 | 52 | return ( 53 | 54 | 55 | { 58 | setOpen(!open); 59 | }} 60 | /> 61 | 62 | {props.value(() => setOpen(false))} 63 | 64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /src/components/loading-component.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from '@/components/ui/skeleton.tsx'; 2 | import * as React from 'react'; 3 | 4 | function LoadingSkeleton() { 5 | // Random width between 50 to 90%. 6 | const width = React.useMemo(() => { 7 | return `${Math.floor(Math.random() * 40) + 75}%`; 8 | }, []); 9 | 10 | return ( 11 | 19 | ); 20 | } 21 | 22 | export function LoadingComponent() { 23 | return ( 24 |
25 | {Array.from({ length: 10 }).map((_, index) => ( 26 | 27 | ))} 28 |
29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /src/components/nav/instance-sidebar.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Suspense } from 'react'; 3 | 4 | import { NavControls } from '@/components/nav/nav-controls.tsx'; 5 | import { NavSettings } from '@/components/nav/nav-settings.tsx'; 6 | import { NavAccount } from '@/components/nav/nav-account.tsx'; 7 | import { NavPlugins } from '@/components/nav/nav-plugins'; 8 | import { InstanceSwitcher } from '@/components/nav/instance-switcher.tsx'; 9 | import { 10 | Sidebar, 11 | SidebarContent, 12 | SidebarFooter, 13 | SidebarHeader, 14 | SidebarRail, 15 | } from '@/components/ui/sidebar.tsx'; 16 | import { NavSecondary } from '@/components/nav/nav-secondary.tsx'; 17 | import { ScrollArea } from '@/components/ui/scroll-area.tsx'; 18 | import { NavDefaultSkeleton } from '@/components/nav/nav-default-skeleton.tsx'; 19 | 20 | export function InstanceSidebar(props: React.ComponentProps) { 21 | return ( 22 | 23 | 24 | 25 | 26 | 27 | 28 | }> 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /src/components/nav/nav-controls.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { TerminalIcon, TextSearchIcon } from 'lucide-react'; 4 | import { 5 | SidebarGroup, 6 | SidebarGroupLabel, 7 | SidebarMenu, 8 | SidebarMenuButton, 9 | SidebarMenuItem, 10 | } from '@/components/ui/sidebar.tsx'; 11 | import { Link, LinkProps, useRouteContext } from '@tanstack/react-router'; 12 | import { ReactNode } from 'react'; 13 | import { useTranslation } from 'react-i18next'; 14 | import { useSuspenseQuery } from '@tanstack/react-query'; 15 | 16 | type NavLinks = { 17 | title: string; 18 | icon: (props: { className: string }) => ReactNode; 19 | linkProps: LinkProps; 20 | }[]; 21 | 22 | export function NavControls() { 23 | const { t } = useTranslation('common'); 24 | const instanceInfoQueryOptions = useRouteContext({ 25 | from: '/_dashboard/instance/$instance', 26 | select: (context) => context.instanceInfoQueryOptions, 27 | }); 28 | const { data: instanceInfo } = useSuspenseQuery(instanceInfoQueryOptions); 29 | 30 | const navLinks: NavLinks = [ 31 | { 32 | title: t('instanceSidebar.console'), 33 | icon: TerminalIcon, 34 | linkProps: { 35 | to: '/instance/$instance', 36 | params: { instance: instanceInfo.id }, 37 | }, 38 | }, 39 | { 40 | title: t('instanceSidebar.audit-log'), 41 | icon: TextSearchIcon, 42 | linkProps: { 43 | to: '/instance/$instance/audit-log', 44 | params: { instance: instanceInfo.id }, 45 | }, 46 | }, 47 | ]; 48 | 49 | return ( 50 | 51 | 52 | {t('instanceSidebar.controlsGroup')} 53 | 54 | 55 | {navLinks.map((item) => ( 56 | 57 | 58 | 65 | 66 | {item.title} 67 | 68 | 69 | 70 | ))} 71 | 72 | 73 | ); 74 | } 75 | -------------------------------------------------------------------------------- /src/components/nav/nav-default-skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | SidebarGroup, 3 | SidebarMenu, 4 | SidebarMenuItem, 5 | SidebarMenuSkeleton, 6 | } from '../ui/sidebar'; 7 | import * as React from 'react'; 8 | 9 | export function NavDefaultSkeleton() { 10 | return ( 11 | 12 | 13 | {Array.from({ length: 5 }).map((_, index) => ( 14 | 15 | 16 | 17 | ))} 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/components/nav/nav-secondary.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { BookOpenTextIcon, CoffeeIcon, type LucideIcon } from 'lucide-react'; 3 | 4 | import { 5 | SidebarGroup, 6 | SidebarGroupContent, 7 | SidebarMenu, 8 | SidebarMenuButton, 9 | SidebarMenuItem, 10 | } from '@/components/ui/sidebar.tsx'; 11 | import { useTranslation } from 'react-i18next'; 12 | import { ExternalLink } from '@/components/external-link.tsx'; 13 | import { SiDiscord } from '@icons-pack/react-simple-icons'; 14 | 15 | type NavLinks = { 16 | title: string; 17 | url: string; 18 | icon: LucideIcon; 19 | }[]; 20 | 21 | export function NavSecondary({ 22 | ...props 23 | }: React.ComponentPropsWithoutRef) { 24 | const { t } = useTranslation('common'); 25 | const items: NavLinks = [ 26 | { 27 | title: t('sidebar.documentation'), 28 | url: 'https://soulfiremc.com/docs', 29 | icon: BookOpenTextIcon, 30 | }, 31 | { 32 | title: t('sidebar.buyMeACoffee'), 33 | url: 'https://ko-fi.com/alexprogrammerde', 34 | icon: CoffeeIcon, 35 | }, 36 | { 37 | title: t('sidebar.discord'), 38 | url: 'https://soulfiremc.com/discord', 39 | icon: SiDiscord, 40 | }, 41 | ]; 42 | 43 | return ( 44 | 45 | 46 | 47 | {items.map((item) => ( 48 | 49 | 50 | 51 | 52 | {item.title} 53 | 54 | 55 | 56 | ))} 57 | 58 | 59 | 60 | ); 61 | } 62 | -------------------------------------------------------------------------------- /src/components/nav/user-sidebar.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Suspense } from 'react'; 3 | import { NavAccount } from '@/components/nav/nav-account.tsx'; 4 | import { 5 | Sidebar, 6 | SidebarContent, 7 | SidebarFooter, 8 | SidebarRail, 9 | } from '@/components/ui/sidebar.tsx'; 10 | import { NavSecondary } from '@/components/nav/nav-secondary.tsx'; 11 | import { ScrollArea } from '@/components/ui/scroll-area.tsx'; 12 | import { NavUserOptions } from '@/components/nav/nav-user-options.tsx'; 13 | import { NavUserAdmin } from '@/components/nav/nav-user-admin.tsx'; 14 | import { NavDefaultSkeleton } from '@/components/nav/nav-default-skeleton.tsx'; 15 | 16 | export function UserSidebar({ 17 | ...props 18 | }: React.ComponentProps) { 19 | return ( 20 | 21 | 22 | 23 | }> 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /src/components/not-found-component.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'react-i18next'; 2 | import { useNavigate, useRouter } from '@tanstack/react-router'; 3 | import { useState } from 'react'; 4 | import { 5 | LoaderCircleIcon, 6 | LogOutIcon, 7 | RotateCwIcon, 8 | SearchXIcon, 9 | } from 'lucide-react'; 10 | import { Button } from '@/components/ui/button.tsx'; 11 | import { isTauri, runAsync } from '@/lib/utils.tsx'; 12 | import { emit } from '@tauri-apps/api/event'; 13 | import { logOut } from '@/lib/web-rpc.ts'; 14 | import { 15 | Card, 16 | CardDescription, 17 | CardFooter, 18 | CardHeader, 19 | CardTitle, 20 | } from '@/components/ui/card.tsx'; 21 | 22 | export function NotFoundComponent() { 23 | const { t } = useTranslation('common'); 24 | const navigate = useNavigate(); 25 | const router = useRouter(); 26 | const [revalidating, setRevalidating] = useState(false); 27 | 28 | return ( 29 |
30 | 31 | 32 | 33 | 34 | {t('notFound.page.title')} 35 | 36 | {t('notFound.page.description')} 37 | 38 | 39 | 57 | 77 | 78 | 79 |
80 | ); 81 | } 82 | -------------------------------------------------------------------------------- /src/components/providers/system-info-context.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export type SystemInfo = { 4 | availableProfiles: string[]; 5 | osType: string; 6 | osVersion: string; 7 | platformName: string; 8 | osLocale: string | null; 9 | archName: string; 10 | mobile: boolean; 11 | sfServerVersion: string; 12 | }; 13 | 14 | export const SystemInfoContext = createContext(null); 15 | -------------------------------------------------------------------------------- /src/components/providers/terminal-theme-context.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export const TerminalThemeContext = createContext<{ 4 | value: string; 5 | setter: (value: string) => void; 6 | }>(null as never); 7 | -------------------------------------------------------------------------------- /src/components/providers/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | import { ThemeProvider as NextThemesProvider } from 'next-themes'; 2 | 3 | export function ThemeProvider({ 4 | children, 5 | ...props 6 | }: Parameters[0]) { 7 | return {children}; 8 | } 9 | -------------------------------------------------------------------------------- /src/components/providers/transport-context.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import { RpcTransport } from '@protobuf-ts/runtime-rpc'; 3 | 4 | export const TransportContext = createContext(null); 5 | -------------------------------------------------------------------------------- /src/components/sf-timeago.tsx: -------------------------------------------------------------------------------- 1 | import { useDateFnsLocale } from '@/hooks/use-date-fns-locale.ts'; 2 | import { useChangingData } from '@/hooks/use-changing-value.ts'; 3 | import { format, formatDistanceToNow } from 'date-fns'; 4 | import React, { useMemo } from 'react'; 5 | import { 6 | Popover, 7 | PopoverContent, 8 | PopoverTrigger, 9 | } from '@/components/ui/popover.tsx'; 10 | 11 | export const SFTimeAgo = React.memo((props: { date: Date }) => { 12 | const dateFnsLocale = useDateFnsLocale(); 13 | const baseText = useChangingData( 14 | () => 15 | formatDistanceToNow(props.date, { 16 | addSuffix: true, 17 | includeSeconds: true, 18 | locale: dateFnsLocale, 19 | }), 20 | 1_000, 21 | [props.date, dateFnsLocale], 22 | ); 23 | const formatted = useMemo(() => { 24 | return format(props.date, 'PPpp', { locale: dateFnsLocale }); 25 | }, [props.date, dateFnsLocale]); 26 | 27 | return ( 28 | 29 | {baseText} 30 | 31 | 32 | 33 | 34 | ); 35 | }); 36 | -------------------------------------------------------------------------------- /src/components/tailwind-indicator.tsx: -------------------------------------------------------------------------------- 1 | export function TailwindIndicator() { 2 | if (process.env.NODE_ENV === 'production') return null; 3 | 4 | return ( 5 |
6 |
xs
7 |
8 | sm 9 |
10 |
md
11 |
lg
12 |
xl
13 |
2xl
14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/components/ui/avatar.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import * as AvatarPrimitive from '@radix-ui/react-avatar'; 5 | 6 | import { cn } from '@/lib/utils'; 7 | 8 | function Avatar({ 9 | className, 10 | ...props 11 | }: React.ComponentProps) { 12 | return ( 13 | 21 | ); 22 | } 23 | 24 | function AvatarImage({ 25 | className, 26 | ...props 27 | }: React.ComponentProps) { 28 | return ( 29 | 34 | ); 35 | } 36 | 37 | function AvatarFallback({ 38 | className, 39 | ...props 40 | }: React.ComponentProps) { 41 | return ( 42 | 50 | ); 51 | } 52 | 53 | export { Avatar, AvatarImage, AvatarFallback }; 54 | -------------------------------------------------------------------------------- /src/components/ui/badge.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Slot } from '@radix-ui/react-slot'; 3 | import { cva, type VariantProps } from 'class-variance-authority'; 4 | 5 | import { cn } from '@/lib/utils'; 6 | 7 | const badgeVariants = cva( 8 | 'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden', 9 | { 10 | variants: { 11 | variant: { 12 | default: 13 | 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90', 14 | secondary: 15 | 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90', 16 | destructive: 17 | 'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60', 18 | outline: 19 | 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground', 20 | }, 21 | }, 22 | defaultVariants: { 23 | variant: 'default', 24 | }, 25 | }, 26 | ); 27 | 28 | function Badge({ 29 | className, 30 | variant, 31 | asChild = false, 32 | ...props 33 | }: React.ComponentProps<'span'> & 34 | VariantProps & { asChild?: boolean }) { 35 | const Comp = asChild ? Slot : 'span'; 36 | 37 | return ( 38 | 43 | ); 44 | } 45 | 46 | export { Badge, badgeVariants }; 47 | -------------------------------------------------------------------------------- /src/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Slot } from '@radix-ui/react-slot'; 3 | import { cva, type VariantProps } from 'class-variance-authority'; 4 | 5 | import { cn } from '@/lib/utils'; 6 | 7 | const buttonVariants = cva( 8 | "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", 9 | { 10 | variants: { 11 | variant: { 12 | default: 13 | 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90', 14 | destructive: 15 | 'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60', 16 | outline: 17 | 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50', 18 | secondary: 19 | 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80', 20 | ghost: 21 | 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50', 22 | link: 'text-primary underline-offset-4 hover:underline', 23 | }, 24 | size: { 25 | default: 'h-9 px-4 py-2 has-[>svg]:px-3', 26 | sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5', 27 | lg: 'h-10 rounded-md px-6 has-[>svg]:px-4', 28 | icon: 'size-9', 29 | }, 30 | }, 31 | defaultVariants: { 32 | variant: 'default', 33 | size: 'default', 34 | }, 35 | }, 36 | ); 37 | 38 | function Button({ 39 | className, 40 | variant, 41 | size, 42 | asChild = false, 43 | ...props 44 | }: React.ComponentProps<'button'> & 45 | VariantProps & { 46 | asChild?: boolean; 47 | }) { 48 | const Comp = asChild ? Slot : 'button'; 49 | 50 | return ( 51 | 56 | ); 57 | } 58 | 59 | export { Button, buttonVariants }; 60 | -------------------------------------------------------------------------------- /src/components/ui/card.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { cn } from '@/lib/utils'; 4 | 5 | function Card({ className, ...props }: React.ComponentProps<'div'>) { 6 | return ( 7 |
15 | ); 16 | } 17 | 18 | function CardHeader({ className, ...props }: React.ComponentProps<'div'>) { 19 | return ( 20 |
28 | ); 29 | } 30 | 31 | function CardTitle({ className, ...props }: React.ComponentProps<'div'>) { 32 | return ( 33 |
38 | ); 39 | } 40 | 41 | function CardDescription({ className, ...props }: React.ComponentProps<'div'>) { 42 | return ( 43 |
48 | ); 49 | } 50 | 51 | function CardAction({ className, ...props }: React.ComponentProps<'div'>) { 52 | return ( 53 |
61 | ); 62 | } 63 | 64 | function CardContent({ className, ...props }: React.ComponentProps<'div'>) { 65 | return ( 66 |
71 | ); 72 | } 73 | 74 | function CardFooter({ className, ...props }: React.ComponentProps<'div'>) { 75 | return ( 76 |
81 | ); 82 | } 83 | 84 | export { 85 | Card, 86 | CardHeader, 87 | CardFooter, 88 | CardTitle, 89 | CardAction, 90 | CardDescription, 91 | CardContent, 92 | }; 93 | -------------------------------------------------------------------------------- /src/components/ui/checkbox.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import * as CheckboxPrimitive from '@radix-ui/react-checkbox'; 5 | import { CheckIcon } from 'lucide-react'; 6 | 7 | import { cn } from '@/lib/utils'; 8 | 9 | function Checkbox({ 10 | className, 11 | ...props 12 | }: React.ComponentProps) { 13 | return ( 14 | 22 | 26 | 27 | 28 | 29 | ); 30 | } 31 | 32 | export { Checkbox }; 33 | -------------------------------------------------------------------------------- /src/components/ui/collapsible.tsx: -------------------------------------------------------------------------------- 1 | import * as CollapsiblePrimitive from '@radix-ui/react-collapsible'; 2 | 3 | function Collapsible({ 4 | ...props 5 | }: React.ComponentProps) { 6 | return ; 7 | } 8 | 9 | function CollapsibleTrigger({ 10 | ...props 11 | }: React.ComponentProps) { 12 | return ( 13 | 17 | ); 18 | } 19 | 20 | function CollapsibleContent({ 21 | ...props 22 | }: React.ComponentProps) { 23 | return ( 24 | 28 | ); 29 | } 30 | 31 | export { Collapsible, CollapsibleTrigger, CollapsibleContent }; 32 | -------------------------------------------------------------------------------- /src/components/ui/input-otp.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import { OTPInput, OTPInputContext } from 'input-otp'; 5 | import { MinusIcon } from 'lucide-react'; 6 | 7 | import { cn } from '@/lib/utils'; 8 | 9 | function InputOTP({ 10 | className, 11 | containerClassName, 12 | ...props 13 | }: React.ComponentProps & { 14 | containerClassName?: string; 15 | }) { 16 | return ( 17 | 26 | ); 27 | } 28 | 29 | function InputOTPGroup({ className, ...props }: React.ComponentProps<'div'>) { 30 | return ( 31 |
36 | ); 37 | } 38 | 39 | function InputOTPSlot({ 40 | index, 41 | className, 42 | ...props 43 | }: React.ComponentProps<'div'> & { 44 | index: number; 45 | }) { 46 | const inputOTPContext = React.useContext(OTPInputContext); 47 | const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {}; 48 | 49 | return ( 50 |
59 | {char} 60 | {hasFakeCaret && ( 61 |
62 |
63 |
64 | )} 65 |
66 | ); 67 | } 68 | 69 | function InputOTPSeparator({ ...props }: React.ComponentProps<'div'>) { 70 | return ( 71 |
72 | 73 |
74 | ); 75 | } 76 | 77 | export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }; 78 | -------------------------------------------------------------------------------- /src/components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { cn } from '@/lib/utils'; 4 | 5 | function Input({ className, type, ...props }: React.ComponentProps<'input'>) { 6 | return ( 7 | 18 | ); 19 | } 20 | 21 | export { Input }; 22 | -------------------------------------------------------------------------------- /src/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import * as LabelPrimitive from '@radix-ui/react-label'; 5 | 6 | import { cn } from '@/lib/utils'; 7 | 8 | function Label({ 9 | className, 10 | ...props 11 | }: React.ComponentProps) { 12 | return ( 13 | 21 | ); 22 | } 23 | 24 | export { Label }; 25 | -------------------------------------------------------------------------------- /src/components/ui/popover.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import * as PopoverPrimitive from '@radix-ui/react-popover'; 5 | 6 | import { cn } from '@/lib/utils'; 7 | 8 | function Popover({ 9 | ...props 10 | }: React.ComponentProps) { 11 | return ; 12 | } 13 | 14 | function PopoverTrigger({ 15 | ...props 16 | }: React.ComponentProps) { 17 | return ; 18 | } 19 | 20 | function PopoverContent({ 21 | className, 22 | align = 'center', 23 | sideOffset = 4, 24 | ...props 25 | }: React.ComponentProps) { 26 | return ( 27 | 28 | 38 | 39 | ); 40 | } 41 | 42 | function PopoverAnchor({ 43 | ...props 44 | }: React.ComponentProps) { 45 | return ; 46 | } 47 | 48 | export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }; 49 | -------------------------------------------------------------------------------- /src/components/ui/scroll-area.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'; 5 | 6 | import { cn } from '@/lib/utils'; 7 | 8 | function ScrollArea({ 9 | className, 10 | children, 11 | viewportRef, 12 | ...props 13 | }: React.ComponentProps & { 14 | viewportRef?: React.RefObject; 15 | }) { 16 | return ( 17 | 22 | 27 | {children} 28 | 29 | 30 | 31 | 32 | ); 33 | } 34 | 35 | function ScrollBar({ 36 | className, 37 | orientation = 'vertical', 38 | ...props 39 | }: React.ComponentProps) { 40 | return ( 41 | 54 | 58 | 59 | ); 60 | } 61 | 62 | export { ScrollArea, ScrollBar }; 63 | -------------------------------------------------------------------------------- /src/components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import * as SeparatorPrimitive from '@radix-ui/react-separator'; 5 | 6 | import { cn } from '@/lib/utils'; 7 | 8 | function Separator({ 9 | className, 10 | orientation = 'horizontal', 11 | decorative = true, 12 | ...props 13 | }: React.ComponentProps) { 14 | return ( 15 | 25 | ); 26 | } 27 | 28 | export { Separator }; 29 | -------------------------------------------------------------------------------- /src/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@/lib/utils'; 2 | 3 | function Skeleton({ className, ...props }: React.ComponentProps<'div'>) { 4 | return ( 5 |
10 | ); 11 | } 12 | 13 | export { Skeleton }; 14 | -------------------------------------------------------------------------------- /src/components/ui/sonner.tsx: -------------------------------------------------------------------------------- 1 | import { useTheme } from 'next-themes'; 2 | import { Toaster as Sonner, ToasterProps } from 'sonner'; 3 | 4 | const Toaster = ({ ...props }: ToasterProps) => { 5 | const { theme = 'system' } = useTheme(); 6 | 7 | return ( 8 | 20 | ); 21 | }; 22 | 23 | export { Toaster }; 24 | -------------------------------------------------------------------------------- /src/components/ui/switch.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import * as SwitchPrimitive from '@radix-ui/react-switch'; 5 | 6 | import { cn } from '@/lib/utils'; 7 | 8 | function Switch({ 9 | className, 10 | ...props 11 | }: React.ComponentProps) { 12 | return ( 13 | 21 | 27 | 28 | ); 29 | } 30 | 31 | export { Switch }; 32 | -------------------------------------------------------------------------------- /src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { cn } from '@/lib/utils'; 4 | 5 | function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) { 6 | return ( 7 |