35
35
<v-list class =" stat-list" >
36
36
<div class =" item-stat pa-4" >
37
37
<p class =" minutes-stat" >Artist</p >
38
- <p class =" minutes-stat" >Listened minutes</p >
38
+ <p class =" minutes-stat align-right " >Listened minutes</p >
39
39
</div >
40
- <v-list-item
41
- v-for =" ({ artist, minutes }, i) of artistsTop"
42
- :to =" itemUrl(artist)"
43
- rounded
44
- @click.right ="
45
- dialog.setContextMenuItem($event as MouseEvent, artist)
46
- "
40
+ <template
41
+ v-for =" ({ artist , listenMinutes , history }, i ) of artistsTop "
47
42
>
48
- <v-list-item-title class =" item-stat" >
49
- <p class =" item-rank" >{{ i + 1 }}</p >
50
- <v-avatar :image =" itemImage(artist)" size =" 36px" />
51
- <p class =" flex-grow-1" >{{ artist.name }}</p >
52
- <p class =" minutes-stat" >
53
- <span class =" font-weight-bold" >{{
54
- minutes.toLocaleString()
55
- }}</span >
56
- mins
57
- </p >
58
- </v-list-item-title >
59
- </v-list-item >
43
+ <v-list-item
44
+ rounded
45
+ @click.right ="
46
+ dialog.setContextMenuItem($event as MouseEvent, artist)
47
+ "
48
+ >
49
+ <v-list-item-title class =" item-stat" >
50
+ <p class =" item-rank" >{{ i + 1 }}</p >
51
+ <v-avatar
52
+ :image ="
53
+ itemImage(artist as SpotifyApi.ArtistObjectFull)
54
+ "
55
+ size =" 36px"
56
+ />
57
+ <router-link
58
+ no-style
59
+ :to =" itemUrl(artist)"
60
+ class =" flex-grow-1"
61
+ >{{ artist.name }}
62
+ </router-link >
63
+ <p class =" minutes-stat align-right" >
64
+ <span class =" font-weight-bold" >{{
65
+ listenMinutes.toLocaleString()
66
+ }}</span >
67
+ mins
68
+ </p >
69
+ <v-btn
70
+ @click =" toggleChart(artist.id)"
71
+ icon =" mdi-chart-line-variant"
72
+ density =" compact"
73
+ variant =" text"
74
+ />
75
+ </v-list-item-title >
76
+ </v-list-item >
77
+ <div v-if =" expandedArtists.has(artist.id)" >
78
+ <line-chart :chart-data =" artistChart(`Minutes listened to ${artist.name}`, history)" />
79
+ </div >
80
+ </template >
60
81
</v-list >
61
82
62
83
<v-divider class =" mt-5 mb-5" />
177
198
import LineChart from " ../components/LineChart.vue" ;
178
199
import { computed , ref } from " vue" ;
179
200
import { useStatsStore } from " ../store/player/playStats" ;
180
- import { ChartData , ItemCollection , TrackStat } from " ../scripts/types" ;
201
+ import {
202
+ ArtistStat ,
203
+ ChartData ,
204
+ ItemCollection ,
205
+ TrackStat ,
206
+ } from " ../scripts/types" ;
181
207
import { useUIStore } from " ../store/UI/UIStore" ;
182
208
import { useSpotifyApiStore } from " ../store/spotify-api" ;
183
209
import TrackListItem from " ../components/track-list/TrackListItem.vue" ;
@@ -204,11 +230,27 @@ const shownCharts = ref([2, 9, 11]);
204
230
const trackLimit = ref (10 );
205
231
const artistLimit = ref (5 );
206
232
207
- const artistsTop = ref (
208
- [] as { artist: SpotifyApi .ArtistObjectFull ; minutes: number }[],
209
- );
233
+ const artistsTop = ref ([] as ArtistStat []);
210
234
const tracksTop = ref ([] as TrackStat []);
211
235
const tracksSkip = ref ([] as TrackStat []);
236
+ const expandedArtists = ref (new Set <string >());
237
+
238
+ function toggleChart(artistId : string ) {
239
+ if (expandedArtists .value .has (artistId )) {
240
+ expandedArtists .value .delete (artistId );
241
+ } else {
242
+ expandedArtists .value .add (artistId );
243
+ }
244
+ }
245
+
246
+ function artistChart(label : string , history : { [key : string ]: number }) {
247
+ return {
248
+ labels: Object .keys (history ).map ((k ) => new Date (k )),
249
+ values: Object .values (history ),
250
+ yAxis: " Minutes" ,
251
+ dataLabel: label ,
252
+ };
253
+ }
212
254
213
255
async function generate() {
214
256
let { topArtists, topTracks, skipTracks, statistics } =
@@ -221,10 +263,10 @@ async function generate() {
221
263
: spotify .getArtist (a .id , true ),
222
264
),
223
265
);
224
- artistsTop .value = artists .map ((artist , i ) => ( {
225
- artist ,
226
- minutes: topArtists [i ]. listenMinutes ,
227
- })) ;
266
+ artistsTop .value = artists .map ((artist , i ) => {
267
+ topArtists [ i ]. artist = artist ;
268
+ return topArtists [i ];
269
+ });
228
270
tracksTop .value = topTracks ;
229
271
tracksSkip .value = skipTracks ;
230
272
344
386
opacity : 0.7 ;
345
387
text-transform : uppercase ;
346
388
font-size : 13px ;
389
+ width : 130px ;
347
390
}
348
391
349
392
.track-list-item {
364
407
.track-list-item-parent.odd-item {
365
408
background-color : rgba (var (--v-theme-on-background ), 0.06 );
366
409
}
410
+
411
+ .align-right {
412
+ text-align : right ;
413
+ }
367
414
</style >
0 commit comments