feat(style): consistent look and use of artist credit label on detail pages

This commit is contained in:
ArneBo 2025-02-23 00:26:33 +01:00
parent 75d4ac5467
commit 966181e480
5 changed files with 366 additions and 415 deletions

View File

@ -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>

View File

@ -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"

View File

@ -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>

View File

@ -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>

View File

@ -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;
}