Skip to content
Snippets Groups Projects
Verified Commit 5d1d5489 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

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

parent c885c10b
No related branches found
No related tags found
No related merge requests found
<template>
<div class="ui card">
<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 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="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>
<div class="content">
<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>
<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 {
......
......@@ -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>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment