fix(front): consistent small cards
This commit is contained in:
parent
10140959d3
commit
3d710dbb02
|
@ -4,9 +4,11 @@ import { computed } from 'vue'
|
||||||
import { useStore } from '~/store'
|
import { useStore } from '~/store'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { momentFormat } from '~/utils/filters'
|
import { momentFormat } from '~/utils/filters'
|
||||||
|
import defaultCover from '~/assets/audio/default-cover.png'
|
||||||
|
|
||||||
import PlayButton from '~/components/audio/PlayButton.vue'
|
import PlayButton from '~/components/audio/PlayButton.vue'
|
||||||
import Card from '~/components/ui/Card.vue'
|
import Card from '~/components/ui/Card.vue'
|
||||||
|
import Link from '~/components/ui/Link.vue'
|
||||||
import TagsList from '~/components/tags/List.vue'
|
import TagsList from '~/components/tags/List.vue'
|
||||||
import Spacer from '~/components/ui/Spacer.vue'
|
import Spacer from '~/components/ui/Spacer.vue'
|
||||||
|
|
||||||
|
@ -39,7 +41,7 @@ if (import.meta.env.PROD) {
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const imageUrl = computed(() => props.album.cover?.urls.original
|
const imageUrl = computed(() => props.album.cover?.urls.original
|
||||||
? store.getters['instance/absoluteUrl'](props.album.cover?.urls.large_square_crop)
|
? store.getters['instance/absoluteUrl'](props.album.cover?.urls.large_square_crop)
|
||||||
: `${import.meta.env.BASE_URL}embed-default-cover.jpeg`
|
: defaultCover
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -49,6 +51,7 @@ const imageUrl = computed(() => props.album.cover?.urls.original
|
||||||
:image="imageUrl"
|
:image="imageUrl"
|
||||||
:tags="album.tags"
|
:tags="album.tags"
|
||||||
:to="{name: 'library.albums.detail', params: {id: album.id}}"
|
:to="{name: 'library.albums.detail', params: {id: album.id}}"
|
||||||
|
small
|
||||||
>
|
>
|
||||||
<template #topright>
|
<template #topright>
|
||||||
<PlayButton
|
<PlayButton
|
||||||
|
@ -62,27 +65,27 @@ const imageUrl = computed(() => props.album.cover?.urls.original
|
||||||
v-for="ac in album.artist_credit"
|
v-for="ac in album.artist_credit"
|
||||||
:key="ac.artist.id"
|
:key="ac.artist.id"
|
||||||
>
|
>
|
||||||
<router-link
|
<Link
|
||||||
:to="{ name: 'library.artists.detail', params: { id: ac.artist.id }}"
|
:to="{ name: 'library.artists.detail', params: { id: ac.artist.id }}"
|
||||||
>
|
>
|
||||||
{{ ac.credit ?? t('components.Queue.meta.unknownArtist') }}
|
{{ ac.credit ?? t('components.Queue.meta.unknownArtist') }}
|
||||||
</router-link>
|
</Link>
|
||||||
<span>{{ ac.joinphrase }}</span>
|
<span>{{ ac.joinphrase }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #action>
|
<template #footer>
|
||||||
<Spacer :size="8" />
|
|
||||||
<span v-if="album.release_date">
|
<span v-if="album.release_date">
|
||||||
{{ momentFormat(new Date(album.release_date), 'Y') }}
|
{{ momentFormat(new Date(album.release_date), 'Y') }}
|
||||||
</span>
|
</span>
|
||||||
|
<i class="bi bi-dot"/>
|
||||||
<span>
|
<span>
|
||||||
<i class="bi bi-music-note-list" />
|
|
||||||
{{ t('components.audio.album.Card.meta.tracks', album.tracks_count) }}
|
{{ t('components.audio.album.Card.meta.tracks', album.tracks_count) }}
|
||||||
</span>
|
</span>
|
||||||
<Spacer h grow />
|
<Spacer h grow />
|
||||||
<PlayButton
|
<PlayButton
|
||||||
id="playmenu"
|
id="playmenu"
|
||||||
:dropdown-only="true"
|
:dropdown-only="true"
|
||||||
|
discrete
|
||||||
:is-playable="album.is_playable"
|
:is-playable="album.is_playable"
|
||||||
:album="album"
|
:album="album"
|
||||||
/>
|
/>
|
||||||
|
@ -92,8 +95,7 @@ const imageUrl = computed(() => props.album.cover?.urls.original
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.play-button {
|
.play-button {
|
||||||
position: absolute;
|
top: 16px;
|
||||||
top: 214px;
|
|
||||||
right: 16px;
|
right: 16px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { computed } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { useStore } from '~/store'
|
import { useStore } from '~/store'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
@ -8,10 +8,13 @@ import PlayButton from '~/components/audio/PlayButton.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'
|
||||||
|
|
||||||
import type { Artist } from '~/types'
|
import type { Artist, Cover, Track } from '~/types'
|
||||||
|
|
||||||
const play = defineEmit<[artist: Artist]>()
|
const play = defineEmit<[artist: Artist]>()
|
||||||
|
|
||||||
|
const albums = ref([] as Album[])
|
||||||
|
const tracks = ref([] as Track[])
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
artist: Artist;
|
artist: Artist;
|
||||||
}
|
}
|
||||||
|
@ -30,25 +33,45 @@ if (import.meta.env.PROD) {
|
||||||
router.push({ name: 'library.artists.detail', params: { id: artist.id } })
|
router.push({ name: 'library.artists.detail', params: { id: artist.id } })
|
||||||
}
|
}
|
||||||
|
|
||||||
const cover = computed(() => !props.artist.cover?.urls.large_square_crop
|
|
||||||
? props.artist.albums.find(album => !!album.cover?.urls.large_square_crop)?.cover
|
|
||||||
: props.artist.cover
|
|
||||||
)
|
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const imageUrl = computed(() => cover.value?.urls.original
|
|
||||||
? store.getters['instance/absoluteUrl'](cover.value.urls.large_square_crop)
|
|
||||||
: `${import.meta.env.BASE_URL}embed-default-cover.jpeg`
|
const cover = computed(() => {
|
||||||
)
|
const artistCover: Cover | undefined = artist.cover
|
||||||
|
|
||||||
|
const albumCover: Cover | undefined = artist.albums
|
||||||
|
.find(album => album.cover?.urls.medium_square_crop)?.cover
|
||||||
|
|
||||||
|
const trackCover: Cover | undefined =
|
||||||
|
tracks.value?.find(
|
||||||
|
track => track.cover
|
||||||
|
)
|
||||||
|
?.cover
|
||||||
|
|
||||||
|
const fallback : Cover = {
|
||||||
|
uuid: '',
|
||||||
|
urls: {
|
||||||
|
original: `${import.meta.env.BASE_URL}embed-default-cover.jpeg`,
|
||||||
|
medium_square_crop: `${import.meta.env.BASE_URL}embed-default-cover.jpeg`,
|
||||||
|
large_square_crop: `${import.meta.env.BASE_URL}embed-default-cover.jpeg`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return artistCover
|
||||||
|
|| albumCover
|
||||||
|
|| trackCover
|
||||||
|
|| fallback
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Card
|
<Card
|
||||||
:title="artist.name"
|
:title="artist.name"
|
||||||
:image="imageUrl"
|
|
||||||
class="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}}"
|
||||||
|
small
|
||||||
>
|
>
|
||||||
<template #topright>
|
<template #topright>
|
||||||
<PlayButton
|
<PlayButton
|
||||||
|
@ -58,9 +81,15 @@ const imageUrl = computed(() => cover.value?.urls.original
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #action>
|
<template #image>
|
||||||
<Spacer :size="8" />
|
<img
|
||||||
<i class="bi bi-music-note-list" />
|
v-lazy="cover.urls.medium_square_crop"
|
||||||
|
:alt="artist.name"
|
||||||
|
class="channel-image"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
<span v-if="artist.content_category === 'music'">
|
<span v-if="artist.content_category === 'music'">
|
||||||
{{ t('components.audio.artist.Card.meta.tracks', artist.tracks_count) }}
|
{{ t('components.audio.artist.Card.meta.tracks', artist.tracks_count) }}
|
||||||
</span>
|
</span>
|
||||||
|
@ -73,6 +102,7 @@ const imageUrl = computed(() => cover.value?.urls.original
|
||||||
:dropdown-only="true"
|
:dropdown-only="true"
|
||||||
:is-playable="artist.is_playable"
|
:is-playable="artist.is_playable"
|
||||||
:artist="artist"
|
:artist="artist"
|
||||||
|
discrete
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -80,9 +110,15 @@ const imageUrl = computed(() => cover.value?.urls.original
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.channel-image {
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 168px;
|
||||||
|
height: 168px;
|
||||||
|
margin: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.play-button {
|
.play-button {
|
||||||
position: absolute;
|
top: 16px;
|
||||||
top: 214px;
|
|
||||||
right: 16px;
|
right: 16px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -22,7 +22,7 @@ const store = useStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const imageUrl = computed(() => props.object.artist?.cover
|
const imageUrl = computed(() => props.object.artist?.cover
|
||||||
? store.getters['instance/absoluteUrl'](props.object.artist.cover.urls.large_square_crop)
|
? store.getters['instance/absoluteUrl'](props.object.artist.cover.urls.medium_square_crop)
|
||||||
: null
|
: null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -46,10 +46,10 @@ const updatedAgo = computed(() => moment(props.object.artist?.modification_date)
|
||||||
<template>
|
<template>
|
||||||
<Card
|
<Card
|
||||||
:title="object.artist?.name"
|
:title="object.artist?.name"
|
||||||
:image="imageUrl"
|
|
||||||
:tags="object.artist?.tags ?? []"
|
:tags="object.artist?.tags ?? []"
|
||||||
class="artist-card"
|
class="artist-card"
|
||||||
:to="{name: 'channels.detail', params: {id: urlId}}"
|
:to="{name: 'channels.detail', params: {id: urlId}}"
|
||||||
|
small
|
||||||
>
|
>
|
||||||
<template #topright>
|
<template #topright>
|
||||||
<PlayButton
|
<PlayButton
|
||||||
|
@ -59,26 +59,35 @@ const updatedAgo = computed(() => moment(props.object.artist?.modification_date)
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #default>
|
<template #image>
|
||||||
<span
|
<img
|
||||||
v-if="object.artist?.content_category === 'podcast'"
|
v-if="imageUrl"
|
||||||
>
|
v-lazy="imageUrl"
|
||||||
<i class="bi bi-music-note-list" />
|
:alt="object.artist?.name"
|
||||||
{{ t('components.audio.ChannelCard.meta.episodes', object.artist.tracks_count) }}
|
class="channel-image"
|
||||||
</span>
|
/>
|
||||||
<span v-else>
|
|
||||||
<i class="bi bi-music-note-list" />
|
|
||||||
{{ t('components.audio.ChannelCard.meta.tracks', object.artist?.tracks_count ?? 0) }}
|
|
||||||
</span>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #action>
|
<template #default>
|
||||||
|
<Spacer :size="8"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
<time
|
<time
|
||||||
:datetime="object.artist?.modification_date"
|
:datetime="object.artist?.modification_date"
|
||||||
:title="updatedTitle"
|
:title="updatedTitle"
|
||||||
>
|
>
|
||||||
{{ updatedAgo }}
|
{{ updatedAgo }}
|
||||||
</time>
|
</time>
|
||||||
|
<i class="bi bi-dot" />
|
||||||
|
<span
|
||||||
|
v-if="object.artist?.content_category === 'podcast'"
|
||||||
|
>
|
||||||
|
{{ t('components.audio.ChannelCard.meta.episodes', object.artist.tracks_count) }}
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
{{ t('components.audio.ChannelCard.meta.tracks', object.artist?.tracks_count ?? 0) }}
|
||||||
|
</span>
|
||||||
<Spacer h grow />
|
<Spacer h grow />
|
||||||
<PlayButton
|
<PlayButton
|
||||||
:dropdown-only="true"
|
:dropdown-only="true"
|
||||||
|
@ -86,15 +95,22 @@ const updatedAgo = computed(() => moment(props.object.artist?.modification_date)
|
||||||
:artist="object.artist"
|
:artist="object.artist"
|
||||||
:channel="object"
|
:channel="object"
|
||||||
:account="object.attributed_to"
|
:account="object.attributed_to"
|
||||||
|
discrete
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.channel-image {
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 168px;
|
||||||
|
height: 168px;
|
||||||
|
margin: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.play-button {
|
.play-button {
|
||||||
position: absolute;
|
top: 16px;
|
||||||
top: 214px;
|
|
||||||
right: 16px;
|
right: 16px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -8,7 +8,10 @@ import { useI18n } from 'vue-i18n'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
import ChannelCard from '~/components/audio/ChannelCard.vue'
|
import ChannelCard from '~/components/audio/ChannelCard.vue'
|
||||||
|
import Layout from '~/components/ui/Layout.vue'
|
||||||
|
import Loader from '~/components/ui/Loader.vue'
|
||||||
import Button from '~/components/ui/Button.vue'
|
import Button from '~/components/ui/Button.vue'
|
||||||
|
import Spacer from '../ui/Spacer.vue'
|
||||||
|
|
||||||
interface Events {
|
interface Events {
|
||||||
(e: 'fetched', channels: BackendResponse<Channel>): void
|
(e: 'fetched', channels: BackendResponse<Channel>): void
|
||||||
|
@ -60,22 +63,16 @@ fetchData()
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<slot />
|
<slot />
|
||||||
<div class="ui hidden divider" />
|
<Layout grid>
|
||||||
<div class="ui app-cards cards">
|
<Loader v-if="isLoading" />
|
||||||
<div
|
|
||||||
v-if="isLoading"
|
|
||||||
class="ui inverted active dimmer"
|
|
||||||
>
|
|
||||||
<div class="ui loader" />
|
|
||||||
</div>
|
|
||||||
<channel-card
|
<channel-card
|
||||||
v-for="object in channels"
|
v-for="object in channels"
|
||||||
:key="object.uuid"
|
:key="object.uuid"
|
||||||
:object="object"
|
:object="object"
|
||||||
/>
|
/>
|
||||||
</div>
|
</Layout>
|
||||||
<template v-if="nextPage">
|
<template v-if="nextPage">
|
||||||
<div class="ui hidden divider" />
|
<Spacer />
|
||||||
<Button
|
<Button
|
||||||
v-if="nextPage"
|
v-if="nextPage"
|
||||||
@click="fetchData(nextPage)"
|
@click="fetchData(nextPage)"
|
||||||
|
|
|
@ -101,13 +101,13 @@ const isOpen = ref(false)
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Popover
|
<Popover
|
||||||
v-if="split || (!discrete && !iconOnly && dropdownOnly)"
|
v-if="split || (!iconOnly && dropdownOnly)"
|
||||||
v-model:open="isOpen"
|
v-model:open="isOpen"
|
||||||
>
|
>
|
||||||
<OptionsButton
|
<OptionsButton
|
||||||
v-if="dropdownOnly"
|
v-if="dropdownOnly"
|
||||||
@click="isOpen = !isOpen"
|
@click="isOpen = !isOpen"
|
||||||
ghost
|
:isGhost="discrete"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
v-else
|
v-else
|
||||||
|
|
|
@ -67,7 +67,7 @@ const url = computed(() => {
|
||||||
v-if="avatar"
|
v-if="avatar"
|
||||||
:actor="actor"
|
:actor="actor"
|
||||||
/>
|
/>
|
||||||
<slot>@{{ repr }}</slot>
|
<slot>{{ repr }}</slot>
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -34,7 +34,6 @@ const defaultAvatarStyle = computed(() => ({ backgroundColor: `#${userColor.valu
|
||||||
:solid="!discrete"
|
:solid="!discrete"
|
||||||
:round="!discrete"
|
:round="!discrete"
|
||||||
>
|
>
|
||||||
<span class="center">
|
|
||||||
<template v-if="avatar">
|
<template v-if="avatar">
|
||||||
<img
|
<img
|
||||||
v-if="user.avatar && user.avatar.urls.medium_square_crop"
|
v-if="user.avatar && user.avatar.urls.medium_square_crop"
|
||||||
|
@ -52,15 +51,5 @@ const defaultAvatarStyle = computed(() => ({ backgroundColor: `#${userColor.valu
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
{{ t('components.common.UserLink.link.username', {username: user.username}) }}
|
{{ t('components.common.UserLink.link.username', {username: user.username}) }}
|
||||||
</span>
|
|
||||||
</Link>
|
</Link>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
a.username {
|
|
||||||
span.center {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ const goToPlaylist = () => {
|
||||||
<Card
|
<Card
|
||||||
:title="playlist.name"
|
:title="playlist.name"
|
||||||
:to="{ name: 'library.playlists.detail', params: { id: playlist.id } }"
|
:to="{ name: 'library.playlists.detail', params: { id: playlist.id } }"
|
||||||
|
small
|
||||||
>
|
>
|
||||||
<template #topright>
|
<template #topright>
|
||||||
<PlayButton
|
<PlayButton
|
||||||
|
@ -81,14 +82,16 @@ const goToPlaylist = () => {
|
||||||
|
|
||||||
<template #default>
|
<template #default>
|
||||||
<div class="playlist-meta">
|
<div class="playlist-meta">
|
||||||
|
<span>{{ t('vui.by-user') }}</span>
|
||||||
<ActorLink
|
<ActorLink
|
||||||
:actor="playlist.actor"
|
:actor="playlist.actor"
|
||||||
|
:avatar="false"
|
||||||
discrete
|
discrete
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #action>
|
<template #footer>
|
||||||
<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
|
||||||
|
@ -117,14 +120,12 @@ const goToPlaylist = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.play-button {
|
.play-button {
|
||||||
position: absolute;
|
top: 16px;
|
||||||
top: 214px;
|
|
||||||
right: 16px;
|
right: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.playlist-meta {
|
.playlist-meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-self: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.playlist-action {
|
.playlist-action {
|
||||||
|
|
|
@ -81,9 +81,9 @@ const toggleRadio = () => {
|
||||||
<template>
|
<template>
|
||||||
<Button
|
<Button
|
||||||
:is-active="running"
|
:is-active="running"
|
||||||
:primary="!playOnly"
|
primary
|
||||||
:secondary="playOnly"
|
|
||||||
:round="playOnly"
|
:round="playOnly"
|
||||||
|
class="play-button"
|
||||||
icon="bi-play-fill"
|
icon="bi-play-fill"
|
||||||
:square="store.state.auth.authenticated && type === 'custom'"
|
:square="store.state.auth.authenticated && type === 'custom'"
|
||||||
@click="toggleRadio"
|
@click="toggleRadio"
|
||||||
|
|
|
@ -38,7 +38,7 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
|
||||||
<template>
|
<template>
|
||||||
<Card
|
<Card
|
||||||
v-if="radio.id"
|
v-if="radio.id"
|
||||||
large
|
small
|
||||||
:title="radio.name"
|
:title="radio.name"
|
||||||
:to="{name: 'library.radios.detail', params: {id: radio.id}}"
|
:to="{name: 'library.radios.detail', params: {id: radio.id}}"
|
||||||
>
|
>
|
||||||
|
@ -55,9 +55,10 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
|
||||||
<user-link
|
<user-link
|
||||||
v-if="radio.user"
|
v-if="radio.user"
|
||||||
:user="radio.user"
|
:user="radio.user"
|
||||||
|
:avatar="false"
|
||||||
discrete
|
discrete
|
||||||
class="left floated"
|
|
||||||
/>
|
/>
|
||||||
|
<Spacer />
|
||||||
<div
|
<div
|
||||||
class="description"
|
class="description"
|
||||||
:class="{expanded: isDescriptionExpanded}"
|
:class="{expanded: isDescriptionExpanded}"
|
||||||
|
@ -65,10 +66,9 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
|
||||||
>
|
>
|
||||||
{{ radio.description }}
|
{{ radio.description }}
|
||||||
</div>
|
</div>
|
||||||
<Spacer />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #action>
|
<template #footer>
|
||||||
<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"
|
||||||
primary
|
primary
|
||||||
|
@ -81,7 +81,7 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
|
||||||
</Card>
|
</Card>
|
||||||
<Card
|
<Card
|
||||||
v-else
|
v-else
|
||||||
large
|
small
|
||||||
:title="radio.name"
|
:title="radio.name"
|
||||||
>
|
>
|
||||||
<template #topright>
|
<template #topright>
|
||||||
|
@ -97,7 +97,9 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
|
||||||
v-if="radio.user"
|
v-if="radio.user"
|
||||||
discrete
|
discrete
|
||||||
:user="radio.user"
|
:user="radio.user"
|
||||||
|
:avatar="false"
|
||||||
/>
|
/>
|
||||||
|
<Spacer />
|
||||||
<div
|
<div
|
||||||
class="description"
|
class="description"
|
||||||
:class="{expanded: isDescriptionExpanded}"
|
:class="{expanded: isDescriptionExpanded}"
|
||||||
|
@ -108,7 +110,7 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
|
||||||
<Spacer />
|
<Spacer />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #action>
|
<template #footer>
|
||||||
<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"
|
||||||
primary
|
primary
|
||||||
|
@ -123,8 +125,8 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
a.username {
|
.play-button {
|
||||||
display: flex;
|
top: 16px;
|
||||||
align-self: center;
|
right: 16px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -146,10 +146,6 @@ const attributes = computed(() =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:has(>.image) {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
>.image {
|
>.image {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: var(--fw-border-radius) var(--fw-border-radius) 0 0;
|
border-radius: var(--fw-border-radius) var(--fw-border-radius) 0 0;
|
||||||
|
@ -225,7 +221,6 @@ const attributes = computed(() =>
|
||||||
>.tags {
|
>.tags {
|
||||||
padding: 0 var(--fw-card-padding);
|
padding: 0 var(--fw-card-padding);
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
align-self: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
>.content {
|
>.content {
|
||||||
|
@ -233,14 +228,16 @@ const attributes = computed(() =>
|
||||||
/* Consider making all line height, vertical paddings, margins and borders,
|
/* Consider making all line height, vertical paddings, margins and borders,
|
||||||
a multiple of a global vertical rhythm so that side-by-side lines coincide */
|
a multiple of a global vertical rhythm so that side-by-side lines coincide */
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
margin-top: 16px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
>.footer {
|
>.footer {
|
||||||
padding: calc(var(--fw-card-padding) - 4px);
|
padding: calc(var(--fw-card-padding) - 4px);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
gap: 4px;
|
||||||
|
align-items: end;
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
>.options-button {
|
>.options-button {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
|
|
@ -3,18 +3,21 @@ import Button from '../Button.vue'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isSquare?: boolean
|
isSquare?: boolean
|
||||||
|
isGhost?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
isSquare: false
|
isSquare: false,
|
||||||
|
isGhost: false
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Button
|
<Button
|
||||||
icon="bi-three-dots-vertical"
|
icon="bi-three-dots-vertical"
|
||||||
class="options-button"
|
:class="['options-button', {'is-ghost': isGhost}]"
|
||||||
secondary
|
:secondary="!isGhost"
|
||||||
|
:ghost="isGhost"
|
||||||
:round="!isSquare"
|
:round="!isSquare"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -3,6 +3,11 @@
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
transition: all .2s ease;
|
transition: all .2s ease;
|
||||||
font-size: 0.6rem !important;
|
font-size: 0.6rem !important;
|
||||||
padding: 0.6em !important;
|
padding: 0.6em;
|
||||||
|
&.is-ghost {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0px;
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue