{/* Audio player preview if narration is uploaded */}
{tour.audio_url && (
Audio preview
)}
Stops on this walk
{STOPS.map((s,i) => (
{i+1}
{s.name}
{s.dist} · {s.duration}
{s.blurb &&
{s.blurb}
}
))}
{isPro && (
Pro tour includes
The full story, not the postcard.
{['Narration by a local historian','Hidden side-stops only locals know','AR overlays at key landmarks','Offline download for the whole route'].map(t => (
{t}
))}
)}
{isPro
?
:
}
);
}
function Stat({ label, value }) {
return (
{value}
{label}
);
}
// Download-for-offline control. Caches the app + this tour over Wi-Fi so it
// plays with no signal on-site. Narration is on-device, so downloads are tiny.
function OfflineDownloadCard({ tour }) {
const off = window.WanderOffline;
const ok = off && off.supported();
const [state, setState] = React.useState(() => (ok && off.has(tour.id)) ? 'done' : 'idle');
const [pct, setPct] = React.useState(0);
if (!ok) return null;
const start = async () => {
setState('downloading'); setPct(0);
try {
await off.download(tour.id, p => setPct(p));
setState('done');
} catch {
setState('idle');
}
};
const undo = async () => { await off.remove(tour.id); setState('idle'); setPct(0); };
const base = { marginTop:18, padding:14, borderRadius:18, display:'flex', alignItems:'center', gap:12 };
if (state === 'done') {
return (