Loading bar all the things
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { RouterView, RouterLink } from 'vue-router'
|
||||
import { HomeIcon, SearchIcon, LibraryIcon, PlusIcon, SettingsIcon, AnimatedLogo } from 'omorphia'
|
||||
import { HomeIcon, SearchIcon, LibraryIcon, PlusIcon, SettingsIcon } from 'omorphia'
|
||||
import { useTheming } from '@/store/state'
|
||||
import AccountsCard from '@/components/ui/AccountsCard.vue'
|
||||
import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue'
|
||||
import { get } from '@/helpers/settings'
|
||||
import Breadcrumbs from '@/components/ui/Breadcrumbs.vue'
|
||||
import RunningAppBar from '@/components/ui/RunningAppBar.vue'
|
||||
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||
|
||||
const themeStore = useTheming()
|
||||
|
||||
@@ -28,7 +29,8 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="!loading" class="container">
|
||||
<SplashScreen v-if="loading" app-loading />
|
||||
<div v-else class="container">
|
||||
<div class="nav-container" :class="{ expanded: !themeStore.collapsedNavigation }">
|
||||
<div class="nav-section">
|
||||
<suspense>
|
||||
@@ -121,9 +123,6 @@ defineExpose({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="loading-page">
|
||||
<AnimatedLogo class="initializing-icon" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -347,23 +346,4 @@ defineExpose({
|
||||
height: 100%;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.loading-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #16181c;
|
||||
height: 100vh;
|
||||
|
||||
.initializing-icon {
|
||||
width: 12rem;
|
||||
height: 12rem;
|
||||
|
||||
:deep(svg) {
|
||||
width: 12rem;
|
||||
height: 12rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -37,10 +37,10 @@
|
||||
<Card v-if="showCard === true" ref="card" class="info-card">
|
||||
<div v-for="loadingBar in currentLoadingBars" :key="loadingBar.id" class="info-text">
|
||||
<h3 class="info-title">
|
||||
{{ loadingBar.bar_type.PackDownload.pack_name }}
|
||||
{{ loadingBar.bar_type.pack_name ?? 'Installing Modpack' }}
|
||||
</h3>
|
||||
<ProgressBar :progress="Math.round(loadingBar.current)" />
|
||||
<div class="row">{{ loadingBar.message }}</div>
|
||||
<div class="row">{{ Math.floor(loadingBar.current) }}% {{ loadingBar.message }}</div>
|
||||
</div>
|
||||
</Card>
|
||||
</transition>
|
||||
@@ -67,7 +67,8 @@ const showCard = ref(false)
|
||||
|
||||
const currentProcesses = ref(await getRunningProfiles())
|
||||
|
||||
await process_listener(async () => {
|
||||
await process_listener(async (event) => {
|
||||
console.log(event)
|
||||
await refresh()
|
||||
})
|
||||
|
||||
@@ -89,11 +90,7 @@ const goToTerminal = () => {
|
||||
router.push(`/instance/${encodeURIComponent(currentProcesses.value[0].path)}/logs`)
|
||||
}
|
||||
|
||||
const currentLoadingBars = ref(
|
||||
Object.values(await progress_bars_list()).filter(
|
||||
(bar) => bar.bar_type !== 'StateInit' && Object.keys(bar.bar_type)[0] === 'PackDownload'
|
||||
)
|
||||
)
|
||||
const currentLoadingBars = ref(Object.values(await progress_bars_list()))
|
||||
|
||||
await loading_listener(async (event) => {
|
||||
console.log('loading listener', event.message, event)
|
||||
@@ -102,9 +99,7 @@ await loading_listener(async (event) => {
|
||||
|
||||
const refreshInfo = async () => {
|
||||
const currentLoadingBarCount = currentLoadingBars.value.length
|
||||
currentLoadingBars.value = Object.values(await progress_bars_list()).filter(
|
||||
(bar) => bar.bar_type !== 'StateInit' && Object.keys(bar.bar_type)[0] === 'PackDownload'
|
||||
)
|
||||
currentLoadingBars.value = Object.values(await progress_bars_list())
|
||||
if (currentLoadingBars.value.length === 0) {
|
||||
showCard.value = false
|
||||
} else if (currentLoadingBarCount < currentLoadingBars.value.length) {
|
||||
|
||||
49
theseus_gui/src/components/ui/SplashScreen.vue
Normal file
49
theseus_gui/src/components/ui/SplashScreen.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div class="page-loading" :class="{ 'app-loading': appLoading }">
|
||||
<AnimatedLogo class="initializing-icon" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { AnimatedLogo } from 'omorphia'
|
||||
|
||||
defineProps({
|
||||
appLoading: Boolean,
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.page-loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
&.app-loading {
|
||||
background-color: #16181c;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.splash-text {
|
||||
margin-top: 2rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
width: 15rem;
|
||||
}
|
||||
}
|
||||
|
||||
.initializing-icon {
|
||||
width: 12rem;
|
||||
height: 12rem;
|
||||
|
||||
:deep(svg),
|
||||
svg {
|
||||
width: 12rem;
|
||||
height: 12rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
Card,
|
||||
ClientIcon,
|
||||
ServerIcon,
|
||||
AnimatedLogo,
|
||||
NavRow,
|
||||
formatCategoryHeader,
|
||||
} from 'omorphia'
|
||||
@@ -23,6 +22,7 @@ import { useBreadcrumbs } from '@/store/breadcrumbs'
|
||||
import { get_categories, get_loaders, get_game_versions } from '@/helpers/tags'
|
||||
import { useRoute } from 'vue-router'
|
||||
import Instance from '@/components/ui/Instance.vue'
|
||||
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
@@ -36,25 +36,28 @@ const breadcrumbs = useBreadcrumbs()
|
||||
const showSnapshots = ref(false)
|
||||
const loading = ref(true)
|
||||
|
||||
const [categories, loaders, availableGameVersions] = await Promise.all([
|
||||
get_categories(),
|
||||
get_loaders(),
|
||||
get_game_versions(),
|
||||
])
|
||||
const categories = ref([])
|
||||
const loaders = ref([])
|
||||
const availableGameVersions = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
;[categories.value, loaders.value, availableGameVersions.value] = await Promise.all([
|
||||
get_categories(),
|
||||
get_loaders(),
|
||||
get_game_versions(),
|
||||
])
|
||||
breadcrumbs.setContext({ name: 'Browse', link: route.path })
|
||||
if (searchStore.projectType === 'modpack') {
|
||||
searchStore.instanceContext = null
|
||||
}
|
||||
searchStore.searchInput = ''
|
||||
handleReset()
|
||||
switchPage(1)
|
||||
await handleReset(true)
|
||||
loading.value = false
|
||||
})
|
||||
|
||||
const sortedCategories = computed(() => {
|
||||
const values = new Map()
|
||||
for (const category of categories.filter(
|
||||
for (const category of categories.value.filter(
|
||||
(cat) =>
|
||||
cat.project_type ===
|
||||
(searchStore.projectType === 'datapack' ? 'mod' : searchStore.projectType)
|
||||
@@ -67,7 +70,7 @@ const sortedCategories = computed(() => {
|
||||
return values
|
||||
})
|
||||
|
||||
const getSearchResults = async (shouldLoad = false) => {
|
||||
const getSearchResults = async () => {
|
||||
const queryString = searchStore.getQueryString()
|
||||
if (searchStore.instanceContext) {
|
||||
showVersions.value = false
|
||||
@@ -75,16 +78,10 @@ const getSearchResults = async (shouldLoad = false) => {
|
||||
searchStore.projectType === 'mod' || searchStore.projectType === 'resourcepack'
|
||||
)
|
||||
}
|
||||
if (shouldLoad === true) {
|
||||
loading.value = true
|
||||
}
|
||||
const response = await ofetch(`https://api.modrinth.com/v2/search${queryString}`)
|
||||
loading.value = false
|
||||
searchStore.setSearchResults(response)
|
||||
}
|
||||
|
||||
getSearchResults(true)
|
||||
|
||||
const handleReset = async () => {
|
||||
searchStore.currentPage = 1
|
||||
searchStore.offset = 0
|
||||
@@ -131,221 +128,227 @@ watch(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="search-container">
|
||||
<aside class="filter-panel">
|
||||
<Instance v-if="searchStore.instanceContext" :instance="searchStore.instanceContext" small />
|
||||
<Button
|
||||
role="button"
|
||||
:disabled="
|
||||
!(
|
||||
searchStore.facets.length > 0 ||
|
||||
searchStore.orFacets.length > 0 ||
|
||||
searchStore.environments.server === true ||
|
||||
searchStore.environments.client === true ||
|
||||
searchStore.openSource === true ||
|
||||
searchStore.activeVersions.length > 0
|
||||
)
|
||||
"
|
||||
@click="handleReset"
|
||||
><ClearIcon />Clear Filters</Button
|
||||
>
|
||||
<div
|
||||
v-for="categoryList in Array.from(sortedCategories)"
|
||||
:key="categoryList[0]"
|
||||
class="categories"
|
||||
>
|
||||
<h2>{{ formatCategoryHeader(categoryList[0]) }}</h2>
|
||||
<div v-for="category in categoryList[1]" :key="category.name">
|
||||
<SearchFilter
|
||||
:active-filters="searchStore.facets"
|
||||
:icon="category.icon"
|
||||
:display-name="category.name"
|
||||
:facet-name="`categories:${encodeURIComponent(category.name)}`"
|
||||
class="filter-checkbox"
|
||||
@toggle="toggleFacet"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
showLoaders &&
|
||||
searchStore.projectType !== 'datapack' &&
|
||||
searchStore.projectType !== 'resourcepack' &&
|
||||
searchStore.projectType !== 'shader'
|
||||
"
|
||||
class="loaders"
|
||||
>
|
||||
<h2>Loaders</h2>
|
||||
<transition name="fade">
|
||||
<SplashScreen v-if="loading" />
|
||||
<div v-else class="search-container">
|
||||
<aside class="filter-panel">
|
||||
<Instance
|
||||
v-if="searchStore.instanceContext"
|
||||
:instance="searchStore.instanceContext"
|
||||
small
|
||||
/>
|
||||
<Button
|
||||
role="button"
|
||||
:disabled="
|
||||
!(
|
||||
searchStore.facets.length > 0 ||
|
||||
searchStore.orFacets.length > 0 ||
|
||||
searchStore.environments.server === true ||
|
||||
searchStore.environments.client === true ||
|
||||
searchStore.openSource === true ||
|
||||
searchStore.activeVersions.length > 0
|
||||
)
|
||||
"
|
||||
@click="handleReset"
|
||||
><ClearIcon />Clear Filters</Button
|
||||
>
|
||||
<div
|
||||
v-for="loader in loaders.filter((l) =>
|
||||
l.supported_project_types?.includes(searchStore.projectType)
|
||||
)"
|
||||
:key="loader"
|
||||
v-for="categoryList in Array.from(sortedCategories)"
|
||||
:key="categoryList[0]"
|
||||
class="categories"
|
||||
>
|
||||
<SearchFilter
|
||||
:active-filters="searchStore.orFacets"
|
||||
:icon="loader.icon"
|
||||
:display-name="loader.name"
|
||||
:facet-name="`categories:${encodeURIComponent(loader.name)}`"
|
||||
class="filter-checkbox"
|
||||
@toggle="toggleOrFacet"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="searchStore.projectType !== 'datapack'" class="environment">
|
||||
<h2>Environments</h2>
|
||||
<SearchFilter
|
||||
v-model="searchStore.environments.client"
|
||||
display-name="Client"
|
||||
facet-name="client"
|
||||
class="filter-checkbox"
|
||||
@click="getSearchResults"
|
||||
>
|
||||
<ClientIcon aria-hidden="true" />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
v-model="searchStore.environments.server"
|
||||
display-name="Server"
|
||||
facet-name="server"
|
||||
class="filter-checkbox"
|
||||
@click="getSearchResults"
|
||||
>
|
||||
<ServerIcon aria-hidden="true" />
|
||||
</SearchFilter>
|
||||
</div>
|
||||
<div v-if="showVersions" class="versions">
|
||||
<h2>Minecraft versions</h2>
|
||||
<Checkbox v-model="showSnapshots" class="filter-checkbox">Show snapshots</Checkbox>
|
||||
<multiselect
|
||||
v-model="searchStore.activeVersions"
|
||||
:options="
|
||||
showSnapshots
|
||||
? availableGameVersions.map((x) => x.version)
|
||||
: availableGameVersions
|
||||
.filter((it) => it.version_type === 'release')
|
||||
.map((x) => x.version)
|
||||
"
|
||||
:multiple="true"
|
||||
:searchable="true"
|
||||
:show-no-results="false"
|
||||
:close-on-select="false"
|
||||
:clear-search-on-select="false"
|
||||
:show-labels="false"
|
||||
placeholder="Choose versions..."
|
||||
@update:model-value="getSearchResults"
|
||||
/>
|
||||
</div>
|
||||
<div class="open-source">
|
||||
<h2>Open source</h2>
|
||||
<Checkbox
|
||||
v-model="searchStore.openSource"
|
||||
class="filter-checkbox"
|
||||
@click="getSearchResults"
|
||||
>
|
||||
Open source
|
||||
</Checkbox>
|
||||
</div>
|
||||
</aside>
|
||||
<div class="search">
|
||||
<Card class="project-type-container">
|
||||
<NavRow
|
||||
:links="
|
||||
searchStore.instanceContext
|
||||
? [
|
||||
{ label: 'Mods', href: `/browse/mod` },
|
||||
{ label: 'Datapacks', href: `/browse/datapack` },
|
||||
{ label: 'Shaders', href: `/browse/shader` },
|
||||
{ label: 'Resource Packs', href: `/browse/resourcepack` },
|
||||
]
|
||||
: [
|
||||
{ label: 'Modpacks', href: '/browse/modpack' },
|
||||
{ label: 'Mods', href: '/browse/mod' },
|
||||
{ label: 'Datapacks', href: '/browse/datapack' },
|
||||
{ label: 'Shaders', href: '/browse/shader' },
|
||||
{ label: 'Resource Packs', href: '/browse/resourcepack' },
|
||||
]
|
||||
"
|
||||
/>
|
||||
</Card>
|
||||
<Card class="search-panel-container">
|
||||
<div class="search-panel">
|
||||
<div class="iconified-input">
|
||||
<SearchIcon aria-hidden="true" />
|
||||
<input
|
||||
v-model="searchStore.searchInput"
|
||||
type="text"
|
||||
:placeholder="`Search ${searchStore.projectType}s...`"
|
||||
@input="getSearchResults"
|
||||
<h2>{{ formatCategoryHeader(categoryList[0]) }}</h2>
|
||||
<div v-for="category in categoryList[1]" :key="category.name">
|
||||
<SearchFilter
|
||||
:active-filters="searchStore.facets"
|
||||
:icon="category.icon"
|
||||
:display-name="category.name"
|
||||
:facet-name="`categories:${encodeURIComponent(category.name)}`"
|
||||
class="filter-checkbox"
|
||||
@toggle="toggleFacet"
|
||||
/>
|
||||
</div>
|
||||
<span>Sort by</span>
|
||||
<DropdownSelect
|
||||
v-model="searchStore.filter"
|
||||
name="Sort dropdown"
|
||||
:options="[
|
||||
'Relevance',
|
||||
'Download count',
|
||||
'Follow count',
|
||||
'Recently published',
|
||||
'Recently updated',
|
||||
]"
|
||||
class="sort-dropdown"
|
||||
@change="getSearchResults"
|
||||
/>
|
||||
<span>Show per page</span>
|
||||
<DropdownSelect
|
||||
v-model="searchStore.limit"
|
||||
name="Limit dropdown"
|
||||
:options="[5, 10, 15, 20, 50, 100]"
|
||||
:default-value="searchStore.limit.toString()"
|
||||
:model-value="searchStore.limit.toString()"
|
||||
class="limit-dropdown"
|
||||
@change="getSearchResults"
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
showLoaders &&
|
||||
searchStore.projectType !== 'datapack' &&
|
||||
searchStore.projectType !== 'resourcepack' &&
|
||||
searchStore.projectType !== 'shader'
|
||||
"
|
||||
class="loaders"
|
||||
>
|
||||
<h2>Loaders</h2>
|
||||
<div
|
||||
v-for="loader in loaders.filter((l) =>
|
||||
l.supported_project_types?.includes(searchStore.projectType)
|
||||
)"
|
||||
:key="loader"
|
||||
>
|
||||
<SearchFilter
|
||||
:active-filters="searchStore.orFacets"
|
||||
:icon="loader.icon"
|
||||
:display-name="loader.name"
|
||||
:facet-name="`categories:${encodeURIComponent(loader.name)}`"
|
||||
class="filter-checkbox"
|
||||
@toggle="toggleOrFacet"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="searchStore.projectType !== 'datapack'" class="environment">
|
||||
<h2>Environments</h2>
|
||||
<SearchFilter
|
||||
v-model="searchStore.environments.client"
|
||||
display-name="Client"
|
||||
facet-name="client"
|
||||
class="filter-checkbox"
|
||||
@click="getSearchResults"
|
||||
>
|
||||
<ClientIcon aria-hidden="true" />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
v-model="searchStore.environments.server"
|
||||
display-name="Server"
|
||||
facet-name="server"
|
||||
class="filter-checkbox"
|
||||
@click="getSearchResults"
|
||||
>
|
||||
<ServerIcon aria-hidden="true" />
|
||||
</SearchFilter>
|
||||
</div>
|
||||
<div v-if="showVersions" class="versions">
|
||||
<h2>Minecraft versions</h2>
|
||||
<Checkbox v-model="showSnapshots" class="filter-checkbox">Show snapshots</Checkbox>
|
||||
<multiselect
|
||||
v-model="searchStore.activeVersions"
|
||||
:options="
|
||||
showSnapshots
|
||||
? availableGameVersions.map((x) => x.version)
|
||||
: availableGameVersions
|
||||
.filter((it) => it.version_type === 'release')
|
||||
.map((x) => x.version)
|
||||
"
|
||||
:multiple="true"
|
||||
:searchable="true"
|
||||
:show-no-results="false"
|
||||
:close-on-select="false"
|
||||
:clear-search-on-select="false"
|
||||
:show-labels="false"
|
||||
placeholder="Choose versions..."
|
||||
@update:model-value="getSearchResults"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
<Pagination
|
||||
:page="searchStore.currentPage"
|
||||
:count="searchStore.pageCount"
|
||||
@switch-page="switchPage"
|
||||
/>
|
||||
<AnimatedLogo v-if="loading" class="loading" />
|
||||
<section v-else class="project-list display-mode--list instance-results" role="list">
|
||||
<ProjectCard
|
||||
v-for="result in searchStore.searchResults"
|
||||
:id="`${result?.project_id}/`"
|
||||
:key="result?.project_id"
|
||||
class="result-project-item"
|
||||
:type="result?.project_type"
|
||||
:name="result?.title"
|
||||
:description="result?.description"
|
||||
:icon-url="result?.icon_url"
|
||||
:downloads="result?.downloads?.toString()"
|
||||
:follows="result?.follows?.toString()"
|
||||
:created-at="result?.date_created"
|
||||
:updated-at="result?.date_modified"
|
||||
:categories="[
|
||||
...categories.filter(
|
||||
(cat) =>
|
||||
result?.display_categories.includes(cat.name) &&
|
||||
cat.project_type === searchStore.projectType
|
||||
),
|
||||
...loaders.filter(
|
||||
(loader) =>
|
||||
result?.display_categories.includes(loader.name) &&
|
||||
loader.supported_project_types?.includes(searchStore.projectType)
|
||||
),
|
||||
]"
|
||||
:project-type-display="result?.project_type"
|
||||
project-type-url="project"
|
||||
:server-side="result?.server_side"
|
||||
:client-side="result?.client_side"
|
||||
:show-updated-date="false"
|
||||
:color="result?.color"
|
||||
<div class="open-source">
|
||||
<h2>Open source</h2>
|
||||
<Checkbox
|
||||
v-model="searchStore.openSource"
|
||||
class="filter-checkbox"
|
||||
@click="getSearchResults"
|
||||
>
|
||||
Open source
|
||||
</Checkbox>
|
||||
</div>
|
||||
</aside>
|
||||
<div class="search">
|
||||
<Card class="project-type-container">
|
||||
<NavRow
|
||||
:links="
|
||||
searchStore.instanceContext
|
||||
? [
|
||||
{ label: 'Mods', href: `/browse/mod` },
|
||||
{ label: 'Datapacks', href: `/browse/datapack` },
|
||||
{ label: 'Shaders', href: `/browse/shader` },
|
||||
{ label: 'Resource Packs', href: `/browse/resourcepack` },
|
||||
]
|
||||
: [
|
||||
{ label: 'Modpacks', href: '/browse/modpack' },
|
||||
{ label: 'Mods', href: '/browse/mod' },
|
||||
{ label: 'Datapacks', href: '/browse/datapack' },
|
||||
{ label: 'Shaders', href: '/browse/shader' },
|
||||
{ label: 'Resource Packs', href: '/browse/resourcepack' },
|
||||
]
|
||||
"
|
||||
/>
|
||||
</Card>
|
||||
<Card class="search-panel-container">
|
||||
<div class="search-panel">
|
||||
<div class="iconified-input">
|
||||
<SearchIcon aria-hidden="true" />
|
||||
<input
|
||||
v-model="searchStore.searchInput"
|
||||
type="text"
|
||||
:placeholder="`Search ${searchStore.projectType}s...`"
|
||||
@input="getSearchResults"
|
||||
/>
|
||||
</div>
|
||||
<span>Sort by</span>
|
||||
<DropdownSelect
|
||||
v-model="searchStore.filter"
|
||||
name="Sort dropdown"
|
||||
:options="[
|
||||
'Relevance',
|
||||
'Download count',
|
||||
'Follow count',
|
||||
'Recently published',
|
||||
'Recently updated',
|
||||
]"
|
||||
class="sort-dropdown"
|
||||
@change="getSearchResults"
|
||||
/>
|
||||
<span>Show per page</span>
|
||||
<DropdownSelect
|
||||
v-model="searchStore.limit"
|
||||
name="Limit dropdown"
|
||||
:options="[5, 10, 15, 20, 50, 100]"
|
||||
:default-value="searchStore.limit.toString()"
|
||||
:model-value="searchStore.limit.toString()"
|
||||
class="limit-dropdown"
|
||||
@change="getSearchResults"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
<Pagination
|
||||
:page="searchStore.currentPage"
|
||||
:count="searchStore.pageCount"
|
||||
@switch-page="switchPage"
|
||||
/>
|
||||
</section>
|
||||
<section class="project-list display-mode--list instance-results" role="list">
|
||||
<ProjectCard
|
||||
v-for="result in searchStore.searchResults"
|
||||
:id="`${result?.project_id}/`"
|
||||
:key="result?.project_id"
|
||||
class="result-project-item"
|
||||
:type="result?.project_type"
|
||||
:name="result?.title"
|
||||
:description="result?.description"
|
||||
:icon-url="result?.icon_url"
|
||||
:downloads="result?.downloads?.toString()"
|
||||
:follows="result?.follows?.toString()"
|
||||
:created-at="result?.date_created"
|
||||
:updated-at="result?.date_modified"
|
||||
:categories="[
|
||||
...categories.filter(
|
||||
(cat) =>
|
||||
result?.display_categories.includes(cat.name) &&
|
||||
cat.project_type === searchStore.projectType
|
||||
),
|
||||
...loaders.filter(
|
||||
(loader) =>
|
||||
result?.display_categories.includes(loader.name) &&
|
||||
loader.supported_project_types?.includes(searchStore.projectType)
|
||||
),
|
||||
]"
|
||||
:project-type-display="result?.project_type"
|
||||
project-type-url="project"
|
||||
:server-side="result?.server_side"
|
||||
:client-side="result?.client_side"
|
||||
:show-updated-date="false"
|
||||
:color="result?.color"
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
|
||||
@@ -457,4 +460,14 @@ watch(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,25 +1,34 @@
|
||||
<script setup>
|
||||
import RowDisplay from '@/components/RowDisplay.vue'
|
||||
import { shallowRef } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { list } from '@/helpers/profile.js'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useBreadcrumbs } from '@/store/breadcrumbs'
|
||||
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const breadcrumbs = useBreadcrumbs()
|
||||
|
||||
const profiles = await list()
|
||||
const recentInstances = shallowRef(Object.values(profiles))
|
||||
const loading = ref(true)
|
||||
const recentInstances = ref(null)
|
||||
|
||||
onMounted(async () => {
|
||||
recentInstances.value = Object.values(await list())
|
||||
loading.value = false
|
||||
})
|
||||
|
||||
breadcrumbs.setRootContext({ name: 'Home', link: route.path })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<RowDisplay label="Jump back in" :instances="recentInstances" :can-paginate="false" />
|
||||
<RowDisplay label="Popular packs" :instances="recentInstances" :can-paginate="true" />
|
||||
<RowDisplay label="Test" :instances="recentInstances" :can-paginate="true" />
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<SplashScreen v-if="loading" />
|
||||
<div v-else class="page-container">
|
||||
<RowDisplay label="Jump back in" :instances="recentInstances" :can-paginate="false" />
|
||||
<RowDisplay label="Popular packs" :instances="recentInstances" :can-paginate="true" />
|
||||
<RowDisplay label="Test" :instances="recentInstances" :can-paginate="true" />
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -30,4 +39,14 @@ breadcrumbs.setRootContext({ name: 'Home', link: route.path })
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
<script setup>
|
||||
import GridDisplay from '@/components/GridDisplay.vue'
|
||||
import { shallowRef } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { list } from '@/helpers/profile'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useBreadcrumbs } from '@/store/breadcrumbs'
|
||||
import { loading_listener } from '@/helpers/events.js'
|
||||
import { progress_bars_list } from '@/helpers/state.js'
|
||||
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const breadcrumbs = useBreadcrumbs()
|
||||
|
||||
const instances = shallowRef(Object.values(await list()))
|
||||
const loadingInstances = shallowRef(Object.values(await progress_bars_list()))
|
||||
const loading = ref(true)
|
||||
const instances = ref(null)
|
||||
const loadingInstances = ref(null)
|
||||
|
||||
breadcrumbs.setRootContext({ name: 'Library', link: route.path })
|
||||
|
||||
onMounted(async () => {
|
||||
instances.value = Object.values(await list())
|
||||
loadingInstances.value = Object.values(await progress_bars_list())
|
||||
loading.value = false
|
||||
})
|
||||
|
||||
loading_listener(async (profile) => {
|
||||
console.log(profile)
|
||||
instances.value = Object.values(await list())
|
||||
@@ -22,8 +31,23 @@ loading_listener(async (profile) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<GridDisplay label="Instances" :instances="instances" />
|
||||
<GridDisplay label="Modpacks" :instances="instances" />
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<SplashScreen v-if="loading" />
|
||||
<div v-else>
|
||||
<GridDisplay label="Instances" :instances="instances" />
|
||||
<GridDisplay label="Modpacks" :instances="instances" />
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import {
|
||||
Card,
|
||||
Slider,
|
||||
@@ -19,17 +19,24 @@ import { useTheming } from '@/store/state'
|
||||
import { get, set } from '@/helpers/settings'
|
||||
import { find_jre_8_jres, find_jre_17_jres, get_jre } from '@/helpers/jre'
|
||||
import { open } from '@tauri-apps/api/dialog'
|
||||
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||
|
||||
const themeStore = useTheming()
|
||||
|
||||
const fetchSettings = await get()
|
||||
const settings = ref(null)
|
||||
const loading = ref(true)
|
||||
|
||||
if (!fetchSettings.java_globals?.JAVA_8)
|
||||
fetchSettings.java_globals.JAVA_8 = { path: '', version: '' }
|
||||
if (!fetchSettings.java_globals?.JAVA_17)
|
||||
fetchSettings.java_globals.JAVA_17 = { path: '', version: '' }
|
||||
onMounted(async () => {
|
||||
const fetchSettings = await get()
|
||||
|
||||
const settings = ref(fetchSettings)
|
||||
if (!fetchSettings.java_globals?.JAVA_8)
|
||||
fetchSettings.java_globals.JAVA_8 = { path: '', version: '' }
|
||||
if (!fetchSettings.java_globals?.JAVA_17)
|
||||
fetchSettings.java_globals.JAVA_17 = { path: '', version: '' }
|
||||
|
||||
settings.value = fetchSettings
|
||||
loading.value = false
|
||||
})
|
||||
const chosenInstallOptions = ref([])
|
||||
const browsingInstall = ref(0)
|
||||
|
||||
@@ -119,232 +126,238 @@ const setJavaInstall = (javaInstall) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Modal ref="detectJavaModal" header="Select java version">
|
||||
<div class="auto-detect-modal">
|
||||
<div class="table">
|
||||
<div class="table-row table-head">
|
||||
<div class="table-cell table-text">Version</div>
|
||||
<div class="table-cell table-text">Path</div>
|
||||
<div class="table-cell table-text">Actions</div>
|
||||
</div>
|
||||
<div
|
||||
v-for="javaInstall in chosenInstallOptions"
|
||||
:key="javaInstall.path"
|
||||
class="table-row"
|
||||
>
|
||||
<div class="table-cell table-text">
|
||||
<span>{{ javaInstall.version }}</span>
|
||||
<transition name="fade">
|
||||
<SplashScreen v-if="loading" />
|
||||
<div v-else>
|
||||
<Modal ref="detectJavaModal" header="Select java version">
|
||||
<div class="auto-detect-modal">
|
||||
<div class="table">
|
||||
<div class="table-row table-head">
|
||||
<div class="table-cell table-text">Version</div>
|
||||
<div class="table-cell table-text">Path</div>
|
||||
<div class="table-cell table-text">Actions</div>
|
||||
</div>
|
||||
<div class="table-cell table-text">
|
||||
<span>{{ javaInstall.path }}</span>
|
||||
</div>
|
||||
<div class="table-cell table-text manage">
|
||||
<Button
|
||||
:disabled="
|
||||
settings.java_globals.JAVA_17.path === javaInstall.path ||
|
||||
settings.java_globals.JAVA_8.path === javaInstall.path
|
||||
"
|
||||
class="select-btn"
|
||||
@click="() => setJavaInstall(javaInstall)"
|
||||
>
|
||||
<span
|
||||
v-if="
|
||||
<div
|
||||
v-for="javaInstall in chosenInstallOptions"
|
||||
:key="javaInstall.path"
|
||||
class="table-row"
|
||||
>
|
||||
<div class="table-cell table-text">
|
||||
<span>{{ javaInstall.version }}</span>
|
||||
</div>
|
||||
<div class="table-cell table-text">
|
||||
<span>{{ javaInstall.path }}</span>
|
||||
</div>
|
||||
<div class="table-cell table-text manage">
|
||||
<Button
|
||||
:disabled="
|
||||
settings.java_globals.JAVA_17.path === javaInstall.path ||
|
||||
settings.java_globals.JAVA_8.path === javaInstall.path
|
||||
"
|
||||
class="select-btn"
|
||||
@click="() => setJavaInstall(javaInstall)"
|
||||
>
|
||||
<CheckIcon />Selected
|
||||
</span>
|
||||
<span v-else><PlusIcon />Select</span>
|
||||
</Button>
|
||||
<span
|
||||
v-if="
|
||||
settings.java_globals.JAVA_17.path === javaInstall.path ||
|
||||
settings.java_globals.JAVA_8.path === javaInstall.path
|
||||
"
|
||||
>
|
||||
<CheckIcon />Selected
|
||||
</span>
|
||||
<span v-else><PlusIcon />Select</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="chosenInstallOptions.length === 0" class="table-row entire-row">
|
||||
<div class="table-cell table-text">No JARS Found!</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="chosenInstallOptions.length === 0" class="table-row entire-row">
|
||||
<div class="table-cell table-text">No JARS Found!</div>
|
||||
</div>
|
||||
</Modal>
|
||||
<Card class="theming">
|
||||
<h2>Display</h2>
|
||||
<div class="toggle-setting">
|
||||
<div class="description">
|
||||
<h3>Color theme</h3>
|
||||
<p>Change the global launcher color theme.</p>
|
||||
</div>
|
||||
<DropdownSelect
|
||||
name="Theme dropdown"
|
||||
:options="themeStore.themeOptions"
|
||||
:default-value="settings.theme"
|
||||
:model-value="settings.theme"
|
||||
class="theme-dropdown"
|
||||
@change="handleTheme"
|
||||
/>
|
||||
</div>
|
||||
<div class="toggle-setting">
|
||||
<div class="description">
|
||||
<h3>Collapsed navigation mode</h3>
|
||||
<p>Change the style of the side navigation bar</p>
|
||||
</div>
|
||||
<Toggle
|
||||
:model-value="themeStore.collapsedNavigation"
|
||||
:checked="themeStore.collapsedNavigation"
|
||||
@update:model-value="(value) => handleCollapse(value)"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
<Card class="settings-card">
|
||||
<h2 class="settings-title">Java</h2>
|
||||
<div class="settings-group">
|
||||
<h3>Java 17 Location</h3>
|
||||
<div class="toggle-setting">
|
||||
<input
|
||||
v-model="settings.java_globals.JAVA_17.path"
|
||||
type="text"
|
||||
class="input installation-input"
|
||||
placeholder="/path/to/java17"
|
||||
/>
|
||||
<span class="installation-buttons">
|
||||
<Button @click="() => loadJavaModal(17)">
|
||||
<SearchIcon />
|
||||
Auto Detect
|
||||
</Button>
|
||||
<Button @click="handleJava17FileInput">
|
||||
<BrowseIcon />
|
||||
Browse
|
||||
</Button>
|
||||
<Button @click="handleJava17Test">
|
||||
<PlayIcon />
|
||||
Test
|
||||
</Button>
|
||||
<AnimatedLogo v-if="testingJava17 === true" class="testing-loader" />
|
||||
<CheckIcon
|
||||
v-else-if="java17Success === true && testingJava17 === false"
|
||||
class="test-success"
|
||||
/>
|
||||
<XIcon
|
||||
v-else-if="java17Success === false && testingJava17 === false"
|
||||
class="test-fail"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
<Card class="theming">
|
||||
<h2>Display</h2>
|
||||
<div class="toggle-setting">
|
||||
<div class="description">
|
||||
<h3>Color theme</h3>
|
||||
<p>Change the global launcher color theme.</p>
|
||||
<div class="settings-group">
|
||||
<h3>Java 8 Location</h3>
|
||||
<div class="toggle-setting">
|
||||
<input
|
||||
v-model="settings.java_globals.JAVA_8.path"
|
||||
type="text"
|
||||
class="input installation-input"
|
||||
placeholder="/path/to/java8"
|
||||
/>
|
||||
<span class="installation-buttons">
|
||||
<Button @click="() => loadJavaModal(8)">
|
||||
<SearchIcon />
|
||||
Auto Detect
|
||||
</Button>
|
||||
<Button @click="handleJava8FileInput">
|
||||
<BrowseIcon />
|
||||
Browse
|
||||
</Button>
|
||||
<Button @click="handleJava8Test">
|
||||
<PlayIcon />
|
||||
Test
|
||||
</Button>
|
||||
<AnimatedLogo v-if="testingJava8 === true" class="testing-loader" />
|
||||
<CheckIcon
|
||||
v-else-if="java8Success === true && testingJava8 === false"
|
||||
class="test-success"
|
||||
/>
|
||||
<XIcon
|
||||
v-else-if="java8Success === false && testingJava8 === false"
|
||||
class="test-fail"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<DropdownSelect
|
||||
name="Theme dropdown"
|
||||
:options="themeStore.themeOptions"
|
||||
:default-value="settings.theme"
|
||||
:model-value="settings.theme"
|
||||
class="theme-dropdown"
|
||||
@change="handleTheme"
|
||||
/>
|
||||
</div>
|
||||
<div class="toggle-setting">
|
||||
<div class="description">
|
||||
<h3>Collapsed navigation mode</h3>
|
||||
<p>Change the style of the side navigation bar</p>
|
||||
</div>
|
||||
<Toggle
|
||||
:model-value="themeStore.collapsedNavigation"
|
||||
:checked="themeStore.collapsedNavigation"
|
||||
@update:model-value="(value) => handleCollapse(value)"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
<Card class="settings-card">
|
||||
<h2 class="settings-title">Java</h2>
|
||||
<div class="settings-group">
|
||||
<h3>Java 17 Location</h3>
|
||||
<div class="toggle-setting">
|
||||
<hr class="card-divider" />
|
||||
<div class="settings-group">
|
||||
<h3>Java Arguments</h3>
|
||||
<input
|
||||
v-model="settings.java_globals.JAVA_17.path"
|
||||
v-model="settings.custom_java_args"
|
||||
type="text"
|
||||
class="input installation-input"
|
||||
placeholder="/path/to/java17"
|
||||
placeholder="Enter java arguments..."
|
||||
/>
|
||||
<span class="installation-buttons">
|
||||
<Button @click="() => loadJavaModal(17)">
|
||||
<SearchIcon />
|
||||
Auto Detect
|
||||
</Button>
|
||||
<Button @click="handleJava17FileInput">
|
||||
<BrowseIcon />
|
||||
Browse
|
||||
</Button>
|
||||
<Button @click="handleJava17Test">
|
||||
<PlayIcon />
|
||||
Test
|
||||
</Button>
|
||||
<AnimatedLogo v-if="testingJava17 === true" class="testing-loader" />
|
||||
<CheckIcon
|
||||
v-else-if="java17Success === true && testingJava17 === false"
|
||||
class="test-success"
|
||||
/>
|
||||
<XIcon
|
||||
v-else-if="java17Success === false && testingJava17 === false"
|
||||
class="test-fail"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-group">
|
||||
<h3>Java 8 Location</h3>
|
||||
<div class="toggle-setting">
|
||||
<div class="settings-group">
|
||||
<h3>Environment Arguments</h3>
|
||||
<input
|
||||
v-model="settings.java_globals.JAVA_8.path"
|
||||
v-model="settings.custom_env_args"
|
||||
type="text"
|
||||
class="input installation-input"
|
||||
placeholder="/path/to/java8"
|
||||
placeholder="Enter environment arguments..."
|
||||
/>
|
||||
<span class="installation-buttons">
|
||||
<Button @click="() => loadJavaModal(8)">
|
||||
<SearchIcon />
|
||||
Auto Detect
|
||||
</Button>
|
||||
<Button @click="handleJava8FileInput">
|
||||
<BrowseIcon />
|
||||
Browse
|
||||
</Button>
|
||||
<Button @click="handleJava8Test">
|
||||
<PlayIcon />
|
||||
Test
|
||||
</Button>
|
||||
<AnimatedLogo v-if="testingJava8 === true" class="testing-loader" />
|
||||
<CheckIcon
|
||||
v-else-if="java8Success === true && testingJava8 === false"
|
||||
class="test-success"
|
||||
/>
|
||||
<XIcon v-else-if="java8Success === false && testingJava8 === false" class="test-fail" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="card-divider" />
|
||||
<div class="settings-group">
|
||||
<h3>Java Arguments</h3>
|
||||
<input
|
||||
v-model="settings.custom_java_args"
|
||||
type="text"
|
||||
class="input installation-input"
|
||||
placeholder="Enter java arguments..."
|
||||
/>
|
||||
</div>
|
||||
<div class="settings-group">
|
||||
<h3>Environment Arguments</h3>
|
||||
<input
|
||||
v-model="settings.custom_env_args"
|
||||
type="text"
|
||||
class="input installation-input"
|
||||
placeholder="Enter environment arguments..."
|
||||
/>
|
||||
</div>
|
||||
<hr class="card-divider" />
|
||||
<div class="settings-group">
|
||||
<div class="sliders">
|
||||
<span class="slider">
|
||||
Minimum Memory
|
||||
<Slider v-model="settings.memory.minimum" :min="1000" :max="8200" :step="10" />
|
||||
</span>
|
||||
<span class="slider">
|
||||
Maximum Memory
|
||||
<Slider v-model="settings.memory.maximum" :min="1000" :max="8200" :step="10" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card class="settings-card">
|
||||
<h2 class="settings-title">Window Size</h2>
|
||||
<div class="settings-group">
|
||||
<hr class="card-divider" />
|
||||
<div class="settings-group">
|
||||
<div class="sliders">
|
||||
<span class="slider">
|
||||
Width
|
||||
<Slider v-model="settings.game_resolution[0]" :min="400" :max="2562" :step="2" />
|
||||
Minimum Memory
|
||||
<Slider v-model="settings.memory.minimum" :min="1000" :max="8200" :step="10" />
|
||||
</span>
|
||||
<span class="slider">
|
||||
Height
|
||||
<Slider v-model="settings.game_resolution[1]" :min="400" :max="2562" :step="2" />
|
||||
Maximum Memory
|
||||
<Slider v-model="settings.memory.maximum" :min="1000" :max="8200" :step="10" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card class="settings-card">
|
||||
<h2 class="settings-title">Launcher Settings</h2>
|
||||
<div class="settings-group">
|
||||
<h3>Resource Management</h3>
|
||||
<div class="toggle-setting">
|
||||
<span>Maximum Concurrent Downloads</span>
|
||||
<Slider
|
||||
v-model="settings.max_concurrent_downloads"
|
||||
class="concurrent-downloads"
|
||||
:min="1"
|
||||
:max="100"
|
||||
:step="1"
|
||||
/>
|
||||
</Card>
|
||||
<Card class="settings-card">
|
||||
<h2 class="settings-title">Window Size</h2>
|
||||
<div class="settings-group">
|
||||
<div class="settings-group">
|
||||
<div class="sliders">
|
||||
<span class="slider">
|
||||
Width
|
||||
<Slider v-model="settings.game_resolution[0]" :min="400" :max="2562" :step="2" />
|
||||
</span>
|
||||
<span class="slider">
|
||||
Height
|
||||
<Slider v-model="settings.game_resolution[1]" :min="400" :max="2562" :step="2" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card class="settings-card">
|
||||
<h2 class="settings-title">Commands</h2>
|
||||
<div class="settings-group">
|
||||
<div class="toggle-setting">
|
||||
Pre Launch
|
||||
<input v-model="settings.hooks.pre_launch" type="text" class="input" />
|
||||
</Card>
|
||||
<Card class="settings-card">
|
||||
<h2 class="settings-title">Launcher Settings</h2>
|
||||
<div class="settings-group">
|
||||
<h3>Resource Management</h3>
|
||||
<div class="toggle-setting">
|
||||
<span>Maximum Concurrent Downloads</span>
|
||||
<Slider
|
||||
v-model="settings.max_concurrent_downloads"
|
||||
class="concurrent-downloads"
|
||||
:min="1"
|
||||
:max="100"
|
||||
:step="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toggle-setting">
|
||||
Wrapper
|
||||
<input v-model="settings.hooks.wrapper" type="text" class="input" />
|
||||
</Card>
|
||||
<Card class="settings-card">
|
||||
<h2 class="settings-title">Commands</h2>
|
||||
<div class="settings-group">
|
||||
<div class="toggle-setting">
|
||||
Pre Launch
|
||||
<input v-model="settings.hooks.pre_launch" type="text" class="input" />
|
||||
</div>
|
||||
<div class="toggle-setting">
|
||||
Wrapper
|
||||
<input v-model="settings.hooks.wrapper" type="text" class="input" />
|
||||
</div>
|
||||
<div class="toggle-setting">
|
||||
Post Launch
|
||||
<input v-model="settings.hooks.post_exit" type="text" class="input" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="toggle-setting">
|
||||
Post Launch
|
||||
<input v-model="settings.hooks.post_exit" type="text" class="input" />
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -467,4 +480,14 @@ const setJavaInstall = (javaInstall) => {
|
||||
.test-fail {
|
||||
color: var(--color-red);
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,50 +1,53 @@
|
||||
<template>
|
||||
<div class="instance-container">
|
||||
<div class="side-cards">
|
||||
<Card class="instance-card">
|
||||
<Avatar size="lg" :src="convertFileSrc(instance.metadata.icon)" />
|
||||
<div class="instance-info">
|
||||
<h2 class="name">{{ instance.metadata.name }}</h2>
|
||||
<span class="metadata">
|
||||
{{ instance.metadata.loader }} {{ instance.metadata.game_version }}
|
||||
<transition name="fade">
|
||||
<SplashScreen v-if="loading" />
|
||||
<div v-else class="instance-container">
|
||||
<div class="side-cards">
|
||||
<Card class="instance-card">
|
||||
<Avatar size="lg" :src="convertFileSrc(instance.metadata.icon)" />
|
||||
<div class="instance-info">
|
||||
<h2 class="name">{{ instance.metadata.name }}</h2>
|
||||
<span class="metadata">
|
||||
{{ instance.metadata.loader }} {{ instance.metadata.game_version }}
|
||||
</span>
|
||||
</div>
|
||||
<span class="button-group">
|
||||
<Button
|
||||
:color="instance.installed ? 'primary' : ''"
|
||||
class="instance-button"
|
||||
:disabled="!instance.installed"
|
||||
@click="run($route.params.id)"
|
||||
>
|
||||
<PlayIcon v-if="instance.installed" />
|
||||
<AnimatedLogo v-else class="loading-icon" />
|
||||
{{ instance.installed ? 'Play' : 'Installing' }}
|
||||
</Button>
|
||||
<Button class="instance-button" icon-only>
|
||||
<OpenFolderIcon />
|
||||
</Button>
|
||||
</span>
|
||||
</Card>
|
||||
<div class="pages-list">
|
||||
<RouterLink :to="`/instance/${encodeURIComponent($route.params.id)}/`" class="btn">
|
||||
<BoxIcon />
|
||||
Mods
|
||||
</RouterLink>
|
||||
<RouterLink :to="`/instance/${encodeURIComponent($route.params.id)}/options`" class="btn">
|
||||
<SettingsIcon />
|
||||
Options
|
||||
</RouterLink>
|
||||
<RouterLink :to="`/instance/${encodeURIComponent($route.params.id)}/logs`" class="btn">
|
||||
<FileIcon />
|
||||
Logs
|
||||
</RouterLink>
|
||||
</div>
|
||||
<span class="button-group">
|
||||
<Button
|
||||
:color="instance.installed ? 'primary' : ''"
|
||||
class="instance-button"
|
||||
:disabled="!instance.installed"
|
||||
@click="run($route.params.id)"
|
||||
>
|
||||
<PlayIcon v-if="instance.installed" />
|
||||
<AnimatedLogo v-else class="loading-icon" />
|
||||
{{ instance.installed ? 'Play' : 'Installing' }}
|
||||
</Button>
|
||||
<Button class="instance-button" icon-only>
|
||||
<OpenFolderIcon />
|
||||
</Button>
|
||||
</span>
|
||||
</Card>
|
||||
<div class="pages-list">
|
||||
<RouterLink :to="`/instance/${encodeURIComponent($route.params.id)}/`" class="btn">
|
||||
<BoxIcon />
|
||||
Mods
|
||||
</RouterLink>
|
||||
<RouterLink :to="`/instance/${encodeURIComponent($route.params.id)}/options`" class="btn">
|
||||
<SettingsIcon />
|
||||
Options
|
||||
</RouterLink>
|
||||
<RouterLink :to="`/instance/${encodeURIComponent($route.params.id)}/logs`" class="btn">
|
||||
<FileIcon />
|
||||
Logs
|
||||
</RouterLink>
|
||||
</div>
|
||||
<div class="content">
|
||||
<Promotion />
|
||||
<router-view :instance="instance" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<Promotion />
|
||||
<router-view :instance="instance" />
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
<script setup>
|
||||
import {
|
||||
@@ -60,23 +63,29 @@ import {
|
||||
import { PlayIcon, OpenFolderIcon } from '@/assets/icons'
|
||||
import { get, run } from '@/helpers/profile'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { shallowRef } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { convertFileSrc } from '@tauri-apps/api/tauri'
|
||||
import { useSearch } from '@/store/search'
|
||||
import { useBreadcrumbs } from '@/store/breadcrumbs'
|
||||
import { profile_listener } from '@/helpers/events.js'
|
||||
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const searchStore = useSearch()
|
||||
const breadcrumbs = useBreadcrumbs()
|
||||
|
||||
const instance = shallowRef(await get(route.params.id))
|
||||
searchStore.instanceContext = instance.value
|
||||
const instance = ref(null)
|
||||
const loading = ref(true)
|
||||
|
||||
breadcrumbs.setName('Instance', instance.value.metadata.name)
|
||||
breadcrumbs.setContext({
|
||||
name: instance.value.metadata.name,
|
||||
link: route.path,
|
||||
onMounted(async () => {
|
||||
instance.value = await get(route.params.id)
|
||||
searchStore.instanceContext = instance.value
|
||||
breadcrumbs.setName('Instance', instance.value.metadata.name)
|
||||
breadcrumbs.setContext({
|
||||
name: instance.value.metadata.name,
|
||||
link: route.path,
|
||||
})
|
||||
loading.value = false
|
||||
})
|
||||
|
||||
profile_listener(async (event) => {
|
||||
@@ -319,4 +328,14 @@ Button {
|
||||
fill: var(--color-base) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,190 +1,201 @@
|
||||
<template>
|
||||
<div class="root-container">
|
||||
<div v-if="data" class="project-sidebar">
|
||||
<Instance v-if="instance" :instance="instance" small />
|
||||
<Card class="sidebar-card">
|
||||
<Avatar size="lg" :src="data.icon_url" />
|
||||
<div class="instance-info">
|
||||
<h2 class="name">{{ data.title }}</h2>
|
||||
{{ data.description }}
|
||||
</div>
|
||||
<Categories
|
||||
class="tags"
|
||||
type=""
|
||||
:categories="[
|
||||
...categories.filter(
|
||||
(cat) => data.categories.includes(cat.name) && cat.project_type === 'mod'
|
||||
),
|
||||
...loaders.filter(
|
||||
(loader) =>
|
||||
data.categories.includes(loader.name) &&
|
||||
loader.supported_project_types?.includes('modpack')
|
||||
),
|
||||
]"
|
||||
>
|
||||
<EnvironmentIndicator
|
||||
:client-side="data.client_side"
|
||||
:server-side="data.server_side"
|
||||
:type="data.project_type"
|
||||
<transition name="fade">
|
||||
<SplashScreen v-if="loading" />
|
||||
<div v-else class="root-container">
|
||||
<div v-if="data" class="project-sidebar">
|
||||
<Instance v-if="instance" :instance="instance" small />
|
||||
<Card class="sidebar-card">
|
||||
<Avatar size="lg" :src="data.icon_url" />
|
||||
<div class="instance-info">
|
||||
<h2 class="name">{{ data.title }}</h2>
|
||||
{{ data.description }}
|
||||
</div>
|
||||
<Categories
|
||||
class="tags"
|
||||
type=""
|
||||
:categories="[
|
||||
...categories.filter(
|
||||
(cat) => data.categories.includes(cat.name) && cat.project_type === 'mod'
|
||||
),
|
||||
...loaders.filter(
|
||||
(loader) =>
|
||||
data.categories.includes(loader.name) &&
|
||||
loader.supported_project_types?.includes('modpack')
|
||||
),
|
||||
]"
|
||||
>
|
||||
<EnvironmentIndicator
|
||||
:client-side="data.client_side"
|
||||
:server-side="data.server_side"
|
||||
:type="data.project_type"
|
||||
/>
|
||||
</Categories>
|
||||
<hr class="card-divider" />
|
||||
<div class="button-group">
|
||||
<Button
|
||||
color="primary"
|
||||
class="instance-button"
|
||||
:disabled="installed === true || installing === true"
|
||||
@click="install(null)"
|
||||
>
|
||||
<DownloadIcon v-if="!installed && !installing" />
|
||||
<CheckIcon v-else-if="installed" />
|
||||
{{ installing ? 'Installing...' : installed ? 'Installed' : 'Install' }}
|
||||
</Button>
|
||||
<a
|
||||
:href="`https://modrinth.com/${data.project_type}/${data.slug}`"
|
||||
rel="external"
|
||||
target="_blank"
|
||||
class="btn"
|
||||
>
|
||||
<ExternalIcon />
|
||||
Site
|
||||
</a>
|
||||
</div>
|
||||
<hr class="card-divider" />
|
||||
<div class="stats">
|
||||
<div class="stat">
|
||||
<DownloadIcon aria-hidden="true" />
|
||||
<p>
|
||||
<strong>{{ formatNumber(data.downloads) }}</strong>
|
||||
<span class="stat-label">
|
||||
download<span v-if="data.downloads !== '1'">s</span></span
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<HeartIcon aria-hidden="true" />
|
||||
<p>
|
||||
<strong>{{ formatNumber(data.followers) }}</strong>
|
||||
<span class="stat-label">
|
||||
follower<span v-if="data.followers !== '1'">s</span></span
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
<div class="stat date">
|
||||
<CalendarIcon aria-hidden="true" />
|
||||
<span
|
||||
><span class="date-label">Created </span>
|
||||
{{ dayjs(data.published).fromNow() }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="stat date">
|
||||
<UpdatedIcon aria-hidden="true" />
|
||||
<span
|
||||
><span class="date-label">Updated </span> {{ dayjs(data.updated).fromNow() }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="card-divider" />
|
||||
<div class="button-group">
|
||||
<Button class="instance-button">
|
||||
<ReportIcon />
|
||||
Report
|
||||
</Button>
|
||||
<Button class="instance-button">
|
||||
<HeartIcon />
|
||||
Follow
|
||||
</Button>
|
||||
</div>
|
||||
<hr class="card-divider" />
|
||||
<div class="links">
|
||||
<a
|
||||
v-if="data.issues_url"
|
||||
:href="data.issues_url"
|
||||
class="title"
|
||||
rel="noopener nofollow ugc"
|
||||
>
|
||||
<IssuesIcon aria-hidden="true" />
|
||||
<span>Issues</span>
|
||||
</a>
|
||||
<a
|
||||
v-if="data.source_url"
|
||||
:href="data.source_url"
|
||||
class="title"
|
||||
rel="noopener nofollow ugc"
|
||||
>
|
||||
<CodeIcon aria-hidden="true" />
|
||||
<span>Source</span>
|
||||
</a>
|
||||
<a v-if="data.wiki_url" :href="data.wiki_url" class="title" rel="noopener nofollow ugc">
|
||||
<WikiIcon aria-hidden="true" />
|
||||
<span>Wiki</span>
|
||||
</a>
|
||||
<a v-if="data.wiki_url" :href="data.wiki_url" class="title" rel="noopener nofollow ugc">
|
||||
<DiscordIcon aria-hidden="true" />
|
||||
<span>Discord</span>
|
||||
</a>
|
||||
<a
|
||||
v-for="(donation, index) in data.donation_urls"
|
||||
:key="index"
|
||||
:href="donation.url"
|
||||
rel="noopener nofollow ugc"
|
||||
>
|
||||
<BuyMeACoffeeIcon v-if="donation.id === 'bmac'" aria-hidden="true" />
|
||||
<PatreonIcon v-else-if="donation.id === 'patreon'" aria-hidden="true" />
|
||||
<KoFiIcon v-else-if="donation.id === 'ko-fi'" aria-hidden="true" />
|
||||
<PaypalIcon v-else-if="donation.id === 'paypal'" aria-hidden="true" />
|
||||
<OpenCollectiveIcon
|
||||
v-else-if="donation.id === 'open-collective'"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<HeartIcon v-else-if="donation.id === 'github'" />
|
||||
<CoinsIcon v-else />
|
||||
<span v-if="donation.id === 'bmac'">Buy Me a Coffee</span>
|
||||
<span v-else-if="donation.id === 'patreon'">Patreon</span>
|
||||
<span v-else-if="donation.id === 'paypal'">PayPal</span>
|
||||
<span v-else-if="donation.id === 'ko-fi'">Ko-fi</span>
|
||||
<span v-else-if="donation.id === 'github'">GitHub Sponsors</span>
|
||||
<span v-else>Donate</span>
|
||||
</a>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
<div v-if="data" class="content-container">
|
||||
<Promotion />
|
||||
<Card class="tabs">
|
||||
<NavRow
|
||||
v-if="data.gallery.length > 0"
|
||||
:links="[
|
||||
{
|
||||
label: 'Description',
|
||||
href: `/project/${$route.params.id}/`,
|
||||
},
|
||||
{
|
||||
label: 'Versions',
|
||||
href: `/project/${$route.params.id}/versions`,
|
||||
},
|
||||
{
|
||||
label: 'Gallery',
|
||||
href: `/project/${$route.params.id}/gallery`,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</Categories>
|
||||
<hr class="card-divider" />
|
||||
<div class="button-group">
|
||||
<Button
|
||||
color="primary"
|
||||
class="instance-button"
|
||||
:disabled="installed === true || installing === true"
|
||||
@click="install(null)"
|
||||
>
|
||||
<DownloadIcon v-if="!installed && !installing" />
|
||||
<CheckIcon v-else-if="installed" />
|
||||
{{ installing ? 'Installing...' : installed ? 'Installed' : 'Install' }}
|
||||
</Button>
|
||||
<a
|
||||
:href="`https://modrinth.com/${data.project_type}/${data.slug}`"
|
||||
rel="external"
|
||||
target="_blank"
|
||||
class="btn"
|
||||
>
|
||||
<ExternalIcon />
|
||||
Site
|
||||
</a>
|
||||
</div>
|
||||
<hr class="card-divider" />
|
||||
<div class="stats">
|
||||
<div class="stat">
|
||||
<DownloadIcon aria-hidden="true" />
|
||||
<p>
|
||||
<strong>{{ formatNumber(data.downloads) }}</strong>
|
||||
<span class="stat-label"> download<span v-if="data.downloads !== '1'">s</span></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<HeartIcon aria-hidden="true" />
|
||||
<p>
|
||||
<strong>{{ formatNumber(data.followers) }}</strong>
|
||||
<span class="stat-label"> follower<span v-if="data.followers !== '1'">s</span></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="stat date">
|
||||
<CalendarIcon aria-hidden="true" />
|
||||
<span
|
||||
><span class="date-label">Created </span> {{ dayjs(data.published).fromNow() }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="stat date">
|
||||
<UpdatedIcon aria-hidden="true" />
|
||||
<span
|
||||
><span class="date-label">Updated </span> {{ dayjs(data.updated).fromNow() }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="card-divider" />
|
||||
<div class="button-group">
|
||||
<Button class="instance-button">
|
||||
<ReportIcon />
|
||||
Report
|
||||
</Button>
|
||||
<Button class="instance-button">
|
||||
<HeartIcon />
|
||||
Follow
|
||||
</Button>
|
||||
</div>
|
||||
<hr class="card-divider" />
|
||||
<div class="links">
|
||||
<a
|
||||
v-if="data.issues_url"
|
||||
:href="data.issues_url"
|
||||
class="title"
|
||||
rel="noopener nofollow ugc"
|
||||
>
|
||||
<IssuesIcon aria-hidden="true" />
|
||||
<span>Issues</span>
|
||||
</a>
|
||||
<a
|
||||
v-if="data.source_url"
|
||||
:href="data.source_url"
|
||||
class="title"
|
||||
rel="noopener nofollow ugc"
|
||||
>
|
||||
<CodeIcon aria-hidden="true" />
|
||||
<span>Source</span>
|
||||
</a>
|
||||
<a v-if="data.wiki_url" :href="data.wiki_url" class="title" rel="noopener nofollow ugc">
|
||||
<WikiIcon aria-hidden="true" />
|
||||
<span>Wiki</span>
|
||||
</a>
|
||||
<a v-if="data.wiki_url" :href="data.wiki_url" class="title" rel="noopener nofollow ugc">
|
||||
<DiscordIcon aria-hidden="true" />
|
||||
<span>Discord</span>
|
||||
</a>
|
||||
<a
|
||||
v-for="(donation, index) in data.donation_urls"
|
||||
:key="index"
|
||||
:href="donation.url"
|
||||
rel="noopener nofollow ugc"
|
||||
>
|
||||
<BuyMeACoffeeIcon v-if="donation.id === 'bmac'" aria-hidden="true" />
|
||||
<PatreonIcon v-else-if="donation.id === 'patreon'" aria-hidden="true" />
|
||||
<KoFiIcon v-else-if="donation.id === 'ko-fi'" aria-hidden="true" />
|
||||
<PaypalIcon v-else-if="donation.id === 'paypal'" aria-hidden="true" />
|
||||
<OpenCollectiveIcon v-else-if="donation.id === 'open-collective'" aria-hidden="true" />
|
||||
<HeartIcon v-else-if="donation.id === 'github'" />
|
||||
<CoinsIcon v-else />
|
||||
<span v-if="donation.id === 'bmac'">Buy Me a Coffee</span>
|
||||
<span v-else-if="donation.id === 'patreon'">Patreon</span>
|
||||
<span v-else-if="donation.id === 'paypal'">PayPal</span>
|
||||
<span v-else-if="donation.id === 'ko-fi'">Ko-fi</span>
|
||||
<span v-else-if="donation.id === 'github'">GitHub Sponsors</span>
|
||||
<span v-else>Donate</span>
|
||||
</a>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
<div v-if="data" class="content-container">
|
||||
<Promotion />
|
||||
<Card class="tabs">
|
||||
<NavRow
|
||||
v-if="data.gallery.length > 0"
|
||||
:links="[
|
||||
{
|
||||
label: 'Description',
|
||||
href: `/project/${$route.params.id}/`,
|
||||
},
|
||||
{
|
||||
label: 'Versions',
|
||||
href: `/project/${$route.params.id}/versions`,
|
||||
},
|
||||
{
|
||||
label: 'Gallery',
|
||||
href: `/project/${$route.params.id}/gallery`,
|
||||
},
|
||||
]"
|
||||
<NavRow
|
||||
v-else
|
||||
:links="[
|
||||
{
|
||||
label: 'Description',
|
||||
href: `/project/${$route.params.id}/`,
|
||||
},
|
||||
{
|
||||
label: 'Versions',
|
||||
href: `/project/${$route.params.id}/versions`,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</Card>
|
||||
<RouterView
|
||||
:project="data"
|
||||
:versions="versions"
|
||||
:members="members"
|
||||
:dependencies="dependencies"
|
||||
:install="install"
|
||||
:installed="installed"
|
||||
/>
|
||||
<NavRow
|
||||
v-else
|
||||
:links="[
|
||||
{
|
||||
label: 'Description',
|
||||
href: `/project/${$route.params.id}/`,
|
||||
},
|
||||
{
|
||||
label: 'Versions',
|
||||
href: `/project/${$route.params.id}/versions`,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</Card>
|
||||
<RouterView
|
||||
:project="data"
|
||||
:versions="versions"
|
||||
:members="members"
|
||||
:dependencies="dependencies"
|
||||
:install="install"
|
||||
:installed="installed"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<InstallConfirmModal ref="confirmModal" />
|
||||
<InstanceInstallModal ref="modInstallModal" />
|
||||
</template>
|
||||
@@ -226,37 +237,51 @@ import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { ofetch } from 'ofetch'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ref, shallowRef, watch } from 'vue'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import { checkInstalled, installVersionDependencies } from '@/helpers/utils'
|
||||
import InstallConfirmModal from '@/components/ui/InstallConfirmModal.vue'
|
||||
import InstanceInstallModal from '@/components/ui/InstanceInstallModal.vue'
|
||||
import Instance from '@/components/ui/Instance.vue'
|
||||
import { useSearch } from '@/store/search'
|
||||
import { useBreadcrumbs } from '@/store/breadcrumbs'
|
||||
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||
|
||||
const searchStore = useSearch()
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const breadcrumbs = useBreadcrumbs()
|
||||
const loading = ref(true)
|
||||
|
||||
const confirmModal = ref(null)
|
||||
const modInstallModal = ref(null)
|
||||
const loaders = ref(await get_loaders())
|
||||
const categories = ref(await get_categories())
|
||||
const loaders = ref(null)
|
||||
const categories = ref(null)
|
||||
const instance = ref(searchStore.instanceContext)
|
||||
const installing = ref(false)
|
||||
|
||||
const [data, versions, members, dependencies] = await Promise.all([
|
||||
ofetch(`https://api.modrinth.com/v2/project/${route.params.id}`).then(shallowRef),
|
||||
ofetch(`https://api.modrinth.com/v2/project/${route.params.id}/version`).then(shallowRef),
|
||||
ofetch(`https://api.modrinth.com/v2/project/${route.params.id}/members`).then(shallowRef),
|
||||
ofetch(`https://api.modrinth.com/v2/project/${route.params.id}/dependencies`).then(shallowRef),
|
||||
])
|
||||
const data = ref(null)
|
||||
const versions = ref(null)
|
||||
const members = ref(null)
|
||||
const dependencies = ref(null)
|
||||
const installed = ref(false)
|
||||
|
||||
const installed = ref(instance.value && checkInstalled(instance.value, data.value.id))
|
||||
onMounted(async () => {
|
||||
;[data.value, versions.value, members.value, dependencies.value] = await Promise.all([
|
||||
ofetch(`https://api.modrinth.com/v2/project/${route.params.id}`),
|
||||
ofetch(`https://api.modrinth.com/v2/project/${route.params.id}/version`),
|
||||
ofetch(`https://api.modrinth.com/v2/project/${route.params.id}/members`),
|
||||
ofetch(`https://api.modrinth.com/v2/project/${route.params.id}/dependencies`),
|
||||
])
|
||||
|
||||
breadcrumbs.setName('Project', data.value.title)
|
||||
loaders.value = await get_loaders()
|
||||
categories.value = await get_categories()
|
||||
|
||||
loading.value = false
|
||||
|
||||
installed.value = instance.value && checkInstalled(instance.value, data.value.id)
|
||||
breadcrumbs.setName('Project', data.value.title)
|
||||
})
|
||||
|
||||
watch(
|
||||
() => route.params.id,
|
||||
@@ -291,7 +316,7 @@ async function install(version) {
|
||||
.map((value) => value.metadata)
|
||||
.find((pack) => pack.linked_data?.project_id === data.value.id)
|
||||
) {
|
||||
let id = await packInstall(queuedVersionData.id)
|
||||
let id = await packInstall(queuedVersionData.id, data.value.title)
|
||||
await router.push({ path: `/instance/${encodeURIComponent(id)}` })
|
||||
} else {
|
||||
confirmModal.value.show(queuedVersionData.id)
|
||||
@@ -487,4 +512,14 @@ async function install(version) {
|
||||
color: var(--color-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user