/* global React */ const { useState, useEffect, useMemo, useRef } = React; const fmtDate = (s) => { const d = new Date(s + 'T00:00:00'); return d.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' }); }; const fmtDateLong = (s) => { const d = new Date(s + 'T00:00:00'); return d.toLocaleDateString('en-GB', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }); }; const fmtN = (n) => n.toLocaleString('en-US'); /* ---------- Masthead / nav ---------- */ function Masthead({ route, nav }) { const tabs = [ ['home', 'Home'], ['mps', 'MPs'], ['topics', 'Topics'], ['sittings', 'Sittings'], ['heatmap', 'Pulse'], ['search', 'Search'], ]; return (
{ e.preventDefault(); nav('home'); }} className="wordmark serif"> Politick Sri Lankan Parliament · Hansard Record
Parliament sitting 20 Mar
); } /* ---------- Footer ---------- */ function Colophon() { return ( ); } /* ---------- Topic tag ---------- */ function TopicTag({ topic, onClick }) { return ( { e.preventDefault(); onClick && onClick(topic); }}> {topic.short || topic.name} ); } function PartyChip({ party }) { if (!party) return null; return ( {party.abbr} ); } /* ---------- Speech item ---------- */ function SpeechItem({ speech, showMp = true, showDate = false, nav }) { return (
{showMp && speech.mp && ( <> { e.preventDefault(); nav('mp', { id: speech.mp.id }); }} className="serif" style={{ fontSize: 16, fontWeight: 600, color: 'var(--ink)', display: 'block', lineHeight: 1.2, letterSpacing: '-0.01em' }} > {speech.mp.name}
· {speech.mp.district}
)} {showDate && (
{fmtDate(speech.sittingDate)} · #{speech.speechOrder}
)}
{speech.debate}

{speech.summary}

{speech.topics.map(t => nav('topic', { slug: tt.slug })} />)} { e.preventDefault(); nav('speech', { id: speech.id }); }} style={{ fontSize: 11, color: 'var(--ink-3)', fontFamily: 'var(--mono)' }} > read full text →
); } /* ---------- Sparkline ---------- */ function Sparkline({ values, width = 120, height = 28, color = 'var(--ink)' }) { if (!values || !values.length) return null; const max = Math.max(...values, 1); const step = width / (values.length - 1 || 1); const points = values.map((v, i) => `${(i * step).toFixed(1)},${(height - (v / max) * height).toFixed(1)}`).join(' '); const bars = values.map((v, i) => { const h = (v / max) * height; return ; }); return ( {bars} ); } /* ---------- Horizontal bar (for topic breakdown) ---------- */ function HBar({ items, max, labelKey = 'label', valueKey = 'value', colorKey, onClick }) { const m = max ?? Math.max(...items.map(i => i[valueKey]), 1); return (
{items.map((it, i) => { const pct = (it[valueKey] / m) * 100; return (
onClick(it) : undefined} style={{ cursor: onClick ? 'pointer' : 'default' }}>
{it[labelKey]} {it[valueKey]}
); })}
); } /* ---------- Tweaks panel ---------- */ function TweaksPanel({ tweaks, setTweaks, active, onClose }) { if (!active) return null; const accents = [ { id: 'civic-red', c: 'oklch(55% 0.15 25)' }, { id: 'ink-blue', c: 'oklch(45% 0.12 250)' }, { id: 'forest', c: 'oklch(45% 0.10 150)' }, { id: 'ochre', c: 'oklch(60% 0.14 70)' }, { id: 'plum', c: 'oklch(45% 0.12 350)' }, ]; return (

Tweaks

Accent
{accents.map(a => (
Display
{['humanist','grotesque','classical'].map(f => ( ))}
Density
Theme
); } Object.assign(window, { fmtDate, fmtDateLong, fmtN, Masthead, Colophon, TopicTag, PartyChip, SpeechItem, Sparkline, HBar, TweaksPanel, });