Compare commits

..

13 Commits

Author SHA1 Message Date
IMB11
35b016c0bd
Merge branch 'main' into cal/dev-136
Signed-off-by: IMB11 <hendersoncal117@gmail.com>
2025-08-08 11:57:27 +01:00
IMB11
167ddb1429
Merge branch 'main' into cal/dev-136 2025-08-06 14:00:40 +01:00
Calum H.
7aa47f9473 fix: lint issues 2025-08-05 11:52:58 +01:00
Calum H. (IMB11)
3f91b55636 fix: prettier frontend 2025-08-05 11:51:07 +01:00
Calum H. (IMB11)
e7f940daa1 chore: fix util lint issues 2025-08-05 11:51:07 +01:00
Calum H. (IMB11)
75b00bec3d chore: fix ui lint issues 2025-08-05 11:51:07 +01:00
Calum H. (IMB11)
2376bea510 chore: fix blog lint issues 2025-08-05 11:51:07 +01:00
Calum H. (IMB11)
981cf159bf chore: fix moderation lint issues 2025-08-05 11:51:07 +01:00
Calum H. (IMB11)
52720ce06a chore: fix assets lint 2025-08-05 11:51:07 +01:00
Calum H. (IMB11)
34e65ace1e chore: fix frontend lint issues 2025-08-05 11:51:07 +01:00
Calum H. (IMB11)
f7fc208b15 chore: lint frontend 2025-08-05 11:49:34 +01:00
Calum H. (IMB11)
5b97f1e9b8 refactor: lint pass over app-frontend 2025-08-05 11:49:02 +01:00
Calum H. (IMB11)
73a353ab8c refactor: migrate to common eslint+prettier configs 2025-08-05 11:47:16 +01:00
523 changed files with 17314 additions and 18234 deletions

View File

@ -1,22 +1,2 @@
import { createConfigForNuxt } from '@nuxt/eslint-config/flat' import config from '@modrinth/tooling-config/eslint/nuxt.mjs'
import { fixupPluginRules } from '@eslint/compat' export default config
import turboPlugin from 'eslint-plugin-turbo'
export default createConfigForNuxt().append([
{
name: 'turbo',
plugins: {
turbo: fixupPluginRules(turboPlugin),
},
rules: {
'turbo/no-undeclared-env-vars': 'error',
},
},
{
name: 'modrinth',
rules: {
'vue/html-self-closing': 'off',
'vue/multi-word-component-names': 'off',
},
},
])

View File

@ -41,6 +41,7 @@
"vue-virtual-scroller": "v2.0.0-beta.8" "vue-virtual-scroller": "v2.0.0-beta.8"
}, },
"devDependencies": { "devDependencies": {
"@modrinth/tooling-config": "workspace:*",
"@eslint/compat": "^1.1.1", "@eslint/compat": "^1.1.1",
"@formatjs/cli": "^6.2.12", "@formatjs/cli": "^6.2.12",
"@nuxt/eslint-config": "^0.5.6", "@nuxt/eslint-config": "^0.5.6",
@ -48,13 +49,11 @@
"@vitejs/plugin-vue": "^5.0.4", "@vitejs/plugin-vue": "^5.0.4",
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.19",
"eslint": "^9.9.1", "eslint": "^9.9.1",
"eslint-config-custom": "workspace:*",
"eslint-plugin-turbo": "^2.5.4", "eslint-plugin-turbo": "^2.5.4",
"postcss": "^8.4.39", "postcss": "^8.4.39",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"sass": "^1.74.1", "sass": "^1.74.1",
"tailwindcss": "^3.4.4", "tailwindcss": "^3.4.4",
"tsconfig": "workspace:*",
"typescript": "^5.5.4", "typescript": "^5.5.4",
"vite": "^5.4.6", "vite": "^5.4.6",
"vue-tsc": "^2.1.6" "vue-tsc": "^2.1.6"

View File

@ -1,6 +1,4 @@
<script setup> <script setup>
import { computed, onMounted, onUnmounted, ref, watch, provide } from 'vue'
import { RouterView, useRoute, useRouter } from 'vue-router'
import { import {
ArrowBigUpDashIcon, ArrowBigUpDashIcon,
ChangeSkinIcon, ChangeSkinIcon,
@ -13,65 +11,69 @@ import {
LogOutIcon, LogOutIcon,
MaximizeIcon, MaximizeIcon,
MinimizeIcon, MinimizeIcon,
NewspaperIcon,
PlusIcon, PlusIcon,
RestoreIcon, RestoreIcon,
RightArrowIcon, RightArrowIcon,
SettingsIcon, SettingsIcon,
WorldIcon, WorldIcon,
XIcon, XIcon,
NewspaperIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { import {
Avatar, Avatar,
Button, Button,
ButtonStyled, ButtonStyled,
NewsArticleCard,
Notifications, Notifications,
OverflowMenu, OverflowMenu,
NewsArticleCard,
} from '@modrinth/ui' } from '@modrinth/ui'
import { useLoading, useTheming } from '@/store/state' import { renderString } from '@modrinth/utils'
import ModrinthAppLogo from '@/assets/modrinth_app.svg?component'
import AccountsCard from '@/components/ui/AccountsCard.vue'
import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue'
import { get } from '@/helpers/settings.ts'
import Breadcrumbs from '@/components/ui/Breadcrumbs.vue'
import RunningAppBar from '@/components/ui/RunningAppBar.vue'
import SplashScreen from '@/components/ui/SplashScreen.vue'
import ErrorModal from '@/components/ui/ErrorModal.vue'
import ModrinthLoadingIndicator from '@/components/LoadingIndicatorBar.vue'
import { handleError, useNotifications } from '@/store/notifications.js'
import { command_listener, warning_listener } from '@/helpers/events.js'
import { type } from '@tauri-apps/plugin-os'
import { getOS, isDev, restartApp } from '@/helpers/utils.js'
import { debugAnalytics, initAnalytics, optOutAnalytics, trackEvent } from '@/helpers/analytics'
import { getCurrentWindow } from '@tauri-apps/api/window'
import { getVersion } from '@tauri-apps/api/app' import { getVersion } from '@tauri-apps/api/app'
import URLConfirmModal from '@/components/ui/URLConfirmModal.vue' import { invoke } from '@tauri-apps/api/core'
import { create_profile_and_install_from_file } from './helpers/pack' import { getCurrentWindow } from '@tauri-apps/api/window'
import { useError } from '@/store/error.js' import { openUrl } from '@tauri-apps/plugin-opener'
import { useCheckDisableMouseover } from '@/composables/macCssFix.js' import { type } from '@tauri-apps/plugin-os'
import ModInstallModal from '@/components/ui/install_flow/ModInstallModal.vue' import { check } from '@tauri-apps/plugin-updater'
import { saveWindowState, StateFlags } from '@tauri-apps/plugin-window-state'
import { computed, onMounted, onUnmounted, provide, ref, watch } from 'vue'
import { RouterView, useRoute, useRouter } from 'vue-router'
import ModrinthAppLogo from '@/assets/modrinth_app.svg?component'
import ModrinthLoadingIndicator from '@/components/LoadingIndicatorBar.vue'
import AccountsCard from '@/components/ui/AccountsCard.vue'
import Breadcrumbs from '@/components/ui/Breadcrumbs.vue'
import ErrorModal from '@/components/ui/ErrorModal.vue'
import FriendsList from '@/components/ui/friends/FriendsList.vue'
import IncompatibilityWarningModal from '@/components/ui/install_flow/IncompatibilityWarningModal.vue' import IncompatibilityWarningModal from '@/components/ui/install_flow/IncompatibilityWarningModal.vue'
import InstallConfirmModal from '@/components/ui/install_flow/InstallConfirmModal.vue' import InstallConfirmModal from '@/components/ui/install_flow/InstallConfirmModal.vue'
import { useInstall } from '@/store/install.js' import ModInstallModal from '@/components/ui/install_flow/ModInstallModal.vue'
import { invoke } from '@tauri-apps/api/core' import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue'
import { get_opening_command, initialize_state } from '@/helpers/state'
import { saveWindowState, StateFlags } from '@tauri-apps/plugin-window-state'
import { renderString } from '@modrinth/utils'
import { useFetch } from '@/helpers/fetch.js'
import { check } from '@tauri-apps/plugin-updater'
import NavButton from '@/components/ui/NavButton.vue'
import { cancelLogin, get as getCreds, login, logout } from '@/helpers/mr_auth.js'
import { get_user } from '@/helpers/cache.js'
import AppSettingsModal from '@/components/ui/modal/AppSettingsModal.vue' import AppSettingsModal from '@/components/ui/modal/AppSettingsModal.vue'
import AuthGrantFlowWaitModal from '@/components/ui/modal/AuthGrantFlowWaitModal.vue' import AuthGrantFlowWaitModal from '@/components/ui/modal/AuthGrantFlowWaitModal.vue'
import NavButton from '@/components/ui/NavButton.vue'
import PromotionWrapper from '@/components/ui/PromotionWrapper.vue' import PromotionWrapper from '@/components/ui/PromotionWrapper.vue'
import { hide_ads_window, init_ads_window } from '@/helpers/ads.js'
import FriendsList from '@/components/ui/friends/FriendsList.vue'
import { openUrl } from '@tauri-apps/plugin-opener'
import QuickInstanceSwitcher from '@/components/ui/QuickInstanceSwitcher.vue' import QuickInstanceSwitcher from '@/components/ui/QuickInstanceSwitcher.vue'
import { get_available_capes, get_available_skins } from './helpers/skins' import RunningAppBar from '@/components/ui/RunningAppBar.vue'
import SplashScreen from '@/components/ui/SplashScreen.vue'
import URLConfirmModal from '@/components/ui/URLConfirmModal.vue'
import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
import { hide_ads_window, init_ads_window } from '@/helpers/ads.js'
import { debugAnalytics, initAnalytics, optOutAnalytics, trackEvent } from '@/helpers/analytics'
import { get_user } from '@/helpers/cache.js'
import { command_listener, warning_listener } from '@/helpers/events.js'
import { useFetch } from '@/helpers/fetch.js'
import { cancelLogin, get as getCreds, login, logout } from '@/helpers/mr_auth.js'
import { get } from '@/helpers/settings.ts'
import { get_opening_command, initialize_state } from '@/helpers/state'
import { getOS, isDev, restartApp } from '@/helpers/utils.js'
import { useError } from '@/store/error.js'
import { useInstall } from '@/store/install.js'
import { handleError, useNotifications } from '@/store/notifications.js'
import { useLoading, useTheming } from '@/store/state'
import { create_profile_and_install_from_file } from './helpers/pack'
import { generateSkinPreviews } from './helpers/rendering/batch-skin-renderer' import { generateSkinPreviews } from './helpers/rendering/batch-skin-renderer'
import { get_available_capes, get_available_skins } from './helpers/skins'
const themeStore = useTheming() const themeStore = useTheming()

View File

@ -1,18 +1,18 @@
export { default as ATLauncherIcon } from './atlauncher.svg'
export { default as BuyMeACoffeeIcon } from './bmac.svg' export { default as BuyMeACoffeeIcon } from './bmac.svg'
export { default as DiscordIcon } from './discord.svg' export { default as DiscordIcon } from './discord.svg'
export { default as GDLauncherIcon } from './gdlauncher.png'
export { default as GithubIcon } from './github.svg'
export { default as GitLabIcon } from './gitlab.svg'
export { default as GoogleIcon } from './google.svg'
export { default as KoFiIcon } from './kofi.svg' export { default as KoFiIcon } from './kofi.svg'
export { default as MastodonIcon } from './mastodon.svg'
export { default as MicrosoftIcon } from './microsoft.svg'
export { default as MultiMCIcon } from './multimc.webp'
export { default as OpenCollectiveIcon } from './opencollective.svg'
export { default as PatreonIcon } from './patreon.svg' export { default as PatreonIcon } from './patreon.svg'
export { default as PaypalIcon } from './paypal.svg' export { default as PaypalIcon } from './paypal.svg'
export { default as OpenCollectiveIcon } from './opencollective.svg'
export { default as TwitterIcon } from './twitter.svg'
export { default as GithubIcon } from './github.svg'
export { default as MastodonIcon } from './mastodon.svg'
export { default as RedditIcon } from './reddit.svg'
export { default as GoogleIcon } from './google.svg'
export { default as MicrosoftIcon } from './microsoft.svg'
export { default as SteamIcon } from './steam.svg'
export { default as GitLabIcon } from './gitlab.svg'
export { default as ATLauncherIcon } from './atlauncher.svg'
export { default as GDLauncherIcon } from './gdlauncher.png'
export { default as MultiMCIcon } from './multimc.webp'
export { default as PrismIcon } from './prism.svg' export { default as PrismIcon } from './prism.svg'
export { default as RedditIcon } from './reddit.svg'
export { default as SteamIcon } from './steam.svg'
export { default as TwitterIcon } from './twitter.svg'

View File

@ -1,9 +1,9 @@
export { default as SwapIcon } from './arrow-left-right.svg'
export { default as ToggleIcon } from './toggle.svg'
export { default as PackageIcon } from './package.svg'
export { default as VersionIcon } from './milestone.svg'
export { default as TextInputIcon } from './text-cursor-input.svg'
export { default as AddProjectImage } from './add-project.svg' export { default as AddProjectImage } from './add-project.svg'
export { default as NewInstanceImage } from './new-instance.svg' export { default as SwapIcon } from './arrow-left-right.svg'
export { default as MenuIcon } from './menu.svg' export { default as MenuIcon } from './menu.svg'
export { default as ChatIcon } from './messages-square.svg' export { default as ChatIcon } from './messages-square.svg'
export { default as VersionIcon } from './milestone.svg'
export { default as NewInstanceImage } from './new-instance.svg'
export { default as PackageIcon } from './package.svg'
export { default as TextInputIcon } from './text-cursor-input.svg'
export { default as ToggleIcon } from './toggle.svg'

View File

@ -1,24 +1,25 @@
<script setup> <script setup>
import Instance from '@/components/ui/Instance.vue'
import { computed, ref } from 'vue'
import { import {
ClipboardCopyIcon, ClipboardCopyIcon,
EyeIcon,
FolderOpenIcon, FolderOpenIcon,
PlayIcon, PlayIcon,
PlusIcon, PlusIcon,
TrashIcon,
StopCircleIcon,
EyeIcon,
SearchIcon, SearchIcon,
StopCircleIcon,
TrashIcon,
XIcon, XIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { Button, DropdownSelect } from '@modrinth/ui' import { Button, DropdownSelect } from '@modrinth/ui'
import { formatCategoryHeader } from '@modrinth/utils' import { formatCategoryHeader } from '@modrinth/utils'
import ContextMenu from '@/components/ui/ContextMenu.vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { computed, ref } from 'vue'
import ContextMenu from '@/components/ui/ContextMenu.vue'
import Instance from '@/components/ui/Instance.vue'
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
import { duplicate, remove } from '@/helpers/profile.js' import { duplicate, remove } from '@/helpers/profile.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
const props = defineProps({ const props = defineProps({
instances: { instances: {

View File

@ -1,5 +1,6 @@
<script setup> <script setup>
import { computed, onBeforeUnmount, ref, watch } from 'vue' import { computed, onBeforeUnmount, ref, watch } from 'vue'
import { useLoading } from '@/store/state.js' import { useLoading } from '@/store/state.js'
const props = defineProps({ const props = defineProps({

View File

@ -1,31 +1,32 @@
<script setup> <script setup>
import { import {
ClipboardCopyIcon, ClipboardCopyIcon,
FolderOpenIcon,
PlayIcon,
PlusIcon,
TrashIcon,
DownloadIcon, DownloadIcon,
GlobeIcon,
StopCircleIcon,
ExternalIcon, ExternalIcon,
EyeIcon, EyeIcon,
FolderOpenIcon,
GlobeIcon,
PlayIcon,
PlusIcon,
StopCircleIcon,
TrashIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue' import { HeadingLink } from '@modrinth/ui'
import Instance from '@/components/ui/Instance.vue' import { openUrl } from '@tauri-apps/plugin-opener'
import { computed, onMounted, onUnmounted, ref } from 'vue' import { computed, onMounted, onUnmounted, ref } from 'vue'
import ContextMenu from '@/components/ui/ContextMenu.vue'
import ProjectCard from '@/components/ui/ProjectCard.vue'
import { get_by_profile_path } from '@/helpers/process.js'
import { handleError } from '@/store/notifications.js'
import { duplicate, kill, remove, run } from '@/helpers/profile.js'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { showProfileInFolder } from '@/helpers/utils.js'
import ContextMenu from '@/components/ui/ContextMenu.vue'
import Instance from '@/components/ui/Instance.vue'
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
import ProjectCard from '@/components/ui/ProjectCard.vue'
import { trackEvent } from '@/helpers/analytics' import { trackEvent } from '@/helpers/analytics'
import { get_by_profile_path } from '@/helpers/process.js'
import { duplicate, kill, remove, run } from '@/helpers/profile.js'
import { showProfileInFolder } from '@/helpers/utils.js'
import { handleSevereError } from '@/store/error.js' import { handleSevereError } from '@/store/error.js'
import { install as installVersion } from '@/store/install.js' import { install as installVersion } from '@/store/install.js'
import { openUrl } from '@tauri-apps/plugin-opener' import { handleError } from '@/store/notifications.js'
import { HeadingLink } from '@modrinth/ui'
const router = useRouter() const router = useRouter()

View File

@ -73,22 +73,23 @@
</template> </template>
<script setup> <script setup>
import { DropdownIcon, PlusIcon, TrashIcon, LogInIcon, SpinnerIcon } from '@modrinth/assets' import { DropdownIcon, LogInIcon, PlusIcon, SpinnerIcon, TrashIcon } from '@modrinth/assets'
import { Avatar, Button, Card } from '@modrinth/ui' import { Avatar, Button, Card } from '@modrinth/ui'
import { ref, computed, onMounted, onBeforeUnmount, onUnmounted } from 'vue' import { computed, onBeforeUnmount, onMounted, onUnmounted, ref } from 'vue'
import { trackEvent } from '@/helpers/analytics'
import { import {
users, get_default_user,
login as login_flow,
remove_user, remove_user,
set_default_user, set_default_user,
login as login_flow, users,
get_default_user,
} from '@/helpers/auth' } from '@/helpers/auth'
import { handleError } from '@/store/state.js'
import { trackEvent } from '@/helpers/analytics'
import { process_listener } from '@/helpers/events' import { process_listener } from '@/helpers/events'
import { handleSevereError } from '@/store/error.js'
import { get_available_skins } from '@/helpers/skins'
import { getPlayerHeadUrl } from '@/helpers/rendering/batch-skin-renderer.ts' import { getPlayerHeadUrl } from '@/helpers/rendering/batch-skin-renderer.ts'
import { get_available_skins } from '@/helpers/skins'
import { handleSevereError } from '@/store/error.js'
import { handleError } from '@/store/state.js'
defineProps({ defineProps({
mode: { mode: {

View File

@ -1,10 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { DropdownIcon, PlusIcon, FolderOpenIcon } from '@modrinth/assets' import { DropdownIcon, FolderOpenIcon, PlusIcon } from '@modrinth/assets'
import { ButtonStyled, OverflowMenu } from '@modrinth/ui' import { ButtonStyled, OverflowMenu } from '@modrinth/ui'
import { open } from '@tauri-apps/plugin-dialog' import { open } from '@tauri-apps/plugin-dialog'
import { useRouter } from 'vue-router'
import { add_project_from_path } from '@/helpers/profile.js' import { add_project_from_path } from '@/helpers/profile.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import { useRouter } from 'vue-router'
const props = defineProps({ const props = defineProps({
instance: { instance: {

View File

@ -42,11 +42,12 @@
</template> </template>
<script setup> <script setup>
import { ChevronRightIcon, ChevronLeftIcon } from '@modrinth/assets' import { ChevronLeftIcon, ChevronRightIcon } from '@modrinth/assets'
import { Button } from '@modrinth/ui' import { Button } from '@modrinth/ui'
import { useBreadcrumbs } from '@/store/breadcrumbs'
import { useRoute } from 'vue-router'
import { computed } from 'vue' import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { useBreadcrumbs } from '@/store/breadcrumbs'
const route = useRoute() const route = useRoute()

View File

@ -1,23 +1,24 @@
<script setup> <script setup>
import { import {
CheckIcon, CheckIcon,
CopyIcon,
DropdownIcon, DropdownIcon,
XIcon,
HammerIcon, HammerIcon,
LogInIcon, LogInIcon,
UpdatedIcon, UpdatedIcon,
CopyIcon, XIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { ChatIcon } from '@/assets/icons'
import { ButtonStyled, Collapsible } from '@modrinth/ui' import { ButtonStyled, Collapsible } from '@modrinth/ui'
import { ref, computed } from 'vue' import { computed, ref } from 'vue'
import { login as login_flow, set_default_user } from '@/helpers/auth.js'
import { handleError } from '@/store/notifications.js' import { ChatIcon } from '@/assets/icons'
import { handleSevereError } from '@/store/error.js'
import { cancel_directory_change } from '@/helpers/settings.ts'
import { install } from '@/helpers/profile.js'
import { trackEvent } from '@/helpers/analytics'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import { trackEvent } from '@/helpers/analytics'
import { login as login_flow, set_default_user } from '@/helpers/auth.js'
import { install } from '@/helpers/profile.js'
import { cancel_directory_change } from '@/helpers/settings.ts'
import { handleSevereError } from '@/store/error.js'
import { handleError } from '@/store/notifications.js'
const errorModal = ref() const errorModal = ref()
const error = ref() const error = ref()

View File

@ -1,12 +1,13 @@
<script setup> <script setup>
import { XIcon, PlusIcon } from '@modrinth/assets' import { PlusIcon, XIcon } from '@modrinth/assets'
import { Button, Checkbox } from '@modrinth/ui' import { Button, Checkbox } from '@modrinth/ui'
import { PackageIcon, VersionIcon } from '@/assets/icons'
import { ref } from 'vue'
import { export_profile_mrpack, get_pack_export_candidates } from '@/helpers/profile.js'
import { open } from '@tauri-apps/plugin-dialog' import { open } from '@tauri-apps/plugin-dialog'
import { handleError } from '@/store/notifications.js' import { ref } from 'vue'
import { PackageIcon, VersionIcon } from '@/assets/icons'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import { export_profile_mrpack, get_pack_export_candidates } from '@/helpers/profile.js'
import { handleError } from '@/store/notifications.js'
const props = defineProps({ const props = defineProps({
instance: { instance: {

View File

@ -1,6 +1,4 @@
<script setup> <script setup>
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { import {
DownloadIcon, DownloadIcon,
GameIcon, GameIcon,
@ -11,14 +9,17 @@ import {
} from '@modrinth/assets' } from '@modrinth/assets'
import { Avatar, ButtonStyled, useRelativeTime } from '@modrinth/ui' import { Avatar, ButtonStyled, useRelativeTime } from '@modrinth/ui'
import { convertFileSrc } from '@tauri-apps/api/core' import { convertFileSrc } from '@tauri-apps/api/core'
import { finish_install, kill, run } from '@/helpers/profile' import dayjs from 'dayjs'
import { get_by_profile_path } from '@/helpers/process' import { computed, onMounted, onUnmounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { trackEvent } from '@/helpers/analytics'
import { process_listener } from '@/helpers/events' import { process_listener } from '@/helpers/events'
import { handleError } from '@/store/state.js' import { get_by_profile_path } from '@/helpers/process'
import { finish_install, kill, run } from '@/helpers/profile'
import { showProfileInFolder } from '@/helpers/utils.js' import { showProfileInFolder } from '@/helpers/utils.js'
import { handleSevereError } from '@/store/error.js' import { handleSevereError } from '@/store/error.js'
import { trackEvent } from '@/helpers/analytics' import { handleError } from '@/store/state.js'
import dayjs from 'dayjs'
const formatRelativeTime = useRelativeTime() const formatRelativeTime = useRelativeTime()

View File

@ -197,7 +197,6 @@
</template> </template>
<script setup> <script setup>
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import { import {
CodeIcon, CodeIcon,
FolderOpenIcon, FolderOpenIcon,
@ -209,23 +208,25 @@ import {
XIcon, XIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { Avatar, Button, Checkbox, Chips } from '@modrinth/ui' import { Avatar, Button, Checkbox, Chips } from '@modrinth/ui'
import { computed, onUnmounted, ref, shallowRef } from 'vue'
import { get_loaders } from '@/helpers/tags'
import { create } from '@/helpers/profile'
import { open } from '@tauri-apps/plugin-dialog'
import { convertFileSrc } from '@tauri-apps/api/core' import { convertFileSrc } from '@tauri-apps/api/core'
import { get_game_versions, get_loader_versions } from '@/helpers/metadata' import { getCurrentWebview } from '@tauri-apps/api/webview'
import { handleError } from '@/store/notifications.js' import { open } from '@tauri-apps/plugin-dialog'
import { computed, onUnmounted, ref, shallowRef } from 'vue'
import Multiselect from 'vue-multiselect' import Multiselect from 'vue-multiselect'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import ProgressBar from '@/components/ui/ProgressBar.vue'
import { trackEvent } from '@/helpers/analytics' import { trackEvent } from '@/helpers/analytics'
import { create_profile_and_install_from_file } from '@/helpers/pack.js'
import { import {
get_default_launcher_path, get_default_launcher_path,
get_importable_instances, get_importable_instances,
import_instance, import_instance,
} from '@/helpers/import.js' } from '@/helpers/import.js'
import ProgressBar from '@/components/ui/ProgressBar.vue' import { get_game_versions, get_loader_versions } from '@/helpers/metadata'
import { getCurrentWebview } from '@tauri-apps/api/webview' import { create_profile_and_install_from_file } from '@/helpers/pack.js'
import { create } from '@/helpers/profile'
import { get_loaders } from '@/helpers/tags'
import { handleError } from '@/store/notifications.js'
const profile_name = ref('') const profile_name = ref('')
const game_version = ref('') const game_version = ref('')

View File

@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { convertFileSrc } from '@tauri-apps/api/core'
import { formatCategory } from '@modrinth/utils'
import { GameIcon, LeftArrowIcon } from '@modrinth/assets' import { GameIcon, LeftArrowIcon } from '@modrinth/assets'
import { Avatar, ButtonStyled } from '@modrinth/ui' import { Avatar, ButtonStyled } from '@modrinth/ui'
import { formatCategory } from '@modrinth/utils'
import { convertFileSrc } from '@tauri-apps/api/core'
type Instance = { type Instance = {
game_version: string game_version: string

View File

@ -35,13 +35,14 @@
</ModalWrapper> </ModalWrapper>
</template> </template>
<script setup> <script setup>
import { PlusIcon, CheckIcon, XIcon } from '@modrinth/assets' import { CheckIcon, PlusIcon, XIcon } from '@modrinth/assets'
import { Button } from '@modrinth/ui' import { Button } from '@modrinth/ui'
import { ref } from 'vue' import { ref } from 'vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import { trackEvent } from '@/helpers/analytics'
import { find_filtered_jres } from '@/helpers/jre.js' import { find_filtered_jres } from '@/helpers/jre.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import { trackEvent } from '@/helpers/analytics'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
const chosenInstallOptions = ref([]) const chosenInstallOptions = ref([])
const detectJavaModal = ref(null) const detectJavaModal = ref(null)

View File

@ -53,20 +53,21 @@
<script setup> <script setup>
import { import {
SearchIcon,
PlayIcon,
CheckIcon, CheckIcon,
XIcon,
FolderSearchIcon,
DownloadIcon, DownloadIcon,
FolderSearchIcon,
PlayIcon,
SearchIcon,
XIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { Button } from '@modrinth/ui' import { Button } from '@modrinth/ui'
import { auto_install_java, find_filtered_jres, get_jre, test_jre } from '@/helpers/jre.js'
import { ref } from 'vue'
import { open } from '@tauri-apps/plugin-dialog' import { open } from '@tauri-apps/plugin-dialog'
import { ref } from 'vue'
import JavaDetectionModal from '@/components/ui/JavaDetectionModal.vue' import JavaDetectionModal from '@/components/ui/JavaDetectionModal.vue'
import { handleError } from '@/store/state.js'
import { trackEvent } from '@/helpers/analytics' import { trackEvent } from '@/helpers/analytics'
import { auto_install_java, find_filtered_jres, get_jre, test_jre } from '@/helpers/jre.js'
import { handleError } from '@/store/state.js'
const props = defineProps({ const props = defineProps({
version: { version: {

View File

@ -1,11 +1,12 @@
<script setup> <script setup>
import { CheckIcon } from '@modrinth/assets' import { CheckIcon } from '@modrinth/assets'
import { Button, Badge } from '@modrinth/ui' import { Badge, Button } from '@modrinth/ui'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { update_managed_modrinth_version } from '@/helpers/profile'
import { releaseColor } from '@/helpers/utils'
import { SwapIcon } from '@/assets/icons/index.js' import { SwapIcon } from '@/assets/icons/index.js'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import { update_managed_modrinth_version } from '@/helpers/profile'
import { releaseColor } from '@/helpers/utils'
const props = defineProps({ const props = defineProps({
versions: { versions: {

View File

@ -30,7 +30,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from 'vue' import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import type { RouteLocationRaw } from 'vue-router' import type { RouteLocationRaw } from 'vue-router'
import { useRoute, RouterLink } from 'vue-router' import { RouterLink, useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()

View File

@ -1,10 +1,10 @@
<script setup> <script setup>
import { Avatar, TagItem } from '@modrinth/ui'
import { DownloadIcon, HeartIcon, TagIcon } from '@modrinth/assets' import { DownloadIcon, HeartIcon, TagIcon } from '@modrinth/assets'
import { formatNumber, formatCategory } from '@modrinth/utils' import { Avatar, TagItem } from '@modrinth/ui'
import { computed } from 'vue' import { formatCategory, formatNumber } from '@modrinth/utils'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime' import relativeTime from 'dayjs/plugin/relativeTime'
import { computed } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
dayjs.extend(relativeTime) dayjs.extend(relativeTime)

View File

@ -1,5 +1,6 @@
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { onMounted, ref } from 'vue'
import { init_ads_window } from '@/helpers/ads.js' import { init_ads_window } from '@/helpers/ads.js'
const adsWrapper = ref(null) const adsWrapper = ref(null)

View File

@ -1,13 +1,14 @@
<script setup> <script setup>
import { list } from '@/helpers/profile' import { SpinnerIcon } from '@modrinth/assets'
import { handleError } from '@/store/notifications'
import dayjs from 'dayjs'
import { onUnmounted, ref } from 'vue'
import { profile_listener } from '@/helpers/events.js'
import NavButton from '@/components/ui/NavButton.vue'
import { Avatar } from '@modrinth/ui' import { Avatar } from '@modrinth/ui'
import { convertFileSrc } from '@tauri-apps/api/core' import { convertFileSrc } from '@tauri-apps/api/core'
import { SpinnerIcon } from '@modrinth/assets' import dayjs from 'dayjs'
import { onUnmounted, ref } from 'vue'
import NavButton from '@/components/ui/NavButton.vue'
import { profile_listener } from '@/helpers/events.js'
import { list } from '@/helpers/profile'
import { handleError } from '@/store/notifications'
const recentInstances = ref([]) const recentInstances = ref([])
const getInstances = async () => { const getInstances = async () => {

View File

@ -96,21 +96,22 @@
<script setup> <script setup>
import { import {
DownloadIcon, DownloadIcon,
DropdownIcon,
StopCircleIcon, StopCircleIcon,
TerminalSquareIcon, TerminalSquareIcon,
DropdownIcon,
UnplugIcon, UnplugIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { Button, ButtonStyled, Card } from '@modrinth/ui' import { Button, ButtonStyled, Card } from '@modrinth/ui'
import { onBeforeUnmount, onMounted, ref } from 'vue' import { onBeforeUnmount, onMounted, ref } from 'vue'
import { get_all as getRunningProcesses, kill as killProcess } from '@/helpers/process'
import { loading_listener, process_listener } from '@/helpers/events'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { progress_bars_list } from '@/helpers/state.js'
import ProgressBar from '@/components/ui/ProgressBar.vue' import ProgressBar from '@/components/ui/ProgressBar.vue'
import { handleError } from '@/store/notifications.js'
import { get_many } from '@/helpers/profile.js'
import { trackEvent } from '@/helpers/analytics' import { trackEvent } from '@/helpers/analytics'
import { loading_listener, process_listener } from '@/helpers/events'
import { get_all as getRunningProcesses, kill as killProcess } from '@/helpers/process'
import { get_many } from '@/helpers/profile.js'
import { progress_bars_list } from '@/helpers/state.js'
import { handleError } from '@/store/notifications.js'
const router = useRouter() const router = useRouter()
const card = ref(null) const card = ref(null)

View File

@ -117,14 +117,15 @@
</template> </template>
<script setup> <script setup>
import { TagsIcon, DownloadIcon, HeartIcon, PlusIcon, CheckIcon } from '@modrinth/assets' import { CheckIcon, DownloadIcon, HeartIcon, PlusIcon, TagsIcon } from '@modrinth/assets'
import { ButtonStyled, Avatar } from '@modrinth/ui' import { Avatar, ButtonStyled } from '@modrinth/ui'
import { formatNumber, formatCategory } from '@modrinth/utils' import { formatCategory, formatNumber } from '@modrinth/utils'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime' import relativeTime from 'dayjs/plugin/relativeTime'
import { ref, computed } from 'vue' import { computed, ref } from 'vue'
import { install as installVersion } from '@/store/install.js'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { install as installVersion } from '@/store/install.js'
dayjs.extend(relativeTime) dayjs.extend(relativeTime)
const router = useRouter() const router = useRouter()

View File

@ -82,11 +82,12 @@
</template> </template>
<script setup> <script setup>
import { MaximizeIcon, MinimizeIcon, XIcon } from '@modrinth/assets'
import { getCurrentWindow } from '@tauri-apps/api/window'
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
import ProgressBar from '@/components/ui/ProgressBar.vue' import ProgressBar from '@/components/ui/ProgressBar.vue'
import { loading_listener } from '@/helpers/events.js' import { loading_listener } from '@/helpers/events.js'
import { getCurrentWindow } from '@tauri-apps/api/window'
import { XIcon, MaximizeIcon, MinimizeIcon } from '@modrinth/assets'
import { getOS } from '@/helpers/utils.js' import { getOS } from '@/helpers/utils.js'
import { useLoading } from '@/store/loading.js' import { useLoading } from '@/store/loading.js'

View File

@ -1,12 +1,13 @@
<script setup> <script setup>
import { Button } from '@modrinth/ui' import { Button } from '@modrinth/ui'
import { ref } from 'vue' import { ref } from 'vue'
import SearchCard from '@/components/ui/SearchCard.vue'
import { get_categories } from '@/helpers/tags.js'
import { handleError } from '@/store/notifications.js'
import { get_version, get_project } from '@/helpers/cache.js'
import { install as installVersion } from '@/store/install.js'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import SearchCard from '@/components/ui/SearchCard.vue'
import { get_project, get_version } from '@/helpers/cache.js'
import { get_categories } from '@/helpers/tags.js'
import { install as installVersion } from '@/store/install.js'
import { handleError } from '@/store/notifications.js'
const confirmModal = ref(null) const confirmModal = ref(null)
const project = ref(null) const project = ref(null)

View File

@ -1,22 +1,23 @@
<script setup lang="ts"> <script setup lang="ts">
import { Avatar, ButtonStyled, OverflowMenu, useRelativeTime } from '@modrinth/ui'
import { import {
UserPlusIcon,
MoreVerticalIcon,
MailIcon, MailIcon,
MoreVerticalIcon,
SettingsIcon, SettingsIcon,
TrashIcon, TrashIcon,
UserPlusIcon,
XIcon, XIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { ref, onUnmounted, watch, computed } from 'vue' import { Avatar, ButtonStyled, OverflowMenu, useRelativeTime } from '@modrinth/ui'
import { friend_listener } from '@/helpers/events'
import { friends, friend_statuses, add_friend, remove_friend } from '@/helpers/friends'
import { get_user_many } from '@/helpers/cache'
import { handleError } from '@/store/notifications.js'
import ContextMenu from '@/components/ui/ContextMenu.vue'
import type { Dayjs } from 'dayjs' import type { Dayjs } from 'dayjs'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { computed, onUnmounted, ref, watch } from 'vue'
import ContextMenu from '@/components/ui/ContextMenu.vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import { get_user_many } from '@/helpers/cache'
import { friend_listener } from '@/helpers/events'
import { add_friend, friend_statuses, friends, remove_friend } from '@/helpers/friends'
import { handleError } from '@/store/notifications.js'
const formatRelativeTime = useRelativeTime() const formatRelativeTime = useRelativeTime()

View File

@ -56,16 +56,17 @@
</template> </template>
<script setup> <script setup>
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import { DownloadIcon, XIcon } from '@modrinth/assets'
import { XIcon, DownloadIcon } from '@modrinth/assets'
import { Button } from '@modrinth/ui' import { Button } from '@modrinth/ui'
import { formatCategory } from '@modrinth/utils' import { formatCategory } from '@modrinth/utils'
import { add_project_from_version as installMod } from '@/helpers/profile'
import { ref } from 'vue' import { ref } from 'vue'
import { handleError } from '@/store/state.js'
import { trackEvent } from '@/helpers/analytics'
import Multiselect from 'vue-multiselect' import Multiselect from 'vue-multiselect'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import { trackEvent } from '@/helpers/analytics'
import { add_project_from_version as installMod } from '@/helpers/profile'
import { handleError } from '@/store/state.js'
const instance = ref(null) const instance = ref(null)
const project = ref(null) const project = ref(null)
const versions = ref(null) const versions = ref(null)

View File

@ -1,11 +1,12 @@
<script setup> <script setup>
import { DownloadIcon, XIcon } from '@modrinth/assets' import { DownloadIcon, XIcon } from '@modrinth/assets'
import { Button } from '@modrinth/ui' import { Button } from '@modrinth/ui'
import { create_profile_and_install as pack_install } from '@/helpers/pack'
import { ref } from 'vue' import { ref } from 'vue'
import { trackEvent } from '@/helpers/analytics'
import { handleError } from '@/store/state.js'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import { trackEvent } from '@/helpers/analytics'
import { create_profile_and_install as pack_install } from '@/helpers/pack'
import { handleError } from '@/store/state.js'
const versionId = ref() const versionId = ref()
const project = ref() const project = ref()

View File

@ -1,28 +1,29 @@
<script setup> <script setup>
import { import {
CheckIcon,
DownloadIcon, DownloadIcon,
PlusIcon, PlusIcon,
RightArrowIcon,
UploadIcon, UploadIcon,
XIcon, XIcon,
RightArrowIcon,
CheckIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { Avatar, Button, Card } from '@modrinth/ui' import { Avatar, Button, Card } from '@modrinth/ui'
import { convertFileSrc } from '@tauri-apps/api/core'
import { open } from '@tauri-apps/plugin-dialog'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { useRouter } from 'vue-router'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import { trackEvent } from '@/helpers/analytics'
import { import {
add_project_from_version as installMod, add_project_from_version as installMod,
check_installed, check_installed,
create,
get, get,
list, list,
create,
} from '@/helpers/profile' } from '@/helpers/profile'
import { open } from '@tauri-apps/plugin-dialog'
import { installVersionDependencies } from '@/store/install.js' import { installVersionDependencies } from '@/store/install.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import { useRouter } from 'vue-router'
import { convertFileSrc } from '@tauri-apps/api/core'
import { trackEvent } from '@/helpers/analytics'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
const router = useRouter() const router = useRouter()

View File

@ -1,16 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import { CopyIcon, EditIcon, PlusIcon, SpinnerIcon, TrashIcon, UploadIcon } from '@modrinth/assets'
import { Avatar, ButtonStyled, Checkbox, OverflowMenu } from '@modrinth/ui'
import { convertFileSrc } from '@tauri-apps/api/core' import { convertFileSrc } from '@tauri-apps/api/core'
import { SpinnerIcon, TrashIcon, UploadIcon, PlusIcon, EditIcon, CopyIcon } from '@modrinth/assets'
import { Avatar, ButtonStyled, OverflowMenu, Checkbox } from '@modrinth/ui'
import { computed, ref, type Ref, watch } from 'vue'
import { duplicate, edit, edit_icon, list, remove } from '@/helpers/profile'
import { handleError } from '@/store/notifications'
import { trackEvent } from '@/helpers/analytics'
import { open } from '@tauri-apps/plugin-dialog' import { open } from '@tauri-apps/plugin-dialog'
import { defineMessages, useVIntl } from '@vintl/vintl' import { defineMessages, useVIntl } from '@vintl/vintl'
import { computed, type Ref, ref, watch } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue' import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
import type { InstanceSettingsTabProps, GameInstance } from '../../../helpers/types' import { trackEvent } from '@/helpers/analytics'
import { duplicate, edit, edit_icon, list, remove } from '@/helpers/profile'
import { handleError } from '@/store/notifications'
import type { GameInstance, InstanceSettingsTabProps } from '../../../helpers/types'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const router = useRouter() const router = useRouter()

View File

@ -1,11 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { Checkbox } from '@modrinth/ui' import { Checkbox } from '@modrinth/ui'
import { computed, ref, watch } from 'vue'
import { handleError } from '@/store/notifications'
import { defineMessages, useVIntl } from '@vintl/vintl' import { defineMessages, useVIntl } from '@vintl/vintl'
import { get } from '@/helpers/settings.ts' import { computed, ref, watch } from 'vue'
import { edit } from '@/helpers/profile' import { edit } from '@/helpers/profile'
import type { InstanceSettingsTabProps, AppSettings, Hooks } from '../../../helpers/types' import { get } from '@/helpers/settings.ts'
import { handleError } from '@/store/notifications'
import type { AppSettings, Hooks, InstanceSettingsTabProps } from '../../../helpers/types'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()

View File

@ -1,23 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import { import {
TransferIcon,
IssuesIcon,
HammerIcon,
DownloadIcon, DownloadIcon,
WrenchIcon, HammerIcon,
UndoIcon, IssuesIcon,
SpinnerIcon, SpinnerIcon,
UnplugIcon, TransferIcon,
UndoIcon,
UnlinkIcon, UnlinkIcon,
UnplugIcon,
WrenchIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { Avatar, Checkbox, Chips, ButtonStyled, TeleportDropdownMenu } from '@modrinth/ui' import { Avatar, ButtonStyled, Checkbox, Chips, TeleportDropdownMenu } from '@modrinth/ui'
import { computed, type ComputedRef, type Ref, ref, shallowRef, watch } from 'vue'
import { edit, install, update_repair_modrinth } from '@/helpers/profile'
import { handleError } from '@/store/notifications'
import { trackEvent } from '@/helpers/analytics'
import { defineMessages, useVIntl } from '@vintl/vintl'
import { get_loader_versions } from '@/helpers/metadata'
import { get_game_versions, get_loaders } from '@/helpers/tags'
import { import {
formatCategory, formatCategory,
type GameVersionTag, type GameVersionTag,
@ -25,14 +18,23 @@ import {
type Project, type Project,
type Version, type Version,
} from '@modrinth/utils' } from '@modrinth/utils'
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue' import { defineMessages, useVIntl } from '@vintl/vintl'
import { get_project, get_version_many } from '@/helpers/cache'
import ModpackVersionModal from '@/components/ui/ModpackVersionModal.vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { computed, type ComputedRef, type Ref, ref, shallowRef, watch } from 'vue'
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
import ModpackVersionModal from '@/components/ui/ModpackVersionModal.vue'
import { trackEvent } from '@/helpers/analytics'
import { get_project, get_version_many } from '@/helpers/cache'
import { get_loader_versions } from '@/helpers/metadata'
import { edit, install, update_repair_modrinth } from '@/helpers/profile'
import { get_game_versions, get_loaders } from '@/helpers/tags'
import { handleError } from '@/store/notifications'
import type { import type {
InstanceSettingsTabProps, InstanceSettingsTabProps,
ManifestLoaderVersion,
Manifest, Manifest,
ManifestLoaderVersion,
} from '../../../helpers/types' } from '../../../helpers/types'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()

View File

@ -1,14 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import { Checkbox, Slider } from '@modrinth/ui'
import { CheckCircleIcon, XCircleIcon } from '@modrinth/assets' import { CheckCircleIcon, XCircleIcon } from '@modrinth/assets'
import { computed, readonly, ref, watch } from 'vue' import { Checkbox, Slider } from '@modrinth/ui'
import { edit, get_optimal_jre_key } from '@/helpers/profile'
import { handleError } from '@/store/notifications'
import { defineMessages, useVIntl } from '@vintl/vintl' import { defineMessages, useVIntl } from '@vintl/vintl'
import { computed, readonly, ref, watch } from 'vue'
import JavaSelector from '@/components/ui/JavaSelector.vue' import JavaSelector from '@/components/ui/JavaSelector.vue'
import { get } from '@/helpers/settings.ts'
import type { InstanceSettingsTabProps, AppSettings, MemorySettings } from '../../../helpers/types'
import useMemorySlider from '@/composables/useMemorySlider' import useMemorySlider from '@/composables/useMemorySlider'
import { edit, get_optimal_jre_key } from '@/helpers/profile'
import { get } from '@/helpers/settings.ts'
import { handleError } from '@/store/notifications'
import type { AppSettings, InstanceSettingsTabProps, MemorySettings } from '../../../helpers/types'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()

View File

@ -1,10 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { Checkbox, Toggle } from '@modrinth/ui' import { Checkbox, Toggle } from '@modrinth/ui'
import { computed, ref, type Ref, watch } from 'vue'
import { handleError } from '@/store/notifications'
import { defineMessages, useVIntl } from '@vintl/vintl' import { defineMessages, useVIntl } from '@vintl/vintl'
import { get } from '@/helpers/settings.ts' import { computed, type Ref, ref, watch } from 'vue'
import { edit } from '@/helpers/profile' import { edit } from '@/helpers/profile'
import { get } from '@/helpers/settings.ts'
import { handleError } from '@/store/notifications'
import type { AppSettings, InstanceSettingsTabProps } from '../../../helpers/types' import type { AppSettings, InstanceSettingsTabProps } from '../../../helpers/types'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()

View File

@ -1,28 +1,29 @@
<script setup lang="ts"> <script setup lang="ts">
import { import {
ReportIcon,
ModrinthIcon,
ShieldIcon,
SettingsIcon,
GaugeIcon,
PaintbrushIcon,
GameIcon,
CoffeeIcon, CoffeeIcon,
GameIcon,
GaugeIcon,
ModrinthIcon,
PaintbrushIcon,
ReportIcon,
SettingsIcon,
ShieldIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { TabbedModal } from '@modrinth/ui' import { TabbedModal } from '@modrinth/ui'
import { computed, ref, watch } from 'vue'
import { useVIntl, defineMessage } from '@vintl/vintl'
import AppearanceSettings from '@/components/ui/settings/AppearanceSettings.vue'
import JavaSettings from '@/components/ui/settings/JavaSettings.vue'
import ResourceManagementSettings from '@/components/ui/settings/ResourceManagementSettings.vue'
import PrivacySettings from '@/components/ui/settings/PrivacySettings.vue'
import DefaultInstanceSettings from '@/components/ui/settings/DefaultInstanceSettings.vue'
import { getVersion } from '@tauri-apps/api/app' import { getVersion } from '@tauri-apps/api/app'
import { version as getOsVersion, platform as getOsPlatform } from '@tauri-apps/plugin-os' import { platform as getOsPlatform, version as getOsVersion } from '@tauri-apps/plugin-os'
import { useTheming } from '@/store/state' import { defineMessage, useVIntl } from '@vintl/vintl'
import FeatureFlagSettings from '@/components/ui/settings/FeatureFlagSettings.vue' import { computed, ref, watch } from 'vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import AppearanceSettings from '@/components/ui/settings/AppearanceSettings.vue'
import DefaultInstanceSettings from '@/components/ui/settings/DefaultInstanceSettings.vue'
import FeatureFlagSettings from '@/components/ui/settings/FeatureFlagSettings.vue'
import JavaSettings from '@/components/ui/settings/JavaSettings.vue'
import PrivacySettings from '@/components/ui/settings/PrivacySettings.vue'
import ResourceManagementSettings from '@/components/ui/settings/ResourceManagementSettings.vue'
import { get, set } from '@/helpers/settings.ts' import { get, set } from '@/helpers/settings.ts'
import { useTheming } from '@/store/state'
const themeStore = useTheming() const themeStore = useTheming()

View File

@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { LogInIcon, SpinnerIcon } from '@modrinth/assets' import { LogInIcon, SpinnerIcon } from '@modrinth/assets'
import { ref } from 'vue' import { ref } from 'vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
defineProps({ defineProps({

View File

@ -1,7 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'
import { ConfirmModal } from '@modrinth/ui' import { ConfirmModal } from '@modrinth/ui'
import { show_ads_window, hide_ads_window } from '@/helpers/ads.js' import { ref } from 'vue'
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
import { useTheming } from '@/store/theme.ts' import { useTheming } from '@/store/theme.ts'
const themeStore = useTheming() const themeStore = useTheming()

View File

@ -2,6 +2,7 @@
import { ChevronRightIcon } from '@modrinth/assets' import { ChevronRightIcon } from '@modrinth/assets'
import { Avatar } from '@modrinth/ui' import { Avatar } from '@modrinth/ui'
import { convertFileSrc } from '@tauri-apps/api/core' import { convertFileSrc } from '@tauri-apps/api/core'
import type { GameInstance } from '@/helpers/types' import type { GameInstance } from '@/helpers/types'
defineProps<{ defineProps<{

View File

@ -1,22 +1,24 @@
<script setup lang="ts"> <script setup lang="ts">
import { import {
ChevronRightIcon, ChevronRightIcon,
CodeIcon,
CoffeeIcon, CoffeeIcon,
InfoIcon, InfoIcon,
WrenchIcon,
MonitorIcon, MonitorIcon,
CodeIcon, WrenchIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { Avatar, TabbedModal, type TabbedModalTab } from '@modrinth/ui' import { Avatar, TabbedModal, type TabbedModalTab } from '@modrinth/ui'
import { ref } from 'vue'
import { defineMessage, useVIntl } from '@vintl/vintl'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import GeneralSettings from '@/components/ui/instance_settings/GeneralSettings.vue'
import { convertFileSrc } from '@tauri-apps/api/core' import { convertFileSrc } from '@tauri-apps/api/core'
import { defineMessage, useVIntl } from '@vintl/vintl'
import { ref } from 'vue'
import GeneralSettings from '@/components/ui/instance_settings/GeneralSettings.vue'
import HooksSettings from '@/components/ui/instance_settings/HooksSettings.vue'
import InstallationSettings from '@/components/ui/instance_settings/InstallationSettings.vue' import InstallationSettings from '@/components/ui/instance_settings/InstallationSettings.vue'
import JavaSettings from '@/components/ui/instance_settings/JavaSettings.vue' import JavaSettings from '@/components/ui/instance_settings/JavaSettings.vue'
import WindowSettings from '@/components/ui/instance_settings/WindowSettings.vue' import WindowSettings from '@/components/ui/instance_settings/WindowSettings.vue'
import HooksSettings from '@/components/ui/instance_settings/HooksSettings.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import type { InstanceSettingsTabProps } from '../../../helpers/types' import type { InstanceSettingsTabProps } from '../../../helpers/types'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()

View File

@ -1,7 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useTemplateRef } from 'vue'
import { NewModal as Modal } from '@modrinth/ui' import { NewModal as Modal } from '@modrinth/ui'
import { show_ads_window, hide_ads_window } from '@/helpers/ads.js' import { useTemplateRef } from 'vue'
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
import { useTheming } from '@/store/theme.ts' import { useTheming } from '@/store/theme.ts'
const themeStore = useTheming() const themeStore = useTheming()

View File

@ -1,7 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'
import { ShareModal } from '@modrinth/ui' import { ShareModal } from '@modrinth/ui'
import { show_ads_window, hide_ads_window } from '@/helpers/ads.js' import { ref } from 'vue'
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
import { useTheming } from '@/store/theme.ts' import { useTheming } from '@/store/theme.ts'
const themeStore = useTheming() const themeStore = useTheming()

View File

@ -1,9 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { TeleportDropdownMenu, ThemeSelector, Toggle } from '@modrinth/ui' import { TeleportDropdownMenu, ThemeSelector, Toggle } from '@modrinth/ui'
import { useTheming } from '@/store/state'
import { get, set } from '@/helpers/settings.ts'
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
import { get, set } from '@/helpers/settings.ts'
import { getOS } from '@/helpers/utils' import { getOS } from '@/helpers/utils'
import { useTheming } from '@/store/state'
import type { ColorTheme } from '@/store/theme.ts' import type { ColorTheme } from '@/store/theme.ts'
const themeStore = useTheming() const themeStore = useTheming()

View File

@ -1,8 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { get, set } from '@/helpers/settings.ts'
import { ref, watch } from 'vue'
import { Slider, Toggle } from '@modrinth/ui' import { Slider, Toggle } from '@modrinth/ui'
import { ref, watch } from 'vue'
import useMemorySlider from '@/composables/useMemorySlider' import useMemorySlider from '@/composables/useMemorySlider'
import { get, set } from '@/helpers/settings.ts'
const fetchSettings = await get() const fetchSettings = await get()
fetchSettings.launchArgs = fetchSettings.extra_launch_args.join(' ') fetchSettings.launchArgs = fetchSettings.extra_launch_args.join(' ')

View File

@ -1,8 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { Toggle } from '@modrinth/ui' import { Toggle } from '@modrinth/ui'
import { useTheming } from '@/store/state'
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
import { get as getSettings, set as setSettings } from '@/helpers/settings.ts' import { get as getSettings, set as setSettings } from '@/helpers/settings.ts'
import { useTheming } from '@/store/state'
import { DEFAULT_FEATURE_FLAGS, type FeatureFlag } from '@/store/theme.ts' import { DEFAULT_FEATURE_FLAGS, type FeatureFlag } from '@/store/theme.ts'
const themeStore = useTheming() const themeStore = useTheming()

View File

@ -1,8 +1,9 @@
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import JavaSelector from '@/components/ui/JavaSelector.vue'
import { get_java_versions, set_java_version } from '@/helpers/jre' import { get_java_versions, set_java_version } from '@/helpers/jre'
import { handleError } from '@/store/notifications' import { handleError } from '@/store/notifications'
import JavaSelector from '@/components/ui/JavaSelector.vue'
const javaVersions = ref(await get_java_versions().catch(handleError)) const javaVersions = ref(await get_java_versions().catch(handleError))
async function updateJavaVersion(version) { async function updateJavaVersion(version) {

View File

@ -1,8 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from 'vue'
import { get, set } from '@/helpers/settings.ts'
import { Toggle } from '@modrinth/ui' import { Toggle } from '@modrinth/ui'
import { ref, watch } from 'vue'
import { optInAnalytics, optOutAnalytics } from '@/helpers/analytics' import { optInAnalytics, optOutAnalytics } from '@/helpers/analytics'
import { get, set } from '@/helpers/settings.ts'
const settings = ref(await get()) const settings = ref(await get())

View File

@ -1,12 +1,13 @@
<script setup> <script setup>
import { Button, Slider } from '@modrinth/ui'
import { ref, watch } from 'vue'
import { get, set } from '@/helpers/settings.ts'
import { purge_cache_types } from '@/helpers/cache.js'
import { handleError } from '@/store/notifications.js'
import { BoxIcon, FolderSearchIcon, TrashIcon } from '@modrinth/assets' import { BoxIcon, FolderSearchIcon, TrashIcon } from '@modrinth/assets'
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue' import { Button, Slider } from '@modrinth/ui'
import { open } from '@tauri-apps/plugin-dialog' import { open } from '@tauri-apps/plugin-dialog'
import { ref, watch } from 'vue'
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
import { purge_cache_types } from '@/helpers/cache.js'
import { get, set } from '@/helpers/settings.ts'
import { handleError } from '@/store/notifications.js'
const settings = ref(await get()) const settings = ref(await get())

View File

@ -100,37 +100,38 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch, useTemplateRef } from 'vue'
import SelectCapeModal from '@/components/ui/skin/SelectCapeModal.vue'
import { import {
SkinPreviewRenderer, CheckIcon,
ChevronRightIcon,
SaveIcon,
SpinnerIcon,
UploadIcon,
XIcon,
} from '@modrinth/assets'
import {
Button, Button,
RadioButtons, ButtonStyled,
CapeButton, CapeButton,
CapeLikeTextButton, CapeLikeTextButton,
ButtonStyled, RadioButtons,
SkinPreviewRenderer,
} from '@modrinth/ui' } from '@modrinth/ui'
import { computed, ref, useTemplateRef, watch } from 'vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import SelectCapeModal from '@/components/ui/skin/SelectCapeModal.vue'
import UploadSkinModal from '@/components/ui/skin/UploadSkinModal.vue'
import { import {
add_and_equip_custom_skin, add_and_equip_custom_skin,
remove_custom_skin,
unequip_skin,
type Skin,
type Cape, type Cape,
type SkinModel,
get_normalized_skin_texture,
determineModelType, determineModelType,
get_normalized_skin_texture,
remove_custom_skin,
type Skin,
type SkinModel,
unequip_skin,
} from '@/helpers/skins.ts' } from '@/helpers/skins.ts'
import { handleError } from '@/store/notifications' import { handleError } from '@/store/notifications'
import {
UploadIcon,
CheckIcon,
SaveIcon,
XIcon,
ChevronRightIcon,
SpinnerIcon,
} from '@modrinth/assets'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import UploadSkinModal from '@/components/ui/skin/UploadSkinModal.vue'
const modal = useTemplateRef('modal') const modal = useTemplateRef('modal')
const selectCapeModal = useTemplateRef('selectCapeModal') const selectCapeModal = useTemplateRef('selectCapeModal')

View File

@ -1,15 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import { useTemplateRef, ref, computed } from 'vue' import { CheckIcon, XIcon } from '@modrinth/assets'
import type { Cape, SkinModel } from '@/helpers/skins.ts'
import { import {
ButtonStyled, ButtonStyled,
ScrollablePanel,
CapeButton, CapeButton,
CapeLikeTextButton, CapeLikeTextButton,
ScrollablePanel,
SkinPreviewRenderer, SkinPreviewRenderer,
} from '@modrinth/ui' } from '@modrinth/ui'
import { CheckIcon, XIcon } from '@modrinth/assets' import { computed, ref, useTemplateRef } from 'vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import type { Cape, SkinModel } from '@/helpers/skins.ts'
const modal = useTemplateRef('modal') const modal = useTemplateRef('modal')

View File

@ -27,12 +27,13 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onBeforeUnmount, watch } from 'vue'
import { UploadIcon } from '@modrinth/assets' import { UploadIcon } from '@modrinth/assets'
import { useNotifications } from '@/store/state'
import { getCurrentWebview } from '@tauri-apps/api/webview' import { getCurrentWebview } from '@tauri-apps/api/webview'
import { onBeforeUnmount, ref, watch } from 'vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import { get_dragged_skin_data } from '@/helpers/skins' import { get_dragged_skin_data } from '@/helpers/skins'
import { useNotifications } from '@/store/state'
const notifications = useNotifications() const notifications = useNotifications()

View File

@ -1,6 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Dayjs } from 'dayjs'
import dayjs from 'dayjs'
import { import {
EyeIcon, EyeIcon,
FolderOpenIcon, FolderOpenIcon,
@ -17,20 +15,23 @@ import {
SmartClickable, SmartClickable,
useRelativeTime, useRelativeTime,
} from '@modrinth/ui' } from '@modrinth/ui'
import { useVIntl } from '@vintl/vintl'
import { computed, nextTick, ref, onMounted, onUnmounted } from 'vue'
import { showProfileInFolder } from '@/helpers/utils'
import { convertFileSrc } from '@tauri-apps/api/core'
import { useRouter } from 'vue-router'
import type { GameInstance } from '@/helpers/types'
import { get_project } from '@/helpers/cache'
import { capitalizeString } from '@modrinth/utils' import { capitalizeString } from '@modrinth/utils'
import { kill, run } from '@/helpers/profile' import { convertFileSrc } from '@tauri-apps/api/core'
import { handleSevereError } from '@/store/error' import { useVIntl } from '@vintl/vintl'
import type { Dayjs } from 'dayjs'
import dayjs from 'dayjs'
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { trackEvent } from '@/helpers/analytics' import { trackEvent } from '@/helpers/analytics'
import { get_by_profile_path } from '@/helpers/process' import { get_project } from '@/helpers/cache'
import { handleError } from '@/store/notifications'
import { process_listener } from '@/helpers/events' import { process_listener } from '@/helpers/events'
import { get_by_profile_path } from '@/helpers/process'
import { kill, run } from '@/helpers/profile'
import type { GameInstance } from '@/helpers/types'
import { showProfileInFolder } from '@/helpers/utils'
import { handleSevereError } from '@/store/error'
import { handleError } from '@/store/notifications'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const formatRelativeTime = useRelativeTime() const formatRelativeTime = useRelativeTime()

View File

@ -1,30 +1,31 @@
<script setup lang="ts"> <script setup lang="ts">
import { import { GAME_MODES, HeadingLink } from '@modrinth/ui'
type ProtocolVersion,
type ServerWorld,
type ServerData,
type WorldWithProfile,
get_recent_worlds,
getWorldIdentifier,
get_profile_protocol_version,
refreshServerData,
start_join_server,
start_join_singleplayer_world,
} from '@/helpers/worlds.ts'
import { HeadingLink, GAME_MODES } from '@modrinth/ui'
import WorldItem from '@/components/ui/world/WorldItem.vue'
import InstanceItem from '@/components/ui/world/InstanceItem.vue'
import { watch, onMounted, onUnmounted, ref, computed } from 'vue'
import type { Dayjs } from 'dayjs' import type { Dayjs } from 'dayjs'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useTheming } from '@/store/theme.ts' import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { kill, run } from '@/helpers/profile'
import { handleError } from '@/store/notifications' import InstanceItem from '@/components/ui/world/InstanceItem.vue'
import WorldItem from '@/components/ui/world/WorldItem.vue'
import { trackEvent } from '@/helpers/analytics' import { trackEvent } from '@/helpers/analytics'
import { process_listener, profile_listener } from '@/helpers/events' import { process_listener, profile_listener } from '@/helpers/events'
import { get_all } from '@/helpers/process' import { get_all } from '@/helpers/process'
import { kill, run } from '@/helpers/profile'
import type { GameInstance } from '@/helpers/types' import type { GameInstance } from '@/helpers/types'
import {
get_profile_protocol_version,
get_recent_worlds,
getWorldIdentifier,
type ProtocolVersion,
refreshServerData,
type ServerData,
type ServerWorld,
start_join_server,
start_join_singleplayer_world,
type WorldWithProfile,
} from '@/helpers/worlds.ts'
import { handleSevereError } from '@/store/error' import { handleSevereError } from '@/store/error'
import { handleError } from '@/store/notifications'
import { useTheming } from '@/store/theme.ts'
const props = defineProps<{ const props = defineProps<{
recentInstances: GameInstance[] recentInstances: GameInstance[]

View File

@ -1,28 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import dayjs from 'dayjs'
import type {
ProtocolVersion,
ServerStatus,
ServerWorld,
SingleplayerWorld,
World,
} from '@/helpers/worlds.ts'
import { set_world_display_status, getWorldIdentifier } from '@/helpers/worlds.ts'
import { formatNumber, getPingLevel } from '@modrinth/utils'
import { import {
useRelativeTime,
Avatar,
ButtonStyled,
commonMessages,
OverflowMenu,
SmartClickable,
} from '@modrinth/ui'
import {
IssuesIcon,
EyeIcon,
ClipboardCopyIcon, ClipboardCopyIcon,
EditIcon, EditIcon,
EyeIcon,
FolderOpenIcon, FolderOpenIcon,
IssuesIcon,
MoreVerticalIcon, MoreVerticalIcon,
NoSignalIcon, NoSignalIcon,
PlayIcon, PlayIcon,
@ -35,14 +17,33 @@ import {
UserIcon, UserIcon,
XIcon, XIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import {
Avatar,
ButtonStyled,
commonMessages,
OverflowMenu,
SmartClickable,
useRelativeTime,
} from '@modrinth/ui'
import { formatNumber, getPingLevel } from '@modrinth/utils'
import { convertFileSrc } from '@tauri-apps/api/core'
import type { MessageDescriptor } from '@vintl/vintl' import type { MessageDescriptor } from '@vintl/vintl'
import { defineMessages, useVIntl } from '@vintl/vintl' import { defineMessages, useVIntl } from '@vintl/vintl'
import dayjs from 'dayjs'
import { Tooltip } from 'floating-vue'
import type { Component } from 'vue' import type { Component } from 'vue'
import { computed } from 'vue' import { computed } from 'vue'
import { copyToClipboard } from '@/helpers/utils'
import { convertFileSrc } from '@tauri-apps/api/core'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { Tooltip } from 'floating-vue'
import { copyToClipboard } from '@/helpers/utils'
import type {
ProtocolVersion,
ServerStatus,
ServerWorld,
SingleplayerWorld,
World,
} from '@/helpers/worlds.ts'
import { getWorldIdentifier, set_world_display_status } from '@/helpers/worlds.ts'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const formatRelativeTime = useRelativeTime() const formatRelativeTime = useRelativeTime()

View File

@ -1,14 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
import { PlayIcon, PlusIcon, XIcon } from '@modrinth/assets' import { PlayIcon, PlusIcon, XIcon } from '@modrinth/assets'
import { ButtonStyled, commonMessages } from '@modrinth/ui' import { ButtonStyled, commonMessages } from '@modrinth/ui'
import { ref } from 'vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import type { GameInstance } from '@/helpers/types'
import InstanceModalTitlePrefix from '@/components/ui/modal/InstanceModalTitlePrefix.vue'
import { add_server_to_profile, type ServerPackStatus, type ServerWorld } from '@/helpers/worlds.ts'
import { defineMessages, useVIntl } from '@vintl/vintl' import { defineMessages, useVIntl } from '@vintl/vintl'
import { handleError } from '@/store/notifications' import { ref } from 'vue'
import InstanceModalTitlePrefix from '@/components/ui/modal/InstanceModalTitlePrefix.vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import ServerModalBody from '@/components/ui/world/modal/ServerModalBody.vue' import ServerModalBody from '@/components/ui/world/modal/ServerModalBody.vue'
import type { GameInstance } from '@/helpers/types'
import { add_server_to_profile, type ServerPackStatus, type ServerWorld } from '@/helpers/worlds.ts'
import { handleError } from '@/store/notifications'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()

View File

@ -1,20 +1,21 @@
<script setup lang="ts"> <script setup lang="ts">
import { SaveIcon, XIcon } from '@modrinth/assets' import { SaveIcon, XIcon } from '@modrinth/assets'
import { ButtonStyled, commonMessages } from '@modrinth/ui' import { ButtonStyled, commonMessages } from '@modrinth/ui'
import { defineMessage, useVIntl } from '@vintl/vintl'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import HideFromHomeOption from '@/components/ui/world/modal/HideFromHomeOption.vue'
import ServerModalBody from '@/components/ui/world/modal/ServerModalBody.vue'
import type { GameInstance } from '@/helpers/types' import type { GameInstance } from '@/helpers/types'
import { import {
type ServerPackStatus, type DisplayStatus,
edit_server_in_profile, edit_server_in_profile,
type ServerPackStatus,
type ServerWorld, type ServerWorld,
set_world_display_status, set_world_display_status,
type DisplayStatus,
} from '@/helpers/worlds.ts' } from '@/helpers/worlds.ts'
import { defineMessage, useVIntl } from '@vintl/vintl'
import { handleError } from '@/store/notifications' import { handleError } from '@/store/notifications'
import ServerModalBody from '@/components/ui/world/modal/ServerModalBody.vue'
import HideFromHomeOption from '@/components/ui/world/modal/HideFromHomeOption.vue'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()

View File

@ -1,14 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
import { ChevronRightIcon, SaveIcon, XIcon, UndoIcon } from '@modrinth/assets' import { ChevronRightIcon, SaveIcon, UndoIcon, XIcon } from '@modrinth/assets'
import { Avatar, ButtonStyled, commonMessages } from '@modrinth/ui' import { Avatar, ButtonStyled, commonMessages } from '@modrinth/ui'
import { defineMessages, useVIntl } from '@vintl/vintl'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import HideFromHomeOption from '@/components/ui/world/modal/HideFromHomeOption.vue'
import type { GameInstance } from '@/helpers/types' import type { GameInstance } from '@/helpers/types'
import type { DisplayStatus, SingleplayerWorld } from '@/helpers/worlds.ts' import type { DisplayStatus, SingleplayerWorld } from '@/helpers/worlds.ts'
import { set_world_display_status, rename_world, reset_world_icon } from '@/helpers/worlds.ts' import { rename_world, reset_world_icon, set_world_display_status } from '@/helpers/worlds.ts'
import { defineMessages, useVIntl } from '@vintl/vintl'
import { handleError } from '@/store/notifications' import { handleError } from '@/store/notifications'
import HideFromHomeOption from '@/components/ui/world/modal/HideFromHomeOption.vue'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { Checkbox } from '@modrinth/ui'
import { defineMessage, useVIntl } from '@vintl/vintl' import { defineMessage, useVIntl } from '@vintl/vintl'
import { computed } from 'vue' import { computed } from 'vue'
import { Checkbox } from '@modrinth/ui'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const value = defineModel<boolean>({ required: true }) const value = defineModel<boolean>({ required: true })

View File

@ -1,7 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { TeleportDropdownMenu } from '@modrinth/ui' import { TeleportDropdownMenu } from '@modrinth/ui'
import { defineMessages, type MessageDescriptor, useVIntl } from '@vintl/vintl'
import type { ServerPackStatus } from '@/helpers/worlds.ts' import type { ServerPackStatus } from '@/helpers/worlds.ts'
import { type MessageDescriptor, defineMessages, useVIntl } from '@vintl/vintl'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()

View File

@ -1,4 +1,5 @@
import { invoke } from '@tauri-apps/api/core' import { invoke } from '@tauri-apps/api/core'
import cssContent from '@/assets/stylesheets/macFix.css?inline' import cssContent from '@/assets/stylesheets/macFix.css?inline'
export async function useCheckDisableMouseover() { export async function useCheckDisableMouseover() {

View File

@ -1,4 +1,5 @@
import { ref, computed } from 'vue' import { computed, ref } from 'vue'
import { get_max_memory } from '@/helpers/jre.js' import { get_max_memory } from '@/helpers/jre.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'

View File

@ -1,6 +1,7 @@
import { fetch } from '@tauri-apps/plugin-http'
import { handleError } from '@/store/state.js'
import { getVersion } from '@tauri-apps/api/app' import { getVersion } from '@tauri-apps/api/app'
import { fetch } from '@tauri-apps/plugin-http'
import { handleError } from '@/store/state.js'
export const useFetch = async (url, item, isSilent) => { export const useFetch = async (url, item, isSilent) => {
try { try {

View File

@ -4,6 +4,7 @@
* and deserialized into a usable JS object. * and deserialized into a usable JS object.
*/ */
import { invoke } from '@tauri-apps/api/core' import { invoke } from '@tauri-apps/api/core'
import { create } from './profile' import { create } from './profile'
/* /*

View File

@ -4,6 +4,7 @@
* and deserialized into a usable JS object. * and deserialized into a usable JS object.
*/ */
import { invoke } from '@tauri-apps/api/core' import { invoke } from '@tauri-apps/api/core'
import { create } from './profile' import { create } from './profile'
// Installs pack from a version ID // Installs pack from a version ID

View File

@ -4,6 +4,7 @@
* and deserialized into a usable JS object. * and deserialized into a usable JS object.
*/ */
import { invoke } from '@tauri-apps/api/core' import { invoke } from '@tauri-apps/api/core'
import { install_to_existing_profile } from '@/helpers/pack.js' import { install_to_existing_profile } from '@/helpers/pack.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'

View File

@ -1,17 +1,18 @@
import * as THREE from 'three' import { ClassicPlayerModel, SlimPlayerModel } from '@modrinth/assets'
import type { Skin, Cape } from '../skins'
import { get_normalized_skin_texture, determineModelType } from '../skins'
import { reactive } from 'vue'
import { import {
setupSkinModel,
disposeCaches,
loadTexture,
applyCapeTexture, applyCapeTexture,
createTransparentTexture, createTransparentTexture,
disposeCaches,
loadTexture,
setupSkinModel,
} from '@modrinth/utils' } from '@modrinth/utils'
import { skinPreviewStorage } from '../storage/skin-preview-storage' import * as THREE from 'three'
import { reactive } from 'vue'
import type { Cape, Skin } from '../skins'
import { determineModelType, get_normalized_skin_texture } from '../skins'
import { headStorage } from '../storage/head-storage' import { headStorage } from '../storage/head-storage'
import { ClassicPlayerModel, SlimPlayerModel } from '@modrinth/assets' import { skinPreviewStorage } from '../storage/skin-preview-storage'
export interface RenderResult { export interface RenderResult {
forwards: string forwards: string

View File

@ -4,8 +4,9 @@
* and deserialized into a usable JS object. * and deserialized into a usable JS object.
*/ */
import { invoke } from '@tauri-apps/api/core' import { invoke } from '@tauri-apps/api/core'
import type { ColorTheme, FeatureFlag } from '@/store/theme.ts'
import type { Hooks, MemorySettings, WindowSize } from '@/helpers/types' import type { Hooks, MemorySettings, WindowSize } from '@/helpers/types'
import type { ColorTheme, FeatureFlag } from '@/store/theme.ts'
// Settings object // Settings object
/* /*

View File

@ -1,6 +1,7 @@
import { invoke } from '@tauri-apps/api/core'
import { handleError } from '@/store/notifications'
import { arrayBufferToBase64 } from '@modrinth/utils' import { arrayBufferToBase64 } from '@modrinth/utils'
import { invoke } from '@tauri-apps/api/core'
import { handleError } from '@/store/notifications'
export interface Cape { export interface Cape {
id: string id: string

View File

@ -1,6 +1,7 @@
import { get_full_path, get_mod_full_path } from '@/helpers/profile'
import { invoke } from '@tauri-apps/api/core' import { invoke } from '@tauri-apps/api/core'
import { get_full_path, get_mod_full_path } from '@/helpers/profile'
export async function isDev() { export async function isDev() {
return await invoke('is_dev') return await invoke('is_dev')
} }

View File

@ -1,9 +1,10 @@
import { autoToHTML } from '@geometrically/minecraft-motd-parser'
import type { GameVersion } from '@modrinth/ui'
import { invoke } from '@tauri-apps/api/core' import { invoke } from '@tauri-apps/api/core'
import dayjs from 'dayjs'
import { get_full_path } from '@/helpers/profile' import { get_full_path } from '@/helpers/profile'
import { openPath } from '@/helpers/utils' import { openPath } from '@/helpers/utils'
import { autoToHTML } from '@geometrically/minecraft-motd-parser'
import dayjs from 'dayjs'
import type { GameVersion } from '@modrinth/ui'
type BaseWorld = { type BaseWorld = {
name: string name: string

View File

@ -1,12 +1,14 @@
import { createApp } from 'vue'
import router from '@/routes'
import App from '@/App.vue'
import { createPinia } from 'pinia'
import FloatingVue from 'floating-vue'
import 'floating-vue/dist/style.css' import 'floating-vue/dist/style.css'
import { createPlugin } from '@vintl/vintl/plugin'
import * as Sentry from '@sentry/vue' import * as Sentry from '@sentry/vue'
import { VueScanPlugin } from '@taijased/vue-render-tracker' import { VueScanPlugin } from '@taijased/vue-render-tracker'
import { createPlugin } from '@vintl/vintl/plugin'
import FloatingVue from 'floating-vue'
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import App from '@/App.vue'
import router from '@/routes'
const VIntlPlugin = createPlugin({ const VIntlPlugin = createPlugin({
controllerOpts: { controllerOpts: {

View File

@ -1,32 +1,33 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, nextTick, ref, shallowRef, watch } from 'vue' import { ClipboardCopyIcon, ExternalIcon, GlobeIcon, SearchIcon, XIcon } from '@modrinth/assets'
import type { Ref } from 'vue'
import { SearchIcon, XIcon, ClipboardCopyIcon, GlobeIcon, ExternalIcon } from '@modrinth/assets'
import type { Category, GameVersion, Platform, ProjectType, SortType, Tags } from '@modrinth/ui' import type { Category, GameVersion, Platform, ProjectType, SortType, Tags } from '@modrinth/ui'
import { import {
SearchFilterControl,
SearchSidebarFilter,
Button, Button,
Checkbox, Checkbox,
DropdownSelect, DropdownSelect,
LoadingIndicator, LoadingIndicator,
Pagination, Pagination,
SearchFilterControl,
SearchSidebarFilter,
useSearch, useSearch,
} from '@modrinth/ui' } from '@modrinth/ui'
import { handleError } from '@/store/state' import { openUrl } from '@tauri-apps/plugin-opener'
import { useBreadcrumbs } from '@/store/breadcrumbs' import { defineMessages, useVIntl } from '@vintl/vintl'
import { get_categories, get_game_versions, get_loaders } from '@/helpers/tags' import type { Ref } from 'vue'
import { computed, nextTick, ref, shallowRef, watch } from 'vue'
import type { LocationQuery } from 'vue-router' import type { LocationQuery } from 'vue-router'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import SearchCard from '@/components/ui/SearchCard.vue'
import { get as getInstance, get_projects as getInstanceProjects } from '@/helpers/profile.js' import ContextMenu from '@/components/ui/ContextMenu.vue'
import { get_search_results } from '@/helpers/cache.js'
import NavTabs from '@/components/ui/NavTabs.vue'
import type Instance from '@/components/ui/Instance.vue' import type Instance from '@/components/ui/Instance.vue'
import InstanceIndicator from '@/components/ui/InstanceIndicator.vue' import InstanceIndicator from '@/components/ui/InstanceIndicator.vue'
import { defineMessages, useVIntl } from '@vintl/vintl' import NavTabs from '@/components/ui/NavTabs.vue'
import ContextMenu from '@/components/ui/ContextMenu.vue' import SearchCard from '@/components/ui/SearchCard.vue'
import { openUrl } from '@tauri-apps/plugin-opener' import { get_search_results } from '@/helpers/cache.js'
import { get as getInstance, get_projects as getInstanceProjects } from '@/helpers/profile.js'
import { get_categories, get_game_versions, get_loaders } from '@/helpers/tags'
import { useBreadcrumbs } from '@/store/breadcrumbs'
import { handleError } from '@/store/state'
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()

View File

@ -1,16 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onUnmounted, computed } from 'vue' import type { SearchResult } from '@modrinth/utils'
import dayjs from 'dayjs'
import { computed, onUnmounted, ref } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import RowDisplay from '@/components/RowDisplay.vue' import RowDisplay from '@/components/RowDisplay.vue'
import { list } from '@/helpers/profile.js' import RecentWorldsList from '@/components/ui/world/RecentWorldsList.vue'
import { get_search_results } from '@/helpers/cache.js'
import { profile_listener } from '@/helpers/events' import { profile_listener } from '@/helpers/events'
import { list } from '@/helpers/profile.js'
import type { GameInstance } from '@/helpers/types'
import { useBreadcrumbs } from '@/store/breadcrumbs' import { useBreadcrumbs } from '@/store/breadcrumbs'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import dayjs from 'dayjs'
import { get_search_results } from '@/helpers/cache.js'
import type { SearchResult } from '@modrinth/utils'
import RecentWorldsList from '@/components/ui/world/RecentWorldsList.vue'
import type { GameInstance } from '@/helpers/types'
const route = useRoute() const route = useRoute()
const breadcrumbs = useBreadcrumbs() const breadcrumbs = useBreadcrumbs()

View File

@ -16,33 +16,34 @@ import {
SkinLikeTextButton, SkinLikeTextButton,
SkinPreviewRenderer, SkinPreviewRenderer,
} from '@modrinth/ui' } from '@modrinth/ui'
import { arrayBufferToBase64 } from '@modrinth/utils'
import { computedAsync } from '@vueuse/core' import { computedAsync } from '@vueuse/core'
import type { Ref } from 'vue' import type { Ref } from 'vue'
import { computed, inject, onMounted, onUnmounted, ref, useTemplateRef, watch } from 'vue' import { computed, inject, onMounted, onUnmounted, ref, useTemplateRef, watch } from 'vue'
import type AccountsCard from '@/components/ui/AccountsCard.vue'
import EditSkinModal from '@/components/ui/skin/EditSkinModal.vue' import EditSkinModal from '@/components/ui/skin/EditSkinModal.vue'
import SelectCapeModal from '@/components/ui/skin/SelectCapeModal.vue' import SelectCapeModal from '@/components/ui/skin/SelectCapeModal.vue'
import UploadSkinModal from '@/components/ui/skin/UploadSkinModal.vue' import UploadSkinModal from '@/components/ui/skin/UploadSkinModal.vue'
import { handleError, useNotifications } from '@/store/notifications' import { trackEvent } from '@/helpers/analytics'
import { get_default_user, login as login_flow, users } from '@/helpers/auth'
import type { RenderResult } from '@/helpers/rendering/batch-skin-renderer.ts'
import { generateSkinPreviews, skinBlobUrlMap } from '@/helpers/rendering/batch-skin-renderer.ts'
import { get as getSettings } from '@/helpers/settings.ts'
import type { Cape, Skin } from '@/helpers/skins.ts' import type { Cape, Skin } from '@/helpers/skins.ts'
import { import {
normalize_skin_texture,
equip_skin, equip_skin,
filterDefaultSkins, filterDefaultSkins,
filterSavedSkins, filterSavedSkins,
get_available_capes, get_available_capes,
get_available_skins, get_available_skins,
get_normalized_skin_texture, get_normalized_skin_texture,
normalize_skin_texture,
remove_custom_skin, remove_custom_skin,
set_default_cape, set_default_cape,
} from '@/helpers/skins.ts' } from '@/helpers/skins.ts'
import { get as getSettings } from '@/helpers/settings.ts'
import { get_default_user, login as login_flow, users } from '@/helpers/auth'
import type { RenderResult } from '@/helpers/rendering/batch-skin-renderer.ts'
import { generateSkinPreviews, skinBlobUrlMap } from '@/helpers/rendering/batch-skin-renderer.ts'
import { handleSevereError } from '@/store/error' import { handleSevereError } from '@/store/error'
import { trackEvent } from '@/helpers/analytics' import { handleError, useNotifications } from '@/store/notifications'
import type AccountsCard from '@/components/ui/AccountsCard.vue'
import { arrayBufferToBase64 } from '@modrinth/utils'
const editSkinModal = useTemplateRef('editSkinModal') const editSkinModal = useTemplateRef('editSkinModal')
const selectCapeModal = useTemplateRef('selectCapeModal') const selectCapeModal = useTemplateRef('selectCapeModal')
const uploadSkinModal = useTemplateRef('uploadSkinModal') const uploadSkinModal = useTemplateRef('uploadSkinModal')

View File

@ -1,6 +1,6 @@
import Index from './Index.vue'
import Browse from './Browse.vue' import Browse from './Browse.vue'
import Worlds from './Worlds.vue' import Index from './Index.vue'
import Skins from './Skins.vue' import Skins from './Skins.vue'
import Worlds from './Worlds.vue'
export { Index, Browse, Worlds, Skins } export { Browse, Index, Skins, Worlds }

View File

@ -157,13 +157,6 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import {
Avatar,
ButtonStyled,
ContentPageHeader,
LoadingIndicator,
OverflowMenu,
} from '@modrinth/ui'
import { import {
CheckCircleIcon, CheckCircleIcon,
ClipboardCopyIcon, ClipboardCopyIcon,
@ -187,24 +180,32 @@ import {
UserPlusIcon, UserPlusIcon,
XIcon, XIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { finish_install, get, get_full_path, kill, run } from '@/helpers/profile' import {
import { get_by_profile_path } from '@/helpers/process' Avatar,
import { process_listener, profile_listener } from '@/helpers/events' ButtonStyled,
import { useRoute, useRouter } from 'vue-router' ContentPageHeader,
import { computed, onUnmounted, ref, watch } from 'vue' LoadingIndicator,
import { handleError, useBreadcrumbs, useLoading } from '@/store/state' OverflowMenu,
import { showProfileInFolder } from '@/helpers/utils.js' } from '@modrinth/ui'
import ContextMenu from '@/components/ui/ContextMenu.vue'
import NavTabs from '@/components/ui/NavTabs.vue'
import { trackEvent } from '@/helpers/analytics'
import { convertFileSrc } from '@tauri-apps/api/core' import { convertFileSrc } from '@tauri-apps/api/core'
import { handleSevereError } from '@/store/error.js'
import { get_project, get_version_many } from '@/helpers/cache.js'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import duration from 'dayjs/plugin/duration' import duration from 'dayjs/plugin/duration'
import relativeTime from 'dayjs/plugin/relativeTime' import relativeTime from 'dayjs/plugin/relativeTime'
import { computed, onUnmounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import ContextMenu from '@/components/ui/ContextMenu.vue'
import ExportModal from '@/components/ui/ExportModal.vue' import ExportModal from '@/components/ui/ExportModal.vue'
import InstanceSettingsModal from '@/components/ui/modal/InstanceSettingsModal.vue' import InstanceSettingsModal from '@/components/ui/modal/InstanceSettingsModal.vue'
import NavTabs from '@/components/ui/NavTabs.vue'
import { trackEvent } from '@/helpers/analytics'
import { get_project, get_version_many } from '@/helpers/cache.js'
import { process_listener, profile_listener } from '@/helpers/events'
import { get_by_profile_path } from '@/helpers/process'
import { finish_install, get, get_full_path, kill, run } from '@/helpers/profile'
import { showProfileInFolder } from '@/helpers/utils.js'
import { handleSevereError } from '@/store/error.js'
import { handleError, useBreadcrumbs, useLoading } from '@/store/state'
dayjs.extend(duration) dayjs.extend(duration)
dayjs.extend(relativeTime) dayjs.extend(relativeTime)

View File

@ -88,26 +88,28 @@
</template> </template>
<script setup> <script setup>
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
import { CheckIcon, ClipboardCopyIcon, ShareIcon, TrashIcon } from '@modrinth/assets' import { CheckIcon, ClipboardCopyIcon, ShareIcon, TrashIcon } from '@modrinth/assets'
import { Button, Card, Checkbox, DropdownSelect } from '@modrinth/ui' import { Button, Card, Checkbox, DropdownSelect } from '@modrinth/ui'
import {
delete_logs_by_filename,
get_logs,
get_output_by_filename,
get_latest_log_cursor,
} from '@/helpers/logs.js'
import { computed, nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, watch } from 'vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import isToday from 'dayjs/plugin/isToday' import isToday from 'dayjs/plugin/isToday'
import isYesterday from 'dayjs/plugin/isYesterday' import isYesterday from 'dayjs/plugin/isYesterday'
import { get_by_profile_path } from '@/helpers/process.js'
import { useRoute } from 'vue-router'
import { process_listener } from '@/helpers/events.js'
import { handleError } from '@/store/notifications.js'
import { ofetch } from 'ofetch' import { ofetch } from 'ofetch'
import { computed, nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import { RecycleScroller } from 'vue-virtual-scroller' import { RecycleScroller } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
import ShareModalWrapper from '@/components/ui/modal/ShareModalWrapper.vue' import ShareModalWrapper from '@/components/ui/modal/ShareModalWrapper.vue'
import { process_listener } from '@/helpers/events.js'
import {
delete_logs_by_filename,
get_latest_log_cursor,
get_logs,
get_output_by_filename,
} from '@/helpers/logs.js'
import { get_by_profile_path } from '@/helpers/process.js'
import { handleError } from '@/store/notifications.js'
dayjs.extend(isToday) dayjs.extend(isToday)
dayjs.extend(isYesterday) dayjs.extend(isYesterday)

View File

@ -276,11 +276,29 @@ import {
RadialHeader, RadialHeader,
Toggle, Toggle,
} from '@modrinth/ui' } from '@modrinth/ui'
import type { ContentItem } from '@modrinth/ui/src/components/content/ContentListItem.vue'
import type { Organization, Project, TeamMember, Version } from '@modrinth/utils' import type { Organization, Project, TeamMember, Version } from '@modrinth/utils'
import { formatProjectType } from '@modrinth/utils' import { formatProjectType } from '@modrinth/utils'
import { getCurrentWebview } from '@tauri-apps/api/webview'
import { defineMessages, useVIntl } from '@vintl/vintl'
import dayjs from 'dayjs'
import type { ComputedRef } from 'vue' import type { ComputedRef } from 'vue'
import { computed, onUnmounted, ref, watch } from 'vue' import { computed, onUnmounted, ref, watch } from 'vue'
import { defineMessages, useVIntl } from '@vintl/vintl'
import { TextInputIcon } from '@/assets/icons'
import AddContentButton from '@/components/ui/AddContentButton.vue'
import type ContextMenu from '@/components/ui/ContextMenu.vue'
import ExportModal from '@/components/ui/ExportModal.vue'
import ShareModalWrapper from '@/components/ui/modal/ShareModalWrapper.vue'
import ModpackVersionModal from '@/components/ui/ModpackVersionModal.vue'
import { trackEvent } from '@/helpers/analytics'
import {
get_organization_many,
get_project_many,
get_team_many,
get_version_many,
} from '@/helpers/cache.js'
import { profile_listener } from '@/helpers/events.js'
import { import {
add_project_from_path, add_project_from_path,
get_projects, get_projects,
@ -289,26 +307,9 @@ import {
update_all, update_all,
update_project, update_project,
} from '@/helpers/profile.js' } from '@/helpers/profile.js'
import { handleError } from '@/store/notifications.js'
import { trackEvent } from '@/helpers/analytics'
import { highlightModInProfile } from '@/helpers/utils.js'
import { TextInputIcon } from '@/assets/icons'
import ExportModal from '@/components/ui/ExportModal.vue'
import ModpackVersionModal from '@/components/ui/ModpackVersionModal.vue'
import AddContentButton from '@/components/ui/AddContentButton.vue'
import {
get_organization_many,
get_project_many,
get_team_many,
get_version_many,
} from '@/helpers/cache.js'
import { profile_listener } from '@/helpers/events.js'
import ShareModalWrapper from '@/components/ui/modal/ShareModalWrapper.vue'
import { getCurrentWebview } from '@tauri-apps/api/webview'
import dayjs from 'dayjs'
import type { CacheBehaviour, ContentFile, GameInstance } from '@/helpers/types' import type { CacheBehaviour, ContentFile, GameInstance } from '@/helpers/types'
import type ContextMenu from '@/components/ui/ContextMenu.vue' import { highlightModInProfile } from '@/helpers/utils.js'
import type { ContentItem } from '@modrinth/ui/src/components/content/ContentListItem.vue' import { handleError } from '@/store/notifications.js'
const props = defineProps<{ const props = defineProps<{
instance: GameInstance instance: GameInstance

View File

@ -1,9 +1,10 @@
<template>{{ instance.name }} overview</template> <template>{{ instance.name }} overview</template>
<script setup lang="ts"> <script setup lang="ts">
import type { GameInstance } from '@/helpers/types'
import type ContextMenu from '@/components/ui/ContextMenu.vue'
import type { Version } from '@modrinth/utils' import type { Version } from '@modrinth/utils'
import type ContextMenu from '@/components/ui/ContextMenu.vue'
import type { GameInstance } from '@/helpers/types'
defineProps<{ defineProps<{
instance: GameInstance instance: GameInstance
options: InstanceType<typeof ContextMenu> options: InstanceType<typeof ContextMenu>

View File

@ -121,54 +121,54 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onUnmounted, watch } from 'vue' import { PlusIcon, SearchIcon, SpinnerIcon, UpdatedIcon, XIcon } from '@modrinth/assets'
import { useRoute } from 'vue-router'
import type { GameInstance } from '@/helpers/types'
import { import {
Button, Button,
ButtonStyled, ButtonStyled,
RadialHeader,
FilterBar, FilterBar,
type FilterBarOption, type FilterBarOption,
type GameVersion,
GAME_MODES, GAME_MODES,
type GameVersion,
RadialHeader,
} from '@modrinth/ui' } from '@modrinth/ui'
import { PlusIcon, SpinnerIcon, UpdatedIcon, SearchIcon, XIcon } from '@modrinth/assets' import type { Version } from '@modrinth/utils'
import { import { defineMessages } from '@vintl/vintl'
type ProtocolVersion, import { computed, onUnmounted, ref, watch } from 'vue'
type SingleplayerWorld, import { useRoute } from 'vue-router'
type World,
type ServerWorld, import type ContextMenu from '@/components/ui/ContextMenu.vue'
type ServerData, import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
type ProfileEvent,
get_profile_protocol_version,
remove_server_from_profile,
delete_world,
start_join_server,
start_join_singleplayer_world,
getWorldIdentifier,
refreshServerData,
refreshWorld,
sortWorlds,
refreshServers,
hasWorldQuickPlaySupport,
refreshWorlds,
handleDefaultProfileUpdateEvent,
showWorldInFolder,
hasServerQuickPlaySupport,
} from '@/helpers/worlds.ts'
import AddServerModal from '@/components/ui/world/modal/AddServerModal.vue' import AddServerModal from '@/components/ui/world/modal/AddServerModal.vue'
import EditServerModal from '@/components/ui/world/modal/EditServerModal.vue' import EditServerModal from '@/components/ui/world/modal/EditServerModal.vue'
import EditWorldModal from '@/components/ui/world/modal/EditSingleplayerWorldModal.vue' import EditWorldModal from '@/components/ui/world/modal/EditSingleplayerWorldModal.vue'
import WorldItem from '@/components/ui/world/WorldItem.vue' import WorldItem from '@/components/ui/world/WorldItem.vue'
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
import { handleError } from '@/store/notifications'
import type ContextMenu from '@/components/ui/ContextMenu.vue'
import type { Version } from '@modrinth/utils'
import { profile_listener } from '@/helpers/events' import { profile_listener } from '@/helpers/events'
import { get_game_versions } from '@/helpers/tags' import { get_game_versions } from '@/helpers/tags'
import { defineMessages } from '@vintl/vintl' import type { GameInstance } from '@/helpers/types'
import {
delete_world,
get_profile_protocol_version,
getWorldIdentifier,
handleDefaultProfileUpdateEvent,
hasServerQuickPlaySupport,
hasWorldQuickPlaySupport,
type ProfileEvent,
type ProtocolVersion,
refreshServerData,
refreshServers,
refreshWorld,
refreshWorlds,
remove_server_from_profile,
type ServerData,
type ServerWorld,
showWorldInFolder,
type SingleplayerWorld,
sortWorlds,
start_join_server,
start_join_singleplayer_world,
type World,
} from '@/helpers/worlds.ts'
import { handleError } from '@/store/notifications'
const route = useRoute() const route = useRoute()

View File

@ -1,7 +1,7 @@
import Index from './Index.vue' import Index from './Index.vue'
import Logs from './Logs.vue'
import Mods from './Mods.vue'
import Overview from './Overview.vue' import Overview from './Overview.vue'
import Worlds from './Worlds.vue' import Worlds from './Worlds.vue'
import Mods from './Mods.vue'
import Logs from './Logs.vue'
export { Index, Overview, Worlds, Mods, Logs } export { Index, Logs, Mods, Overview, Worlds }

View File

@ -1,15 +1,16 @@
<script setup> <script setup>
import { onUnmounted, ref, shallowRef } from 'vue'
import { list } from '@/helpers/profile.js'
import { useRoute } from 'vue-router'
import { useBreadcrumbs } from '@/store/breadcrumbs.js'
import { profile_listener } from '@/helpers/events.js'
import { handleError } from '@/store/notifications.js'
import { Button } from '@modrinth/ui'
import { PlusIcon } from '@modrinth/assets' import { PlusIcon } from '@modrinth/assets'
import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue' import { Button } from '@modrinth/ui'
import { onUnmounted, ref, shallowRef } from 'vue'
import { useRoute } from 'vue-router'
import { NewInstanceImage } from '@/assets/icons' import { NewInstanceImage } from '@/assets/icons'
import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue'
import NavTabs from '@/components/ui/NavTabs.vue' import NavTabs from '@/components/ui/NavTabs.vue'
import { profile_listener } from '@/helpers/events.js'
import { list } from '@/helpers/profile.js'
import { useBreadcrumbs } from '@/store/breadcrumbs.js'
import { handleError } from '@/store/notifications.js'
const route = useRoute() const route = useRoute()
const breadcrumbs = useBreadcrumbs() const breadcrumbs = useBreadcrumbs()

View File

@ -1,6 +1,6 @@
import Custom from './Custom.vue'
import Downloaded from './Downloaded.vue'
import Index from './Index.vue' import Index from './Index.vue'
import Overview from './Overview.vue' import Overview from './Overview.vue'
import Downloaded from './Downloaded.vue'
import Custom from './Custom.vue'
export { Index, Overview, Downloaded, Custom } export { Custom, Downloaded, Index, Overview }

View File

@ -83,18 +83,19 @@
<script setup> <script setup>
import { import {
ExpandIcon,
RightArrowIcon,
LeftArrowIcon,
ExternalIcon,
ContractIcon,
XIcon,
CalendarIcon, CalendarIcon,
ContractIcon,
ExpandIcon,
ExternalIcon,
LeftArrowIcon,
RightArrowIcon,
XIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { Button, Card } from '@modrinth/ui' import { Button, Card } from '@modrinth/ui'
import { ref } from 'vue' import { ref } from 'vue'
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
import { trackEvent } from '@/helpers/analytics' import { trackEvent } from '@/helpers/analytics'
import { show_ads_window, hide_ads_window } from '@/helpers/ads.js'
const props = defineProps({ const props = defineProps({
project: { project: {

View File

@ -131,41 +131,41 @@
<script setup> <script setup>
import { import {
BookmarkIcon, BookmarkIcon,
MoreVerticalIcon,
DownloadIcon,
ReportIcon,
HeartIcon,
ExternalIcon,
CheckIcon, CheckIcon,
GlobeIcon,
ClipboardCopyIcon, ClipboardCopyIcon,
DownloadIcon,
ExternalIcon,
GlobeIcon,
HeartIcon,
MoreVerticalIcon,
ReportIcon,
} from '@modrinth/assets' } from '@modrinth/assets'
import { import {
ProjectHeader,
ProjectSidebarCompatibility,
ButtonStyled, ButtonStyled,
OverflowMenu, OverflowMenu,
ProjectSidebarLinks, ProjectBackgroundGradient,
ProjectHeader,
ProjectSidebarCompatibility,
ProjectSidebarCreators, ProjectSidebarCreators,
ProjectSidebarDetails, ProjectSidebarDetails,
ProjectBackgroundGradient, ProjectSidebarLinks,
} from '@modrinth/ui' } from '@modrinth/ui'
import { openUrl } from '@tauri-apps/plugin-opener'
import { get_categories, get_game_versions, get_loaders } from '@/helpers/tags'
import { get as getInstance, get_projects as getInstanceProjects } from '@/helpers/profile'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime' import relativeTime from 'dayjs/plugin/relativeTime'
import { useRoute, useRouter } from 'vue-router'
import { ref, shallowRef, watch } from 'vue' import { ref, shallowRef, watch } from 'vue'
import { useBreadcrumbs } from '@/store/breadcrumbs' import { useRoute, useRouter } from 'vue-router'
import { handleError } from '@/store/notifications.js'
import ContextMenu from '@/components/ui/ContextMenu.vue' import ContextMenu from '@/components/ui/ContextMenu.vue'
import { install as installVersion } from '@/store/install.js'
import { get_project, get_team, get_version_many } from '@/helpers/cache.js'
import NavTabs from '@/components/ui/NavTabs.vue'
import { useTheming } from '@/store/state.js'
import InstanceIndicator from '@/components/ui/InstanceIndicator.vue' import InstanceIndicator from '@/components/ui/InstanceIndicator.vue'
import { openUrl } from '@tauri-apps/plugin-opener' import NavTabs from '@/components/ui/NavTabs.vue'
import { get_project, get_team, get_version_many } from '@/helpers/cache.js'
import { get as getInstance, get_projects as getInstanceProjects } from '@/helpers/profile'
import { get_categories, get_game_versions, get_loaders } from '@/helpers/tags'
import { useBreadcrumbs } from '@/store/breadcrumbs'
import { install as installVersion } from '@/store/install.js'
import { handleError } from '@/store/notifications.js'
import { useTheming } from '@/store/state.js'
dayjs.extend(relativeTime) dayjs.extend(relativeTime)

View File

@ -182,15 +182,16 @@
</template> </template>
<script setup> <script setup>
import { DownloadIcon, FileIcon, ReportIcon, ExternalIcon, CheckIcon } from '@modrinth/assets' import { CheckIcon, DownloadIcon, ExternalIcon, FileIcon, ReportIcon } from '@modrinth/assets'
import { Avatar, Badge, Breadcrumbs, Button, Card, CopyCode } from '@modrinth/ui'
import { formatBytes, renderString } from '@modrinth/utils' import { formatBytes, renderString } from '@modrinth/utils'
import { Breadcrumbs, Badge, Avatar, Card, Button, CopyCode } from '@modrinth/ui' import { computed, ref, watch } from 'vue'
import { releaseColor } from '@/helpers/utils'
import { ref, watch, computed } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { useBreadcrumbs } from '@/store/breadcrumbs'
import { SwapIcon } from '@/assets/icons' import { SwapIcon } from '@/assets/icons'
import { get_project_many, get_version_many } from '@/helpers/cache.js' import { get_project_many, get_version_many } from '@/helpers/cache.js'
import { releaseColor } from '@/helpers/utils'
import { useBreadcrumbs } from '@/store/breadcrumbs'
const breadcrumbs = useBreadcrumbs() const breadcrumbs = useBreadcrumbs()

View File

@ -65,9 +65,10 @@
</template> </template>
<script setup> <script setup>
import { ProjectPageVersions, ButtonStyled, OverflowMenu } from '@modrinth/ui'
import { CheckIcon, DownloadIcon, ExternalIcon, MoreVerticalIcon } from '@modrinth/assets' import { CheckIcon, DownloadIcon, ExternalIcon, MoreVerticalIcon } from '@modrinth/assets'
import { ButtonStyled, OverflowMenu, ProjectPageVersions } from '@modrinth/ui'
import { ref } from 'vue' import { ref } from 'vue'
import { SwapIcon } from '@/assets/icons/index.js' import { SwapIcon } from '@/assets/icons/index.js'
import { get_game_versions, get_loaders } from '@/helpers/tags.js' import { get_game_versions, get_loaders } from '@/helpers/tags.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'

View File

@ -1,7 +1,7 @@
import Index from './Index.vue'
import Description from './Description.vue' import Description from './Description.vue'
import Versions from './Versions.vue'
import Gallery from './Gallery.vue' import Gallery from './Gallery.vue'
import Index from './Index.vue'
import Version from './Version.vue' import Version from './Version.vue'
import Versions from './Versions.vue'
export { Index, Description, Versions, Gallery, Version } export { Description, Gallery, Index, Version, Versions }

View File

@ -1,8 +1,9 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import * as Pages from '@/pages' import * as Pages from '@/pages'
import * as Project from '@/pages/project'
import * as Instance from '@/pages/instance' import * as Instance from '@/pages/instance'
import * as Library from '@/pages/library' import * as Library from '@/pages/library'
import * as Project from '@/pages/project'
/** /**
* Configures application routing. Add page to pages/index and then add to route table here. * Configures application routing. Add page to pages/index and then add to route table here.

View File

@ -1,4 +1,9 @@
import dayjs from 'dayjs'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { trackEvent } from '@/helpers/analytics.js'
import { get_project, get_version_many } from '@/helpers/cache.js'
import { create_profile_and_install as packInstall } from '@/helpers/pack.js'
import { import {
add_project_from_version, add_project_from_version,
check_installed, check_installed,
@ -8,10 +13,6 @@ import {
remove_project, remove_project,
} from '@/helpers/profile.js' } from '@/helpers/profile.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import { get_project, get_version_many } from '@/helpers/cache.js'
import { create_profile_and_install as packInstall } from '@/helpers/pack.js'
import { trackEvent } from '@/helpers/analytics.js'
import dayjs from 'dayjs'
export const useInstall = defineStore('installStore', { export const useInstall = defineStore('installStore', {
state: () => ({ state: () => ({

View File

@ -1,7 +1,7 @@
import { useTheming } from './theme.ts'
import { useBreadcrumbs } from './breadcrumbs' import { useBreadcrumbs } from './breadcrumbs'
import { useLoading } from './loading'
import { useNotifications, handleError } from './notifications'
import { useInstall } from './install' import { useInstall } from './install'
import { useLoading } from './loading'
import { handleError, useNotifications } from './notifications'
import { useTheming } from './theme.ts'
export { useTheming, useBreadcrumbs, useLoading, useNotifications, handleError, useInstall } export { handleError, useBreadcrumbs, useInstall, useLoading, useNotifications, useTheming }

View File

@ -1,9 +1,8 @@
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path' import { resolve } from 'path'
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import svgLoader from 'vite-svg-loader' import svgLoader from 'vite-svg-loader'
import vue from '@vitejs/plugin-vue'
import tauriConf from '../app/tauri.conf.json' import tauriConf from '../app/tauri.conf.json'
const projectRootDir = resolve(__dirname) const projectRootDir = resolve(__dirname)

View File

@ -1,7 +0,0 @@
module.exports = {
root: true,
extends: ["../../packages/eslint-config-custom/nuxt.js"],
rules: {
"import/no-unresolved": "off",
},
};

View File

@ -1,4 +0,0 @@
{
"endOfLine": "auto",
"plugins": ["prettier-plugin-tailwindcss"]
}

View File

@ -1,6 +1,6 @@
project_id: 518556 project_id: 518556
preserve_hierarchy: true preserve_hierarchy: true
commit_message: "[ci skip]" commit_message: '[ci skip]'
files: files:
- source: /locales/en-US/* - source: /locales/en-US/*

View File

@ -0,0 +1,10 @@
import config from '@modrinth/tooling-config/eslint/nuxt.mjs'
export default config.append([
{
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'import/no-unresolved': 'off',
'no-undef': 'off',
},
},
])

View File

@ -1,27 +1,28 @@
import { promises as fs } from "fs"; import { pathToFileURL } from 'node:url'
import { pathToFileURL } from "node:url";
import svgLoader from "vite-svg-loader";
import { resolve, basename, relative } from "pathe";
import { defineNuxtConfig } from "nuxt/config";
import { $fetch } from "ofetch";
import { globIterate } from "glob";
import { match as matchLocale } from "@formatjs/intl-localematcher";
import { consola } from "consola";
const STAGING_API_URL = "https://staging-api.modrinth.com/v2/"; import { match as matchLocale } from '@formatjs/intl-localematcher'
import { consola } from 'consola'
import { promises as fs } from 'fs'
import { globIterate } from 'glob'
import { defineNuxtConfig } from 'nuxt/config'
import { $fetch } from 'ofetch'
import { basename, relative, resolve } from 'pathe'
import svgLoader from 'vite-svg-loader'
const STAGING_API_URL = 'https://staging-api.modrinth.com/v2/'
const preloadedFonts = [ const preloadedFonts = [
"inter/Inter-Regular.woff2", 'inter/Inter-Regular.woff2',
"inter/Inter-Medium.woff2", 'inter/Inter-Medium.woff2',
"inter/Inter-SemiBold.woff2", 'inter/Inter-SemiBold.woff2',
"inter/Inter-Bold.woff2", 'inter/Inter-Bold.woff2',
]; ]
const favicons = { const favicons = {
"(prefers-color-scheme:no-preference)": "/favicon-light.ico", '(prefers-color-scheme:no-preference)': '/favicon-light.ico',
"(prefers-color-scheme:light)": "/favicon-light.ico", '(prefers-color-scheme:light)': '/favicon-light.ico',
"(prefers-color-scheme:dark)": "/favicon.ico", '(prefers-color-scheme:dark)': '/favicon.ico',
}; }
/** /**
* Tags of locales that are auto-discovered besides the default locale. * Tags of locales that are auto-discovered besides the default locale.
@ -29,52 +30,52 @@ const favicons = {
* Preferably only the locales that reach a certain threshold of complete * Preferably only the locales that reach a certain threshold of complete
* translations would be included in this array. * translations would be included in this array.
*/ */
const enabledLocales: string[] = []; const enabledLocales: string[] = []
/** /**
* Overrides for the categories of the certain locales. * Overrides for the categories of the certain locales.
*/ */
const localesCategoriesOverrides: Partial<Record<string, "fun" | "experimental">> = { const localesCategoriesOverrides: Partial<Record<string, 'fun' | 'experimental'>> = {
"en-x-pirate": "fun", 'en-x-pirate': 'fun',
"en-x-updown": "fun", 'en-x-updown': 'fun',
"en-x-lolcat": "fun", 'en-x-lolcat': 'fun',
"en-x-uwu": "fun", 'en-x-uwu': 'fun',
"ru-x-bandit": "fun", 'ru-x-bandit': 'fun',
ar: "experimental", ar: 'experimental',
he: "experimental", he: 'experimental',
pes: "experimental", pes: 'experimental',
}; }
export default defineNuxtConfig({ export default defineNuxtConfig({
srcDir: "src/", srcDir: 'src/',
app: { app: {
head: { head: {
htmlAttrs: { htmlAttrs: {
lang: "en", lang: 'en',
}, },
title: "Modrinth", title: 'Modrinth',
link: [ link: [
// The type is necessary because the linter can't always compare this very nested/complex type on itself // The type is necessary because the linter can't always compare this very nested/complex type on itself
...preloadedFonts.map((font): object => { ...preloadedFonts.map((font): object => {
return { return {
rel: "preload", rel: 'preload',
href: `https://cdn-raw.modrinth.com/fonts/${font}?v=3.19`, href: `https://cdn-raw.modrinth.com/fonts/${font}?v=3.19`,
as: "font", as: 'font',
type: "font/woff2", type: 'font/woff2',
crossorigin: "anonymous", crossorigin: 'anonymous',
}; }
}), }),
...Object.entries(favicons).map(([media, href]): object => { ...Object.entries(favicons).map(([media, href]): object => {
return { rel: "icon", type: "image/x-icon", href, media }; return { rel: 'icon', type: 'image/x-icon', href, media }
}), }),
...Object.entries(favicons).map(([media, href]): object => { ...Object.entries(favicons).map(([media, href]): object => {
return { rel: "apple-touch-icon", type: "image/x-icon", href, media, sizes: "64x64" }; return { rel: 'apple-touch-icon', type: 'image/x-icon', href, media, sizes: '64x64' }
}), }),
{ {
rel: "search", rel: 'search',
type: "application/opensearchdescription+xml", type: 'application/opensearchdescription+xml',
href: "/opensearch.xml", href: '/opensearch.xml',
title: "Modrinth mods", title: 'Modrinth mods',
}, },
], ],
}, },
@ -85,19 +86,19 @@ export default defineNuxtConfig({
}, },
esbuild: { esbuild: {
define: { define: {
global: "globalThis", global: 'globalThis',
}, },
}, },
cacheDir: "../../node_modules/.vite/apps/knossos", cacheDir: '../../node_modules/.vite/apps/knossos',
resolve: { resolve: {
dedupe: ["vue"], dedupe: ['vue'],
}, },
plugins: [ plugins: [
svgLoader({ svgLoader({
svgoConfig: { svgoConfig: {
plugins: [ plugins: [
{ {
name: "preset-default", name: 'preset-default',
params: { params: {
overrides: { overrides: {
removeViewBox: false, removeViewBox: false,
@ -110,33 +111,33 @@ export default defineNuxtConfig({
], ],
}, },
hooks: { hooks: {
async "build:before"() { async 'build:before'() {
// 30 minutes // 30 minutes
const TTL = 30 * 60 * 1000; const TTL = 30 * 60 * 1000
let state: { let state: {
lastGenerated?: string; lastGenerated?: string
apiUrl?: string; apiUrl?: string
categories?: any[]; categories?: any[]
loaders?: any[]; loaders?: any[]
gameVersions?: any[]; gameVersions?: any[]
donationPlatforms?: any[]; donationPlatforms?: any[]
reportTypes?: any[]; reportTypes?: any[]
homePageProjects?: any[]; homePageProjects?: any[]
homePageSearch?: any[]; homePageSearch?: any[]
homePageNotifs?: any[]; homePageNotifs?: any[]
products?: any[]; products?: any[]
errors?: number[]; errors?: number[]
} = {}; } = {}
try { try {
state = JSON.parse(await fs.readFile("./src/generated/state.json", "utf8")); state = JSON.parse(await fs.readFile('./src/generated/state.json', 'utf8'))
} catch { } catch {
// File doesn't exist, create folder // File doesn't exist, create folder
await fs.mkdir("./src/generated", { recursive: true }); await fs.mkdir('./src/generated', { recursive: true })
} }
const API_URL = getApiUrl(); const API_URL = getApiUrl()
if ( if (
// Skip regeneration if within TTL... // Skip regeneration if within TTL...
@ -147,28 +148,29 @@ export default defineNuxtConfig({
// ...and if no errors were caught during the last generation // ...and if no errors were caught during the last generation
(state.errors ?? []).length === 0 (state.errors ?? []).length === 0
) { ) {
console.log( console.log(
"Tags already recently generated. Delete apps/frontend/generated/state.json to force regeneration.", "Tags already recently generated. Delete apps/frontend/generated/state.json to force regeneration.",
); );
return; return
} }
state.lastGenerated = new Date().toISOString(); state.lastGenerated = new Date().toISOString()
state.apiUrl = API_URL; state.apiUrl = API_URL
const headers = { const headers = {
headers: { headers: {
"user-agent": "Knossos generator (support@modrinth.com)", 'user-agent': 'Knossos generator (support@modrinth.com)',
}, },
}; }
const caughtErrorCodes = new Set<number>(); const caughtErrorCodes = new Set<number>()
function handleFetchError(err: any, defaultValue: any) { function handleFetchError(err: any, defaultValue: any) {
console.error("Error generating state: ", err); console.error('Error generating state: ', err)
caughtErrorCodes.add(err.status); caughtErrorCodes.add(err.status)
return defaultValue; return defaultValue
} }
const [ const [
@ -198,152 +200,152 @@ export default defineNuxtConfig({
$fetch(`${API_URL}search?limit=3&query=&index=updated`, headers).catch((err) => $fetch(`${API_URL}search?limit=3&query=&index=updated`, headers).catch((err) =>
handleFetchError(err, {}), handleFetchError(err, {}),
), ),
$fetch(`${API_URL.replace("/v2/", "/_internal/")}billing/products`, headers).catch((err) => $fetch(`${API_URL.replace('/v2/', '/_internal/')}billing/products`, headers).catch((err) =>
handleFetchError(err, []), handleFetchError(err, []),
), ),
]); ])
state.categories = categories; state.categories = categories
state.loaders = loaders; state.loaders = loaders
state.gameVersions = gameVersions; state.gameVersions = gameVersions
state.donationPlatforms = donationPlatforms; state.donationPlatforms = donationPlatforms
state.reportTypes = reportTypes; state.reportTypes = reportTypes
state.homePageProjects = homePageProjects; state.homePageProjects = homePageProjects
state.homePageSearch = homePageSearch; state.homePageSearch = homePageSearch
state.homePageNotifs = homePageNotifs; state.homePageNotifs = homePageNotifs
state.products = products; state.products = products
state.errors = [...caughtErrorCodes]; state.errors = [...caughtErrorCodes]
await fs.writeFile("./src/generated/state.json", JSON.stringify(state)); await fs.writeFile('./src/generated/state.json', JSON.stringify(state))
console.log("Tags generated!"); console.log('Tags generated!')
}, },
"pages:extend"(routes) { 'pages:extend'(routes) {
routes.splice( routes.splice(
routes.findIndex((x) => x.name === "search-searchProjectType"), routes.findIndex((x) => x.name === 'search-searchProjectType'),
1, 1,
); )
const types = ["mods", "modpacks", "plugins", "resourcepacks", "shaders", "datapacks"]; const types = ['mods', 'modpacks', 'plugins', 'resourcepacks', 'shaders', 'datapacks']
types.forEach((type) => types.forEach((type) =>
routes.push({ routes.push({
name: `search-${type}`, name: `search-${type}`,
path: `/${type}`, path: `/${type}`,
file: resolve(__dirname, "src/pages/search/[searchProjectType].vue"), file: resolve(__dirname, 'src/pages/search/[searchProjectType].vue'),
children: [], children: [],
}), }),
); )
}, },
async "vintl:extendOptions"(opts) { async 'vintl:extendOptions'(opts) {
opts.locales ??= []; opts.locales ??= []
const isProduction = getDomain() === "https://modrinth.com"; const isProduction = getDomain() === 'https://modrinth.com'
const resolveCompactNumberDataImport = await (async () => { const resolveCompactNumberDataImport = await (async () => {
const compactNumberLocales: string[] = []; const compactNumberLocales: string[] = []
for await (const localeFile of globIterate( for await (const localeFile of globIterate(
"node_modules/@vintl/compact-number/dist/locale-data/*.mjs", 'node_modules/@vintl/compact-number/dist/locale-data/*.mjs',
{ ignore: "**/*.data.mjs" }, { ignore: '**/*.data.mjs' },
)) { )) {
const tag = basename(localeFile, ".mjs"); const tag = basename(localeFile, '.mjs')
compactNumberLocales.push(tag); compactNumberLocales.push(tag)
} }
function resolveImport(tag: string) { function resolveImport(tag: string) {
const matchedTag = matchLocale([tag], compactNumberLocales, "en-x-placeholder"); const matchedTag = matchLocale([tag], compactNumberLocales, 'en-x-placeholder')
return matchedTag === "en-x-placeholder" return matchedTag === 'en-x-placeholder'
? undefined ? undefined
: `@vintl/compact-number/locale-data/${matchedTag}`; : `@vintl/compact-number/locale-data/${matchedTag}`
} }
return resolveImport; return resolveImport
})(); })()
const resolveOmorphiaLocaleImport = await (async () => { const resolveOmorphiaLocaleImport = await (async () => {
const omorphiaLocales: string[] = []; const omorphiaLocales: string[] = []
const omorphiaLocaleSets = new Map<string, { files: { from: string }[] }>(); const omorphiaLocaleSets = new Map<string, { files: { from: string }[] }>()
for await (const localeDir of globIterate("node_modules/@modrinth/ui/src/locales/*", { for await (const localeDir of globIterate('node_modules/@modrinth/ui/src/locales/*', {
posix: true, posix: true,
})) { })) {
const tag = basename(localeDir); const tag = basename(localeDir)
omorphiaLocales.push(tag); omorphiaLocales.push(tag)
const localeFiles: { from: string; format?: string }[] = []; const localeFiles: { from: string; format?: string }[] = []
omorphiaLocaleSets.set(tag, { files: localeFiles }); omorphiaLocaleSets.set(tag, { files: localeFiles })
for await (const localeFile of globIterate(`${localeDir}/*`, { posix: true })) { for await (const localeFile of globIterate(`${localeDir}/*`, { posix: true })) {
localeFiles.push({ localeFiles.push({
from: pathToFileURL(localeFile).toString(), from: pathToFileURL(localeFile).toString(),
format: "default", format: 'default',
}); })
} }
} }
return function resolveLocaleImport(tag: string) { return function resolveLocaleImport(tag: string) {
return omorphiaLocaleSets.get(matchLocale([tag], omorphiaLocales, "en-x-placeholder")); return omorphiaLocaleSets.get(matchLocale([tag], omorphiaLocales, 'en-x-placeholder'))
}; }
})(); })()
for await (const localeDir of globIterate("src/locales/*/", { posix: true })) { for await (const localeDir of globIterate('src/locales/*/', { posix: true })) {
const tag = basename(localeDir); const tag = basename(localeDir)
if (isProduction && !enabledLocales.includes(tag) && opts.defaultLocale !== tag) continue; if (isProduction && !enabledLocales.includes(tag) && opts.defaultLocale !== tag) continue
const locale = const locale =
opts.locales.find((locale) => locale.tag === tag) ?? opts.locales.find((locale) => locale.tag === tag) ??
opts.locales[opts.locales.push({ tag }) - 1]!; opts.locales[opts.locales.push({ tag }) - 1]!
const localeFiles = (locale.files ??= []); const localeFiles = (locale.files ??= [])
for await (const localeFile of globIterate(`${localeDir}/*`, { posix: true })) { for await (const localeFile of globIterate(`${localeDir}/*`, { posix: true })) {
const fileName = basename(localeFile); const fileName = basename(localeFile)
if (fileName === "index.json") { if (fileName === 'index.json') {
localeFiles.push({ localeFiles.push({
from: `./${relative("./src", localeFile)}`, from: `./${relative('./src', localeFile)}`,
format: "crowdin", format: 'crowdin',
}); })
} else if (fileName === "meta.json") { } else if (fileName === 'meta.json') {
const meta: Record<string, { message: string }> = await fs const meta: Record<string, { message: string }> = await fs
.readFile(localeFile, "utf8") .readFile(localeFile, 'utf8')
.then((date) => JSON.parse(date)); .then((date) => JSON.parse(date))
const localeMeta = (locale.meta ??= {}); const localeMeta = (locale.meta ??= {})
for (const key in meta) { for (const key in meta) {
const value = meta[key]; const value = meta[key]
if (value === undefined) continue; if (value === undefined) continue
localeMeta[key] = value.message; localeMeta[key] = value.message
} }
} else { } else {
(locale.resources ??= {})[fileName] = `./${relative("./src", localeFile)}`; ;(locale.resources ??= {})[fileName] = `./${relative('./src', localeFile)}`
} }
} }
const categoryOverride = localesCategoriesOverrides[tag]; const categoryOverride = localesCategoriesOverrides[tag]
if (categoryOverride != null) { if (categoryOverride != null) {
(locale.meta ??= {}).category = categoryOverride; ;(locale.meta ??= {}).category = categoryOverride
} }
const omorphiaLocaleData = resolveOmorphiaLocaleImport(tag); const omorphiaLocaleData = resolveOmorphiaLocaleImport(tag)
if (omorphiaLocaleData != null) { if (omorphiaLocaleData != null) {
localeFiles.push(...omorphiaLocaleData.files); localeFiles.push(...omorphiaLocaleData.files)
} }
const cnDataImport = resolveCompactNumberDataImport(tag); const cnDataImport = resolveCompactNumberDataImport(tag)
if (cnDataImport != null) { if (cnDataImport != null) {
(locale.additionalImports ??= []).push({ ;(locale.additionalImports ??= []).push({
from: cnDataImport, from: cnDataImport,
resolve: false, resolve: false,
}); })
} }
} }
}, },
}, },
runtimeConfig: { runtimeConfig: {
// @ts-ignore // @ts-expect-error
apiBaseUrl: process.env.BASE_URL ?? globalThis.BASE_URL ?? getApiUrl(), apiBaseUrl: process.env.BASE_URL ?? globalThis.BASE_URL ?? getApiUrl(),
// @ts-ignore // @ts-expect-error
rateLimitKey: process.env.RATE_LIMIT_IGNORE_KEY ?? globalThis.RATE_LIMIT_IGNORE_KEY, rateLimitKey: process.env.RATE_LIMIT_IGNORE_KEY ?? globalThis.RATE_LIMIT_IGNORE_KEY,
pyroBaseUrl: process.env.PYRO_BASE_URL, pyroBaseUrl: process.env.PYRO_BASE_URL,
public: { public: {
@ -353,25 +355,26 @@ export default defineNuxtConfig({
production: isProduction(), production: isProduction(),
featureFlagOverrides: getFeatureFlagOverrides(), featureFlagOverrides: getFeatureFlagOverrides(),
owner: process.env.VERCEL_GIT_REPO_OWNER || "modrinth", owner: process.env.VERCEL_GIT_REPO_OWNER || 'modrinth',
slug: process.env.VERCEL_GIT_REPO_SLUG || "code", slug: process.env.VERCEL_GIT_REPO_SLUG || 'code',
branch: branch:
process.env.VERCEL_GIT_COMMIT_REF || process.env.VERCEL_GIT_COMMIT_REF ||
process.env.CF_PAGES_BRANCH || process.env.CF_PAGES_BRANCH ||
// @ts-ignore // @ts-expect-error
globalThis.CF_PAGES_BRANCH || globalThis.CF_PAGES_BRANCH ||
"master", 'master',
hash: hash:
process.env.VERCEL_GIT_COMMIT_SHA || process.env.VERCEL_GIT_COMMIT_SHA ||
process.env.CF_PAGES_COMMIT_SHA || process.env.CF_PAGES_COMMIT_SHA ||
// @ts-ignore // @ts-expect-error
globalThis.CF_PAGES_COMMIT_SHA || globalThis.CF_PAGES_COMMIT_SHA ||
"unknown", 'unknown',
stripePublishableKey: stripePublishableKey:
process.env.STRIPE_PUBLISHABLE_KEY || process.env.STRIPE_PUBLISHABLE_KEY ||
// @ts-expect-error
globalThis.STRIPE_PUBLISHABLE_KEY || globalThis.STRIPE_PUBLISHABLE_KEY ||
"pk_test_51JbFxJJygY5LJFfKV50mnXzz3YLvBVe2Gd1jn7ljWAkaBlRz3VQdxN9mXcPSrFbSqxwAb0svte9yhnsmm7qHfcWn00R611Ce7b", 'pk_test_51JbFxJJygY5LJFfKV50mnXzz3YLvBVe2Gd1jn7ljWAkaBlRz3VQdxN9mXcPSrFbSqxwAb0svte9yhnsmm7qHfcWn00R611Ce7b',
}, },
}, },
typescript: { typescript: {
@ -380,62 +383,62 @@ export default defineNuxtConfig({
typeCheck: false, typeCheck: false,
tsConfig: { tsConfig: {
compilerOptions: { compilerOptions: {
moduleResolution: "bundler", moduleResolution: 'bundler',
allowImportingTsExtensions: true, allowImportingTsExtensions: true,
}, },
}, },
}, },
modules: ["@vintl/nuxt", "@pinia/nuxt"], modules: ['@vintl/nuxt', '@pinia/nuxt'],
vintl: { vintl: {
defaultLocale: "en-US", defaultLocale: 'en-US',
locales: [ locales: [
{ {
tag: "en-US", tag: 'en-US',
meta: { meta: {
static: { static: {
iso: "en", iso: 'en',
}, },
}, },
}, },
], ],
storage: "cookie", storage: 'cookie',
parserless: "only-prod", parserless: 'only-prod',
seo: { seo: {
defaultLocaleHasParameter: false, defaultLocaleHasParameter: false,
}, },
onParseError({ error, message, messageId, moduleId, parseMessage, parserOptions }) { onParseError({ error, message, messageId, moduleId, parseMessage, parserOptions }) {
const errorMessage = String(error); const errorMessage = String(error)
const modulePath = relative(__dirname, moduleId); const modulePath = relative(__dirname, moduleId)
try { try {
const fallback = parseMessage(message, { ...parserOptions, ignoreTag: true }); const fallback = parseMessage(message, { ...parserOptions, ignoreTag: true })
consola.warn( consola.warn(
`[i18n] ${messageId} in ${modulePath} cannot be parsed normally due to ${errorMessage}. The tags will will not be parsed.`, `[i18n] ${messageId} in ${modulePath} cannot be parsed normally due to ${errorMessage}. The tags will will not be parsed.`,
); )
return fallback; return fallback
} catch (err) { } catch (err) {
const secondaryErrorMessage = String(err); const secondaryErrorMessage = String(err)
const reason = const reason =
errorMessage === secondaryErrorMessage errorMessage === secondaryErrorMessage
? errorMessage ? errorMessage
: `${errorMessage} and ${secondaryErrorMessage}`; : `${errorMessage} and ${secondaryErrorMessage}`
consola.warn( consola.warn(
`[i18n] ${messageId} in ${modulePath} cannot be parsed due to ${reason}. It will be skipped.`, `[i18n] ${messageId} in ${modulePath} cannot be parsed due to ${reason}. It will be skipped.`,
); )
} }
}, },
}, },
nitro: { nitro: {
moduleSideEffects: ["@vintl/compact-number/locale-data"], moduleSideEffects: ['@vintl/compact-number/locale-data'],
}, },
devtools: { devtools: {
enabled: true, enabled: true,
}, },
css: ["~/assets/styles/tailwind.css"], css: ['~/assets/styles/tailwind.css'],
postcss: { postcss: {
plugins: { plugins: {
tailwindcss: {}, tailwindcss: {},
@ -443,50 +446,50 @@ export default defineNuxtConfig({
}, },
}, },
routeRules: { routeRules: {
"/**": { '/**': {
headers: { headers: {
"Accept-CH": "Sec-CH-Prefers-Color-Scheme", 'Accept-CH': 'Sec-CH-Prefers-Color-Scheme',
"Critical-CH": "Sec-CH-Prefers-Color-Scheme", 'Critical-CH': 'Sec-CH-Prefers-Color-Scheme',
}, },
}, },
}, },
compatibilityDate: "2024-07-03", compatibilityDate: '2024-07-03',
telemetry: false, telemetry: false,
}); })
function getApiUrl() { function getApiUrl() {
// @ts-ignore // @ts-expect-error
return process.env.BROWSER_BASE_URL ?? globalThis.BROWSER_BASE_URL ?? STAGING_API_URL; return process.env.BROWSER_BASE_URL ?? globalThis.BROWSER_BASE_URL ?? STAGING_API_URL
} }
function isProduction() { function isProduction() {
return process.env.NODE_ENV === "production"; return process.env.NODE_ENV === 'production'
} }
function getFeatureFlagOverrides() { function getFeatureFlagOverrides() {
return JSON.parse(process.env.FLAG_OVERRIDES ?? "{}"); return JSON.parse(process.env.FLAG_OVERRIDES ?? '{}')
} }
function getDomain() { function getDomain() {
if (process.env.NODE_ENV === "production") { if (process.env.NODE_ENV === 'production') {
if (process.env.SITE_URL) { if (process.env.SITE_URL) {
return process.env.SITE_URL; return process.env.SITE_URL
} }
// @ts-ignore // @ts-expect-error
else if (process.env.CF_PAGES_URL || globalThis.CF_PAGES_URL) { else if (process.env.CF_PAGES_URL || globalThis.CF_PAGES_URL) {
// @ts-ignore // @ts-expect-error
return process.env.CF_PAGES_URL ?? globalThis.CF_PAGES_URL; return process.env.CF_PAGES_URL ?? globalThis.CF_PAGES_URL
} else if (process.env.HEROKU_APP_NAME) { } else if (process.env.HEROKU_APP_NAME) {
return `https://${process.env.HEROKU_APP_NAME}.herokuapp.com`; return `https://${process.env.HEROKU_APP_NAME}.herokuapp.com`
} else if (process.env.VERCEL_URL) { } else if (process.env.VERCEL_URL) {
return `https://${process.env.VERCEL_URL}`; return `https://${process.env.VERCEL_URL}`
} else if (getApiUrl() === STAGING_API_URL) { } else if (getApiUrl() === STAGING_API_URL) {
return "https://staging.modrinth.com"; return 'https://staging.modrinth.com'
} else { } else {
return "https://modrinth.com"; return 'https://modrinth.com'
} }
} else { } else {
const port = process.env.PORT || 3000; const port = process.env.PORT || 3000
return `http://localhost:${port}`; return `http://localhost:${port}`
} }
} }

View File

@ -71,5 +71,6 @@
"vue3-apexcharts": "^1.5.2", "vue3-apexcharts": "^1.5.2",
"xss": "^1.0.14" "xss": "^1.0.14"
}, },
"web-types": "../../web-types.json" "web-types": "../../web-types.json",
"prettier": "@modrinth/tooling-config/prettier.nuxt.config.js"
} }

View File

@ -6,6 +6,6 @@
</NuxtLayout> </NuxtLayout>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import ModrinthLoadingIndicator from "~/components/ui/modrinth-loading-indicator.ts"; import ModrinthLoadingIndicator from '~/components/ui/modrinth-loading-indicator.ts'
import Notifications from "~/components/ui/Notifications.vue"; import Notifications from '~/components/ui/Notifications.vue'
</script> </script>

Some files were not shown because too many files have changed in this diff Show More