/** * llmindex.io — shared UI primitives (score display with mandatory CI whiskers) * Author: Simon-Pierre Boucher * Contact: contact@spboucher.ai * License: Proprietary — © Simon-Pierre Boucher, all rights reserved */ import type { ReactElement } from 'react'; export interface ScoreBarProps { score: number; scoreLow: number; scoreHigh: number; max?: number; } /** * Horizontal score bar with a CI whisker. Uncertainty is always rendered — * a score without its CI is a methodology violation (§8). */ export function ScoreBar({ score, scoreLow, scoreHigh, max = 1000 }: ScoreBarProps): ReactElement { const pct = (v: number): number => Math.min(100, Math.max(0, (v / max) * 100)); return (
); } export function ScoreValue({ score, scoreLow, scoreHigh }: ScoreBarProps): ReactElement { return ( {score}{' '} [{scoreLow}–{scoreHigh}] ); } export function DemoBanner(): ReactElement { return (
Demo data — these scores are deterministic placeholders, not a real evaluation. They will be replaced by the first published IRT fit run.
); } export function formatUsd(v: number | null | undefined): string { if (v == null) return '—'; return v < 1 ? `$${v.toFixed(3)}` : `$${v.toFixed(2)}`; } export function formatMs(v: number | null | undefined): string { if (v == null) return '—'; return v >= 1000 ? `${(v / 1000).toFixed(1)}s` : `${Math.round(v)}ms`; }