See #432: added tag detail page
This commit is contained in:
parent
3e9bda24e1
commit
e678b03ad8
|
@ -2,10 +2,11 @@
|
|||
<div class="wrapper">
|
||||
<h3 class="ui header">
|
||||
<slot name="title"></slot>
|
||||
<span v-if="showCount" class="ui tiny circular label">{{ count }}</span>
|
||||
</h3>
|
||||
<button :disabled="!previousPage" @click="fetchData(previousPage)" :class="['ui', {disabled: !previousPage}, 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'angle left', 'icon']"></i></button>
|
||||
<button :disabled="!nextPage" @click="fetchData(nextPage)" :class="['ui', {disabled: !nextPage}, 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'angle right', 'icon']"></i></button>
|
||||
<button @click="fetchData('albums/')" :class="['ui', 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'refresh', 'icon']"></i></button>
|
||||
<button v-if="controls" :disabled="!previousPage" @click="fetchData(previousPage)" :class="['ui', {disabled: !previousPage}, 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'angle left', '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>
|
||||
<div class="ui hidden divider"></div>
|
||||
<div class="ui five cards">
|
||||
<div v-if="isLoading" class="ui inverted active dimmer">
|
||||
|
@ -33,6 +34,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!isLoading && albums.length === 0">No results matching your query.</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -43,7 +45,9 @@ import PlayButton from '@/components/audio/PlayButton'
|
|||
|
||||
export default {
|
||||
props: {
|
||||
filters: {type: Object, required: true}
|
||||
filters: {type: Object, required: true},
|
||||
controls: {type: Boolean, default: true},
|
||||
showCount: {type: Boolean, default: false},
|
||||
},
|
||||
components: {
|
||||
PlayButton
|
||||
|
@ -52,6 +56,7 @@ export default {
|
|||
return {
|
||||
albums: [],
|
||||
limit: 12,
|
||||
count: 0,
|
||||
isLoading: false,
|
||||
errors: null,
|
||||
previousPage: null,
|
||||
|
@ -76,6 +81,7 @@ export default {
|
|||
self.nextPage = response.data.next
|
||||
self.isLoading = false
|
||||
self.albums = response.data.results
|
||||
self.count = response.data.count
|
||||
}, error => {
|
||||
self.isLoading = false
|
||||
self.errors = error.backendErrors
|
||||
|
|
|
@ -142,8 +142,14 @@ export default {
|
|||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.ui.three.cards .card {
|
||||
width: 25em;
|
||||
width: 100%;
|
||||
}
|
||||
@include media(">tablet") {
|
||||
.ui.three.cards .card {
|
||||
width: 25em;
|
||||
}
|
||||
}
|
||||
.with-overlay {
|
||||
background-size: cover !important;
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<div>
|
||||
<h3 class="ui header">
|
||||
<slot name="title"></slot>
|
||||
<span v-if="showCount" class="ui tiny circular label">{{ count }}</span>
|
||||
</h3>
|
||||
<button :disabled="!previousPage" @click="fetchData(previousPage)" :class="['ui', {disabled: !previousPage}, 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'angle up', 'icon']"></i></button>
|
||||
<button :disabled="!nextPage" @click="fetchData(nextPage)" :class="['ui', {disabled: !nextPage}, 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'angle down', 'icon']"></i></button>
|
||||
<button @click="fetchData(url)" :class="['ui', 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'refresh', 'icon']"></i></button>
|
||||
<div class="ui divided unstackable items">
|
||||
<div class="item" v-for="object in objects" :key="object.id">
|
||||
<div :class="['item', itemClasses]" v-for="object in objects" :key="object.id">
|
||||
<div class="ui tiny image">
|
||||
<img v-if="object.track.album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](object.track.album.cover.medium_square_crop)">
|
||||
<img v-else src="../../../assets/audio/default-cover.png">
|
||||
|
@ -28,7 +29,9 @@
|
|||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
<div class="extra">
|
||||
<tags-list label-classes="tiny" :truncate-size="20" :limit="2" :show-more="false" :tags="object.track.tags"></tags-list>
|
||||
|
||||
<div class="extra" v-if="isActivity">
|
||||
<span class="left floated">@{{ object.user.username }}</span>
|
||||
<span class="right floated"><human-date :date="object.creation_date" /></span>
|
||||
</div>
|
||||
|
@ -50,19 +53,25 @@
|
|||
import _ from '@/lodash'
|
||||
import axios from 'axios'
|
||||
import PlayButton from '@/components/audio/PlayButton'
|
||||
import TagsList from "@/components/tags/List"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
filters: {type: Object, required: true},
|
||||
url: {type: String, required: true}
|
||||
url: {type: String, required: true},
|
||||
isActivity: {type: Boolean, default: true},
|
||||
showCount: {type: Boolean, default: false},
|
||||
limit: {type: Number, default: 5},
|
||||
itemClasses: {type: String, default: ''},
|
||||
},
|
||||
components: {
|
||||
PlayButton
|
||||
PlayButton,
|
||||
TagsList
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
objects: [],
|
||||
limit: 5,
|
||||
count: 0,
|
||||
isLoading: false,
|
||||
errors: null,
|
||||
previousPage: null,
|
||||
|
@ -86,7 +95,15 @@ export default {
|
|||
self.previousPage = response.data.previous
|
||||
self.nextPage = response.data.next
|
||||
self.isLoading = false
|
||||
self.objects = response.data.results
|
||||
self.count = response.data.count
|
||||
if (self.isActivity) {
|
||||
// we have listening/favorites objects, not directly tracks
|
||||
self.objects = response.data.results
|
||||
} else {
|
||||
self.objects = response.data.results.map((r) => {
|
||||
return {track: r}
|
||||
})
|
||||
}
|
||||
}, error => {
|
||||
self.isLoading = false
|
||||
self.errors = error.backendErrors
|
||||
|
@ -129,4 +146,18 @@ export default {
|
|||
.ui.divided.items > .item:last-child {
|
||||
padding-bottom: 1em !important;
|
||||
}
|
||||
|
||||
@include media(">tablet") {
|
||||
.divided.items > .track-item.inline {
|
||||
width: 25em;
|
||||
float: left;
|
||||
border-top: none;
|
||||
&,
|
||||
&:first-child {
|
||||
margin-top: 0.5em !important;
|
||||
margin-right: 0.5em !important;
|
||||
padding: 1em 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
<template>
|
||||
<main v-title="labels.title">
|
||||
<section class="ui vertical stripe segment">
|
||||
<h2 class="ui header">
|
||||
<span class="ui circular huge hashtag label">
|
||||
{{ labels.title }}
|
||||
</span>
|
||||
</h2>
|
||||
<div class="ui hidden divider"></div>
|
||||
<div class="ui row">
|
||||
<artist-widget :controls="false" :filters="{playable: true, ordering: '-creation_date', tag: id}">
|
||||
<template slot="title">
|
||||
<router-link :to="{name: 'library.artists.browse', query: {tag: id}}">
|
||||
<translate translate-context="*/*/*">Artists</translate>
|
||||
</router-link>
|
||||
</template>
|
||||
</artist-widget>
|
||||
<div class="ui hidden divider"></div>
|
||||
<div class="ui hidden divider"></div>
|
||||
<album-widget :show-count="true" :controls="false" :filters="{playable: true, ordering: '-creation_date', tag: id}">
|
||||
<template slot="title">
|
||||
<router-link :to="{name: 'library.albums.browse', query: {tag: id}}">
|
||||
<translate translate-context="*/*/*">Albums</translate>
|
||||
</router-link>
|
||||
</template>
|
||||
</album-widget>
|
||||
<div class="ui hidden divider"></div>
|
||||
<div class="ui hidden divider"></div>
|
||||
<track-widget :show-count="true" :limit="12" item-classes="track-item inline" :url="'/tracks/'" :is-activity="false" :filters="{playable: true, ordering: '-creation_date', tag: id}">
|
||||
<template slot="title">
|
||||
<translate translate-context="*/*/*">Tracks</translate>
|
||||
</template>
|
||||
</track-widget>
|
||||
<div class="ui clearing hidden divider"></div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
import TrackWidget from "@/components/audio/track/Widget"
|
||||
import AlbumWidget from "@/components/audio/album/Widget"
|
||||
import ArtistWidget from "@/components/audio/artist/Widget"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
id: { type: String, required: true }
|
||||
},
|
||||
components: {
|
||||
ArtistWidget,
|
||||
AlbumWidget,
|
||||
TrackWidget,
|
||||
},
|
||||
computed: {
|
||||
labels() {
|
||||
let title = `#${this.id}`
|
||||
return {
|
||||
title
|
||||
}
|
||||
},
|
||||
isAuthenticated () {
|
||||
return this.$store.state.auth.authenticated
|
||||
},
|
||||
hasFavorites () {
|
||||
return this.$store.state.favorites.count > 0
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
.ui.circular.label {
|
||||
padding-left: 1em !important;
|
||||
padding-right: 1em !important;
|
||||
}
|
||||
</style>
|
|
@ -473,6 +473,13 @@ export default new Router({
|
|||
id: route.params.id,
|
||||
defaultEdit: route.query.mode === 'edit' })
|
||||
},
|
||||
{
|
||||
path: 'tags/:id',
|
||||
name: 'library.tags.detail',
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "core" */ "@/components/library/TagDetail"),
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: 'artists/:id',
|
||||
component: () =>
|
||||
|
|
|
@ -370,7 +370,7 @@ input + .help {
|
|||
|
||||
|
||||
.tag-list {
|
||||
margin-top: 1em;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
@import "./themes/_light.scss";
|
||||
|
|
Loading…
Reference in New Issue