feat(style): consistent look and use of artist credit label on detail pages
This commit is contained in:
parent
75d4ac5467
commit
966181e480
|
@ -2,7 +2,7 @@
|
|||
import type { ArtistCredit } from '~/types'
|
||||
import { useStore } from '~/store'
|
||||
|
||||
import Link from '~/components/ui/Link.vue'
|
||||
import Pill from '~/components/ui/Pill.vue'
|
||||
|
||||
const store = useStore()
|
||||
|
||||
|
@ -23,31 +23,28 @@ const getRoute = (ac: ArtistCredit) => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="artist-label ui image label">
|
||||
<template
|
||||
v-for="ac in props.artistCredit"
|
||||
:key="ac.artist.id"
|
||||
>
|
||||
<Link
|
||||
solid
|
||||
secondary
|
||||
round
|
||||
min-content
|
||||
:to="getRoute(ac)"
|
||||
<router-link
|
||||
:to="{name: 'library.artists.detail', params: {id: ac.artist.id }}"
|
||||
@click.stop.prevent=""
|
||||
>
|
||||
<Pill>
|
||||
<template #image>
|
||||
<img
|
||||
v-if="ac.index === 0 && ac.artist.cover && ac.artist.cover.urls.original"
|
||||
v-lazy="store.getters['instance/absoluteUrl'](ac.artist.cover.urls.medium_square_crop)"
|
||||
alt=""
|
||||
:class="[{circular: ac.artist.content_category != 'podcast'}]"
|
||||
>
|
||||
<i
|
||||
v-else-if="ac.index === 0"
|
||||
:class="[ac.artist.content_category != 'podcast' ? 'circular' : 'bordered', 'inverted violet bi bi-users icon']"
|
||||
v-if="ac.artist.cover && ac.artist.cover.urls.original"
|
||||
v-lazy="store.getters['instance/absoluteUrl'](ac.artist.cover.urls.small_square_crop)"
|
||||
:alt="ac.artist.name"
|
||||
/>
|
||||
<i
|
||||
v-else
|
||||
class="bi bi-person-circle"
|
||||
/>
|
||||
</template>
|
||||
{{ ac.credit }}
|
||||
</Link>
|
||||
<span>{{ ac.joinphrase }}</span>
|
||||
</Pill>
|
||||
</router-link>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -69,7 +69,7 @@ const labels = computed(() => ({
|
|||
|
||||
const {
|
||||
isShuffled,
|
||||
shuffle
|
||||
shuffle,
|
||||
} = useQueue()
|
||||
|
||||
const isLoading = ref(false)
|
||||
|
@ -150,10 +150,7 @@ const remove = async () => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<Layout
|
||||
stack
|
||||
main
|
||||
>
|
||||
<Layout stack main>
|
||||
<Loader
|
||||
v-if="isLoading"
|
||||
v-title="labels.title"
|
||||
|
@ -165,27 +162,15 @@ const remove = async () => {
|
|||
v-lazy="store.getters['instance/absoluteUrl'](object.cover.urls.large_square_crop)"
|
||||
:alt="object.title"
|
||||
class="channel-image"
|
||||
>
|
||||
<img
|
||||
v-else-if="object.artist_credit && object.artist_credit[0] && object.artist_credit[0].artist.cover"
|
||||
v-lazy="object.artist_credit[0].artist.cover.urls.large_square_crop"
|
||||
:alt="object.artist_credit[0].artist.name"
|
||||
class="channel-image"
|
||||
>
|
||||
/>
|
||||
<img
|
||||
v-else
|
||||
alt=""
|
||||
class="channel-image"
|
||||
src="../../assets/audio/default-cover.png"
|
||||
>
|
||||
<!-- ({target}) => target -->
|
||||
<!-- Header (TODO: Put into Header component) Hint: Header is heavier fontweight than h1! -->
|
||||
<Layout
|
||||
stack
|
||||
style="flex: 1; gap: 8px;"
|
||||
>
|
||||
<h1>{{ object.title }}</h1>
|
||||
<!-- <Header :h1="object.title" /> -->
|
||||
/>
|
||||
<Layout stack style="flex: 1; gap: 8px;">
|
||||
<h1 style="margin-top: 64px; margin-bottom: 8px;">{{ object.title }}</h1>
|
||||
<artist-credit-label
|
||||
v-if="artistCredit"
|
||||
:artist-credit="artistCredit"
|
||||
|
@ -204,10 +189,7 @@ const remove = async () => {
|
|||
{{ t('components.library.AlbumBase.meta.tracks', totalTracks) }}
|
||||
</span>
|
||||
</template>
|
||||
<i
|
||||
v-if="totalDuration > 0"
|
||||
class="bi bi-dot"
|
||||
/>
|
||||
<i v-if="totalDuration > 0" class="bi bi-dot" />
|
||||
<human-duration
|
||||
v-if="totalDuration > 0"
|
||||
:duration="totalDuration"
|
||||
|
@ -242,23 +224,14 @@ const remove = async () => {
|
|||
artistCredit[0].artist.channel &&
|
||||
artistCredit[0].artist.attributed_to?.full_username === store.state.auth.fullUsername"
|
||||
:is-loading="isLoading"
|
||||
icon="bi-trash"
|
||||
@confirm="remove()"
|
||||
icon="bi-trash"
|
||||
>
|
||||
{{ t('components.library.AlbumDropdown.button.delete') }}
|
||||
</DangerousButton>
|
||||
<Spacer
|
||||
h
|
||||
grow
|
||||
/>
|
||||
<TrackFavoriteIcon
|
||||
v-if="store.state.auth.authenticated"
|
||||
:album="object"
|
||||
/>
|
||||
<TrackPlaylistIcon
|
||||
v-if="store.state.auth.authenticated"
|
||||
:album="object"
|
||||
/>
|
||||
<Spacer h grow />
|
||||
<TrackFavoriteIcon v-if="store.state.auth.authenticated" :album="object" />
|
||||
<TrackPlaylistIcon v-if="store.state.auth.authenticated" :album="object" />
|
||||
<!-- TODO: Share Button -->
|
||||
<album-dropdown
|
||||
:object="object"
|
||||
|
|
|
@ -25,6 +25,7 @@ import Layout from '~/components/ui/Layout.vue'
|
|||
import Modal from '~/components/ui/Modal.vue'
|
||||
import Spacer from '~/components/ui/Spacer.vue'
|
||||
|
||||
|
||||
interface Props {
|
||||
id: number
|
||||
}
|
||||
|
@ -55,6 +56,7 @@ const musicbrainzUrl = computed(() => object.value?.mbid ? `https://musicbrainz.
|
|||
const discogsUrl = computed(() => `https://discogs.com/search/?type=artist&title=${encodeURI(object.value?.name ?? '')}`)
|
||||
const publicLibraries = computed(() => libraries.value?.filter(library => library.privacy_level === 'everyone') ?? [])
|
||||
|
||||
|
||||
const cover = computed(() => {
|
||||
const artistCover: Cover | undefined = object.value?.cover
|
||||
|
||||
|
@ -120,11 +122,7 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<Layout
|
||||
v-title="labels.title"
|
||||
stack
|
||||
main
|
||||
>
|
||||
<Layout stack main v-title="labels.title">
|
||||
<Loader v-if="isLoading" />
|
||||
<template v-if="object && !isLoading">
|
||||
<Layout flex>
|
||||
|
@ -133,16 +131,9 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
:alt="object.name"
|
||||
class="channel-image"
|
||||
>
|
||||
<Layout
|
||||
stack
|
||||
style="flex: 1; gap: 8px;"
|
||||
>
|
||||
<h1>{{ object.name }}</h1>
|
||||
<Layout
|
||||
flex
|
||||
class="meta"
|
||||
style="gap: 0;"
|
||||
>
|
||||
<Layout stack style="flex: 1; gap: 8px;">
|
||||
<h1 style="margin-top: 64px; margin-bottom: 8px;">{{ object.name }}</h1>
|
||||
<Layout flex class="meta" style="gap: 0;">
|
||||
<div
|
||||
v-if="albums"
|
||||
>
|
||||
|
@ -190,8 +181,8 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
|
||||
<PopoverItem
|
||||
v-if="publicLibraries.length > 0"
|
||||
icon="bi-code-square"
|
||||
@click="showEmbedModal = true"
|
||||
icon="bi-code-square"
|
||||
>
|
||||
{{ t('components.library.ArtistBase.button.embed') }}
|
||||
</PopoverItem>
|
||||
|
|
|
@ -11,6 +11,7 @@ import { useStore } from '~/store'
|
|||
import axios from 'axios'
|
||||
|
||||
import ActorLink from '~/components/common/ActorLink.vue'
|
||||
import ArtistCreditLabel from '~/components/audio/ArtistCreditLabel.vue'
|
||||
import TrackFavoriteIcon from '~/components/favorites/TrackFavoriteIcon.vue'
|
||||
import TrackPlaylistIcon from '~/components/playlists/TrackPlaylistIcon.vue'
|
||||
import EmbedWizard from '~/components/audio/EmbedWizard.vue'
|
||||
|
@ -76,6 +77,8 @@ const attributedToUrl = computed(() => router.resolve({
|
|||
}
|
||||
})?.href)
|
||||
|
||||
const artistCredit = track.value?.artist_credit
|
||||
|
||||
const totalDuration = computed(() => track.value?.uploads[0]?.duration ?? 0)
|
||||
|
||||
const { t } = useI18n()
|
||||
|
@ -126,10 +129,7 @@ watch(showDeleteModal, (newValue) => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<Layout
|
||||
stack
|
||||
main
|
||||
>
|
||||
<Layout stack main>
|
||||
<Loader
|
||||
v-if="isLoading"
|
||||
v-title="labels.title"
|
||||
|
@ -155,16 +155,9 @@ watch(showDeleteModal, (newValue) => {
|
|||
src="../../assets/audio/default-cover.png"
|
||||
>
|
||||
|
||||
<Layout
|
||||
stack
|
||||
style="flex: 1; gap: 8px;"
|
||||
>
|
||||
<Layout
|
||||
flex
|
||||
no-gap
|
||||
style="align-items: baseline; margin-bottom: 24px;"
|
||||
>
|
||||
<h1>{{ track.title }}</h1>
|
||||
<Layout stack style="flex: 1; gap: 8px;">
|
||||
<Layout flex no-gap style="align-items: baseline;">
|
||||
<h1 style="margin-top: 64px; margin-bottom: 8px;">{{ track.title }}</h1>
|
||||
<Spacer grow />
|
||||
<Button
|
||||
v-if="upload"
|
||||
|
@ -178,14 +171,14 @@ watch(showDeleteModal, (newValue) => {
|
|||
{{ labels.download }}
|
||||
</Button>
|
||||
</Layout>
|
||||
<artist-credit-label
|
||||
:artist-credit="track.artist_credit"
|
||||
/>
|
||||
<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"
|
||||
/>
|
||||
<i v-if="totalDuration > 0" class="bi bi-dot" />
|
||||
<human-duration
|
||||
v-if="totalDuration > 0"
|
||||
:duration="totalDuration"
|
||||
|
@ -200,19 +193,10 @@ watch(showDeleteModal, (newValue) => {
|
|||
:track="track"
|
||||
/>
|
||||
|
||||
<Spacer
|
||||
h
|
||||
grow
|
||||
/>
|
||||
<Spacer h grow />
|
||||
|
||||
<TrackFavoriteIcon
|
||||
v-if="store.state.auth.authenticated"
|
||||
:track="track"
|
||||
/>
|
||||
<TrackPlaylistIcon
|
||||
v-if="store.state.auth.authenticated"
|
||||
:track="track"
|
||||
/>
|
||||
<TrackFavoriteIcon v-if="store.state.auth.authenticated" :track="track" />
|
||||
<TrackPlaylistIcon v-if="store.state.auth.authenticated" :track="track" />
|
||||
<Popover v-model:open="open">
|
||||
<template #default="{ toggleOpen }">
|
||||
<OptionsButton @click="toggleOpen" />
|
||||
|
@ -229,8 +213,8 @@ watch(showDeleteModal, (newValue) => {
|
|||
|
||||
<PopoverItem
|
||||
v-if="isEmbedable"
|
||||
icon="bi-code-slash"
|
||||
@click="showEmbedModal = !showEmbedModal"
|
||||
icon="bi-code-slash"
|
||||
>
|
||||
{{ t('components.library.TrackBase.button.embed') }}
|
||||
</PopoverItem>
|
||||
|
@ -267,8 +251,8 @@ watch(showDeleteModal, (newValue) => {
|
|||
store.state.auth.authenticated &&
|
||||
artist.channel &&
|
||||
artist.attributed_to.full_username === store.state.auth.fullUsername"
|
||||
icon="bi-trash"
|
||||
@click="showDeleteModal = true"
|
||||
icon="bi-trash"
|
||||
>
|
||||
{{ t('components.library.TrackBase.button.delete') }}
|
||||
</PopoverItem>
|
||||
|
@ -278,8 +262,8 @@ watch(showDeleteModal, (newValue) => {
|
|||
<PopoverItem
|
||||
v-for="obj in getReportableObjects({ track })"
|
||||
:key="obj.target.type + obj.target.id"
|
||||
icon="bi-flag"
|
||||
@click="report(obj)"
|
||||
icon="bi-flag"
|
||||
>
|
||||
{{ obj.label }}
|
||||
</PopoverItem>
|
||||
|
@ -391,6 +375,7 @@ watch(showDeleteModal, (newValue) => {
|
|||
@libraries-loaded="libraries = $event"
|
||||
/>
|
||||
</template>
|
||||
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
overflow: hidden;
|
||||
height: calc(2em - 4px);
|
||||
margin: 2px;
|
||||
align-content: center;
|
||||
|
||||
+ .pill-content {
|
||||
padding-left: 0.25em;
|
||||
|
@ -45,6 +46,10 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
> i.bi {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
> img {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue