paginate stats page
This commit is contained in:
@@ -3,21 +3,30 @@
|
|||||||
import type { ActivitySummary, BASIndex, Sport } from '../lib/types';
|
import type { ActivitySummary, BASIndex, Sport } from '../lib/types';
|
||||||
import { formatDistance, formatDuration, sportIcon, sportColor, sportLabel } from '../lib/format';
|
import { formatDistance, formatDuration, sportIcon, sportColor, sportLabel } from '../lib/format';
|
||||||
|
|
||||||
|
const PAGE_YEARS = 4;
|
||||||
|
|
||||||
let all: ActivitySummary[] = [];
|
let all: ActivitySummary[] = [];
|
||||||
let sport: Sport | 'all' = 'all';
|
let sport: Sport | 'all' = 'all';
|
||||||
|
let page = 0;
|
||||||
let loading = true;
|
let loading = true;
|
||||||
let theme = 'dark';
|
let theme = 'dark';
|
||||||
let mounted = false;
|
let mounted = false;
|
||||||
|
|
||||||
|
$: totalPages = Math.ceil(allYears.length / PAGE_YEARS);
|
||||||
|
$: years = allYears.slice(page * PAGE_YEARS, (page + 1) * PAGE_YEARS);
|
||||||
|
|
||||||
$: if (mounted) {
|
$: if (mounted) {
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
if (sport === 'all') params.delete('sport'); else params.set('sport', sport);
|
if (sport === 'all') params.delete('sport'); else params.set('sport', sport);
|
||||||
|
if (page === 0) params.delete('page'); else params.set('page', String(page));
|
||||||
const qs = params.toString();
|
const qs = params.toString();
|
||||||
history.replaceState(null, '', qs ? `?${qs}` : window.location.pathname);
|
history.replaceState(null, '', qs ? `?${qs}` : window.location.pathname);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
sport = (new URLSearchParams(window.location.search).get('sport') as Sport | 'all') ?? 'all';
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
sport = (params.get('sport') as Sport | 'all') ?? 'all';
|
||||||
|
page = parseInt(params.get('page') ?? '0', 10) || 0;
|
||||||
mounted = true;
|
mounted = true;
|
||||||
const res = await fetch(`${import.meta.env.BASE_URL}data/index.json`);
|
const res = await fetch(`${import.meta.env.BASE_URL}data/index.json`);
|
||||||
const index: BASIndex = await res.json();
|
const index: BASIndex = await res.json();
|
||||||
@@ -209,8 +218,6 @@
|
|||||||
: ([] as Sport[]);
|
: ([] as Sport[]);
|
||||||
|
|
||||||
// ── Calendar helpers ──────────────────────────────────────────────────────
|
// ── Calendar helpers ──────────────────────────────────────────────────────
|
||||||
const now = new Date();
|
|
||||||
const years = [now.getFullYear(), now.getFullYear()-1, now.getFullYear()-2, now.getFullYear()-3];
|
|
||||||
|
|
||||||
function localISO(d: Date): string {
|
function localISO(d: Date): string {
|
||||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
||||||
@@ -277,9 +284,26 @@
|
|||||||
<div class="h-64 rounded-xl bg-zinc-800 animate-pulse mb-6"></div>
|
<div class="h-64 rounded-xl bg-zinc-800 animate-pulse mb-6"></div>
|
||||||
{:else}
|
{:else}
|
||||||
|
|
||||||
|
<!-- Pagination controls -->
|
||||||
|
{#if totalPages > 1}
|
||||||
|
<div class="flex items-center justify-between mb-6">
|
||||||
|
<button
|
||||||
|
class="px-3 py-1.5 rounded-lg border border-zinc-700 text-sm text-zinc-400 hover:border-zinc-500 hover:text-white transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
|
||||||
|
disabled={page === 0}
|
||||||
|
on:click={() => page -= 1}
|
||||||
|
>← Newer</button>
|
||||||
|
<span class="text-sm text-zinc-500">{years[years.length - 1]} – {years[0]}</span>
|
||||||
|
<button
|
||||||
|
class="px-3 py-1.5 rounded-lg border border-zinc-700 text-sm text-zinc-400 hover:border-zinc-500 hover:text-white transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
|
||||||
|
disabled={page >= totalPages - 1}
|
||||||
|
on:click={() => page += 1}
|
||||||
|
>Older →</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<!-- Year totals -->
|
<!-- Year totals -->
|
||||||
<div class="grid grid-cols-2 sm:grid-cols-4 gap-4 mb-8">
|
<div class="grid grid-cols-2 sm:grid-cols-4 gap-4 mb-8">
|
||||||
{#each allYears.slice(0, 4) as year}
|
{#each years as year}
|
||||||
{@const t = totalsByYear.get(year)}
|
{@const t = totalsByYear.get(year)}
|
||||||
<div class="bg-zinc-900 rounded-xl border border-zinc-800 p-4">
|
<div class="bg-zinc-900 rounded-xl border border-zinc-800 p-4">
|
||||||
<p class="text-xs text-zinc-500 mb-1">{year}</p>
|
<p class="text-xs text-zinc-500 mb-1">{year}</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user