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
+18 -10
View File
@@ -6,17 +6,25 @@ import ActivityDetail from '../../components/ActivityDetail.svelte';
import type { BASIndex, ActivitySummary, AthleteZones } from '../../lib/types';
export async function getStaticPaths() {
const dataDir = process.env.BINCIO_DATA_DIR
?? resolve(process.cwd(), '..', 'bincio_data');
const raw = readFileSync(join(dataDir, 'index.json'), 'utf-8');
const index: BASIndex = JSON.parse(raw);
try {
const candidates = [
process.env.BINCIO_DATA_DIR,
resolve(process.cwd(), 'public', 'data'), // symlinked by `bincio render`
resolve(process.cwd(), '..', 'bincio_data'),
].filter(Boolean) as string[];
const dataDir = candidates.find(d => { try { readFileSync(join(d, 'index.json')); return true; } catch { return false; } })!;
const raw = readFileSync(join(dataDir, 'index.json'), 'utf-8');
const index: BASIndex = JSON.parse(raw);
return index.activities
.filter(a => a.privacy !== 'private' && a.id)
.map(a => ({
params: { id: a.id },
props: { activity: a, athlete: index.owner.athlete ?? null },
}));
return index.activities
.filter(a => a.privacy !== 'private' && a.id)
.map(a => ({
params: { id: a.id },
props: { activity: a, athlete: index.owner.athlete ?? null },
}));
} catch {
return [];
}
}
const { activity, athlete } = Astro.props as { activity: ActivitySummary; athlete: AthleteZones | null };
@@ -0,0 +1,8 @@
---
import Base from '../../../layouts/Base.astro';
import LocalActivityDetail from '../../../components/LocalActivityDetail.svelte';
const base = import.meta.env.BASE_URL;
---
<Base title="Activity — BincioActivity">
<LocalActivityDetail {base} client:only="svelte" />
</Base>