Enhance artists list by using our new artist card and remove masonry

This commit is contained in:
Eliot Berriot 2019-07-25 12:29:40 +02:00
parent c885c10be1
commit 5d1d54890a
No known key found for this signature in database
GPG Key ID: DD6965E2476E5C27
3 changed files with 89 additions and 135 deletions

View File

@ -1,61 +1,38 @@
<template>
<div class="ui card">
<div class="flat inline card">
<div :class="['ui', 'image', 'with-overlay', {'default-cover': !cover.original}]" v-lazy:background-image="imageUrl">
<play-button class="play-overlay" :icon-only="true" :is-playable="artist.is_playable" :button-classes="['ui', 'circular', 'large', 'orange', 'icon', 'button']" :artist="artist"></play-button>
</div>
<div class="content">
<div class="header">
<router-link class="discrete link" :to="{name: 'library.artists.detail', params: {id: artist.id }}">
{{ artist.name }}
</router-link>
</div>
<div class="description">
<table class="ui compact very basic fixed single line unstackable table">
<tbody>
<tr v-for="album in albums">
<td>
<img class="ui mini image" v-if="album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](album.cover.small_square_crop)">
<img class="ui mini image" v-else src="../../../assets/audio/default-cover.png">
</td>
<td colspan="4">
<router-link :title="album.title" class="discrete link" :to="{name: 'library.albums.detail', params: {id: album.id }}">
<strong>{{ album.title }}</strong>
</router-link><br />
{{ album.tracks_count }} tracks
</td>
<td>
<play-button class="right floated basic icon" :is-playable="album.is_playable" :discrete="true" :album="album"></play-button>
</td>
</tr>
</tbody>
</table>
<div class="center aligned segment" v-if="artist.albums.length > initialAlbums">
<em v-if="!showAllAlbums" @click="showAllAlbums = true" class="expand">
<translate translate-context="Content/Artist/Card.Link" :translate-params="{count: artist.albums.length - initialAlbums}" :translate-n="artist.albums.length - initialAlbums" translate-plural="Show %{ count } more albums">Show 1 more album</translate>
</em>
<em v-else @click="showAllAlbums = false" class="expand">
<translate translate-context="Content/*/Card.Link/Verb">Collapse</translate>
</em>
</div>
</div>
</div>
<div class="extra content">
<span>
<i class="sound icon"></i>
<translate translate-context="Content/Artist/Card" :translate-params="{count: artist.albums.length}" :translate-n="artist.albums.length" translate-plural="%{ count } albums">1 album</translate>
</span>
<play-button :is-playable="isPlayable" class="mini basic orange right floated" :artist="artist">
<translate translate-context="Content/Queue/Button.Label/Short, Verb">Play all</translate>
</play-button>
<router-link :title="artist.name" :to="{name: 'library.artists.detail', params: {id: artist.id}}">
{{ artist.name|truncate(30) }}
</router-link>
<div>
<i class="small sound icon"></i>
<translate translate-context="Content/Artist/Card" :translate-params="{count: artist.albums.length}" :translate-n="artist.albums.length" translate-plural="%{ count } albums">1 album</translate>
</div>
<tags-list label-classes="tiny" :truncate-size="20" :limit="2" :show-more="false" :tags="artist.tags"></tags-list>
<play-button
class="play-button basic icon"
:dropdown-only="true"
:is-playable="artist.is_playable"
:dropdown-icon-classes="['ellipsis', 'vertical', 'large', 'grey']"
:artist="artist"></play-button>
</div>
</div>
</template>
<script>
import backend from '@/audio/backend'
import PlayButton from '@/components/audio/PlayButton'
import TagsList from "@/components/tags/List"
export default {
props: ['artist'],
components: {
PlayButton
PlayButton,
TagsList
},
data () {
return {
@ -65,16 +42,23 @@ export default {
}
},
computed: {
albums () {
if (this.showAllAlbums) {
return this.artist.albums
imageUrl () {
let url = '../../../assets/audio/default-cover.png'
let cover = this.cover
if (cover.original) {
url = this.$store.getters['instance/absoluteUrl'](cover.medium_square_crop)
} else {
return null
}
return this.artist.albums.slice(0, this.initialAlbums)
return url
},
isPlayable () {
return this.artist.albums.filter((a) => {
return a.is_playable
}).length > 0
cover () {
return this.artist.albums.map((a) => {
return a.cover
}).filter((c) => {
return !!c
})[0] || {}
}
}
}
@ -82,4 +66,27 @@ export default {
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.default-cover {
background-image: url("../../../assets/audio/default-cover.png") !important;
}
.play-button {
position: absolute;
right: 0;
bottom: 0;
}
.with-overlay {
background-size: cover !important;
background-position: center !important;
height: 8em;
width: 8em;
display: flex !important;
justify-content: center !important;
align-items: center !important;
}
.flat.card .with-overlay.image {
border-radius: 50% !important;
margin: 0 auto;
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<div class="wrapper">
<h3 class="ui header">
<h3 v-if="header" class="ui header">
<slot name="title"></slot>
<span class="ui tiny circular label">{{ count }}</span>
</h3>
@ -12,28 +12,7 @@
<div v-if="isLoading" class="ui inverted active dimmer">
<div class="ui loader"></div>
</div>
<div class="flat inline card" v-for="object in objects" :key="object.id">
<div :class="['ui', 'image', 'with-overlay', {'default-cover': !getCover(object).original}]" v-lazy:background-image="getImageUrl(object)">
<play-button class="play-overlay" :icon-only="true" :is-playable="object.is_playable" :button-classes="['ui', 'circular', 'large', 'orange', 'icon', 'button']" :artist="object"></play-button>
</div>
<div class="content">
<router-link :title="object.name" :to="{name: 'library.artists.detail', params: {id: object.id}}">
{{ object.name|truncate(30) }}
</router-link>
<div>
<i class="small sound icon"></i>
<translate translate-context="Content/Artist/Card" :translate-params="{count: object.albums.length}" :translate-n="object.albums.length" translate-plural="%{ count } albums">1 album</translate>
</div>
<tags-list label-classes="tiny" :truncate-size="20" :limit="2" :show-more="false" :tags="object.tags"></tags-list>
<play-button
class="play-button basic icon"
:dropdown-only="true"
:is-playable="object.is_playable"
:dropdown-icon-classes="['ellipsis', 'vertical', 'large', 'grey']"
:artist="object"></play-button>
</div>
</div>
<artist-card :artist="artist" v-for="artist in objects" :key="artist.id"></artist-card>
</div>
<div v-if="!isLoading && objects.length === 0">No results matching your query.</div>
</div>
@ -42,17 +21,16 @@
<script>
import _ from '@/lodash'
import axios from 'axios'
import PlayButton from '@/components/audio/PlayButton'
import TagsList from "@/components/tags/List"
import ArtistCard from "@/components/audio/artist/Card"
export default {
props: {
filters: {type: Object, required: true},
controls: {type: Boolean, default: true},
header: {type: Boolean, default: true},
},
components: {
PlayButton,
TagsList
ArtistCard,
},
data () {
return {
@ -96,23 +74,6 @@ export default {
this.offset = Math.max(this.offset - this.limit, 0)
}
},
getImageUrl (object) {
let url = '../../../assets/audio/default-cover.png'
let cover = this.getCover(object)
if (cover.original) {
url = this.$store.getters['instance/absoluteUrl'](cover.medium_square_crop)
} else {
return null
}
return url
},
getCover (object) {
return object.albums.map((a) => {
return a.cover
}).filter((c) => {
return !!c
})[0] || {}
}
},
watch: {
offset () {
@ -127,21 +88,12 @@ export default {
<style scoped lang="scss">
@import "../../../style/vendor/media";
.default-cover {
background-image: url("../../../assets/audio/default-cover.png") !important;
}
.wrapper {
width: 100%;
}
.ui.cards {
justify-content: flex-start;
}
.play-button {
position: absolute;
right: 0;
bottom: 0;
}
.ui.three.cards .card {
width: 100%;
@ -151,19 +103,6 @@ export default {
width: 25em;
}
}
.with-overlay {
background-size: cover !important;
background-position: center !important;
height: 8em;
width: 8em;
display: flex !important;
justify-content: center !important;
align-items: center !important;
}
.flat.card .with-overlay.image {
border-radius: 50% !important;
margin: 0 auto;
}
</style>
<style>
.ui.cards .ui.button {

View File

@ -35,27 +35,18 @@
<label><translate translate-context="Content/Search/Dropdown.Label/Noun">Results per page</translate></label>
<select class="ui dropdown" v-model="paginateBy">
<option :value="parseInt(12)">12</option>
<option :value="parseInt(25)">25</option>
<option :value="parseInt(30)">30</option>
<option :value="parseInt(50)">50</option>
</select>
</div>
</div>
</div>
<div class="ui hidden divider"></div>
<div
v-if="result"
v-masonry
transition-duration="0"
item-selector=".card"
percent-position="true"
stagger="0">
<div v-if="result.results.length > 0" class="ui cards">
<artist-card
v-masonry-tile
v-for="artist in result.results"
:key="artist.id"
:artist="artist"></artist-card>
<div v-if="result && result.results.length > 0" class="ui three cards">
<div v-if="isLoading" class="ui inverted active dimmer">
<div class="ui loader"></div>
</div>
<artist-card :artist="artist" v-for="artist in result.results" :key="artist.id"></artist-card>
</div>
<div class="ui center aligned basic segment">
<pagination
@ -108,7 +99,7 @@ export default {
page: parseInt(this.defaultPage),
query: this.defaultQuery,
tags: this.defaultTags.filter((t) => { return t.length > 0 }) || [],
paginateBy: parseInt(this.defaultPaginateBy || 12),
paginateBy: parseInt(this.defaultPaginateBy || 30),
orderingDirection: defaultOrdering.direction || "+",
ordering: defaultOrdering.field,
orderingOptions: [["creation_date", "creation_date"], ["name", "name"]]
@ -205,5 +196,22 @@ export default {
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
<style scoped lang="scss">
@import "../../style/vendor/media";
.wrapper {
width: 100%;
}
.ui.cards {
justify-content: flex-start;
}
.ui.three.cards .card {
width: 100%;
}
@include media(">tablet") {
.ui.three.cards .card {
width: 25em;
}
}
</style>