/* ===== Compliance / KPI right-side panel ===== */ const Bar = ({ value, max, color = 'var(--mojro-red)', warnAt = 0.85, badAt = 1.0, label, sub, mono = false }) => { const pct = Math.min(1, value / max); const cls = pct >= badAt ? 'bad' : pct >= warnAt ? 'warn' : 'ok'; const tint = cls === 'bad' ? 'var(--bad)' : cls === 'warn' ? 'var(--warn)' : color; return (
{label} {sub}
{warnAt && (
)}
); }; const AxleChart = ({ axles }) => { const max = Math.max(...axles.map(a => a.limit)); return (
{axles.map(a => { const h = (a.load / max) * 70; const cls = a.load > a.limit ? 'var(--bad)' : a.load > a.limit*0.9 ? 'var(--warn)' : 'var(--ok)'; return (
{a.load > a.limit*0.9 && (
{a.load}t
)}
); })}
{axles.map(a => (
{a.name}
{a.load}/{a.limit}t
))}
); }; const CogIndicator = ({ x = 0.42, y = 0.5, safeXMin=0.35, safeXMax=0.60, safeYMin=0.30, safeYMax=0.70 }) => { const inSafe = x >= safeXMin && x <= safeXMax && y >= safeYMin && y <= safeYMax; return (
{/* safe zone */}
{/* center crosshair */}
{/* CoG dot */}
{/* front label */}
FRONT
REAR
); }; const ViolationList = ({ items, onSelect }) => { if (!items.length) { return (
All rules satisfied
); } return (
{items.map(v => (
onSelect && onSelect(v.item)} style={{ padding:'8px 10px', background: v.severity === 'bad' ? 'var(--bad-bg)' : 'var(--warn-bg)', border: '1px solid ' + (v.severity === 'bad' ? 'rgba(193,51,51,0.25)' : 'rgba(201,138,27,0.25)'), borderRadius: 6, cursor:'pointer' }}>
{v.rule} #{v.item}
{v.detail}
))}
); }; const CompliancePanel = ({ kpis, axles, violations, onSelectItem }) => { return (
Compliance
Live load summary
v.severity==='bad').length ? 'chip--bad' : violations.length ? 'chip--warn' : 'chip--ok')}> {violations.length === 0 ? : } {violations.length || 'OK'} {violations.length === 1 ? 'issue' : violations.length ? 'issues' : ''}
{/* metric cards */}
= 95 ? 'bad' : kpis.volumePct >= 70 ? 'ok' : 'warn'} /> 0.95 ? 'bad' : 'ok'}/>
Volume utilisation
Axle loads
Centre of gravity
From front: {Math.round(kpis.cogX*100)}% Lateral offset: {Math.round((kpis.cogY-0.5)*100)}%
Active violations
Decision log
); }; const KpiTile = ({ label, value, sub, tone = 'ok' }) => { const palette = { ok:'var(--ok)', warn:'var(--warn)', bad:'var(--bad)', info:'var(--info)' }; return (
{label}
{value}
{sub}
); }; const DecisionRow = ({ tone='info', text }) => { const c = tone === 'ok' ? 'var(--ok)' : tone === 'warn' ? 'var(--warn)' : 'var(--info)'; return (
{text}
); }; window.CompliancePanel = CompliancePanel; window.Bar = Bar; window.AxleChart = AxleChart; window.CogIndicator = CogIndicator;