Files
modrinth/packages/ui/src/components/version/VersionSummary.vue
T
02a7774722 fix: add download attribute to fix JAR files saving as ZIP in Chromium (#6065)
* fix: add download attribute to fix JAR files saving as ZIP in Chromium

- JAR files were downloading with a `.zip` extension in Chromium-based browsers (Chrome, Edge, Arc, Brave, Opera, Vivaldi)
- Root cause: JAR files are ZIP archives internally, so Chromium sniffs the `Content-Type` as `application/zip` and overrides the filename extension when no `download` attribute is present
- Fix: add `download="<filename>"` to all file download `<a>` tags so the browser uses the original filename from the API

* fix: add download attribute to remaining download links

Missed in initial pass: changelog page button, versions overflow
menu, settings/versions overflow menu. Also adds `download` prop
to Button and OverflowMenu to support dropdown link items.

Adds missing `getPrimaryFile` definition in changelog.vue.

---------

Co-authored-by: Mr_chank <180248271+chank-op@users.noreply.github.com>
Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com>
2026-05-15 14:58:26 +00:00

66 lines
1.8 KiB
Vue

<template>
<div
class="grid grid-cols-[min-content_auto_min-content_min-content] items-center gap-2 rounded-2xl border-[1px] border-divider bg-bg p-2"
>
<VersionChannelIndicator :channel="version.version_type" />
<div class="flex min-w-0 flex-col gap-1">
<h1 class="my-0 truncate text-nowrap text-base font-extrabold leading-none text-contrast">
{{ version.version_number }}
</h1>
<p class="m-0 truncate text-nowrap text-xs font-semibold text-secondary">
{{ version.name }}
</p>
</div>
<ButtonStyled color="brand">
<a
:href="downloadUrl"
:download="primaryFilename"
class="min-w-0"
@click="emit('onDownload')"
>
<DownloadIcon aria-hidden="true" /> Download
</a>
</ButtonStyled>
<ButtonStyled circular>
<button
class="min-w-0"
aria-label="View version"
@click="
emit('onNavigate', `/project/${props.version.project_id}/version/${props.version.id}`)
"
>
<ExternalIcon aria-hidden="true" />
</button>
</ButtonStyled>
</div>
</template>
<script setup lang="ts">
import { DownloadIcon, ExternalIcon } from '@modrinth/assets'
import type { Version, VersionFile } from '@modrinth/utils'
import { computed } from 'vue'
import { ButtonStyled, VersionChannelIndicator } from '../index'
const props = defineProps<{
version: Version
decorateDownloadUrl?: (url: string) => string
}>()
const primaryFile = computed<VersionFile>(
() => props.version.files.find((x) => x.primary) || props.version.files[0],
)
const downloadUrl = computed(() => {
const raw = primaryFile.value.url
return props.decorateDownloadUrl ? props.decorateDownloadUrl(raw) : raw
})
const primaryFilename = computed(() => primaryFile.value.filename)
const emit = defineEmits<{
onDownload: []
onNavigate: [url: string]
}>()
</script>