feat: add download button to audio preview player (#8628)

## Summary
- Adds a download icon button to the `AudioPreviewPlayer` widget for
PreviewAudio and SaveAudio nodes
- Reuses the existing `downloadFile` utility (same as video download)
- Button appears inline next to volume/options controls, matching the
player's existing UI style

## Test plan
- [x] Add a PreviewAudio or SaveAudio node, run a workflow that produces
audio output
- [x] Verify the download icon appears in the audio player controls
- [x] Click the download button and confirm the audio file downloads
correctly
- [x] Verify the button does not appear when no audio is loaded


https://github.com/user-attachments/assets/7fb2df16-82a6-40aa-a938-aed57032e30b

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8628-feat-add-download-button-to-audio-preview-player-2fe6d73d365081e3997fc45d3bb8cffc)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Johnpaul Chiwetelu
2026-02-06 01:35:32 +01:00
committed by GitHub
parent 478cfc0b5e
commit 7d3d00858a
4 changed files with 134 additions and 15 deletions

View File

@@ -16,11 +16,11 @@
<!-- Left Actions -->
<div class="relative flex shrink-0 items-center justify-start gap-2">
<!-- Play/Pause Button -->
<div
role="button"
:tabindex="0"
<Button
variant="textonly"
size="unset"
:aria-label="$t('g.playPause')"
class="flex size-6 cursor-pointer items-center justify-center rounded hover:bg-interface-menu-component-surface-hovered"
class="size-6 rounded"
@click="togglePlayPause"
>
<i
@@ -28,7 +28,7 @@
class="text-secondary icon-[lucide--play] size-4"
/>
<i v-else class="text-secondary icon-[lucide--pause] size-4" />
</div>
</Button>
<!-- Time Display -->
<div class="text-sm font-normal text-nowrap text-base-foreground">
@@ -57,11 +57,11 @@
<!-- Right Actions -->
<div class="relative flex shrink-0 items-center justify-start gap-2">
<!-- Volume Button -->
<div
role="button"
:tabindex="0"
<Button
variant="textonly"
size="unset"
:aria-label="$t('g.volume')"
class="flex size-6 cursor-pointer items-center justify-center rounded hover:bg-interface-menu-component-surface-hovered"
class="size-6 rounded"
@click="toggleMute"
>
<i
@@ -73,19 +73,32 @@
class="text-secondary icon-[lucide--volume-1] size-4"
/>
<i v-else class="text-secondary icon-[lucide--volume-x] size-4" />
</div>
</Button>
<!-- Download Button -->
<Button
v-if="modelValue"
size="icon-sm"
variant="textonly"
:aria-label="$t('g.downloadAudio')"
:title="$t('g.downloadAudio')"
class="size-6 hover:bg-interface-menu-component-surface-hovered"
@click="handleDownload"
>
<i class="text-secondary icon-[lucide--download] size-4" />
</Button>
<!-- Options Button -->
<div
<Button
v-if="showOptionsButton"
role="button"
:tabindex="0"
variant="textonly"
size="unset"
:aria-label="$t('g.moreOptions')"
class="flex size-6 cursor-pointer items-center justify-center rounded hover:bg-interface-menu-component-surface-hovered"
class="size-6 rounded"
@click="toggleOptionsMenu"
>
<i class="text-secondary icon-[lucide--more-vertical] size-4" />
</div>
</Button>
</div>
<!-- Options Menu -->
@@ -137,11 +150,16 @@ import { computed, ref, useTemplateRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { whenever } from '@vueuse/core'
import { useToast } from 'primevue/usetoast'
import { downloadFile } from '@/base/common/downloadUtil'
import Button from '@/components/ui/button/Button.vue'
import { cn } from '@/utils/tailwindUtil'
import { formatTime } from '../../utils/audioUtils'
const { t } = useI18n()
const toast = useToast()
const props = withDefaults(
defineProps<{
@@ -187,6 +205,20 @@ const togglePlayPause = () => {
isPlaying.value = !isPlaying.value
}
const handleDownload = () => {
if (!modelValue.value) return
try {
downloadFile(modelValue.value)
} catch {
toast.add({
severity: 'error',
summary: t('g.error'),
detail: t('g.failedToDownloadFile'),
life: 3000
})
}
}
const toggleMute = () => {
if (audioRef.value) {
isMuted.value = !isMuted.value