import { useState } from 'react'; import { DimensionBreakdownPanel } from '../ticker/DimensionBreakdownPanel'; import type { DimensionScoreDetail, CompositeBreakdown } from '../../lib/types'; interface ScoreCardProps { compositeScore: number | null; dimensions: DimensionScoreDetail[]; compositeBreakdown?: CompositeBreakdown | null; /** Hide the composite ring/header when the composite is shown elsewhere * (e.g. the Standing matrix) and this card only carries the dimension detail. */ showComposite?: boolean; } function scoreColor(score: number): string { if (score > 70) return 'text-emerald-400'; if (score >= 40) return 'text-amber-400'; return 'text-red-400'; } function ringGradient(score: number): string { if (score > 70) return '#10b981'; if (score >= 40) return '#f59e0b'; return '#ef4444'; } function barGradient(score: number): string { if (score > 70) return 'from-emerald-500 to-emerald-400'; if (score >= 40) return 'from-amber-500 to-amber-400'; return 'from-red-500 to-red-400'; } function ScoreRing({ score }: { score: number }) { const radius = 36; const circumference = 2 * Math.PI * radius; const clamped = Math.max(0, Math.min(100, score)); const offset = circumference - (clamped / 100) * circumference; const color = ringGradient(score); return (
Composite Score
{compositeScore !== null ? Math.round(compositeScore) : '—'}
{compositeBreakdown && ({compositeBreakdown.sentiment_adjustment != null && compositeBreakdown.base_score != null && Math.abs(compositeBreakdown.sentiment_adjustment) >= 0.05 ? `Base ${Math.round(compositeBreakdown.base_score)} · sentiment ${ compositeBreakdown.sentiment_adjustment >= 0 ? '+' : '−' }${Math.abs(compositeBreakdown.sentiment_adjustment).toFixed(1)}` : 'Weighted base of the other dimensions; sentiment adjusts it up or down.'}
)}Dimensions
{dimensions.map((d) => { const isExpanded = expanded[d.dimension] ?? false; const weight = compositeBreakdown?.renormalized_weights?.[d.dimension] ?? compositeBreakdown?.weights?.[d.dimension]; return (