mirror of
https://github.com/maciejpedzich/spotifyplaylistarchive.com.git
synced 2024-09-19 18:16:19 +02:00
Create a unified TrackEntriesTable component
This commit is contained in:
parent
f742bb4cd4
commit
fb9e64f085
115
components/TrackEntriesTable.vue
Normal file
115
components/TrackEntriesTable.vue
Normal file
@ -0,0 +1,115 @@
|
||||
<script setup lang="ts">
|
||||
import formatDuration from 'format-duration';
|
||||
import {
|
||||
intervalToDuration,
|
||||
formatDuration as dateFnsFormatDuration
|
||||
} from 'date-fns';
|
||||
|
||||
import DataTable from 'primevue/datatable';
|
||||
import Column from 'primevue/column';
|
||||
|
||||
import { Track } from '~~/models/track';
|
||||
|
||||
const props = defineProps<{
|
||||
loading: boolean;
|
||||
tracks: Track[] | null;
|
||||
page: 'snapshot' | 'stats';
|
||||
}>();
|
||||
|
||||
const dateFormatter = new Intl.DateTimeFormat('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
});
|
||||
|
||||
const formatDate = (date: string | null) =>
|
||||
date ? dateFormatter.format(new Date(date)) : 'N/A';
|
||||
|
||||
const displayRetentionText = (retention: number) => {
|
||||
const durationObject = intervalToDuration({ start: 0, end: retention });
|
||||
const displayText = dateFnsFormatDuration(durationObject, {
|
||||
format: ['years', 'months', 'days'],
|
||||
delimiter: ', '
|
||||
});
|
||||
|
||||
return displayText;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DataTable
|
||||
class="w-full mx-5 mt-3 mb-5"
|
||||
:loading="props.loading"
|
||||
:value="props.tracks"
|
||||
:rows="10"
|
||||
:rows-per-page-options="[10, 20, 50, 100]"
|
||||
paginator
|
||||
paginator-template="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
|
||||
current-page-report-template="Showing {first} to {last} of {totalRecords}"
|
||||
responsive-layout="stack"
|
||||
>
|
||||
<Column field="name" header="Title">
|
||||
<template #body="{ data: track }">
|
||||
<NuxtLink :to="track.url" target="_blank">
|
||||
{{ track.name }}
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="artists" header="Artist(s)">
|
||||
<template #body="{ data: track }">
|
||||
<div>
|
||||
<div v-for="(artist, index) of track.artists" :key="artist.url">
|
||||
<NuxtLink :to="artist.url" target="_blank">
|
||||
{{ artist.name }}
|
||||
</NuxtLink>
|
||||
<span v-if="index !== track.artists.length - 1" class="md:mr-1"
|
||||
>,</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="album.name" header="Album">
|
||||
<template #body="{ data: track }">
|
||||
<NuxtLink :to="track.album.url" target="_blank">
|
||||
{{ track.album.name }}
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</Column>
|
||||
<template v-if="props.page === 'snapshot'">
|
||||
<Column field="added_at" header="Date added" sortable>
|
||||
<template #body="{ data: track }">
|
||||
{{ formatDate(track.added_at) }}
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="duration_ms" header="Duration" sortable>
|
||||
<template #body="{ data: track }">
|
||||
{{ formatDuration(track.duration_ms) }}
|
||||
</template>
|
||||
</Column>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Column field="date_added" header="Date added">
|
||||
<template #body="{ data: track }">
|
||||
<span>
|
||||
{{ formatDate(track.date_added) }}
|
||||
</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="date_removed" header="Date removed">
|
||||
<template #body="{ data: track }">
|
||||
<span>
|
||||
{{ formatDate(track.date_removed) }}
|
||||
</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="retention" header="Retention">
|
||||
<template #body="{ data: track }">
|
||||
<span>
|
||||
{{ displayRetentionText(track.retention) }}
|
||||
</span>
|
||||
</template>
|
||||
</Column>
|
||||
</template>
|
||||
</DataTable>
|
||||
</template>
|
@ -1,35 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { $fetch } from 'ohmyfetch';
|
||||
import { intervalToDuration, formatDuration } from 'date-fns';
|
||||
|
||||
import ProgressSpinner from 'primevue/progressspinner';
|
||||
import DataTable from 'primevue/datatable';
|
||||
import Column from 'primevue/column';
|
||||
|
||||
import { Cumulative } from '~~/models/cumulative';
|
||||
|
||||
const route = useRoute();
|
||||
const playlistId = route.params.playlistId as string;
|
||||
|
||||
const dateFormatter = new Intl.DateTimeFormat('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
});
|
||||
|
||||
const formatDate = (date: string | null) =>
|
||||
date ? dateFormatter.format(new Date(date)) : 'N/A';
|
||||
|
||||
const displayRetentionText = (retention: number) => {
|
||||
const durationObject = intervalToDuration({ start: 0, end: retention });
|
||||
const displayText = formatDuration(durationObject, {
|
||||
format: ['years', 'months', 'days'],
|
||||
delimiter: ', '
|
||||
});
|
||||
|
||||
return displayText;
|
||||
};
|
||||
|
||||
const {
|
||||
pending,
|
||||
error,
|
||||
@ -58,70 +34,10 @@ const {
|
||||
<template>
|
||||
<NuxtLayout name="centered-content">
|
||||
<ClientOnly>
|
||||
<ProgressSpinner v-if="pending" />
|
||||
<p v-else-if="error">
|
||||
<p v-if="error">
|
||||
Something went wrong while fetching the longest standing tracks
|
||||
</p>
|
||||
<DataTable
|
||||
class="w-full mx-5 mt-3 mb-5"
|
||||
:value="tracks"
|
||||
paginator
|
||||
:rows="10"
|
||||
:rows-per-page-options="[10, 20, 50, 100]"
|
||||
paginator-template="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
|
||||
current-page-report-template="Showing {first} to {last} of {totalRecords}"
|
||||
responsive-layout="stack"
|
||||
>
|
||||
<Column field="name" header="Title">
|
||||
<template #body="{ data: track }">
|
||||
<NuxtLink :to="track.url" target="_blank">
|
||||
{{ track.name }}
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="artists" header="Artist(s)">
|
||||
<template #body="{ data: track }">
|
||||
<div>
|
||||
<div v-for="(artist, index) of track.artists" :key="artist.url">
|
||||
<NuxtLink :to="artist.url" target="_blank">
|
||||
{{ artist.name }}
|
||||
</NuxtLink>
|
||||
<span v-if="index !== track.artists.length - 1" class="md:mr-1"
|
||||
>,</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="album.name" header="Album">
|
||||
<template #body="{ data: track }">
|
||||
<NuxtLink :to="track.album.url" target="_blank">
|
||||
{{ track.album.name }}
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="date_added" header="Date added">
|
||||
<template #body="{ data: track }">
|
||||
<span>
|
||||
{{ formatDate(track.date_added) }}
|
||||
</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="date_removed" header="Date removed">
|
||||
<template #body="{ data: track }">
|
||||
<span>
|
||||
{{ formatDate(track.date_removed) }}
|
||||
</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="retention" header="Retention">
|
||||
<template #body="{ data: track }">
|
||||
<span>
|
||||
{{ displayRetentionText(track.retention) }}
|
||||
</span>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
<TrackEntriesTable :loading="pending" :tracks="tracks" page="stats" />
|
||||
</ClientOnly>
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
@ -2,16 +2,17 @@
|
||||
import { decode as decodeHtmlEntities } from 'html-entities';
|
||||
import formatDuration from 'format-duration';
|
||||
|
||||
import DataTable from 'primevue/datatable';
|
||||
import Column from 'primevue/column';
|
||||
|
||||
import { Playlist } from '~~/models/playlist';
|
||||
|
||||
const route = useRoute();
|
||||
const playlistId = route.params.playlistId as string;
|
||||
const commitSha = route.params.commitSha as string;
|
||||
|
||||
const { error, data: snapshot } = useFetch<Playlist>(
|
||||
const {
|
||||
pending,
|
||||
error,
|
||||
data: snapshot
|
||||
} = useFetch<Playlist>(
|
||||
() =>
|
||||
`https://raw.githubusercontent.com/mackorone/spotify-playlist-archive/${commitSha}/playlists/pretty/${playlistId}.json`,
|
||||
{ key: `snapshot-${commitSha}`, parseResponse: JSON.parse }
|
||||
@ -25,14 +26,8 @@ const totalTrackDuration = computed(() =>
|
||||
);
|
||||
|
||||
const numberFormatter = new Intl.NumberFormat('en-US');
|
||||
const dateFormatter = new Intl.DateTimeFormat('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
});
|
||||
|
||||
const humanizeNumber = (num: number) => numberFormatter.format(num);
|
||||
const formatDate = (date: string) => dateFormatter.format(Date.parse(date));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -58,52 +53,11 @@ const formatDate = (date: string) => dateFormatter.format(Date.parse(date));
|
||||
</ul>
|
||||
</div>
|
||||
<ClientOnly>
|
||||
<DataTable
|
||||
:value="snapshot.tracks"
|
||||
paginator
|
||||
:rows="10"
|
||||
:rows-per-page-options="[10, 20, 50, 100]"
|
||||
paginator-template="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
|
||||
current-page-report-template="Showing {first} to {last} of {totalRecords}"
|
||||
responsive-layout="stack"
|
||||
>
|
||||
<Column field="name" header="Title" sortable>
|
||||
<template #body="{ data: track }">
|
||||
<NuxtLink :to="track.url" target="_blank">
|
||||
{{ track.name }}
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="artists" header="Artist(s)">
|
||||
<template #body="{ data: track }">
|
||||
<div v-for="(artist, index) of track.artists" :key="artist.url">
|
||||
<NuxtLink :to="artist.url" target="_blank">
|
||||
{{ artist.name }}
|
||||
</NuxtLink>
|
||||
<span v-if="index !== track.artists.length - 1" class="md:mr-1"
|
||||
>,</span
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="album.name" header="Album" sortable>
|
||||
<template #body="{ data: track }">
|
||||
<NuxtLink :to="track.album.url" target="_blank">
|
||||
{{ track.album.name }}
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="added_at" header="Date added" sortable>
|
||||
<template #body="{ data: track }">
|
||||
{{ formatDate(track.added_at) }}
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="duration_ms" header="Duration" sortable>
|
||||
<template #body="{ data: track }">
|
||||
{{ formatDuration(track.duration_ms) }}
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
<TrackEntriesTable
|
||||
:loading="pending"
|
||||
:tracks="snapshot.tracks"
|
||||
page="snapshot"
|
||||
/>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user