fix(front): consistent playbutton and style in all cards
This commit is contained in:
parent
275094bfee
commit
6f728036ec
|
@ -50,7 +50,15 @@ const imageUrl = computed(() => props.album.cover?.urls.original
|
||||||
:tags="album.tags"
|
:tags="album.tags"
|
||||||
:to="{name: 'library.albums.detail', params: {id: album.id}}"
|
:to="{name: 'library.albums.detail', params: {id: album.id}}"
|
||||||
>
|
>
|
||||||
<template
|
<template #topright>
|
||||||
|
<PlayButton
|
||||||
|
icon-only
|
||||||
|
:is-playable="album.is_playable"
|
||||||
|
:album="album"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #default
|
||||||
v-for="ac in album.artist_credit"
|
v-for="ac in album.artist_credit"
|
||||||
:key="ac.artist.id"
|
:key="ac.artist.id"
|
||||||
>
|
>
|
||||||
|
@ -62,14 +70,6 @@ const imageUrl = computed(() => props.album.cover?.urls.original
|
||||||
<span>{{ ac.joinphrase }}</span>
|
<span>{{ ac.joinphrase }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<TagsList
|
|
||||||
label-classes="tiny"
|
|
||||||
:truncate-size="20"
|
|
||||||
:limit="2"
|
|
||||||
:show-more="false"
|
|
||||||
:tags="album.tags"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<template #action>
|
<template #action>
|
||||||
<Spacer :size="8" />
|
<Spacer :size="8" />
|
||||||
<span v-if="album.release_date">
|
<span v-if="album.release_date">
|
||||||
|
@ -90,30 +90,10 @@ const imageUrl = computed(() => props.album.cover?.urls.original
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style lang="scss" scoped>
|
||||||
.funkwhale {
|
.play-button {
|
||||||
&.card.album-card {
|
position: absolute;
|
||||||
--fw-border-radius: 12px;
|
top: 214px;
|
||||||
--Card-width: 208px;
|
right: 16px;
|
||||||
--Card-image-width: var(--Card-width);
|
|
||||||
--Card-padding: 16px;
|
|
||||||
|
|
||||||
> .card-image {
|
|
||||||
border-radius: 0 !important;
|
|
||||||
width: var(--Card-image-width);
|
|
||||||
margin: calc(-1 * var(--Card-padding)) calc(-1 * var(--Card-padding)) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .card-title {
|
|
||||||
font-size: 1rem;
|
|
||||||
text-align: left !important;
|
|
||||||
padding-top: 16px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .card-content {
|
|
||||||
padding-top: 0 !important;
|
|
||||||
text-align: left !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { useStore } from '~/store'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
import PlayButton from '~/components/audio/PlayButton.vue'
|
import PlayButton from '~/components/audio/PlayButton.vue'
|
||||||
import TagsList from '~/components/tags/List.vue'
|
|
||||||
import Card from '~/components/ui/Card.vue'
|
import Card from '~/components/ui/Card.vue'
|
||||||
import Spacer from '~/components/ui/Spacer.vue'
|
import Spacer from '~/components/ui/Spacer.vue'
|
||||||
|
|
||||||
|
@ -47,10 +46,17 @@ const imageUrl = computed(() => cover.value?.urls.original
|
||||||
<Card
|
<Card
|
||||||
:title="artist.name"
|
:title="artist.name"
|
||||||
:image="imageUrl"
|
:image="imageUrl"
|
||||||
class="card artist-card"
|
class="artist-card"
|
||||||
:tags="artist.tags"
|
:tags="artist.tags"
|
||||||
:to="{name: 'library.artists.detail', params: {id: artist.id}}"
|
:to="{name: 'library.artists.detail', params: {id: artist.id}}"
|
||||||
>
|
>
|
||||||
|
<template #topright>
|
||||||
|
<PlayButton
|
||||||
|
icon-only
|
||||||
|
:is-playable="artist.is_playable"
|
||||||
|
:artist="artist"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #action>
|
<template #action>
|
||||||
<Spacer :size="8" />
|
<Spacer :size="8" />
|
||||||
|
@ -73,20 +79,10 @@ const imageUrl = computed(() => cover.value?.urls.original
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
|
.play-button {
|
||||||
.funkwhale {
|
position: absolute;
|
||||||
.card.artist-card {
|
top: 214px;
|
||||||
|
right: 16px;
|
||||||
> .card-image {
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 248px;
|
|
||||||
margin: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.play-button {
|
|
||||||
top: calc(var(--fw-card-width) - 44px - 8px) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -48,9 +48,18 @@ const updatedAgo = computed(() => moment(props.object.artist?.modification_date)
|
||||||
:title="object.artist?.name"
|
:title="object.artist?.name"
|
||||||
:image="imageUrl"
|
:image="imageUrl"
|
||||||
:tags="object.artist?.tags ?? []"
|
:tags="object.artist?.tags ?? []"
|
||||||
|
class="artist-card"
|
||||||
:to="{name: 'channels.detail', params: {id: urlId}}"
|
:to="{name: 'channels.detail', params: {id: urlId}}"
|
||||||
>
|
>
|
||||||
<div class="content">
|
<template #topright>
|
||||||
|
<PlayButton
|
||||||
|
icon-only
|
||||||
|
:is-playable="object.artist?.is_playable"
|
||||||
|
:artist="object.artist"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #default>
|
||||||
<span
|
<span
|
||||||
v-if="object.artist?.content_category === 'podcast'"
|
v-if="object.artist?.content_category === 'podcast'"
|
||||||
>
|
>
|
||||||
|
@ -61,7 +70,8 @@ const updatedAgo = computed(() => moment(props.object.artist?.modification_date)
|
||||||
<i class="bi bi-music-note-list" />
|
<i class="bi bi-music-note-list" />
|
||||||
{{ t('components.audio.ChannelCard.meta.tracks', object.artist?.tracks_count ?? 0) }}
|
{{ t('components.audio.ChannelCard.meta.tracks', object.artist?.tracks_count ?? 0) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</template>
|
||||||
|
|
||||||
<template #action>
|
<template #action>
|
||||||
<time
|
<time
|
||||||
:datetime="object.artist?.modification_date"
|
:datetime="object.artist?.modification_date"
|
||||||
|
@ -80,3 +90,11 @@ const updatedAgo = computed(() => moment(props.object.artist?.modification_date)
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.play-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 214px;
|
||||||
|
right: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -96,15 +96,6 @@ const labels = computed(() => ({
|
||||||
: t('components.audio.PlayButton.button.playTracks')
|
: t('components.audio.PlayButton.button.playTracks')
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const title = computed(() => {
|
|
||||||
|
|
||||||
if (props.track) {
|
|
||||||
return t('components.audio.PlayButton.title.unavailable')
|
|
||||||
}
|
|
||||||
|
|
||||||
return ''
|
|
||||||
})
|
|
||||||
|
|
||||||
const isOpen = ref(false)
|
const isOpen = ref(false)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -124,11 +115,10 @@ const isOpen = ref(false)
|
||||||
disabled: !playable,
|
disabled: !playable,
|
||||||
primary: playable,
|
primary: playable,
|
||||||
split: true,
|
split: true,
|
||||||
splitIcon: 'bi-caret-down-fill',
|
splitIcon: 'bi-caret-down-fill'
|
||||||
splitTitle: title
|
|
||||||
}"
|
}"
|
||||||
:aria-label="labels.replacePlay"
|
:aria-label="labels.replacePlay"
|
||||||
:class="[...buttonClasses]"
|
:class="[...buttonClasses, 'play-button']"
|
||||||
:isloading="isLoading"
|
:isloading="isLoading"
|
||||||
:dropdownOnly="dropdownOnly"
|
:dropdownOnly="dropdownOnly"
|
||||||
@click.stop.prevent="replacePlay()"
|
@click.stop.prevent="replacePlay()"
|
||||||
|
@ -238,12 +228,12 @@ const isOpen = ref(false)
|
||||||
primary: playable,
|
primary: playable,
|
||||||
}"
|
}"
|
||||||
:aria-label="labels.replacePlay"
|
:aria-label="labels.replacePlay"
|
||||||
:class="[...buttonClasses]"
|
:class="[...buttonClasses, 'play-button']"
|
||||||
:isloading="isLoading"
|
:isloading="isLoading"
|
||||||
:tiny="iconOnly && discrete"
|
:square="iconOnly"
|
||||||
:icon="!playing ? playIconClass : 'bi-pause-fill'"
|
:icon="!playing ? playIconClass : 'bi-pause-fill'"
|
||||||
:round="iconOnly"
|
:round="iconOnly"
|
||||||
:secondary="iconOnly && !discrete"
|
:primary="iconOnly && !discrete"
|
||||||
:ghost="discrete"
|
:ghost="discrete"
|
||||||
@click.stop.prevent="replacePlay()"
|
@click.stop.prevent="replacePlay()"
|
||||||
>
|
>
|
||||||
|
|
|
@ -59,6 +59,14 @@ const goToPlaylist = () => {
|
||||||
:title="playlist.name"
|
:title="playlist.name"
|
||||||
:to="{ name: 'library.playlists.detail', params: { id: playlist.id } }"
|
:to="{ name: 'library.playlists.detail', params: { id: playlist.id } }"
|
||||||
>
|
>
|
||||||
|
<template #topright>
|
||||||
|
<PlayButton
|
||||||
|
iconOnly
|
||||||
|
:is-playable="playlist.is_playable"
|
||||||
|
:playlist="playlist"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #image>
|
<template #image>
|
||||||
<div class="playlist-grid">
|
<div class="playlist-grid">
|
||||||
<img
|
<img
|
||||||
|
@ -71,18 +79,11 @@ const goToPlaylist = () => {
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #topright>
|
|
||||||
<PlayButton
|
|
||||||
iconOnly
|
|
||||||
:is-playable="playlist.is_playable"
|
|
||||||
:playlist="playlist"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default>
|
<template #default>
|
||||||
<div class="playlist-meta">
|
<div class="playlist-meta">
|
||||||
<ActorLink
|
<ActorLink
|
||||||
:actor="playlist.actor"
|
:actor="playlist.actor"
|
||||||
|
discrete
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -91,6 +92,7 @@ const goToPlaylist = () => {
|
||||||
<div class="playlist-action">
|
<div class="playlist-action">
|
||||||
<span>{{ t('components.playlists.Card.meta.tracks', playlist.tracks_count) }}</span>
|
<span>{{ t('components.playlists.Card.meta.tracks', playlist.tracks_count) }}</span>
|
||||||
<PlayButton
|
<PlayButton
|
||||||
|
v-if="playlist.is_playable"
|
||||||
dropdown-only
|
dropdown-only
|
||||||
:is-playable="playlist.is_playable"
|
:is-playable="playlist.is_playable"
|
||||||
:playlist="playlist"
|
:playlist="playlist"
|
||||||
|
@ -114,10 +116,15 @@ const goToPlaylist = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.play-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 214px;
|
||||||
|
right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.playlist-meta {
|
.playlist-meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.playlist-action {
|
.playlist-action {
|
||||||
|
|
|
@ -85,6 +85,7 @@ const toggleRadio = () => {
|
||||||
:secondary="playOnly"
|
:secondary="playOnly"
|
||||||
:round="playOnly"
|
:round="playOnly"
|
||||||
icon="bi-play-fill"
|
icon="bi-play-fill"
|
||||||
|
:square="store.state.auth.authenticated && type === 'custom'"
|
||||||
@click="toggleRadio"
|
@click="toggleRadio"
|
||||||
>
|
>
|
||||||
<div v-if="!playOnly">{{ buttonLabel }}</div>
|
<div v-if="!playOnly">{{ buttonLabel }}</div>
|
||||||
|
|
|
@ -42,14 +42,6 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
|
||||||
:title="radio.name"
|
:title="radio.name"
|
||||||
:to="{name: 'library.radios.detail', params: {id: radio.id}}"
|
:to="{name: 'library.radios.detail', params: {id: radio.id}}"
|
||||||
>
|
>
|
||||||
<div
|
|
||||||
class="description"
|
|
||||||
:class="{expanded: isDescriptionExpanded}"
|
|
||||||
@click="isDescriptionExpanded = !isDescriptionExpanded"
|
|
||||||
>
|
|
||||||
{{ radio.description }}
|
|
||||||
</div>
|
|
||||||
<Spacer />
|
|
||||||
<template #topright>
|
<template #topright>
|
||||||
<radio-button
|
<radio-button
|
||||||
:type="type"
|
:type="type"
|
||||||
|
@ -58,13 +50,24 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
|
||||||
playOnly
|
playOnly
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div class="extra content">
|
|
||||||
|
<template #default>
|
||||||
<user-link
|
<user-link
|
||||||
v-if="radio.user"
|
v-if="radio.user"
|
||||||
:user="radio.user"
|
:user="radio.user"
|
||||||
|
discrete
|
||||||
class="left floated"
|
class="left floated"
|
||||||
/>
|
/>
|
||||||
|
<div
|
||||||
|
class="description"
|
||||||
|
:class="{expanded: isDescriptionExpanded}"
|
||||||
|
@click="isDescriptionExpanded = !isDescriptionExpanded"
|
||||||
|
>
|
||||||
|
{{ radio.description }}
|
||||||
</div>
|
</div>
|
||||||
|
<Spacer />
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #action>
|
<template #action>
|
||||||
<Button
|
<Button
|
||||||
v-if="store.state.auth.authenticated && type === 'custom' && radio.user.id === store.state.auth.profile?.id"
|
v-if="store.state.auth.authenticated && type === 'custom' && radio.user.id === store.state.auth.profile?.id"
|
||||||
|
@ -81,6 +84,20 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
|
||||||
large
|
large
|
||||||
:title="radio.name"
|
:title="radio.name"
|
||||||
>
|
>
|
||||||
|
<template #topright>
|
||||||
|
<radio-button
|
||||||
|
:type="type"
|
||||||
|
:custom-radio-id="customRadioId"
|
||||||
|
:object-id="objectId"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #default>
|
||||||
|
<user-link
|
||||||
|
v-if="radio.user"
|
||||||
|
discrete
|
||||||
|
:user="radio.user"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
class="description"
|
class="description"
|
||||||
:class="{expanded: isDescriptionExpanded}"
|
:class="{expanded: isDescriptionExpanded}"
|
||||||
|
@ -89,17 +106,8 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
|
||||||
{{ radio.description }}
|
{{ radio.description }}
|
||||||
</div>
|
</div>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<div class="extra content">
|
</template>
|
||||||
<user-link
|
|
||||||
v-if="radio.user"
|
|
||||||
:user="radio.user"
|
|
||||||
/>
|
|
||||||
<radio-button
|
|
||||||
:type="type"
|
|
||||||
:custom-radio-id="customRadioId"
|
|
||||||
:object-id="objectId"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<template #action>
|
<template #action>
|
||||||
<Button
|
<Button
|
||||||
v-if="store.state.auth.authenticated && type === 'custom' && radio.user.id === store.state.auth.profile?.id"
|
v-if="store.state.auth.authenticated && type === 'custom' && radio.user.id === store.state.auth.profile?.id"
|
||||||
|
@ -112,3 +120,11 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
a.username {
|
||||||
|
display: flex;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, useSlots, onMounted } from 'vue'
|
import { ref, computed, useSlots, onMounted } from 'vue'
|
||||||
|
|
||||||
import { type ColorProps, type VariantProps, type DefaultProps, type RaisedProps, color } from '~/composables/color';
|
import { type ColorProps, type VariantProps, type DefaultProps, type RaisedProps, type PastelProps, color } from '~/composables/color';
|
||||||
import { type WidthProps, width } from '~/composables/width'
|
import { type WidthProps, width } from '~/composables/width'
|
||||||
import { type AlignmentProps, align } from '~/composables/alignment'
|
import { type AlignmentProps, align } from '~/composables/alignment'
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
autofocus? : boolean
|
autofocus? : boolean
|
||||||
ariaPressed? : true
|
ariaPressed? : true
|
||||||
} & (ColorProps | DefaultProps)
|
} & (ColorProps | DefaultProps | PastelProps )
|
||||||
& VariantProps
|
& VariantProps
|
||||||
& RaisedProps
|
& RaisedProps
|
||||||
& WidthProps
|
& WidthProps
|
||||||
|
|
Loading…
Reference in New Issue