See #973: Album card

This commit is contained in:
Eliot Berriot 2019-12-26 16:54:31 +01:00
parent 7c8b592f61
commit 1acd5a1f35
No known key found for this signature in database
GPG Key ID: 6B501DFD73514E14
5 changed files with 69 additions and 171 deletions

View File

@ -1,109 +1,51 @@
<template> <template>
<div :class="['ui', 'card', mode]"> <div class="card app-card">
<div
@click="$router.push({name: 'library.albums.detail', params: {id: album.id}})"
:class="['ui', 'image', {'default-cover': !album.cover.original}]" v-lazy:background-image="imageUrl">
<play-button :icon-only="true" :is-playable="album.is_playable" :button-classes="['ui', 'circular', 'large', 'orange', 'icon', 'button']" :album="album"></play-button>
</div>
<div class="content"> <div class="content">
<div class="right floated tiny ui image"> <strong>
<img v-if="album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](album.cover.square_crop)"> <router-link class="discrete link" :title="album.title" :to="{name: 'library.albums.detail', params: {id: album.id}}">
<img v-else src="../../../assets/audio/default-cover.png"> {{ album.title }}
</div> </router-link>
<div class="header"> </strong>
<router-link class="discrete link" :to="{name: 'library.albums.detail', params: {id: album.id }}">{{ album.title }} </router-link> <div class="description">
</div>
<div class="meta">
<span> <span>
<router-link :title="album.artist.name" tag="span" :to="{name: 'library.artists.detail', params: {id: album.artist.id }}"> <router-link :title="album.artist.name" class="discrete link" :to="{name: 'library.artists.detail', params: {id: album.artist.id}}">
<span v-translate="{artist: album.artist.name}" translate-context="Content/Album/Card" :translate-params="{artist: album.artist.name}">By %{ artist }</span> {{ album.artist.name }}
</router-link> </router-link>
</span><span class="time" v-if="album.release_date"> {{ album.release_date | year }}</span> </span>
</div>
<div class="description" v-if="mode === 'rich'">
<table class="ui very basic fixed single line compact unstackable table">
<tbody>
<tr v-for="track in tracks">
<td class="play-cell">
<play-button :class="['basic', {orange: currentTrack && isPlaying && track.id === currentTrack.id}, 'icon']" :discrete="true" :track="track"></play-button>
</td>
<td class="content-cell" colspan="5">
<track-favorite-icon :track="track"></track-favorite-icon>
<router-link :title="track.title" class="track discrete link" :to="{name: 'library.tracks.detail', params: {id: track.id }}">
<template v-if="track.position">
{{ track.position }}.
</template>
{{ track.title }}
</router-link>
</td>
</tr>
</tbody>
</table>
<div class="center aligned segment" v-if="album.tracks.length > initialTracks">
<em v-if="!showAllTracks" @click="showAllTracks = true" class="expand">
<translate translate-context="Content/Album/Card.Link/Verb" :translate-params="{count: album.tracks.length - initialTracks}" :translate-n="album.tracks.length - initialTracks" translate-plural="Show %{ count } more tracks">Show %{ count } more track</translate>
</em>
<em v-else @click="showAllTracks = false" class="expand">
<translate translate-context="*/*/Button,Label">Collapse</translate>
</em>
</div>
</div> </div>
</div> </div>
<div class="extra content"> <div class="extra content">
<play-button class="mini basic orange right floated" :tracks="tracksWithAlbum" :album="album">
<translate translate-context="Content/Queue/Button.Label/Short, Verb">Play all</translate>
</play-button>
<span>
<i class="music icon"></i>
<translate translate-context="*/*/*" :translate-params="{count: album.tracks.length}" :translate-n="album.tracks.length" translate-plural="%{ count } tracks">%{ count } track</translate> <translate translate-context="*/*/*" :translate-params="{count: album.tracks.length}" :translate-n="album.tracks.length" translate-plural="%{ count } tracks">%{ count } track</translate>
</span> <play-button class="right floated basic icon" :dropdown-only="true" :is-playable="album.is_playable" :dropdown-icon-classes="['ellipsis', 'horizontal', 'large', 'grey']" :album="album"></play-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { mapGetters } from "vuex"
import backend from '@/audio/backend'
import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
import PlayButton from '@/components/audio/PlayButton' import PlayButton from '@/components/audio/PlayButton'
export default { export default {
props: { props: {
album: {type: Object}, album: {type: Object},
mode: {type: String, default: 'rich'},
}, },
components: { components: {
TrackFavoriteIcon,
PlayButton PlayButton
}, },
data () {
return {
backend: backend,
initialTracks: 5,
showAllTracks: false
}
},
computed: { computed: {
tracks () { imageUrl () {
if (this.showAllTracks) { let url = '../../../assets/audio/default-cover.png'
return this.album.tracks
if (this.album.cover.original) {
url = this.$store.getters['instance/absoluteUrl'](this.album.cover.medium_square_crop)
} else {
return null
} }
return this.album.tracks.slice(0, this.initialTracks) return url
},
...mapGetters({
currentTrack: "queue/currentTrack",
}),
isPlaying () {
return this.$store.state.player.playing
},
tracksWithAlbum () {
// needed to include album data (especially cover)
// with tracks appended in queue (#795)
let self = this
return this.album.tracks.map(t => {
return {
...t,
album: {
...self.album,
tracks: []
}
}
})
} }
} }
} }
@ -111,35 +53,9 @@ export default {
<!-- Add "scoped" attribute to limit CSS to this component only --> <!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss"> <style scoped lang="scss">
.content-cell {
.link, .default-cover {
.button { background-image: url("../../../assets/audio/default-cover.png") !important;
padding: 0.5em 0;
}
.link {
margin-left: 0.5em;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
tr {
.favorite-icon:not(.favorited) {
visibility: hidden;
}
&:hover .favorite-icon {
visibility: visible;
}
.favorite-icon {
float: right;
}
}
.expand {
cursor: pointer;
} }
.ui .card.rich {
align-self: flex-start;
}
</style> </style>

View File

@ -9,31 +9,11 @@
<button v-if="controls" :disabled="!nextPage" @click="fetchData(nextPage)" :class="['ui', {disabled: !nextPage}, 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'angle right', 'icon']"></i></button> <button v-if="controls" :disabled="!nextPage" @click="fetchData(nextPage)" :class="['ui', {disabled: !nextPage}, 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'angle right', 'icon']"></i></button>
<button v-if="controls" @click="fetchData('albums/')" :class="['ui', 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'refresh', 'icon']"></i></button> <button v-if="controls" @click="fetchData('albums/')" :class="['ui', 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'refresh', 'icon']"></i></button>
<div class="ui hidden divider"></div> <div class="ui hidden divider"></div>
<div class="ui five cards"> <div class="ui app-cards cards">
<div v-if="isLoading" class="ui inverted active dimmer"> <div v-if="isLoading" class="ui inverted active dimmer">
<div class="ui loader"></div> <div class="ui loader"></div>
</div> </div>
<div class="card" v-for="album in albums" :key="album.id"> <album-card v-for="album in albums" :album="album" :key="album.id" />
<div :class="['ui', 'image', 'with-overlay', {'default-cover': !album.cover.original}]" v-lazy:background-image="getImageUrl(album)">
<play-button class="play-overlay" :icon-only="true" :is-playable="album.is_playable" :button-classes="['ui', 'circular', 'large', 'orange', 'icon', 'button']" :album="album"></play-button>
</div>
<div class="content">
<router-link :title="album.title" :to="{name: 'library.albums.detail', params: {id: album.id}}">
{{ album.title|truncate(25) }}
</router-link>
<div class="description">
<span>
<router-link :title="album.artist.name" class="discrete link" :to="{name: 'library.artists.detail', params: {id: album.artist.id}}">
{{ album.artist.name|truncate(23) }}
</router-link>
</span>
</div>
</div>
<div class="extra content">
<human-date class="left floated" :date="album.creation_date"></human-date>
<play-button class="right floated basic icon" :dropdown-only="true" :is-playable="album.is_playable" :dropdown-icon-classes="['ellipsis', 'horizontal', 'large', 'grey']" :album="album"></play-button>
</div>
</div>
</div> </div>
<template v-if="!isLoading && albums.length === 0"> <template v-if="!isLoading && albums.length === 0">
<div class="ui placeholder segment"> <div class="ui placeholder segment">
@ -49,7 +29,7 @@
<script> <script>
import _ from '@/lodash' import _ from '@/lodash'
import axios from 'axios' import axios from 'axios'
import PlayButton from '@/components/audio/PlayButton' import AlbumCard from '@/components/audio/album/Card'
export default { export default {
props: { props: {
@ -59,7 +39,7 @@ export default {
limit: {type: Number, default: 12}, limit: {type: Number, default: 12},
}, },
components: { components: {
PlayButton AlbumCard
}, },
data () { data () {
return { return {
@ -102,16 +82,6 @@ export default {
this.offset = Math.max(this.offset - this.limit, 0) this.offset = Math.max(this.offset - this.limit, 0)
} }
}, },
getImageUrl (album) {
let url = '../../../assets/audio/default-cover.png'
if (album.cover.original) {
url = this.$store.getters['instance/absoluteUrl'](album.cover.medium_square_crop)
} else {
return null
}
return url
}
}, },
watch: { watch: {
offset () { offset () {
@ -124,11 +94,7 @@ export default {
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "../../../style/vendor/media";
.default-cover {
background-image: url("../../../assets/audio/default-cover.png") !important;
}
.wrapper { .wrapper {
width: 100%; width: 100%;
@ -136,18 +102,6 @@ export default {
.ui.cards { .ui.cards {
justify-content: flex-start; justify-content: flex-start;
} }
.ui.five.cards > .card {
width: 15em;
}
.with-overlay {
background-size: cover !important;
background-position: center !important;
height: 15em;
width: 15em;
display: flex !important;
justify-content: center !important;
align-items: center !important;
}
</style> </style>
<style> <style>
.ui.cards .ui.button { .ui.cards .ui.button {

View File

@ -51,10 +51,8 @@
class="ui stackable three column doubling grid"> class="ui stackable three column doubling grid">
<div <div
v-if="result.results.length > 0" v-if="result.results.length > 0"
class="ui cards"> class="ui app-cards cards">
<album-card <album-card
:mode="'simple'"
v-masonry-tile
v-for="album in result.results" v-for="album in result.results"
:key="album.id" :key="album.id"
:album="album"></album-card> :album="album"></album-card>

View File

@ -21,8 +21,8 @@
<h2> <h2>
<translate translate-context="Content/Artist/Title">Albums by this artist</translate> <translate translate-context="Content/Artist/Title">Albums by this artist</translate>
</h2> </h2>
<div class="ui cards"> <div class="ui cards app-cards">
<album-card :mode="'rich'" :album="album" :key="album.id" v-for="album in allAlbums"></album-card> <album-card :album="album" :key="album.id" v-for="album in allAlbums"></album-card>
</div> </div>
<div class="ui hidden divider"></div> <div class="ui hidden divider"></div>
<button :class="['ui', {loading: isLoadingMoreAlbums}, 'button']" v-if="nextAlbumsUrl && loadMoreAlbumsUrl" @click="loadMoreAlbums(loadMoreAlbumsUrl)"> <button :class="['ui', {loading: isLoadingMoreAlbums}, 'button']" v-if="nextAlbumsUrl && loadMoreAlbumsUrl" @click="loadMoreAlbums(loadMoreAlbumsUrl)">

View File

@ -438,5 +438,35 @@ input + .help {
} }
} }
} }
.ui.cards.app-cards {
> .app-card {
display: inline-block;
width: 15em;
> .image {
background-size: cover !important;
background-position: center !important;
height: 15em;
width: 15em;
display: flex !important;
justify-content: flex-end !important;
align-items: flex-end !important;
padding: 0.5em;
.button {
margin: 0;
}
}
.extra {
border-top: 0 !important;
}
.content:not(.extra) {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.floating.dropdown > .icon {
margin-right: 0;
}
}
}
@import "./themes/_light.scss"; @import "./themes/_light.scss";
@import "./themes/_dark.scss"; @import "./themes/_dark.scss";