funkwhale/front/src/ui/components/UploadList.vue

193 lines
4.1 KiB
Vue

<script setup lang="ts">
import type { UploadGroupEntry } from '~/ui/stores/upload'
import { bytesToHumanSize } from '~/ui/composables/bytes'
import { UseTimeAgo } from '@vueuse/components'
import CoverArt from '~/ui/components/CoverArt.vue'
import { Icon } from '@iconify/vue'
defineProps<{
uploads: UploadGroupEntry[]
wide?: boolean
}>()
// TODO: Delete this file, please.
</script>
<template>
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
<div class="file-list">
<div
v-for="track in uploads"
:key="track.id"
class="list-track"
:class="{ wide }"
>
<CoverArt
:src="track.metadata"
class="track-cover"
/>
<Transition mode="out-in">
<div
v-if="track.metadata?.tags"
class="track-data"
>
<div class="track-title">
{{ track.metadata.tags.title }}
</div>
{{ `${track.metadata.tags.artist} / ${track.metadata.tags.album}` }}
</div>
<div
v-else
class="track-title"
>
{{ track.file.name }}
</div>
</Transition>
<div class="upload-state">
<FwTooltip
v-if="track.failReason"
:tooltip="track.failReason"
>
<FwPill color="red">
<template #image>
<Icon
icon="bi:question"
class="h-4 w-4"
/>
</template>
failed
</FwPill>
</FwTooltip>
<FwPill
v-else
:color="track.importedAt ? 'blue' : 'secondary'"
>
{{
track.importedAt
? 'imported'
: track.progress === 100
? 'processing'
: 'uploading'
}}
</FwPill>
<div
v-if="track.importedAt"
class="track-timeago"
>
<UseTimeAgo
v-slot="{ timeAgo }"
:time="track.importedAt"
>
{{ timeAgo }}
</UseTimeAgo>
</div>
<div
v-else
class="track-progress"
>
{{ `${bytesToHumanSize(track.file.size / 100 * track.progress)}
/ ${bytesToHumanSize(track.file.size)}
⋅ ${track.progress}%` }}
</div>
</div>
<FwButton
v-if="track.failReason"
icon="bi:arrow-repeat"
variant="ghost"
color="secondary"
@click="track.retry()"
/>
<FwButton
v-else
icon="bi:chevron-right"
variant="ghost"
color="secondary"
:is-loading="!track.importedAt"
:disabled="!track.importedAt"
/>
</div>
</div>
<!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
</template>
<style scoped lang="scss">
.list-track {
display: flex;
align-items: center;
padding: .5rem 0;
&:not(:first-child) {
border-top: 1px solid var(--fw-gray-200);
}
> :deep(.track-cover) {
height: 3rem;
width: 3rem;
border-radius: 0.5rem;
margin-right: 1rem;
}
.track-data,
.track-title {
font-size: 0.875rem;
color: var(--fw-gray-960);
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
&.v-enter-active,
&.v-leave-active {
transition: transform 0.2s ease, opacity 0.2s ease;
}
&.v-enter-from {
transform: translateY(1rem);
opacity: 0;
}
&.v-leave-to {
transform: translateY(-1rem);
opacity: 0;
}
}
.track-timeago,
.track-progress {
font-size: 0.875rem;
color: var(--fw-gray-600);
}
.upload-state {
margin-left: auto;
text-align: right;
flex-shrink: 0;
padding-left: 1ch;
margin-right: 0.5rem;
:deep(.funkwhale.pill) {
margin-right: -0.5rem !important;
}
}
:deep(.funkwhale.button):not(:hover) {
background: transparent !important;
border-color: transparent !important;
}
&.wide {
.upload-state {
display: flex;
align-items: center;
margin-right: 1rem;
.track-timeago,
.track-progress {
order: -1;
margin-right: 1rem;
}
}
}
}
</style>