style: added new release style; refactor: Artist page with composition API (to finish); refactor: extracted new release check logic
This commit is contained in:
parent
d04439857a
commit
ced8650ee6
File diff suppressed because one or more lines are too long
@ -17,7 +17,7 @@
|
|||||||
<li
|
<li
|
||||||
v-for="(item, name) in artistReleases"
|
v-for="(item, name) in artistReleases"
|
||||||
:key="name"
|
:key="name"
|
||||||
class="section-tabs__tab"
|
class="section-tabs__tab uppercase-first-letter"
|
||||||
@click="changeTab(name)"
|
@click="changeTab(name)"
|
||||||
:class="{ active: currentTab === name }"
|
:class="{ active: currentTab === name }"
|
||||||
>
|
>
|
||||||
@ -33,6 +33,7 @@
|
|||||||
:key="data.title"
|
:key="data.title"
|
||||||
@click="data.sortKey ? sortBy(data.sortKey) : null"
|
@click="data.sortKey ? sortBy(data.sortKey) : null"
|
||||||
:style="{ width: data.width ? data.width : 'auto' }"
|
:style="{ width: data.width ? data.width : 'auto' }"
|
||||||
|
class="uppercase-first-letter"
|
||||||
:class="{
|
:class="{
|
||||||
'sort-asc': data.sortKey == sortKey && sortOrder == 'asc',
|
'sort-asc': data.sortKey == sortKey && sortOrder == 'asc',
|
||||||
'sort-desc': data.sortKey == sortKey && sortOrder == 'desc',
|
'sort-desc': data.sortKey == sortKey && sortOrder == 'desc',
|
||||||
@ -46,8 +47,8 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="release in showTable">
|
<tr v-for="release in sortedData" :key="release.releaseID">
|
||||||
<router-link
|
<RouterLink
|
||||||
tag="td"
|
tag="td"
|
||||||
class="flex items-center clickable"
|
class="flex items-center clickable"
|
||||||
:to="{ name: 'Album', params: { id: release.releaseID } }"
|
:to="{ name: 'Album', params: { id: release.releaseID } }"
|
||||||
@ -57,12 +58,17 @@
|
|||||||
:src="release.releaseCover"
|
:src="release.releaseCover"
|
||||||
style="margin-right: 16px; width: 56px; height: 56px"
|
style="margin-right: 16px; width: 56px; height: 56px"
|
||||||
/>
|
/>
|
||||||
<i v-if="release.isReleaseExplicit" class="material-icons explicit-icon">explicit</i>
|
<i v-if="release.isReleaseExplicit" class="material-icons title-icon title-icon--explicit">explicit</i>
|
||||||
{{ release.releaseTitle }}
|
{{ release.releaseTitle }}
|
||||||
<i v-if="checkNewRelease(release.releaseDate)" class="material-icons" style="color: #ff7300">fiber_new</i>
|
<i
|
||||||
</router-link>
|
v-if="checkNewRelease(release.releaseDate)"
|
||||||
<td>{{ release.releaseDate }}</td>
|
class="material-icons title-icon title-icon--new title-icon--right"
|
||||||
<td>{{ release.releaseTracksNumber }}</td>
|
>
|
||||||
|
fiber_new
|
||||||
|
</i>
|
||||||
|
</RouterLink>
|
||||||
|
<td class="text-center">{{ release.releaseDate }}</td>
|
||||||
|
<td class="text-center">{{ release.releaseTracksNumber }}</td>
|
||||||
<td @click.stop="sendAddToQueue(release.releaseLink)" class="clickable">
|
<td @click.stop="sendAddToQueue(release.releaseLink)" class="clickable">
|
||||||
<i class="material-icons" :title="$t('globals.download_hint')"> file_download </i>
|
<i class="material-icons" :title="$t('globals.download_hint')"> file_download </i>
|
||||||
</td>
|
</td>
|
||||||
@ -73,80 +79,75 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { defineComponent, ref, unref, reactive, computed, onMounted, toRefs } from '@vue/composition-api'
|
||||||
import { orderBy } from 'lodash-es'
|
import { orderBy } from 'lodash-es'
|
||||||
|
|
||||||
import { socket } from '@/utils/socket'
|
import { socket } from '@/utils/socket'
|
||||||
import { sendAddToQueue } from '@/utils/downloads'
|
import { sendAddToQueue } from '@/utils/downloads'
|
||||||
import EventBus from '@/utils/EventBus'
|
import { checkNewRelease } from '@/utils/dates'
|
||||||
import { formatArtistData } from '@/data/artist'
|
import { formatArtistData, getArtistData } from '@/data/artist'
|
||||||
import { standardizeData } from '@/data/standardize'
|
import { standardizeData } from '@/data/standardize'
|
||||||
import { ref, reactive, computed, onMounted, toRefs, onDeactivated } from '@vue/composition-api'
|
|
||||||
|
|
||||||
export default {
|
export default defineComponent({
|
||||||
setup() {
|
setup(props, ctx) {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
currentTab: '',
|
currentTab: '',
|
||||||
sortKey: 'releaseDate',
|
sortKey: 'releaseDate',
|
||||||
sortOrder: 'desc',
|
sortOrder: 'desc',
|
||||||
artistReleases: {},
|
artistReleases: {},
|
||||||
artistID: '',
|
|
||||||
artistName: '',
|
artistName: '',
|
||||||
artistPicture: ''
|
artistPicture: '',
|
||||||
|
currentRelease: computed(() => state.artistReleases[state.currentTab])
|
||||||
})
|
})
|
||||||
|
|
||||||
const currentRelease = computed(() => state.artistReleases[state.currentTab])
|
const artistID = computed(() => ctx.root.$router.currentRoute.params.id)
|
||||||
|
const hasDataLoaded = ref(false)
|
||||||
|
|
||||||
const setupData = data => {
|
getArtistData(unref(artistID))
|
||||||
const {
|
.then(artistData => {
|
||||||
data: [{ artistID, artistName, artistPictureXL, artistReleases }]
|
hasDataLoaded.value = true
|
||||||
} = standardizeData({ data: [data], hasLoaded: true }, formatArtistData)
|
|
||||||
|
|
||||||
Object.assign(state, {
|
const {
|
||||||
artistID,
|
data: [{ artistName, artistPictureXL, artistReleases }]
|
||||||
artistName,
|
} = standardizeData({ data: [artistData], hasLoaded: unref(hasDataLoaded) }, formatArtistData)
|
||||||
artistPicture: artistPictureXL,
|
|
||||||
artistReleases
|
Object.assign(state, {
|
||||||
|
artistName,
|
||||||
|
artistPicture: artistPictureXL,
|
||||||
|
artistReleases,
|
||||||
|
currentTab: Object.keys(artistReleases)[0]
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
.catch(err => console.error(err))
|
||||||
|
|
||||||
// ? Is it not granted that it's always 'all' ?
|
const sortedData = computed(() => {
|
||||||
state.currentTab = Object.keys(artistReleases)[0]
|
if (!unref(hasDataLoaded)) {
|
||||||
}
|
return []
|
||||||
|
|
||||||
const reset = () => {
|
|
||||||
state.currentTab = ''
|
|
||||||
state.sortKey = 'releaseDate'
|
|
||||||
state.sortOrder = 'desc'
|
|
||||||
}
|
|
||||||
|
|
||||||
onDeactivated(reset)
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
socket.on('show_artist', setupData)
|
|
||||||
})
|
|
||||||
|
|
||||||
const showTable = computed(() => {
|
|
||||||
if (Object.keys(state.artistReleases).length !== 0) {
|
|
||||||
let sortKey = state.sortKey
|
|
||||||
|
|
||||||
if (sortKey == 'releaseTracksNumber') {
|
|
||||||
sortKey = o => new Number(o.releaseTracksNumber)
|
|
||||||
}
|
|
||||||
|
|
||||||
return orderBy(currentRelease.value, sortKey, state.sortOrder)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return []
|
let sortKey = state.sortKey
|
||||||
|
|
||||||
|
if (sortKey === 'releaseTracksNumber') {
|
||||||
|
sortKey = o => new Number(o.releaseTracksNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
return orderBy(state.currentRelease, sortKey, state.sortOrder)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const changeTab = newTab => {
|
||||||
|
state.currentTab = newTab
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
downloadLink: computed(() => `https://www.deezer.com/artist/${state.artistID}`),
|
downloadLink: computed(() => `https://www.deezer.com/artist/${unref(artistID)}`),
|
||||||
headerStyle: computed(() => ({
|
headerStyle: computed(() => ({
|
||||||
backgroundImage: `linear-gradient(to bottom, transparent 0%, var(--main-background) 100%), url(${state.artistPicture})`
|
backgroundImage: `linear-gradient(to bottom, transparent 0%, var(--main-background) 100%), url(${state.artistPicture})`
|
||||||
})),
|
})),
|
||||||
showTable,
|
sortedData,
|
||||||
sendAddToQueue,
|
sendAddToQueue,
|
||||||
currentRelease
|
checkNewRelease,
|
||||||
|
changeTab
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -170,19 +171,8 @@ export default {
|
|||||||
this.sortKey = key
|
this.sortKey = key
|
||||||
this.sortOrder = 'asc'
|
this.sortOrder = 'asc'
|
||||||
}
|
}
|
||||||
},
|
|
||||||
changeTab(tab) {
|
|
||||||
this.currentTab = tab
|
|
||||||
},
|
|
||||||
checkNewRelease(date) {
|
|
||||||
let g1 = new Date()
|
|
||||||
let g2 = new Date(date)
|
|
||||||
g2.setDate(g2.getDate() + 3)
|
|
||||||
g1.setHours(0, 0, 0, 0)
|
|
||||||
|
|
||||||
return g1.getTime() <= g2.getTime()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<h1 class="flex items-center m-0 text-5xl">
|
<h1 class="flex items-center m-0 text-5xl">
|
||||||
{{ title }} <i v-if="explicit" class="material-icons explicit-icon explicit-icon--right">explicit</i>
|
{{ title }} <i v-if="explicit" class="material-icons title-icon title-icon--right">explicit</i>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<h2 class="m-0 mb-3 text-lg">
|
<h2 class="m-0 mb-3 text-lg">
|
||||||
@ -60,7 +60,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="table__cell--large table__cell--with-icon">
|
<td class="table__cell--large table__cell--with-icon">
|
||||||
<div class="table__cell-content table__cell-content--vertical-center">
|
<div class="table__cell-content table__cell-content--vertical-center">
|
||||||
<i v-if="track.explicit_lyrics" class="material-icons explicit-icon"> explicit </i>
|
<i v-if="track.explicit_lyrics" class="material-icons title-icon"> explicit </i>
|
||||||
{{
|
{{
|
||||||
track.title +
|
track.title +
|
||||||
(track.title_version && track.title.indexOf(track.title_version) == -1
|
(track.title_version && track.title.indexOf(track.title_version) == -1
|
||||||
@ -127,7 +127,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>{{ i + 1 }}</td>
|
<td>{{ i + 1 }}</td>
|
||||||
<td class="flex items-center">
|
<td class="flex items-center">
|
||||||
<i v-if="track.explicit" class="material-icons explicit-icon">explicit</i>
|
<i v-if="track.explicit" class="material-icons title-icon">explicit</i>
|
||||||
{{ track.name }}
|
{{ track.name }}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ track.artists[0].name }}</td>
|
<td>{{ track.artists[0].name }}</td>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
<span class="primary-text">
|
<span class="primary-text">
|
||||||
<i
|
<i
|
||||||
v-if="release.isAlbumExplicit"
|
v-if="release.isAlbumExplicit"
|
||||||
class="material-icons explicit-icon"
|
class="material-icons title-icon"
|
||||||
style="font-size: 1.0625rem !important"
|
style="font-size: 1.0625rem !important"
|
||||||
>
|
>
|
||||||
explicit
|
explicit
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
<td class="table__cell table__cell--large">
|
<td class="table__cell table__cell--large">
|
||||||
<div class="break-words table__cell-content table__cell-content--vertical-center">
|
<div class="break-words table__cell-content table__cell-content--vertical-center">
|
||||||
<i v-if="track.isTrackExplicit" class="material-icons explicit-icon">explicit</i>
|
<i v-if="track.isTrackExplicit" class="material-icons title-icon">explicit</i>
|
||||||
{{ formatTitle(track) }}
|
{{ formatTitle(track) }}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
import { socket } from '@/utils/socket'
|
||||||
import { getPropertyWithFallback } from '@/utils/utils'
|
import { getPropertyWithFallback } from '@/utils/utils'
|
||||||
|
|
||||||
export function formatArtistData(artistData) {
|
export function formatArtistData(artistData) {
|
||||||
return {
|
return {
|
||||||
artistID: getPropertyWithFallback(artistData, 'id'),
|
|
||||||
artistName: getPropertyWithFallback(artistData, 'name'),
|
artistName: getPropertyWithFallback(artistData, 'name'),
|
||||||
artistPictureXL: getPropertyWithFallback(artistData, 'picture_xl'),
|
artistPictureXL: getPropertyWithFallback(artistData, 'picture_xl'),
|
||||||
artistReleases: formatArtistReleases(getPropertyWithFallback(artistData, 'releases'))
|
artistReleases: formatArtistReleases(getPropertyWithFallback(artistData, 'releases'))
|
||||||
@ -33,3 +33,27 @@ function formatArtistReleases(artistReleases) {
|
|||||||
|
|
||||||
return formattedReleases
|
return formattedReleases
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let artistData = {}
|
||||||
|
let cached = false
|
||||||
|
|
||||||
|
export function getArtistData(artistID) {
|
||||||
|
if (cached) {
|
||||||
|
return artistData
|
||||||
|
} else {
|
||||||
|
socket.emit('getTracklist', {
|
||||||
|
type: 'artist',
|
||||||
|
id: artistID
|
||||||
|
})
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
socket.on('show_artist', data => {
|
||||||
|
artistData = data
|
||||||
|
// cached = true
|
||||||
|
|
||||||
|
socket.off('show_artist')
|
||||||
|
resolve(data)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -35,7 +35,10 @@ const routes = [
|
|||||||
{
|
{
|
||||||
path: '/artist/:id',
|
path: '/artist/:id',
|
||||||
name: 'Artist',
|
name: 'Artist',
|
||||||
component: Artist
|
component: Artist,
|
||||||
|
meta: {
|
||||||
|
notKeepAlive: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/album/:id',
|
path: '/album/:id',
|
||||||
@ -123,12 +126,6 @@ router.beforeEach((to, from, next) => {
|
|||||||
let getTracklistParams = null
|
let getTracklistParams = null
|
||||||
|
|
||||||
switch (to.name) {
|
switch (to.name) {
|
||||||
case 'Artist':
|
|
||||||
getTracklistParams = {
|
|
||||||
type: 'artist',
|
|
||||||
id: to.params.id
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'Tracklist':
|
case 'Tracklist':
|
||||||
getTracklistParams = {
|
getTracklistParams = {
|
||||||
type: to.params.type,
|
type: to.params.type,
|
||||||
|
15
src/styles/vendor/material-icons.css
vendored
15
src/styles/vendor/material-icons.css
vendored
@ -26,15 +26,22 @@
|
|||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
.material-icons.explicit-icon {
|
.material-icons.title-icon {
|
||||||
margin-right: 0.3125em;
|
margin-right: 0.3125em;
|
||||||
margin-left: -3px;
|
margin-left: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-icons.title-icon.title-icon--right {
|
||||||
|
margin-right: 0px;
|
||||||
|
margin-left: 0.3125em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-icons.title-icon.title-icon--explicit {
|
||||||
color: hsl(240, 5%, 59%);
|
color: hsl(240, 5%, 59%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.material-icons.explicit-icon.explicit-icon--right {
|
.material-icons.title-icon.title-icon--new {
|
||||||
margin-right: 0px;
|
color: hsl(27, 100%, 50%);
|
||||||
margin-left: 0.3125em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.material-icons.disabled {
|
.material-icons.disabled {
|
||||||
|
14
src/utils/dates.js
Normal file
14
src/utils/dates.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* @param {Date} dateToCheck
|
||||||
|
* @returns {boolean} The passed date is less than 3 days distant from today,
|
||||||
|
* therefore it's considered a new release, if referring to a track or album
|
||||||
|
*/
|
||||||
|
export function checkNewRelease(dateToCheck) {
|
||||||
|
let now = new Date()
|
||||||
|
now.setHours(0, 0, 0, 0)
|
||||||
|
|
||||||
|
dateToCheck = new Date(dateToCheck)
|
||||||
|
dateToCheck.setDate(dateToCheck.getDate() + 3)
|
||||||
|
|
||||||
|
return now.getTime() <= dateToCheck.getTime()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user