local activity storage and convert page fixes

- Replace rdp dependency with inline pure-Python RDP implementation
    so the bincio wheel runs in Pyodide (no pure-Python wheel existed for rdp)
  - Fix convert page script: remove define:vars so Vite bundles it and
    TypeScript imports (localstore, format) work correctly
  - Rename wheel to proper PEP 427 filename (bincio-0.1.0-py3-none-any.whl)
  - Use en-GB date format on convert result, consistent with the feed
  - Add /activity/local/ page + LocalActivityDetail for IDB-only activities;
    feed links local activities there instead of the SSG route
  - Fix getStaticPaths: try public/data symlink as fallback, never crash on
    missing index.json
  - Fix ActivityDetail.onMount: load detail even when detail_url is absent
    so locally converted activities show map and charts
  - Derive track_url and detail_url from id in toSummary() since they are
    not present in the detail JSON
  - Reload on bfcache restore (pageshow) so client:only components re-mount
    after back navigation
This commit is contained in:
Davide Scaini
2026-04-08 14:14:42 +02:00
parent 5bf0f3636c
commit 083c67d018
8 changed files with 77 additions and 16 deletions
+3 -2
View File
@@ -92,6 +92,7 @@ const baseUrl = import.meta.env.BASE_URL ?? '/';
<script>
import { saveActivityLocally } from '../../lib/localstore';
import { formatDate, formatTime } from '../../lib/format';
// ── Config ──────────────────────────────────────────────────────────────────
const _cfg = document.getElementById('conv-config') as HTMLElement;
@@ -269,7 +270,7 @@ json.dumps({'id': act_id, 'detail': detail, 'geojson': geojson})
const d = r.detail;
document.getElementById('res-sport-icon').textContent = SPORT_ICONS[d.sport] ?? '⚡';
document.getElementById('res-title').textContent = d.title || 'Untitled';
document.getElementById('res-date').textContent = d.started_at ? new Date(d.started_at).toLocaleString() : '';
document.getElementById('res-date').textContent = d.started_at ? `${formatDate(d.started_at)} · ${formatTime(d.started_at)}` : '';
const distKm = d.distance_m ? (d.distance_m / 1000).toFixed(1) + ' km' : '—';
const dur = d.moving_time_s ?? d.duration_s;
@@ -299,7 +300,7 @@ json.dumps({'id': act_id, 'detail': detail, 'geojson': geojson})
await saveActivityLocally(lastResult.detail, lastResult.geojson ?? null);
btn.textContent = '✓ Saved to device';
btn.style.background = '#16a34a';
saveStatus.textContent = 'Activity saved. Visit the feed to see it.';
saveStatus.innerHTML = `Activity saved. <a href="${baseUrl}activity/local/?id=${lastResult.id}" style="color:#86efac;text-decoration:underline">View activity →</a>`;
saveStatus.style.color = '#4ade80';
} catch (e) {
btn.disabled = false;