122 lines
3.1 KiB
Vue
122 lines
3.1 KiB
Vue
<script setup lang="ts">
|
|
import type { Track, Artist, Album, Playlist, Library, Channel, Actor } from '~/types'
|
|
import type { PlayOptionsProps } from '~/composables/audio/usePlayOptions'
|
|
import type { /* Track, */ Cover } from '~/types'
|
|
|
|
import axios from 'axios'
|
|
import PlayButton from '~/components/audio/PlayButton.vue'
|
|
import usePlayOptions from '~/composables/audio/usePlayOptions'
|
|
import { ref } from 'vue'
|
|
import useQueue from '~/composables/audio/useQueue'
|
|
|
|
interface Props extends PlayOptionsProps {
|
|
tracks: Track[]
|
|
track: Track
|
|
index: number
|
|
|
|
showArt?: boolean
|
|
displayActions?: boolean
|
|
defaultCover?: Cover | null
|
|
|
|
// TODO(wvffle): Remove after https://github.com/vuejs/core/pull/4512 is merged
|
|
isPlayable?: boolean
|
|
artist?: Artist | null
|
|
album?: Album | null
|
|
playlist?: Playlist | null
|
|
library?: Library | null
|
|
channel?: Channel | null
|
|
account?: Actor | null
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
showArt: true,
|
|
displayActions: true,
|
|
defaultCover: () => null
|
|
})
|
|
|
|
const description = ref('')
|
|
|
|
const { currentTrack } = useQueue()
|
|
const { activateTrack } = usePlayOptions(props)
|
|
|
|
const fetchData = async () => {
|
|
try {
|
|
const response = await axios.get(`tracks/${props.track.id}/`)
|
|
description.value = response.data.description.text
|
|
} catch (error) {
|
|
// TODO (wvffle): Handle error
|
|
}
|
|
}
|
|
|
|
// NOTE: Let the <Suspense> take care of showing the loader
|
|
await fetchData()
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
:class="[
|
|
{ active: currentTrack && track.id === currentTrack.id },
|
|
'track-row podcast row',
|
|
]"
|
|
@dblclick="activateTrack(track, index)"
|
|
>
|
|
<div
|
|
v-if="showArt"
|
|
class="image left floated column"
|
|
role="button"
|
|
@click.prevent.exact="activateTrack(track, index)"
|
|
>
|
|
<img
|
|
v-if="track.cover?.urls.original "
|
|
v-lazy="$store.getters['instance/absoluteUrl'](track.cover.urls.medium_square_crop)"
|
|
alt=""
|
|
class="ui artist-track mini image"
|
|
>
|
|
<img
|
|
v-else-if="defaultCover"
|
|
v-lazy="$store.getters['instance/absoluteUrl'](defaultCover.urls.medium_square_crop)"
|
|
alt=""
|
|
class="ui artist-track mini image"
|
|
>
|
|
<img
|
|
v-else
|
|
alt=""
|
|
class="ui artist-track mini image"
|
|
src="../../../assets/audio/default-cover.png"
|
|
>
|
|
</div>
|
|
<div
|
|
tabindex="0"
|
|
class="content left floated column"
|
|
>
|
|
<a
|
|
class="podcast-episode-title ellipsis"
|
|
@click.prevent.exact="activateTrack(track, index)"
|
|
>{{ track.title }}</a>
|
|
<p
|
|
v-if="description"
|
|
class="podcast-episode-meta"
|
|
>
|
|
{{ description }}
|
|
</p>
|
|
</div>
|
|
<div
|
|
v-if="displayActions"
|
|
class="meta right floated column"
|
|
>
|
|
<play-button
|
|
id="playmenu"
|
|
class="play-button basic icon"
|
|
:dropdown-only="true"
|
|
:is-playable="track.is_playable"
|
|
:dropdown-icon-classes="[
|
|
'ellipsis',
|
|
'vertical',
|
|
'large really discrete',
|
|
]"
|
|
:track="track"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|