mirror of
https://github.com/modrinth/code.git
synced 2026-09-03 13:36:48 +00:00
feat: implement opening project download modal in place in version page
This commit is contained in:
@@ -89,7 +89,7 @@ import {
|
|||||||
} from '@modrinth/ui'
|
} from '@modrinth/ui'
|
||||||
import type { DisplayProjectType } from '@modrinth/utils'
|
import type { DisplayProjectType } from '@modrinth/utils'
|
||||||
import { useQuery } from '@tanstack/vue-query'
|
import { useQuery } from '@tanstack/vue-query'
|
||||||
import { computed, ref, watch } from 'vue'
|
import { computed, nextTick, ref, watch } from 'vue'
|
||||||
|
|
||||||
import { navigateTo } from '#app'
|
import { navigateTo } from '#app'
|
||||||
import { saveFeatureFlags } from '~/composables/featureFlags.ts'
|
import { saveFeatureFlags } from '~/composables/featureFlags.ts'
|
||||||
@@ -118,11 +118,13 @@ type NewModalRef = {
|
|||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
projectId: string
|
projectId?: string
|
||||||
downloadReason?: CdnDownloadReason
|
downloadReason?: CdnDownloadReason
|
||||||
|
useRouteHash?: boolean
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
downloadReason: 'standalone',
|
downloadReason: 'standalone',
|
||||||
|
useRouteHash: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -140,19 +142,20 @@ const debug = useDebugLogger('DownloadModal')
|
|||||||
|
|
||||||
const modal = ref<NewModalRef | null>(null)
|
const modal = ref<NewModalRef | null>(null)
|
||||||
const modalOpen = ref(false)
|
const modalOpen = ref(false)
|
||||||
|
const showProjectId = ref<string | null>(null)
|
||||||
const downloadProjectResetKey = ref(0)
|
const downloadProjectResetKey = ref(0)
|
||||||
const projectDownloadSelection = ref<ProjectDownloadSelection>({
|
const projectDownloadSelection = ref<ProjectDownloadSelection>(getDefaultProjectDownloadSelection())
|
||||||
currentGameVersion: null,
|
|
||||||
currentPlatform: null,
|
|
||||||
selectedVersion: null,
|
|
||||||
selectedPrimaryFile: null,
|
|
||||||
})
|
|
||||||
|
|
||||||
const routeProjectId = computed(() => props.projectId)
|
const routeProjectId = computed(() => showProjectId.value ?? props.projectId ?? null)
|
||||||
|
|
||||||
const { data: projectRaw, error: projectV2Error } = useQuery({
|
const {
|
||||||
|
data: projectRaw,
|
||||||
|
error: projectV2Error,
|
||||||
|
refetch: refetchProject,
|
||||||
|
} = useQuery({
|
||||||
queryKey: computed(() => ['project', 'v2', routeProjectId.value]),
|
queryKey: computed(() => ['project', 'v2', routeProjectId.value]),
|
||||||
queryFn: () => client.labrinth.projects_v2.get(routeProjectId.value),
|
queryFn: () => client.labrinth.projects_v2.get(routeProjectId.value!),
|
||||||
|
enabled: computed(() => !!routeProjectId.value),
|
||||||
staleTime: STALE_TIME,
|
staleTime: STALE_TIME,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -320,23 +323,33 @@ function onShow() {
|
|||||||
modalOpen.value = true
|
modalOpen.value = true
|
||||||
debug('on-show fired')
|
debug('on-show fired')
|
||||||
versionsEnabled.value = true
|
versionsEnabled.value = true
|
||||||
navigateTo({ query: route.query, hash: '#download' }, { replace: true })
|
if (props.useRouteHash && !showProjectId.value) {
|
||||||
|
navigateTo({ query: route.query, hash: '#download' }, { replace: true })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onHide() {
|
function onHide() {
|
||||||
|
const hadShowProjectId = !!showProjectId.value
|
||||||
modalOpen.value = false
|
modalOpen.value = false
|
||||||
navigateTo({ query: route.query, hash: '' }, { replace: true })
|
showProjectId.value = null
|
||||||
|
if (props.useRouteHash && !hadShowProjectId) {
|
||||||
|
navigateTo({ query: route.query, hash: '' }, { replace: true })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function show(event?: MouseEvent) {
|
async function show(event?: MouseEvent, projectId?: string): Promise<void> {
|
||||||
if (!modal.value || modalOpen.value) return
|
if (!modal.value || modalOpen.value) return
|
||||||
|
showProjectId.value = projectId ?? null
|
||||||
|
await nextTick()
|
||||||
|
if (!(await loadProjectForModal(!!projectId))) return
|
||||||
modalOpen.value = true
|
modalOpen.value = true
|
||||||
modal.value.show(event)
|
modal.value.show(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
async function hide() {
|
||||||
if (!modal.value || !modalOpen.value) return
|
if (!modal.value || !modalOpen.value) return
|
||||||
modal.value?.hide()
|
modal.value?.hide()
|
||||||
|
await nextTick()
|
||||||
downloadProjectResetKey.value += 1
|
downloadProjectResetKey.value += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,17 +357,43 @@ function onDownload() {
|
|||||||
emit('download')
|
emit('download')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDefaultProjectDownloadSelection(): ProjectDownloadSelection {
|
||||||
|
return {
|
||||||
|
currentGameVersion: null,
|
||||||
|
currentPlatform: null,
|
||||||
|
selectedVersion: null,
|
||||||
|
selectedPrimaryFile: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadProjectForModal(forceRefetch: boolean) {
|
||||||
|
if (!routeProjectId.value) return false
|
||||||
|
if (!forceRefetch && projectRaw.value) return true
|
||||||
|
|
||||||
|
const { data } = await refetchProject()
|
||||||
|
return !!data
|
||||||
|
}
|
||||||
|
|
||||||
function openFromHash() {
|
function openFromHash() {
|
||||||
if (!modal.value || modalOpen.value || route.hash !== '#download') return
|
if (
|
||||||
|
!props.useRouteHash ||
|
||||||
|
!modal.value ||
|
||||||
|
modalOpen.value ||
|
||||||
|
showProjectId.value ||
|
||||||
|
route.hash !== '#download'
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
debug('hash #download watch fired, opening modal')
|
debug('hash #download watch fired, opening modal')
|
||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
route.hash === '#download' ||
|
props.useRouteHash &&
|
||||||
route.query.version !== undefined ||
|
(route.hash === '#download' ||
|
||||||
route.query.loader !== undefined
|
route.query.version !== undefined ||
|
||||||
|
route.query.loader !== undefined)
|
||||||
) {
|
) {
|
||||||
debug('eager loadVersions from setup', {
|
debug('eager loadVersions from setup', {
|
||||||
hash: route.hash,
|
hash: route.hash,
|
||||||
@@ -367,6 +406,10 @@ if (
|
|||||||
|
|
||||||
watch(modal, openFromHash)
|
watch(modal, openFromHash)
|
||||||
watch(() => route.hash, openFromHash)
|
watch(() => route.hash, openFromHash)
|
||||||
|
watch(routeProjectId, () => {
|
||||||
|
projectDownloadSelection.value = getDefaultProjectDownloadSelection()
|
||||||
|
downloadProjectResetKey.value += 1
|
||||||
|
})
|
||||||
|
|
||||||
defineExpose({ show, hide })
|
defineExpose({ show, hide })
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -80,6 +80,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</NewModal>
|
</NewModal>
|
||||||
|
<ProjectDownloadModal
|
||||||
|
ref="dependencyDownloadModal"
|
||||||
|
download-reason="dependency"
|
||||||
|
:use-route-hash="false"
|
||||||
|
@download="emit('onDownload')"
|
||||||
|
/>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<nuxt-link
|
<nuxt-link
|
||||||
class="mb-4 flex w-fit items-center gap-2 rounded-lg px-2 py-0.5 pl-0 text-link"
|
class="mb-4 flex w-fit items-center gap-2 rounded-lg px-2 py-0.5 pl-0 text-link"
|
||||||
@@ -364,14 +370,14 @@
|
|||||||
>
|
>
|
||||||
<DownloadIcon />
|
<DownloadIcon />
|
||||||
</a>
|
</a>
|
||||||
<a
|
<button
|
||||||
v-else-if="dependency.project"
|
v-else-if="dependency.project"
|
||||||
v-tooltip="formatMessage(messages.downloadProject)"
|
v-tooltip="formatMessage(messages.downloadProject)"
|
||||||
:href="`/project/${dependency.project.id}#download`"
|
:aria-label="formatMessage(messages.downloadProject)"
|
||||||
target="_blank"
|
@click="openDependencyDownloadModal(dependency.project.id, $event)"
|
||||||
>
|
>
|
||||||
<DownloadIcon />
|
<DownloadIcon />
|
||||||
</a>
|
</button>
|
||||||
</ButtonStyled>
|
</ButtonStyled>
|
||||||
</template>
|
</template>
|
||||||
</VersionPage>
|
</VersionPage>
|
||||||
@@ -519,6 +525,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
|
|||||||
import { onServerPrefetch } from 'vue'
|
import { onServerPrefetch } from 'vue'
|
||||||
|
|
||||||
import CreateProjectVersionModal from '~/components/ui/create-project-version/CreateProjectVersionModal.vue'
|
import CreateProjectVersionModal from '~/components/ui/create-project-version/CreateProjectVersionModal.vue'
|
||||||
|
import ProjectDownloadModal from '~/components/ui/ProjectDownloadModal/index.vue'
|
||||||
import { getSignInRouteObj } from '~/composables/auth.ts'
|
import { getSignInRouteObj } from '~/composables/auth.ts'
|
||||||
import { projectQueryOptions, STALE_TIME } from '~/composables/queries/project'
|
import { projectQueryOptions, STALE_TIME } from '~/composables/queries/project'
|
||||||
import { versionQueryOptions } from '~/composables/queries/version'
|
import { versionQueryOptions } from '~/composables/queries/version'
|
||||||
@@ -774,6 +781,7 @@ useSeoMeta({
|
|||||||
const editModal = useTemplateRef('editModal')
|
const editModal = useTemplateRef('editModal')
|
||||||
const confirmModal = useTemplateRef('confirmModal')
|
const confirmModal = useTemplateRef('confirmModal')
|
||||||
const packageModal = useTemplateRef('packageModal')
|
const packageModal = useTemplateRef('packageModal')
|
||||||
|
const dependencyDownloadModal = useTemplateRef('dependencyDownloadModal')
|
||||||
|
|
||||||
const packageLoaders = ref(['forge', 'fabric', 'quilt', 'neoforge'])
|
const packageLoaders = ref(['forge', 'fabric', 'quilt', 'neoforge'])
|
||||||
const packageLoaderOptions = [
|
const packageLoaderOptions = [
|
||||||
@@ -796,6 +804,10 @@ function handleOpenEditVersionModal(versionId: string, projectId: string, stageI
|
|||||||
editModal.value?.openEditVersionModal(versionId, projectId, stageId)
|
editModal.value?.openEditVersionModal(versionId, projectId, stageId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openDependencyDownloadModal(projectId: string, event: MouseEvent) {
|
||||||
|
dependencyDownloadModal.value?.show(event, projectId)
|
||||||
|
}
|
||||||
|
|
||||||
const deleteVersionMutation = useMutation({
|
const deleteVersionMutation = useMutation({
|
||||||
mutationFn: () => client.labrinth.versions_v3.deleteVersion(version.value!.id),
|
mutationFn: () => client.labrinth.versions_v3.deleteVersion(version.value!.id),
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
@@ -1065,7 +1077,11 @@ function getDependencyVersion(dependency: Labrinth.Versions.v3.Dependency) {
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
return projectOnlyDependencyVersions.value?.[dependency.project_id]
|
return (
|
||||||
|
(Object.keys(projectOnlyDependencyVersions.value || {}).length === 1 &&
|
||||||
|
projectOnlyDependencyVersions.value?.[dependency.project_id]) ||
|
||||||
|
undefined
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDependencyPrimaryFile(version?: Labrinth.Versions.v2.Version) {
|
function getDependencyPrimaryFile(version?: Labrinth.Versions.v2.Version) {
|
||||||
|
|||||||
Reference in New Issue
Block a user