fix(front): consistent header on track detail

This commit is contained in:
ArneBo 2025-04-09 14:56:05 +02:00
parent 8d775fc5ed
commit 378455b0eb
2 changed files with 260 additions and 268 deletions

View File

@ -18,6 +18,7 @@ import TrackPlaylistIcon from '~/components/playlists/TrackPlaylistIcon.vue'
import EmbedWizard from '~/components/audio/EmbedWizard.vue' import EmbedWizard from '~/components/audio/EmbedWizard.vue'
import HumanDuration from '~/components/common/HumanDuration.vue' import HumanDuration from '~/components/common/HumanDuration.vue'
import Layout from '~/components/ui/Layout.vue' import Layout from '~/components/ui/Layout.vue'
import Header from '~/components/ui/Header.vue'
import Loader from '~/components/ui/Loader.vue' import Loader from '~/components/ui/Loader.vue'
import Modal from '~/components/ui/Modal.vue' import Modal from '~/components/ui/Modal.vue'
import PlayButton from '~/components/audio/PlayButton.vue' import PlayButton from '~/components/audio/PlayButton.vue'
@ -153,283 +154,275 @@ watch(showDeleteModal, (newValue) => {
</script> </script>
<template> <template>
<Layout <Loader
stack v-if="isLoading"
main v-title="labels.title"
/>
<Header
v-if="track"
:h1="track.title"
:action="{
text: labels.download,
to: downloadUrl,
solid: true,
primary: true,
icon: 'bi-download',
lowHeight: true
}"
page-heading
> >
<Loader <template #image>
v-if="isLoading" <img
v-title="labels.title" v-if="track.cover"
v-lazy="store.getters['instance/absoluteUrl'](track.cover.urls.large_square_crop)"
alt=""
class="channel-image"
>
<img
v-if="track.album && track.album.cover"
v-lazy="store.getters['instance/absoluteUrl'](track.album.cover.urls.large_square_crop)"
alt=""
class="channel-image"
>
<img
v-else
alt=""
class="channel-image"
src="../../assets/audio/default-cover.png"
>
</template>
<artist-credit-label
:artist-credit="track.artist_credit"
/> />
<template v-if="track"> <div class="meta">
<Layout flex> <span>{{ t('components.library.TrackBase.title') }}</span>
<img <i class="bi bi-dot" />
v-if="track.cover" <span>{{ track.album.title }}</span>
v-lazy="store.getters['instance/absoluteUrl'](track.cover.urls.large_square_crop)" <i
alt="" v-if="totalDuration > 0"
class="channel-image" class="bi bi-dot"
> />
<img <human-duration
v-if="track.album && track.album.cover" v-if="totalDuration > 0"
v-lazy="store.getters['instance/absoluteUrl'](track.album.cover.urls.large_square_crop)" :duration="totalDuration"
alt="" />
class="channel-image" </div>
>
<img
v-else
alt=""
class="channel-image"
src="../../assets/audio/default-cover.png"
>
<Layout <Layout flex>
stack <PlayButton
style="flex: 1; gap: 8px;" :is-playable="track.is_playable"
> class="vibrant"
<Layout split
flex :track="track"
no-gap low-height
style="align-items: baseline;" />
>
<h1 style="margin-top: 64px; margin-bottom: 8px;"> <Spacer
{{ track.title }} h
</h1> grow
<Spacer grow /> />
<Button
v-if="upload" <TrackFavoriteIcon
:aria-label="labels.download" v-if="store.state.auth.authenticated"
:to="downloadUrl" :track="track"
target="_blank" square-small
primary />
icon="bi-download" <TrackPlaylistIcon
:title="labels.download" v-if="store.state.auth.authenticated"
> :track="track"
{{ labels.download }} square-small
</Button> />
</Layout> <Popover v-model="open">
<artist-credit-label <template #default="{ toggleOpen }">
:artist-credit="track.artist_credit" <OptionsButton
is-square-small
@click="toggleOpen"
/> />
<div class="meta">
<span>{{ t('components.library.TrackBase.title') }}</span>
<i class="bi bi-dot" />
<span>{{ track.album.title }}</span>
<i
v-if="totalDuration > 0"
class="bi bi-dot"
/>
<human-duration
v-if="totalDuration > 0"
:duration="totalDuration"
/>
</div>
<Layout flex>
<PlayButton
:is-playable="track.is_playable"
class="vibrant"
split
:track="track"
/>
<Spacer
h
grow
/>
<TrackFavoriteIcon
v-if="store.state.auth.authenticated"
:track="track"
/>
<TrackPlaylistIcon
v-if="store.state.auth.authenticated"
:track="track"
/>
<Popover v-model="open">
<template #default="{ toggleOpen }">
<OptionsButton @click="toggleOpen" />
</template>
<template #items>
<PopoverItem
v-if="domain != store.getters['instance/domain']"
:to="track.fid"
target="_blank"
icon="bi-box-arrow-up-right"
>
{{ t('components.library.TrackBase.link.domain', { domain }) }}
</PopoverItem>
<PopoverItem
v-if="isEmbedable"
icon="bi-code-slash"
@click="showEmbedModal = !showEmbedModal"
>
{{ t('components.library.TrackBase.button.embed') }}
</PopoverItem>
<PopoverItem
:to="wikipediaUrl"
target="_blank"
rel="noreferrer noopener"
icon="bi-wikipedia"
>
{{ t('components.library.TrackBase.link.wikipedia') }}
</PopoverItem>
<PopoverItem
v-if="discogsUrl"
:to="discogsUrl"
target="_blank"
rel="noreferrer noopener"
icon="bi-box-arrow-up-right"
>
{{ t('components.library.TrackBase.link.discogs') }}
</PopoverItem>
<PopoverItem
v-if="track.is_local"
icon="bi-pencil-fill"
:to="{ name: 'library.tracks.edit', params: { id: track.id } }"
>
{{ t('components.library.TrackBase.button.edit') }}
</PopoverItem>
<PopoverItem
v-if="artist &&
store.state.auth.authenticated &&
artist.channel &&
artist.attributed_to?.full_username === store.state.auth.fullUsername"
icon="bi-trash"
@click="showDeleteModal = true"
>
{{ t('components.library.TrackBase.button.delete') }}
</PopoverItem>
<hr>
<PopoverItem
v-for="obj in getReportableObjects({ track })"
:key="obj.target.type + obj.target.id"
icon="bi-flag"
@click="report(obj)"
>
{{ obj.label }}
</PopoverItem>
<hr>
<PopoverItem
v-if="store.state.auth.availablePermissions['library']"
:to="{
name: 'manage.library.tracks.detail',
params: { id: track.id }
}"
icon="bi-wrench"
>
{{ t('components.library.TrackBase.link.moderation') }}
</PopoverItem>
<PopoverItem
v-if="store.state.auth.profile?.is_superuser"
:to="store.getters['instance/absoluteUrl'](`/api/admin/music/track/${track.id}`)"
target="_blank"
rel="noopener noreferrer"
icon="bi-wrench"
>
{{ t('components.library.TrackBase.link.django') }}
</PopoverItem>
</template>
</Popover>
</Layout>
</Layout>
</Layout>
<hr>
<Layout
flex
gap-8
>
<span v-if="track.attributed_to">
{{ t('components.library.TrackBase.subtitle.with-uploader') }}
</span>
<span v-else>
{{ t('components.library.TrackBase.subtitle.without-uploader') }}
</span>
<ActorLink
v-if="track.attributed_to"
:actor="track.attributed_to"
:avatar="false"
/>
<time
:title="track.creation_date"
:datetime="track.creation_date"
>
{{ momentFormat(new Date(track.creation_date), 'LL') }}
</time>
</Layout>
<Spacer :size="16" />
<Modal
v-if="isEmbedable"
v-model="showEmbedModal"
:title="t('components.library.TrackBase.modal.embed.header')"
>
<embed-wizard
:id="track.id"
type="track"
/>
<template #actions>
<Button
secondary
@click="showEmbedModal = false"
>
{{ t('components.library.TrackBase.button.cancel') }}
</Button>
</template> </template>
</Modal> <template #items>
<Modal <PopoverItem
v-model="showDeleteModal" v-if="domain != store.getters['instance/domain']"
:title="t('components.library.TrackBase.modal.delete.header')" :to="track.fid"
destructive target="_blank"
> icon="bi-box-arrow-up-right"
<template #alert>
<Alert red>
{{ t('components.library.TrackBase.modal.delete.content.warning') }}
</Alert>
</template>
<template #actions>
<Button
secondary
@click="showDeleteModal = false"
> >
{{ t('components.library.TrackBase.button.cancel') }} {{ t('components.library.TrackBase.link.domain', { domain }) }}
</Button> </PopoverItem>
<Button
destructive <PopoverItem
:is-loading="isLoading" v-if="isEmbedable"
@click="remove()" icon="bi-code-slash"
@click="showEmbedModal = !showEmbedModal"
>
{{ t('components.library.TrackBase.button.embed') }}
</PopoverItem>
<PopoverItem
:to="wikipediaUrl"
target="_blank"
rel="noreferrer noopener"
icon="bi-wikipedia"
>
{{ t('components.library.TrackBase.link.wikipedia') }}
</PopoverItem>
<PopoverItem
v-if="discogsUrl"
:to="discogsUrl"
target="_blank"
rel="noreferrer noopener"
icon="bi-box-arrow-up-right"
>
{{ t('components.library.TrackBase.link.discogs') }}
</PopoverItem>
<PopoverItem
v-if="track.is_local"
icon="bi-pencil-fill"
:to="{ name: 'library.tracks.edit', params: { id: track.id } }"
>
{{ t('components.library.TrackBase.button.edit') }}
</PopoverItem>
<PopoverItem
v-if="artist &&
store.state.auth.authenticated &&
artist.channel &&
artist.attributed_to?.full_username === store.state.auth.fullUsername"
icon="bi-trash"
@click="showDeleteModal = true"
> >
{{ t('components.library.TrackBase.button.delete') }} {{ t('components.library.TrackBase.button.delete') }}
</Button> </PopoverItem>
<hr>
<PopoverItem
v-for="obj in getReportableObjects({ track })"
:key="obj.target.type + obj.target.id"
icon="bi-flag"
@click="report(obj)"
>
{{ obj.label }}
</PopoverItem>
<hr>
<PopoverItem
v-if="store.state.auth.availablePermissions['library']"
:to="{
name: 'manage.library.tracks.detail',
params: { id: track.id }
}"
icon="bi-wrench"
>
{{ t('components.library.TrackBase.link.moderation') }}
</PopoverItem>
<PopoverItem
v-if="store.state.auth.profile?.is_superuser"
:to="store.getters['instance/absoluteUrl'](`/api/admin/music/track/${track.id}`)"
target="_blank"
rel="noopener noreferrer"
icon="bi-wrench"
>
{{ t('components.library.TrackBase.link.django') }}
</PopoverItem>
</template> </template>
</Modal> </Popover>
<router-view </Layout>
v-if="track" </Header>
:key="route.fullPath" <hr>
:track="track" <Layout
:object="track" flex
object-type="track" gap-8
@libraries-loaded="libraries = $event" >
/> <span v-if="track?.attributed_to">
</template> {{ t('components.library.TrackBase.subtitle.with-uploader') }}
</span>
<span v-else>
{{ t('components.library.TrackBase.subtitle.without-uploader') }}
</span>
<ActorLink
v-if="track?.attributed_to"
:actor="track?.attributed_to"
:avatar="false"
/>
<time
:title="track?.creation_date"
:datetime="track?.creation_date"
>
{{ track?.creation_date ? momentFormat(new Date(track.creation_date), 'LL') : '' }}
</time>
</Layout> </Layout>
<Spacer :size="64" />
<Modal
v-if="isEmbedable"
v-model="showEmbedModal"
:title="t('components.library.TrackBase.modal.embed.header')"
>
<embed-wizard
:id="track?.id || undefined"
type="track"
/>
<template #actions>
<Button
secondary
@click="showEmbedModal = false"
>
{{ t('components.library.TrackBase.button.cancel') }}
</Button>
</template>
</Modal>
<Modal
v-model="showDeleteModal"
:title="t('components.library.TrackBase.modal.delete.header')"
destructive
>
<template #alert>
<Alert red>
{{ t('components.library.TrackBase.modal.delete.content.warning') }}
</Alert>
</template>
<template #actions>
<Button
secondary
@click="showDeleteModal = false"
>
{{ t('components.library.TrackBase.button.cancel') }}
</Button>
<Button
destructive
:is-loading="isLoading"
@click="remove()"
>
{{ t('components.library.TrackBase.button.delete') }}
</Button>
</template>
</Modal>
<router-view
v-if="track"
:key="route.fullPath"
:track="track"
:object="track"
object-type="track"
@libraries-loaded="libraries = $event"
/>
</template> </template>
<style scoped> <style lang="scss" scoped>
.meta { .meta {
line-height: 48px; font-size: 15px;
} line-height: 32px;
@include light-theme {
color: var(--fw-gray-700);
}
@include dark-theme {
color: var(--fw-gray-500);
}
}
</style> </style>

View File

@ -147,7 +147,6 @@ const trackDetails: {
flex flex
style="gap: 24px;" style="gap: 24px;"
> >
<Spacer />
<Layout <Layout
stack stack
style="flex: 1; gap: 0;" style="flex: 1; gap: 0;"