mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 21:26:40 +00:00
feat: create instance with content in creation flow modal
- search modpack becomes search projects - creation flow modal context receives prepareProjectInstall and createProjectInstall callbacks, from content-install.ts (shared with ContentInstallModal)
This commit is contained in:
@@ -280,8 +280,7 @@ const {
|
||||
fetchExistingInstanceNames,
|
||||
handleCreate,
|
||||
handleBrowseModpacks,
|
||||
searchModpacks,
|
||||
getProjectVersions,
|
||||
searchProjects,
|
||||
getLoaderManifest,
|
||||
setModpackAlreadyInstalledModal,
|
||||
handleModpackDuplicateCreateAnyway,
|
||||
@@ -719,6 +718,7 @@ const {
|
||||
projectInfo: contentInstallProjectInfo,
|
||||
handleInstallToInstance,
|
||||
handleCreateAndInstall,
|
||||
prepareNewInstance,
|
||||
handleNavigate: handleContentInstallNavigate,
|
||||
handleCancel: handleContentInstallCancel,
|
||||
setContentInstallModal,
|
||||
@@ -738,6 +738,35 @@ const {
|
||||
handleIncompatibilityWarningCancel: handleContentInstallIncompatibilityWarningCancel,
|
||||
} = contentInstall
|
||||
|
||||
async function prepareCreationProjectInstall(projectId, projectType) {
|
||||
if (projectType === 'modpack') {
|
||||
await contentInstall.install(
|
||||
projectId,
|
||||
null,
|
||||
null,
|
||||
'CreationModalProject',
|
||||
undefined,
|
||||
(instanceId) => void router.push(`/instance/${encodeURIComponent(instanceId)}`),
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
await prepareNewInstance(projectId)
|
||||
const info = contentInstallProjectInfo.value
|
||||
if (!info) throw new Error(`Project information is unavailable: '${projectId}'`)
|
||||
|
||||
return {
|
||||
projectId,
|
||||
title: info.title,
|
||||
iconUrl: info.iconUrl,
|
||||
link: info.link,
|
||||
owner: info.owner,
|
||||
compatibleLoaders: [...contentInstallLoaders.value],
|
||||
gameVersions: [...contentInstallGameVersions.value],
|
||||
releaseGameVersions: new Set(contentInstallReleaseGameVersions.value),
|
||||
}
|
||||
}
|
||||
|
||||
const serverInstall = createServerInstall({ router, handleError, popupNotificationManager })
|
||||
provideServerInstall(serverInstall)
|
||||
const {
|
||||
@@ -1581,8 +1610,9 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
type="instance"
|
||||
show-snapshot-toggle
|
||||
:fetch-existing-instance-names="fetchExistingInstanceNames"
|
||||
:search-modpacks="searchModpacks"
|
||||
:get-project-versions="getProjectVersions"
|
||||
:search-projects="searchProjects"
|
||||
:prepare-project-install="prepareCreationProjectInstall"
|
||||
:create-project-install="handleCreateAndInstall"
|
||||
:get-loader-manifest="getLoaderManifest"
|
||||
@create="handleCreate"
|
||||
@browse-modpacks="handleBrowseModpacks"
|
||||
|
||||
@@ -147,6 +147,7 @@ export interface ContentInstallContext {
|
||||
loader: string
|
||||
gameVersion: string
|
||||
}) => Promise<void>
|
||||
prepareNewInstance: (projectId: string) => Promise<void>
|
||||
handleNavigate: (instance: ContentInstallInstance) => void
|
||||
handleCancel: () => void
|
||||
setContentInstallModal: (ref: ModalRef) => void
|
||||
@@ -425,7 +426,12 @@ export function createContentInstall(opts: {
|
||||
project: Labrinth.Projects.v2.Project,
|
||||
versions: Labrinth.Versions.v2.Version[],
|
||||
onInstall: ContentInstallCallback,
|
||||
hints?: { preferredLoader?: string; preferredGameVersion?: string; showProjectInfo?: boolean },
|
||||
hints?: {
|
||||
preferredLoader?: string
|
||||
preferredGameVersion?: string
|
||||
showProjectInfo?: boolean
|
||||
showModal?: boolean
|
||||
},
|
||||
) {
|
||||
currentProject = project
|
||||
currentVersions = versions
|
||||
@@ -435,6 +441,7 @@ export function createContentInstall(opts: {
|
||||
loading.value = true
|
||||
defaultTab.value = 'existing'
|
||||
|
||||
let projectInfoPromise: Promise<unknown> = Promise.resolve()
|
||||
if (hints?.showProjectInfo) {
|
||||
projectInfo.value = {
|
||||
title: project.title,
|
||||
@@ -442,7 +449,7 @@ export function createContentInstall(opts: {
|
||||
link: `/project/${project.slug ?? project.id}`,
|
||||
}
|
||||
if (project.organization) {
|
||||
get_organization(project.organization)
|
||||
projectInfoPromise = get_organization(project.organization)
|
||||
.then((org: { id: string; slug: string; name: string; icon_url?: string }) => {
|
||||
if (projectInfo.value) {
|
||||
const orgSlug = org.slug ?? org.id
|
||||
@@ -459,7 +466,7 @@ export function createContentInstall(opts: {
|
||||
})
|
||||
.catch(() => {})
|
||||
} else if (project.team) {
|
||||
get_team(project.team)
|
||||
projectInfoPromise = get_team(project.team)
|
||||
.then(
|
||||
(
|
||||
members: {
|
||||
@@ -510,10 +517,12 @@ export function createContentInstall(opts: {
|
||||
: null
|
||||
|
||||
await nextTick()
|
||||
modalRef?.show()
|
||||
trackEvent('ProjectInstallStart', { source: 'ProjectInstallModal' })
|
||||
if (hints?.showModal !== false) {
|
||||
modalRef?.show()
|
||||
trackEvent('ProjectInstallStart', { source: 'ProjectInstallModal' })
|
||||
}
|
||||
|
||||
get_game_versions()
|
||||
const gameVersionMetadataPromise = get_game_versions()
|
||||
.then((allGameVersions) => {
|
||||
const releases = new Set<string>()
|
||||
const ordered: string[] = []
|
||||
@@ -560,6 +569,24 @@ export function createContentInstall(opts: {
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
await gameVersionMetadataPromise
|
||||
await projectInfoPromise
|
||||
}
|
||||
|
||||
async function prepareNewInstance(projectId: string) {
|
||||
const project: Labrinth.Projects.v2.Project = await get_project(projectId, 'must_revalidate')
|
||||
if (!project || project.project_type === 'modpack') {
|
||||
throw new Error(`Project cannot be prepared as a new instance: '${projectId}'`)
|
||||
}
|
||||
|
||||
const versions = (
|
||||
(await get_version_many(project.versions)) as Labrinth.Versions.v2.Version[]
|
||||
).sort((a, b) => dayjs(b.date_published).valueOf() - dayjs(a.date_published).valueOf())
|
||||
|
||||
await showModInstallModal(project, versions, () => {}, {
|
||||
showProjectInfo: true,
|
||||
showModal: false,
|
||||
})
|
||||
}
|
||||
|
||||
function getInstallTargets(versions: Labrinth.Versions.v2.Version[]) {
|
||||
@@ -926,6 +953,7 @@ export function createContentInstall(opts: {
|
||||
projectInfo,
|
||||
handleInstallToInstance,
|
||||
handleCreateAndInstall,
|
||||
prepareNewInstance,
|
||||
handleNavigate,
|
||||
handleCancel,
|
||||
setContentInstallModal(ref: ModalRef) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useRouter } from 'vue-router'
|
||||
import type UnknownPackWarningModal from '@/components/ui/install_flow/UnknownPackWarningModal.vue'
|
||||
import type ModpackAlreadyInstalledModal from '@/components/ui/modal/ModpackAlreadyInstalledModal.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { get_project_versions, get_search_results } from '@/helpers/cache.js'
|
||||
import { get_search_results } from '@/helpers/cache.js'
|
||||
import { import_instance } from '@/helpers/import.js'
|
||||
import {
|
||||
type CreatePackLocation,
|
||||
@@ -185,8 +185,10 @@ export function setupCreationModal(notificationManager: AbstractWebNotificationM
|
||||
router.push('/browse/modpack')
|
||||
}
|
||||
|
||||
async function searchModpacks(query: string, limit: number = 10) {
|
||||
const params = [`facets=[["project_type:modpack"]]`, `limit=${limit}`]
|
||||
async function searchProjects(query: string, limit: number = 10) {
|
||||
const projectTypes = ['mod', 'modpack', 'resourcepack', 'shader', 'datapack']
|
||||
const facets = JSON.stringify([projectTypes.map((type) => `project_type:${type}`)])
|
||||
const params = [`facets=${encodeURIComponent(facets)}`, `limit=${limit}`]
|
||||
if (query) {
|
||||
params.push(`query=${encodeURIComponent(query)}`)
|
||||
}
|
||||
@@ -195,19 +197,13 @@ export function setupCreationModal(notificationManager: AbstractWebNotificationM
|
||||
return { hits: [], offset: 0, limit, total_hits: 0 }
|
||||
}
|
||||
|
||||
async function getProjectVersions(projectId: string) {
|
||||
const versions = await get_project_versions(projectId)
|
||||
return versions ?? []
|
||||
}
|
||||
|
||||
return {
|
||||
installationModal,
|
||||
unknownPackWarningModal,
|
||||
fetchExistingInstanceNames,
|
||||
handleCreate,
|
||||
handleBrowseModpacks,
|
||||
searchModpacks,
|
||||
getProjectVersions,
|
||||
searchProjects,
|
||||
getLoaderManifest,
|
||||
setModpackAlreadyInstalledModal,
|
||||
handleModpackDuplicateCreateAnyway,
|
||||
|
||||
@@ -9,9 +9,9 @@ import {
|
||||
getStoredServerAddonInstallQueue,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
type ModpackSearchResult,
|
||||
type PendingServerContentInstall,
|
||||
type PendingServerContentInstallType,
|
||||
type ProjectSearchResult,
|
||||
readPendingServerContentInstalls,
|
||||
readStoredServerInstallQueue,
|
||||
removePendingServerContentInstall,
|
||||
@@ -69,7 +69,7 @@ export interface ServerInstallContentContext {
|
||||
installQueuedServerInstallsAndBack: () => Promise<boolean>
|
||||
initServerContext: () => Promise<void>
|
||||
watchServerContextChanges: () => void
|
||||
searchServerModpacks: (query: string, limit?: number) => Promise<ModpackSearchResult>
|
||||
searchServerModpacks: (query: string, limit?: number) => Promise<ProjectSearchResult>
|
||||
getServerProjectVersions: (projectId: string) => Promise<{ id: string }[]>
|
||||
enforceSetupModpackRoute: (currentProjectType: string | undefined) => void
|
||||
getQueuedServerInstallPlans: () => Map<string, BrowseInstallPlan<InstallableSearchResult>>
|
||||
|
||||
@@ -1,5 +1,50 @@
|
||||
<template>
|
||||
<div class="space-y-6">
|
||||
<div
|
||||
v-if="ctx.projectInstall.value"
|
||||
class="flex items-center gap-2.5 rounded-[20px] bg-surface-2 p-3"
|
||||
>
|
||||
<AutoLink :to="ctx.projectInstall.value.link" class="shrink-0">
|
||||
<div
|
||||
class="size-14 shrink-0 overflow-hidden rounded-2xl border border-solid border-surface-5"
|
||||
>
|
||||
<Avatar
|
||||
v-if="ctx.projectInstall.value.iconUrl"
|
||||
:src="ctx.projectInstall.value.iconUrl"
|
||||
:alt="ctx.projectInstall.value.title"
|
||||
size="100%"
|
||||
no-shadow
|
||||
/>
|
||||
</div>
|
||||
</AutoLink>
|
||||
<div class="flex flex-col gap-1">
|
||||
<AutoLink
|
||||
:to="ctx.projectInstall.value.link"
|
||||
class="font-semibold text-contrast hover:underline"
|
||||
>
|
||||
{{ ctx.projectInstall.value.title }}
|
||||
</AutoLink>
|
||||
<div
|
||||
v-if="ctx.projectInstall.value.owner"
|
||||
class="flex items-center gap-2 text-sm text-secondary"
|
||||
>
|
||||
<AutoLink
|
||||
:to="ctx.projectInstall.value.owner.link"
|
||||
class="flex items-center gap-1.5 text-inherit no-underline hover:underline"
|
||||
>
|
||||
<Avatar
|
||||
:src="ctx.projectInstall.value.owner.iconUrl"
|
||||
:alt="ctx.projectInstall.value.owner.name"
|
||||
size="1.25rem"
|
||||
:circle="ctx.projectInstall.value.owner.circle"
|
||||
no-shadow
|
||||
/>
|
||||
<span class="font-medium">{{ ctx.projectInstall.value.owner.name }}</span>
|
||||
</AutoLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Instance-specific: Icon upload -->
|
||||
<div v-if="ctx.flowType === 'instance'" class="flex items-center gap-4">
|
||||
<Avatar :src="ctx.instanceIconUrl.value ?? undefined" size="5rem" />
|
||||
@@ -156,6 +201,7 @@ import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useDebugLogger } from '#ui/composables/debug-logger'
|
||||
|
||||
import { injectFilePicker, injectModrinthClient, injectTags } from '../../../../providers'
|
||||
import AutoLink from '../../../base/AutoLink.vue'
|
||||
import Avatar from '../../../base/Avatar.vue'
|
||||
import ButtonStyled from '../../../base/ButtonStyled.vue'
|
||||
import Chips from '../../../base/Chips.vue'
|
||||
@@ -269,6 +315,9 @@ function formatLoaderVersionTypeLabel(type: LoaderVersionType): string {
|
||||
// For instance flow, prepend 'vanilla' to available loaders.
|
||||
// For server flows, vanilla is a separate option in the setup type stage, so exclude it here.
|
||||
const effectiveLoaders = computed(() => {
|
||||
if (ctx.projectInstall.value) {
|
||||
return ctx.projectInstall.value.compatibleLoaders
|
||||
}
|
||||
if (ctx.flowType === 'instance') {
|
||||
return ['vanilla', ...ctx.availableLoaders.filter((l) => l !== 'vanilla')]
|
||||
}
|
||||
@@ -337,6 +386,7 @@ function toApiLoaderName(loader: string): string {
|
||||
}
|
||||
|
||||
const gameVersionsLoading = computed(() => {
|
||||
if (ctx.projectInstall.value) return false
|
||||
const loader = selectedLoader.value
|
||||
if (!loader || loader === 'vanilla') return false
|
||||
if (loader === 'paper') return ctx.paperSupportedVersions.value === null
|
||||
@@ -346,6 +396,16 @@ const gameVersionsLoading = computed(() => {
|
||||
|
||||
// Game versions from tags provider, filtered by loader support
|
||||
const gameVersionOptions = computed<ComboboxOption<string>[]>(() => {
|
||||
if (ctx.projectInstall.value) {
|
||||
const versions =
|
||||
ctx.showSnapshots.value || ctx.projectInstall.value.releaseGameVersions.size === 0
|
||||
? ctx.projectInstall.value.gameVersions
|
||||
: ctx.projectInstall.value.gameVersions.filter((version) =>
|
||||
ctx.projectInstall.value!.releaseGameVersions.has(version),
|
||||
)
|
||||
return versions.map((version) => ({ value: version, label: version }))
|
||||
}
|
||||
|
||||
const versions = ctx.showSnapshots.value
|
||||
? tags.gameVersions.value
|
||||
: tags.gameVersions.value.filter((v) => v.version_type === 'release')
|
||||
@@ -510,6 +570,7 @@ function getLoaderVersionsForGameVersion(
|
||||
watch(
|
||||
() => selectedLoader.value,
|
||||
async (loader) => {
|
||||
if (ctx.projectInstall.value) return
|
||||
await fetchLoaderMetadata(loader)
|
||||
},
|
||||
{ immediate: true },
|
||||
@@ -525,6 +586,7 @@ watch(
|
||||
loaderVersionsData.value = []
|
||||
selectedLoaderVersion.value = null
|
||||
|
||||
if (ctx.projectInstall.value) return
|
||||
if (!loader || !gameVersion || loader === 'vanilla') return
|
||||
|
||||
loaderVersionsLoading.value = true
|
||||
|
||||
+59
-28
@@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-4">
|
||||
<span class="font-semibold text-contrast">
|
||||
{{ formatMessage(messages.knownModpackPrompt) }}
|
||||
{{ formatMessage(messages.knownProjectPrompt) }}
|
||||
</span>
|
||||
<Combobox
|
||||
v-model="ctx.modpackSearchProjectId.value"
|
||||
v-model="ctx.projectSearchProjectId.value"
|
||||
v-tooltip="ctx.finishDisabled.value ? ctx.finishDisabledTooltip.value : undefined"
|
||||
:options="ctx.modpackSearchOptions.value"
|
||||
:options="ctx.projectSearchOptions.value"
|
||||
searchable
|
||||
:disabled="ctx.finishDisabled.value"
|
||||
:search-placeholder="formatMessage(messages.searchModpackPlaceholder)"
|
||||
:search-placeholder="formatMessage(messages.searchProjectPlaceholder)"
|
||||
:no-options-message="
|
||||
searchLoading
|
||||
? formatMessage(commonMessages.loadingLabel)
|
||||
@@ -18,10 +18,20 @@
|
||||
:disable-search-filter="true"
|
||||
@search-input="handleSearch"
|
||||
>
|
||||
<template #option-suffix>
|
||||
<RightArrowIcon
|
||||
class="size-5 shrink-0 text-secondary opacity-0 transition-opacity group-hover/option:opacity-100 group-data-[focused=true]/option:opacity-100"
|
||||
/>
|
||||
<template #option-suffix="{ item }">
|
||||
<div
|
||||
class="flex shrink-0 items-center gap-1.5 text-sm font-semibold text-secondary opacity-0 transition-opacity group-hover/option:opacity-100 group-data-[focused=true]/option:opacity-100"
|
||||
>
|
||||
<span>
|
||||
{{
|
||||
formatMessage(
|
||||
isModpackOption(item.value) ? messages.installModpack : messages.createInstance,
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
<DownloadIcon v-if="isModpackOption(item.value)" class="size-5 shrink-0" />
|
||||
<RightArrowIcon v-else class="size-5 shrink-0" />
|
||||
</div>
|
||||
</template>
|
||||
</Combobox>
|
||||
|
||||
@@ -104,6 +114,7 @@ import {
|
||||
BoxIcon,
|
||||
BoxImportIcon,
|
||||
CompassIcon,
|
||||
DownloadIcon,
|
||||
ImportIcon,
|
||||
RightArrowIcon,
|
||||
} from '@modrinth/assets'
|
||||
@@ -126,18 +137,26 @@ const { formatMessage } = useVIntl()
|
||||
const searchLoading = ref(false)
|
||||
|
||||
const messages = defineMessages({
|
||||
knownModpackPrompt: {
|
||||
id: 'creation-flow.modal.modpack.known-modpack.prompt',
|
||||
defaultMessage: 'Already know the modpack you want to install?',
|
||||
knownProjectPrompt: {
|
||||
id: 'creation-flow.modal.project.known-project.prompt',
|
||||
defaultMessage: 'Already know what you want to play?',
|
||||
},
|
||||
searchModpackPlaceholder: {
|
||||
id: 'creation-flow.modal.modpack.search.placeholder',
|
||||
defaultMessage: 'Search for modpack',
|
||||
searchProjectPlaceholder: {
|
||||
id: 'creation-flow.modal.project.search.placeholder',
|
||||
defaultMessage: 'Search mods, modpacks, and more...',
|
||||
},
|
||||
noResultsFound: {
|
||||
id: 'creation-flow.modal.modpack.search.no-results',
|
||||
id: 'creation-flow.modal.project.search.no-results',
|
||||
defaultMessage: 'No results found',
|
||||
},
|
||||
installModpack: {
|
||||
id: 'creation-flow.modal.project.search.install-modpack',
|
||||
defaultMessage: 'Install modpack',
|
||||
},
|
||||
createInstance: {
|
||||
id: 'creation-flow.modal.project.search.create-instance',
|
||||
defaultMessage: 'Create instance',
|
||||
},
|
||||
instanceTypeTitle: {
|
||||
id: 'creation-flow.modal.setup-type.title.instance',
|
||||
defaultMessage: 'Choose instance type',
|
||||
@@ -206,6 +225,10 @@ const setupTypeTitle = computed(() => {
|
||||
return formatMessage(messages.worldTypeTitle)
|
||||
})
|
||||
|
||||
function isModpackOption(projectId: string) {
|
||||
return ctx.projectSearchHits.value[projectId]?.projectType === 'modpack'
|
||||
}
|
||||
|
||||
function setSetupType(type: 'custom' | 'vanilla') {
|
||||
debug('selected:', type)
|
||||
_setSetupType(type)
|
||||
@@ -249,18 +272,23 @@ async function triggerFileInput() {
|
||||
|
||||
async function search(query: string) {
|
||||
try {
|
||||
const results = await ctx.searchModpacks(query.trim(), 10)
|
||||
if (!query.trim()) {
|
||||
ctx.projectSearchOptions.value = []
|
||||
return
|
||||
}
|
||||
const results = await ctx.searchProjects(query.trim(), 10)
|
||||
|
||||
ctx.modpackSearchHits.value = {}
|
||||
ctx.projectSearchHits.value = {}
|
||||
for (const hit of results.hits) {
|
||||
ctx.modpackSearchHits.value[hit.project_id] = {
|
||||
ctx.projectSearchHits.value[hit.project_id] = {
|
||||
title: hit.title,
|
||||
iconUrl: hit.icon_url,
|
||||
latestVersion: hit.latest_version,
|
||||
projectType: hit.project_type ?? 'modpack',
|
||||
}
|
||||
}
|
||||
|
||||
ctx.modpackSearchOptions.value = results.hits.map((hit) => ({
|
||||
ctx.projectSearchOptions.value = results.hits.map((hit) => ({
|
||||
label: hit.title,
|
||||
value: hit.project_id,
|
||||
icon: defineAsyncComponent(() =>
|
||||
@@ -275,8 +303,8 @@ async function search(query: string) {
|
||||
),
|
||||
}))
|
||||
} catch (error) {
|
||||
debug('modpack search failed:', error)
|
||||
ctx.modpackSearchOptions.value = []
|
||||
debug('project search failed:', error)
|
||||
ctx.projectSearchOptions.value = []
|
||||
} finally {
|
||||
searchLoading.value = false
|
||||
}
|
||||
@@ -288,23 +316,26 @@ async function handleSearch(query: string) {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
ctx.modpackSearchProjectId.value = undefined
|
||||
ctx.projectSearchProjectId.value = undefined
|
||||
search('')
|
||||
})
|
||||
|
||||
watch(
|
||||
() => ctx.modpackSearchProjectId.value,
|
||||
() => ctx.projectSearchProjectId.value,
|
||||
async (projectId, oldProjectId) => {
|
||||
if (projectId === oldProjectId) return
|
||||
|
||||
ctx.modpackSearchVersionId.value = undefined
|
||||
ctx.modpackVersionOptions.value = []
|
||||
if (!projectId) return
|
||||
const hit = ctx.projectSearchHits.value[projectId]
|
||||
|
||||
if (ctx.flowType === 'instance') {
|
||||
void ctx.selectProject(projectId, hit?.projectType ?? 'mod')
|
||||
return
|
||||
}
|
||||
|
||||
const hit = ctx.modpackSearchHits.value[projectId]
|
||||
try {
|
||||
const versions = await ctx.getProjectVersions(projectId)
|
||||
if (ctx.modpackSearchProjectId.value !== projectId || versions.length === 0) return
|
||||
if (ctx.projectSearchProjectId.value !== projectId || versions.length === 0) return
|
||||
|
||||
selectModpack()
|
||||
ctx.modpackSelection.value = {
|
||||
@@ -315,7 +346,7 @@ watch(
|
||||
}
|
||||
proceedWithModpack()
|
||||
} catch (error) {
|
||||
debug('failed to load modpack versions:', error)
|
||||
debug('failed to load project versions:', error)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from '#ui/composables/i18n'
|
||||
import { formatLoaderLabel } from '#ui/utils/loaders'
|
||||
|
||||
import { createContext, injectModrinthClient } from '../../../providers'
|
||||
import { createContext, injectModrinthClient, injectNotificationManager } from '../../../providers'
|
||||
import type { ImportableLauncher } from '../../../providers/instance-import'
|
||||
import type { MultiStageModal, StageConfigInput } from '../../base'
|
||||
import type { ComboboxOption } from '../../base/Combobox.vue'
|
||||
@@ -97,15 +97,17 @@ export interface ModpackSelection {
|
||||
iconUrl?: string
|
||||
}
|
||||
|
||||
export interface ModpackSearchHit {
|
||||
export interface ProjectSearchHit {
|
||||
title: string
|
||||
iconUrl?: string
|
||||
latestVersion?: string
|
||||
projectType: string
|
||||
}
|
||||
|
||||
export interface ModpackSearchResult {
|
||||
export interface ProjectSearchResult {
|
||||
hits: {
|
||||
project_id: string
|
||||
project_type?: string
|
||||
title: string
|
||||
icon_url: string
|
||||
latest_version?: string
|
||||
@@ -115,6 +117,30 @@ export interface ModpackSearchResult {
|
||||
limit: number
|
||||
}
|
||||
|
||||
export interface ProjectInstallSelection {
|
||||
projectId: string
|
||||
title: string
|
||||
iconUrl?: string | null
|
||||
link: string
|
||||
owner?: {
|
||||
name: string
|
||||
iconUrl?: string
|
||||
circle?: boolean
|
||||
link: string | (() => void)
|
||||
} | null
|
||||
compatibleLoaders: string[]
|
||||
gameVersions: string[]
|
||||
releaseGameVersions: Set<string>
|
||||
}
|
||||
|
||||
export interface ProjectInstallCreateData {
|
||||
name: string
|
||||
iconPath: string | null
|
||||
iconPreviewUrl: string | null
|
||||
loader: string
|
||||
gameVersion: string
|
||||
}
|
||||
|
||||
export interface CreationFlowContextValue {
|
||||
// Flow
|
||||
flowType: FlowType
|
||||
@@ -165,13 +191,12 @@ export interface CreationFlowContextValue {
|
||||
modpackSelection: Ref<ModpackSelection | null>
|
||||
modpackFile: Ref<File | null>
|
||||
modpackFilePath: Ref<string | null>
|
||||
projectInstall: Ref<ProjectInstallSelection | null>
|
||||
|
||||
// Modpack search state (persisted across stage navigation)
|
||||
modpackSearchProjectId: Ref<string | undefined>
|
||||
modpackSearchVersionId: Ref<string | undefined>
|
||||
modpackSearchOptions: Ref<ComboboxOption<string>[]>
|
||||
modpackVersionOptions: Ref<ComboboxOption<string>[]>
|
||||
modpackSearchHits: Ref<Record<string, ModpackSearchHit>>
|
||||
// Project search state (persisted across stage navigation)
|
||||
projectSearchProjectId: Ref<string | undefined>
|
||||
projectSearchOptions: Ref<ComboboxOption<string>[]>
|
||||
projectSearchHits: Ref<Record<string, ProjectSearchHit>>
|
||||
|
||||
// Import state (instance flow only)
|
||||
importLaunchers: Ref<ImportableLauncher[]>
|
||||
@@ -202,13 +227,14 @@ export interface CreationFlowContextValue {
|
||||
setSetupType: (type: SetupType) => void
|
||||
setImportMode: () => void
|
||||
browseModpacks: () => void
|
||||
selectProject: (projectId: string, projectType: string) => Promise<void>
|
||||
finish: () => void
|
||||
buildProperties: () => Archon.Content.v1.PropertiesFields
|
||||
fetchLoaderMetadata: (loader?: string | null) => Promise<void>
|
||||
prefetchLoaderMetadata: () => Promise<void>
|
||||
|
||||
// Platform-provided search
|
||||
searchModpacks: (query: string, limit?: number) => Promise<ModpackSearchResult>
|
||||
searchProjects: (query: string, limit?: number) => Promise<ProjectSearchResult>
|
||||
getProjectVersions: (projectId: string) => Promise<{ id: string }[]>
|
||||
getLoaderManifest: LoaderManifestResolver | null
|
||||
}
|
||||
@@ -228,7 +254,12 @@ export interface CreationFlowOptions {
|
||||
initialGameVersion?: string
|
||||
fetchExistingInstanceNames?: () => Promise<string[]>
|
||||
onBack?: () => void
|
||||
searchModpacks?: (query: string, limit?: number) => Promise<ModpackSearchResult>
|
||||
searchProjects?: (query: string, limit?: number) => Promise<ProjectSearchResult>
|
||||
prepareProjectInstall?: (
|
||||
projectId: string,
|
||||
projectType: string,
|
||||
) => Promise<ProjectInstallSelection | null>
|
||||
createProjectInstall?: (data: ProjectInstallCreateData) => Promise<void>
|
||||
getProjectVersions?: (projectId: string) => Promise<{ id: string }[]>
|
||||
getLoaderManifest?: LoaderManifestResolver
|
||||
finishDisabled?: ComputedRef<boolean>
|
||||
@@ -246,6 +277,7 @@ export function createCreationFlowContext(
|
||||
): CreationFlowContextValue {
|
||||
const debug = useDebugLogger('CreationFlow')
|
||||
const client = injectModrinthClient()
|
||||
const { handleError } = injectNotificationManager()
|
||||
const queryClient = useQueryClient()
|
||||
const { formatMessage } = useVIntl()
|
||||
const availableLoaders = options.availableLoaders ?? ['fabric', 'neoforge', 'forge', 'quilt']
|
||||
@@ -255,7 +287,9 @@ export function createCreationFlowContext(
|
||||
const initialLoader = options.initialLoader ?? null
|
||||
const initialGameVersion = options.initialGameVersion ?? null
|
||||
const onBack = options.onBack ?? null
|
||||
const searchModpacks = options.searchModpacks!
|
||||
const searchProjects = options.searchProjects!
|
||||
const prepareProjectInstall = options.prepareProjectInstall
|
||||
const createProjectInstall = options.createProjectInstall
|
||||
const getProjectVersions = options.getProjectVersions!
|
||||
const getLoaderManifest = options.getLoaderManifest ?? null
|
||||
const finishDisabled = options.finishDisabled ?? computed(() => false)
|
||||
@@ -317,13 +351,12 @@ export function createCreationFlowContext(
|
||||
const modpackSelection = ref<ModpackSelection | null>(null)
|
||||
const modpackFile = ref<File | null>(null)
|
||||
const modpackFilePath = ref<string | null>(null)
|
||||
const projectInstall = ref<ProjectInstallSelection | null>(null)
|
||||
|
||||
// Modpack search state (persisted across stage navigation)
|
||||
const modpackSearchProjectId = ref<string | undefined>()
|
||||
const modpackSearchVersionId = ref<string | undefined>()
|
||||
const modpackSearchOptions = ref<ComboboxOption<string>[]>([])
|
||||
const modpackVersionOptions = ref<ComboboxOption<string>[]>([])
|
||||
const modpackSearchHits = ref<Record<string, ModpackSearchHit>>({})
|
||||
// Project search state (persisted across stage navigation)
|
||||
const projectSearchProjectId = ref<string | undefined>()
|
||||
const projectSearchOptions = ref<ComboboxOption<string>[]>([])
|
||||
const projectSearchHits = ref<Record<string, ProjectSearchHit>>({})
|
||||
|
||||
// Import state (instance flow only)
|
||||
const importLaunchers = ref<ImportableLauncher[]>([])
|
||||
@@ -340,7 +373,10 @@ export function createCreationFlowContext(
|
||||
|
||||
// hideLoaderVersion: hides the loader version section (vanilla world type OR vanilla selected as loader chip)
|
||||
const hideLoaderVersion = computed(
|
||||
() => setupType.value === 'vanilla' || selectedLoader.value === 'vanilla',
|
||||
() =>
|
||||
setupType.value === 'vanilla' ||
|
||||
selectedLoader.value === 'vanilla' ||
|
||||
projectInstall.value !== null,
|
||||
)
|
||||
|
||||
function toApiLoaderName(loader: string): string {
|
||||
@@ -450,11 +486,10 @@ export function createCreationFlowContext(
|
||||
modpackSelection.value = null
|
||||
modpackFile.value = null
|
||||
modpackFilePath.value = null
|
||||
modpackSearchProjectId.value = undefined
|
||||
modpackSearchVersionId.value = undefined
|
||||
modpackSearchOptions.value = []
|
||||
modpackVersionOptions.value = []
|
||||
modpackSearchHits.value = {}
|
||||
projectInstall.value = null
|
||||
projectSearchProjectId.value = undefined
|
||||
projectSearchOptions.value = []
|
||||
projectSearchHits.value = {}
|
||||
|
||||
// Import state
|
||||
importLaunchers.value = []
|
||||
@@ -470,6 +505,7 @@ export function createCreationFlowContext(
|
||||
function setSetupType(type: SetupType) {
|
||||
debug('setSetupType:', type)
|
||||
isImportMode.value = false
|
||||
projectInstall.value = null
|
||||
setupType.value = type
|
||||
if (type === 'modpack') {
|
||||
selectedLoader.value = null
|
||||
@@ -501,6 +537,37 @@ export function createCreationFlowContext(
|
||||
emit.browseModpacks()
|
||||
}
|
||||
|
||||
async function selectProject(projectId: string, projectType: string) {
|
||||
if (!prepareProjectInstall) return
|
||||
|
||||
try {
|
||||
const selection = await prepareProjectInstall(projectId, projectType)
|
||||
if (selection) {
|
||||
setProjectInstall(selection)
|
||||
} else {
|
||||
modal.value?.hide()
|
||||
}
|
||||
} catch (error) {
|
||||
projectSearchProjectId.value = undefined
|
||||
handleError(error as Error)
|
||||
}
|
||||
}
|
||||
|
||||
function setProjectInstall(selection: ProjectInstallSelection) {
|
||||
projectInstall.value = selection
|
||||
projectSearchProjectId.value = undefined
|
||||
setupType.value = 'custom'
|
||||
isImportMode.value = false
|
||||
modpackSelection.value = null
|
||||
instanceName.value = selection.title
|
||||
selectedLoader.value = selection.compatibleLoaders[0] ?? null
|
||||
selectedGameVersion.value =
|
||||
selection.gameVersions.find((version) => selection.releaseGameVersions.has(version)) ??
|
||||
selection.gameVersions[0] ??
|
||||
null
|
||||
modal.value?.setStage('custom-setup')
|
||||
}
|
||||
|
||||
function finish() {
|
||||
if (finishDisabled.value) return
|
||||
|
||||
@@ -513,6 +580,22 @@ export function createCreationFlowContext(
|
||||
hasModpackFile: !!modpackFile.value,
|
||||
})
|
||||
loading.value = true
|
||||
if (
|
||||
projectInstall.value &&
|
||||
createProjectInstall &&
|
||||
selectedLoader.value &&
|
||||
selectedGameVersion.value
|
||||
) {
|
||||
modal.value?.hide()
|
||||
void createProjectInstall({
|
||||
name: instanceName.value.trim() || projectInstall.value.title,
|
||||
iconPath: instanceIconPath.value,
|
||||
iconPreviewUrl: instanceIconUrl.value,
|
||||
loader: selectedLoader.value,
|
||||
gameVersion: selectedGameVersion.value,
|
||||
}).catch(handleError)
|
||||
return
|
||||
}
|
||||
emit.create(contextValue)
|
||||
}
|
||||
|
||||
@@ -577,11 +660,10 @@ export function createCreationFlowContext(
|
||||
modpackSelection,
|
||||
modpackFile,
|
||||
modpackFilePath,
|
||||
modpackSearchProjectId,
|
||||
modpackSearchVersionId,
|
||||
modpackSearchOptions,
|
||||
modpackVersionOptions,
|
||||
modpackSearchHits,
|
||||
projectInstall,
|
||||
projectSearchProjectId,
|
||||
projectSearchOptions,
|
||||
projectSearchHits,
|
||||
importLaunchers,
|
||||
importSelectedInstances,
|
||||
importSearchQuery,
|
||||
@@ -598,11 +680,12 @@ export function createCreationFlowContext(
|
||||
setSetupType,
|
||||
setImportMode,
|
||||
browseModpacks,
|
||||
selectProject,
|
||||
finish,
|
||||
buildProperties,
|
||||
fetchLoaderMetadata,
|
||||
prefetchLoaderMetadata,
|
||||
searchModpacks,
|
||||
searchProjects,
|
||||
getProjectVersions,
|
||||
getLoaderManifest,
|
||||
}
|
||||
|
||||
@@ -19,7 +19,9 @@ import {
|
||||
type CreationFlowContextValue,
|
||||
type FlowType,
|
||||
type LoaderManifestResolver,
|
||||
type ModpackSearchResult,
|
||||
type ProjectInstallCreateData,
|
||||
type ProjectInstallSelection,
|
||||
type ProjectSearchResult,
|
||||
provideCreationFlowContext,
|
||||
} from './creation-flow-context'
|
||||
|
||||
@@ -35,7 +37,12 @@ const props = withDefaults(
|
||||
fetchExistingInstanceNames?: () => Promise<string[]>
|
||||
onBack?: (() => void) | null
|
||||
fade?: 'standard' | 'warning' | 'danger'
|
||||
searchModpacks?: (query: string, limit?: number) => Promise<ModpackSearchResult>
|
||||
searchProjects?: (query: string, limit?: number) => Promise<ProjectSearchResult>
|
||||
prepareProjectInstall?: (
|
||||
projectId: string,
|
||||
projectType: string,
|
||||
) => Promise<ProjectInstallSelection | null>
|
||||
createProjectInstall?: (data: ProjectInstallCreateData) => Promise<void>
|
||||
getProjectVersions?: (projectId: string) => Promise<{ id: string }[]>
|
||||
getLoaderManifest?: LoaderManifestResolver
|
||||
finishDisabled?: boolean
|
||||
@@ -77,7 +84,9 @@ const ctx = createCreationFlowContext(
|
||||
initialGameVersion: props.initialGameVersion,
|
||||
fetchExistingInstanceNames: props.fetchExistingInstanceNames,
|
||||
onBack: props.onBack ?? undefined,
|
||||
searchModpacks: props.searchModpacks,
|
||||
searchProjects: props.searchProjects,
|
||||
prepareProjectInstall: props.prepareProjectInstall,
|
||||
createProjectInstall: props.createProjectInstall,
|
||||
getProjectVersions: props.getProjectVersions,
|
||||
getLoaderManifest: props.getLoaderManifest,
|
||||
finishDisabled: computed(() => props.finishDisabled ?? false),
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
:initial-loader="initialLoader"
|
||||
:initial-game-version="initialGameVersion"
|
||||
:fade="props.initialSetup ? undefined : 'danger'"
|
||||
:search-modpacks="searchModpacks"
|
||||
:search-projects="searchModpacks"
|
||||
:get-project-versions="getProjectVersions"
|
||||
:finish-disabled="!canCompleteSetup"
|
||||
:finish-disabled-tooltip="!canCompleteSetup ? permissionDeniedMessage : undefined"
|
||||
|
||||
@@ -6,7 +6,7 @@ export type {
|
||||
Gamemode,
|
||||
GeneratorSettingsMode,
|
||||
LoaderVersionType,
|
||||
ModpackSearchResult,
|
||||
ProjectSearchResult,
|
||||
SetupType,
|
||||
} from '../../flows/creation-flow-modal/creation-flow-context'
|
||||
export { default as CreationFlowModal } from '../../flows/creation-flow-modal/index.vue'
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
type="server-onboarding"
|
||||
:available-loaders="['vanilla', 'fabric', 'neoforge', 'forge', 'quilt', 'paper', 'purpur']"
|
||||
:show-snapshot-toggle="true"
|
||||
:search-modpacks="searchModpacks"
|
||||
:search-projects="searchModpacks"
|
||||
:get-project-versions="getProjectVersions"
|
||||
:finish-disabled="!canSetup"
|
||||
:finish-disabled-tooltip="!canSetup ? permissionDeniedMessage : undefined"
|
||||
|
||||
@@ -779,15 +779,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Zrušit vše"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Už víš modpack, který chceš nainstalovat?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Nenalezeny žádné výsledky"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Hledat modpack"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Instance je nastavení Minecraftu s konkrétním loaderem, verzí a módy."
|
||||
},
|
||||
@@ -4551,4 +4542,3 @@
|
||||
"defaultMessage": "Typ"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -491,12 +491,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Ryd alle"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Ingen resultater fundet"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Søg efter modpack"
|
||||
},
|
||||
"creation-flow.modal.setup-type.option.modpack-base.title": {
|
||||
"defaultMessage": "Installer modpack"
|
||||
},
|
||||
@@ -2241,4 +2235,3 @@
|
||||
"defaultMessage": "Vanilla Shader"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -884,15 +884,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Alle entfernen"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Weisst du schon, welches Modpack du installieren möchtest?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Keine Ergebnisse gefunden"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Nach Modpack suchen"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Eine Instanz ist eine Einrichtung von Minecraft mit einem bestimmten Loader, einer bestimmten Version und Mods."
|
||||
},
|
||||
@@ -5931,4 +5922,3 @@
|
||||
"defaultMessage": "Typ"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -884,15 +884,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Alle entfernen"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Weißt du schon, welches Modpack du installieren möchtest?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Keine Ergebnisse gefunden"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Nach Modpack suchen"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Eine Instanz ist eine Einrichtung von Minecraft mit einem bestimmten Loader, einer bestimmten Version und Mods."
|
||||
},
|
||||
@@ -5931,4 +5922,3 @@
|
||||
"defaultMessage": "Typ"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -884,14 +884,20 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Clear all"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Already know the modpack you want to install?"
|
||||
"creation-flow.modal.project.known-project.prompt": {
|
||||
"defaultMessage": "Already know what you want to play?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"creation-flow.modal.project.search.create-instance": {
|
||||
"defaultMessage": "Create instance"
|
||||
},
|
||||
"creation-flow.modal.project.search.install-modpack": {
|
||||
"defaultMessage": "Install modpack"
|
||||
},
|
||||
"creation-flow.modal.project.search.no-results": {
|
||||
"defaultMessage": "No results found"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Search for modpack"
|
||||
"creation-flow.modal.project.search.placeholder": {
|
||||
"defaultMessage": "Search mods, modpacks, and more..."
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "An instance is a Minecraft setup with a specific loader, version, and mods."
|
||||
|
||||
@@ -851,15 +851,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Limpiar todo"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "¿Ya sabes qué modpack quieres instalar?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "No se encontraron resultados"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Buscar un modpack"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Una instancia es una configuración de Minecraft con un loader, una versión y unos mods específicos."
|
||||
},
|
||||
@@ -5778,4 +5769,3 @@
|
||||
"defaultMessage": "Tipo"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -788,15 +788,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Borrar todo"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "¿Ya sabes cuál es el modpack que quieres instalar?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Ningún resultado encontrado"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Buscar por modpack"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Una instancia es una configuración de Minecraft con un específico loader, versión, y mods."
|
||||
},
|
||||
|
||||
@@ -884,15 +884,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Effacer tout"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Vous avez déjà le modpack en tête ?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Aucun résultat"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Rechercher un modpack"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Une instance est un setup Minecraft avec un mod loader, une version, et des mods spécifiques."
|
||||
},
|
||||
|
||||
@@ -776,15 +776,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Összes törlése"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Már tudod, melyik modcsomagot szeretnéd telepíteni?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Nincs találat"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Modcsomag keresése"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "A játékpéldány egy külön Minecraft-környezet egy adott modbetöltővel, verzióval és modokkal."
|
||||
},
|
||||
|
||||
@@ -740,9 +740,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Kosongkan semua"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Hasil pencarian tidak ditemukan"
|
||||
},
|
||||
"creation-flow.modal.setup-type.option.vanilla-minecraft.description": {
|
||||
"defaultMessage": "Minecraft klasik tanpa mod atau pasang-masuk."
|
||||
},
|
||||
@@ -2988,4 +2985,3 @@
|
||||
"defaultMessage": "Anda memiliki perubahan yang belum tersimpan."
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -860,15 +860,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Deseleziona tutto"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Sai già quale pacchetto di mod installare?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Nessun risultato trovato"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Cerca tra i pacchetti"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Un'istanza è una combinazione di loader, versione e mod per Minecraft."
|
||||
},
|
||||
|
||||
@@ -854,15 +854,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "全ての選択を解除"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "インストールしたいMODパックは既に決まっていますか?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "見つかりません"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Modパックを検索"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "インスタンスとは、特定のローダー、バージョン、およびModを備えたMinecraftの起動構成のことです"
|
||||
},
|
||||
|
||||
@@ -851,15 +851,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "모두 해제"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "설치하고 싶은 모드팩을 이미 알고 계신가요?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "결과 없음"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "모드팩 검색"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "인스턴스란 특정 로더, 버전 및 모드가 적용된 Minecraft 환경을 의미합니다."
|
||||
},
|
||||
|
||||
@@ -731,15 +731,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Kosongkan semua"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Sudah tahu pek mod yang ingin anda pasang?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Tiada hasil dijumpai"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Cari pek mod"
|
||||
},
|
||||
"creation-flow.modal.setup-type.option.custom-setup.title": {
|
||||
"defaultMessage": "Persediaan tersuai"
|
||||
},
|
||||
@@ -5028,4 +5019,3 @@
|
||||
"defaultMessage": "Jenis"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -884,15 +884,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Alles wissen"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Weet je al welk modpack je wilt installeren?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Geen resultaten gevonden"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Modpack zoeken"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Een instantie is een Minecraft-installatie met een specifieke loader, versie en mods."
|
||||
},
|
||||
|
||||
@@ -473,12 +473,6 @@
|
||||
"creation-flow.modal.import-instance.search.placeholder": {
|
||||
"defaultMessage": "Søk etter instansnavn"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Ingen resultater funnet"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Søk etter modpakke"
|
||||
},
|
||||
"external-files.permissions-card.add-files-modal.selected-count": {
|
||||
"defaultMessage": "{count, plural, one {# fil} other {# filer}} valgt"
|
||||
},
|
||||
@@ -2781,4 +2775,3 @@
|
||||
"defaultMessage": "Du har ulagrede endringer."
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -884,15 +884,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Wyczyść wszystko"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Wiesz już którą paczkę modów chcesz zainstalować?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Brak wyników wyszukiwania"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Szukaj paczki modów"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Instancja to instalacja Minecraft w danej wersji, z danym loaderem i modami."
|
||||
},
|
||||
|
||||
@@ -884,15 +884,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Limpar tudo"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Já sabe qual pacote de mods deseja instalar?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Nenhum resultado encontrado"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Buscar pacotes de mods"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Uma instância é uma configuração do Minecraft com um loader, versão e mods específicos."
|
||||
},
|
||||
|
||||
@@ -824,15 +824,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Очистить всë"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Уже знаете, какую сборку хотите скачать?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Ничего не найдено"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Поиск сборки"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Сборка — это установка Minecraft с определённым загрузчиком модов, версией и модами."
|
||||
},
|
||||
|
||||
@@ -851,15 +851,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Obriši sve"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Već znaš koji modpak želiš da instaliraš?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Nema pronađenih rezultata"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Potraži modpack"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Instanca je podešavanje Mínecrafta sa određenim programom za učitavanje, verzijom i modovima."
|
||||
},
|
||||
@@ -5778,4 +5769,3 @@
|
||||
"defaultMessage": "Tip"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -815,15 +815,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Töm allt"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Vet du redan modpaketet du vill installera?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Inga resultat hittades"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Sök efter modpaket"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "En instans är ett Minecraft-upplägg med en specifik laddare, version och moddar."
|
||||
},
|
||||
|
||||
@@ -851,15 +851,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Tümünü temizle"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Yüklemek istediğiniz mod paketini zaten biliyor musunuz?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Sonuç bulunamadı"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Mod paketi ara"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Her bir 'kurulum', kendine has yükleyicisi (modloader), sürümü ve modları olan bir Minecraft kurulumudur."
|
||||
},
|
||||
|
||||
@@ -806,15 +806,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Очистити всі"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Уже знаєте яку збірку хочете встановити?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Результатів не знайдено"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Пошук збірок"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Профіль — це налаштування Minecraft із певним завантажувачем, версією та модами."
|
||||
},
|
||||
|
||||
@@ -785,15 +785,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "Xóa hết"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "Biết modpack bạn định cài là gì rồi?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "Không tìm thấy"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "Tìm modpack"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "Cấu hình là một bản cài Minecraft với mod, phiên bản và loader của riêng nó."
|
||||
},
|
||||
@@ -5076,4 +5067,3 @@
|
||||
"defaultMessage": "Đội ngũ Modrinth"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -884,15 +884,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "清除所有"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "已经知道你想安装哪个整合包?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "未找到结果"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "搜索整合包"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "实例是带有特定加载器、游戏版本和模组的一套 Minecraft 配置。"
|
||||
},
|
||||
@@ -5931,4 +5922,3 @@
|
||||
"defaultMessage": "类型"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -884,15 +884,6 @@
|
||||
"creation-flow.modal.import-instance.selection.clear-all": {
|
||||
"defaultMessage": "清除全部"
|
||||
},
|
||||
"creation-flow.modal.modpack.known-modpack.prompt": {
|
||||
"defaultMessage": "已經選好想要安裝的模組包了嗎?"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.no-results": {
|
||||
"defaultMessage": "找不到結果"
|
||||
},
|
||||
"creation-flow.modal.modpack.search.placeholder": {
|
||||
"defaultMessage": "搜尋模組包"
|
||||
},
|
||||
"creation-flow.modal.setup-type.instance.description": {
|
||||
"defaultMessage": "實例是指具有特定載入器、版本及模組的 Minecraft 設定。"
|
||||
},
|
||||
@@ -5931,4 +5922,3 @@
|
||||
"defaultMessage": "類型"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,10 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import ButtonStyled from '../../components/base/ButtonStyled.vue'
|
||||
import type { CreationFlowContextValue } from '../../components/flows/creation-flow-modal/creation-flow-context'
|
||||
import type {
|
||||
CreationFlowContextValue,
|
||||
ProjectInstallCreateData,
|
||||
} from '../../components/flows/creation-flow-modal/creation-flow-context'
|
||||
import CreationFlowModal from '../../components/flows/creation-flow-modal/index.vue'
|
||||
|
||||
const meta = {
|
||||
@@ -106,7 +109,50 @@ export const Instance: Story = {
|
||||
const onCreate = (config: CreationFlowContextValue) => {
|
||||
lastEvent.value = `create emitted — loader: ${config.selectedLoader.value}, version: ${config.selectedGameVersion.value}`
|
||||
}
|
||||
return { modalRef, openModal, lastEvent, onCreate }
|
||||
const prepareProjectInstall = async (projectId: string, projectType: string) => {
|
||||
lastEvent.value = `project selected — ${projectId}`
|
||||
if (projectType === 'modpack') return null
|
||||
return {
|
||||
projectId,
|
||||
title: 'Fabric API',
|
||||
iconUrl: 'https://cdn.modrinth.com/data/P7dR8mSH/icon.png',
|
||||
link: '/project/fabric-api',
|
||||
compatibleLoaders: ['fabric'],
|
||||
gameVersions: ['1.21.5', '1.21.4'],
|
||||
releaseGameVersions: new Set(['1.21.5', '1.21.4']),
|
||||
}
|
||||
}
|
||||
const createProjectInstall = async (data: ProjectInstallCreateData) => {
|
||||
lastEvent.value = `project instance created — ${data.name}`
|
||||
}
|
||||
const searchProjects = async () => ({
|
||||
hits: [
|
||||
{
|
||||
project_id: 'fabric-api',
|
||||
project_type: 'mod',
|
||||
title: 'Fabric API',
|
||||
icon_url: 'https://cdn.modrinth.com/data/P7dR8mSH/icon.png',
|
||||
},
|
||||
{
|
||||
project_id: 'adrenaline',
|
||||
project_type: 'modpack',
|
||||
title: 'Adrenaline',
|
||||
icon_url: 'https://cdn.modrinth.com/data/RPYx1T0D/icon.png',
|
||||
},
|
||||
],
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
total_hits: 2,
|
||||
})
|
||||
return {
|
||||
modalRef,
|
||||
openModal,
|
||||
lastEvent,
|
||||
onCreate,
|
||||
prepareProjectInstall,
|
||||
createProjectInstall,
|
||||
searchProjects,
|
||||
}
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="flex flex-col gap-4 items-center">
|
||||
@@ -118,6 +164,9 @@ export const Instance: Story = {
|
||||
ref="modalRef"
|
||||
type="instance"
|
||||
:show-snapshot-toggle="true"
|
||||
:search-projects="searchProjects"
|
||||
:prepare-project-install="prepareProjectInstall"
|
||||
:create-project-install="createProjectInstall"
|
||||
@hide="() => {}"
|
||||
@browse-modpacks="() => console.log('browse-modpacks emitted')"
|
||||
@create="onCreate"
|
||||
|
||||
Reference in New Issue
Block a user