diff --git a/extract_config.yaml b/extract_config.yaml index 2f608bc..9623156 100644 --- a/extract_config.yaml +++ b/extract_config.yaml @@ -11,7 +11,7 @@ input: metadata_csv: ~/src/cycling_data_davide/activities.csv output: - dir: ~/bincio_data + dir: ~/src/bincio_data default_privacy: public diff --git a/site/src/components/StatsView.svelte b/site/src/components/StatsView.svelte index a5ddf0d..0510bc0 100644 --- a/site/src/components/StatsView.svelte +++ b/site/src/components/StatsView.svelte @@ -28,14 +28,15 @@ })(); let hoveredDate: string | null = null; + let pinnedDate: string | null = null; + let tooltipEl: HTMLElement | null = null; let tooltipPos = { x: 0, y: 0 }; let hideTimer: ReturnType | null = null; - $: tooltipActivities = hoveredDate ? (activitiesByDate.get(hoveredDate) ?? []) : []; - function onCellEnter(date: string, e: MouseEvent) { - if (!date || !activitiesByDate.has(date)) return; - if (hideTimer) { clearTimeout(hideTimer); hideTimer = null; } - hoveredDate = date; + $: tooltipDate = pinnedDate ?? hoveredDate; + $: tooltipActivities = tooltipDate ? (activitiesByDate.get(tooltipDate) ?? []) : []; + + function updatePos(e: MouseEvent) { const vw = window.innerWidth; const vh = window.innerHeight; tooltipPos = { @@ -44,18 +45,49 @@ }; } + function onCellEnter(date: string, e: MouseEvent) { + if (!date || !activitiesByDate.has(date)) return; + if (pinnedDate) return; + if (hideTimer) { clearTimeout(hideTimer); hideTimer = null; } + hoveredDate = date; + updatePos(e); + } + function onCellLeave() { + if (pinnedDate) return; hideTimer = setTimeout(() => { hoveredDate = null; }, 120); } + function onCellClick(date: string, e: MouseEvent) { + if (!date || !activitiesByDate.has(date)) return; + e.stopPropagation(); + if (pinnedDate === date) { + pinnedDate = null; + } else { + pinnedDate = date; + updatePos(e); + } + } + function onTooltipEnter() { if (hideTimer) { clearTimeout(hideTimer); hideTimer = null; } } function onTooltipLeave() { + if (pinnedDate) return; hoveredDate = null; } + function onWindowClick(e: MouseEvent) { + if (!pinnedDate) return; + if (tooltipEl && tooltipEl.contains(e.target as Node)) return; + pinnedDate = null; + } + + function onKeydown(e: KeyboardEvent) { + if (e.key === 'Escape') pinnedDate = null; + } + // ── Heatmap data ───────────────────────────────────────────────────────── // byDateBySport: date → sport → total distance (m) $: byDateBySport = (() => { @@ -269,10 +301,11 @@ {#each week as date}
onCellEnter(date, e)} on:mouseleave={onCellLeave} + on:click={e => onCellClick(date, e)} /> {/each}
@@ -306,17 +339,29 @@ {/if} + + -{#if hoveredDate && tooltipActivities.length > 0} +{#if tooltipDate && tooltipActivities.length > 0}
-

- {new Date(hoveredDate + 'T12:00:00').toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' })} -

+
+

+ {new Date(tooltipDate + 'T12:00:00').toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' })} +

+ {#if pinnedDate} + + {/if} +
{#each tooltipActivities as a}