feat: cockpit
This commit is contained in:
@@ -122,16 +122,16 @@ function EcoEventRow({ ev, showActual }: { ev: any; showActual: boolean }) {
|
||||
<div className="flex items-center gap-1.5 text-[10px]">
|
||||
<span className="shrink-0">{CURRENCY_FLAGS[ev.currency] ?? ev.currency}</span>
|
||||
<span className={clsx('w-1.5 h-1.5 rounded-full shrink-0', IMPACT_DOT[ev.impact] ?? 'bg-slate-400')} />
|
||||
<span className="text-white truncate flex-1 line-clamp-1">{ev.event_name}</span>
|
||||
<span className="text-slate-200 truncate flex-1 line-clamp-1 max-w-[108px]" title={ev.event_name}>{ev.event_name}</span>
|
||||
{showActual && ev.actual_value ? (
|
||||
<span className="text-[9px] font-mono shrink-0">
|
||||
<span className="text-[10px] font-mono shrink-0">
|
||||
<span className="text-white font-semibold">{ev.actual_value}</span>
|
||||
{ev.forecast_value && <span className="text-slate-600"> /{ev.forecast_value}</span>}
|
||||
{ev.forecast_value && <span className="text-slate-400"> /{ev.forecast_value}</span>}
|
||||
</span>
|
||||
) : ev.forecast_value ? (
|
||||
<span className="text-[9px] font-mono text-slate-600 shrink-0">F {ev.forecast_value}</span>
|
||||
<span className="text-[10px] font-mono text-slate-400 shrink-0">F {ev.forecast_value}</span>
|
||||
) : null}
|
||||
{ev.event_time && <span className="text-slate-700 text-[9px] shrink-0 font-mono">{ev.event_time}</span>}
|
||||
{ev.event_time && <span className="text-slate-500 text-[9px] shrink-0 font-mono">{ev.event_time}</span>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -347,7 +347,7 @@ export default function Dashboard() {
|
||||
<div className="section-title flex items-center gap-1 mb-0">
|
||||
<Globe className="w-3 h-3" /> Geopolitical Risk
|
||||
</div>
|
||||
<Link to="/geo" className="flex items-center gap-0.5 text-[10px] text-slate-600 hover:text-slate-300 transition-colors">
|
||||
<Link to="/geo" className="flex items-center gap-0.5 text-[10px] text-slate-400 hover:text-slate-300 transition-colors">
|
||||
Geo news <ArrowUpRight className="w-2.5 h-2.5" />
|
||||
</Link>
|
||||
</div>
|
||||
@@ -376,14 +376,16 @@ export default function Dashboard() {
|
||||
<div className={clsx('h-2 rounded-full', gauge.bg)} style={{ width: `${riskScore.score}%` }} />
|
||||
</div>
|
||||
{riskScore.computed_at && (
|
||||
<div className="mt-1.5 text-[9px] text-slate-600 shrink-0">
|
||||
Score IA — figé au dernier cycle ({formatTimeShort(riskScore.computed_at)})
|
||||
{riskScore.rationale && <span className="text-slate-500"> · {riskScore.rationale}</span>}
|
||||
<div className="mt-1.5 text-[9px] text-slate-400 shrink-0">
|
||||
<span>AI Score — frozen at last cycle ({formatTimeShort(riskScore.computed_at)})</span>
|
||||
{riskScore.rationale && (
|
||||
<p className="text-slate-500 line-clamp-2 mt-0.5" title={riskScore.rationale}>{riskScore.rationale}</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{topNews.length > 0 && (
|
||||
<div className="mt-2.5 pt-2 border-t border-slate-700/30 flex flex-col flex-1 min-h-0">
|
||||
<div className="flex items-center gap-1 text-[9px] text-slate-600 mb-1 shrink-0">
|
||||
<div className="mt-2 pt-2 border-t border-slate-700/30 flex flex-col flex-1 min-h-0">
|
||||
<div className="flex items-center gap-1 text-[9px] text-slate-400 mb-1 shrink-0">
|
||||
<Newspaper className="w-2.5 h-2.5" /> Top news
|
||||
</div>
|
||||
<div className="space-y-1.5 overflow-y-auto flex-1 min-h-0">
|
||||
@@ -410,7 +412,7 @@ export default function Dashboard() {
|
||||
<div ref={watchlistCardRef} className="card col-span-1">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div className="section-title mb-0">📡 Watchlist Radar</div>
|
||||
<Link to="/config" className="flex items-center gap-0.5 text-[10px] text-slate-600 hover:text-slate-300 transition-colors">
|
||||
<Link to="/config" className="flex items-center gap-0.5 text-[10px] text-slate-400 hover:text-slate-300 transition-colors">
|
||||
Manage <ArrowUpRight className="w-2.5 h-2.5" />
|
||||
</Link>
|
||||
</div>
|
||||
@@ -419,7 +421,7 @@ export default function Dashboard() {
|
||||
<ResponsiveContainer width="100%" height={130}>
|
||||
<RadarChart data={watchlistRadarData}>
|
||||
<PolarGrid stroke="#1e2d4d" />
|
||||
<PolarAngleAxis dataKey="subject" tick={{ fill: '#64748b', fontSize: 9 }} />
|
||||
<PolarAngleAxis dataKey="subject" tick={{ fill: '#94a3b8', fontSize: 9 }} />
|
||||
<Radar dataKey="ref" stroke="#334155" strokeDasharray="3 3" fill="transparent" isAnimationActive={false} />
|
||||
<Radar dataKey="value" stroke="#3b82f6" fill="#3b82f6" fillOpacity={0.25} />
|
||||
</RadarChart>
|
||||
@@ -427,9 +429,9 @@ export default function Dashboard() {
|
||||
<div className="mt-1.5 pt-1.5 border-t border-slate-700/30 space-y-1">
|
||||
{((watchlistQuotesData as any)?.items ?? []).map((it: any) => (
|
||||
<div key={it.ticker} className="flex items-center justify-between text-[10px]">
|
||||
<span className="text-slate-400 font-mono">{it.ticker}</span>
|
||||
<span className="text-slate-300 font-mono">{it.ticker}</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-slate-500 font-mono">{fmtPrice(it.price)}</span>
|
||||
<span className="text-slate-400 font-mono">{fmtPrice(it.price)}</span>
|
||||
<span className={clsx('font-mono font-bold w-12 text-right', (it.change_pct ?? 0) >= 0 ? 'text-emerald-400' : 'text-red-400')}>
|
||||
{it.change_pct != null ? `${it.change_pct >= 0 ? '+' : ''}${it.change_pct.toFixed(2)}%` : '—'}
|
||||
</span>
|
||||
@@ -499,7 +501,7 @@ export default function Dashboard() {
|
||||
style={row1Height ? { height: row1Height } : undefined}>
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<span className="section-title mb-0 text-[10px]">🌐 Macro Regime</span>
|
||||
<ArrowUpRight className="w-3 h-3 text-slate-600" />
|
||||
<ArrowUpRight className="w-3 h-3 text-slate-500" />
|
||||
</div>
|
||||
<div className={clsx('text-base font-bold mt-1', colorClass)}>
|
||||
{macroInfo ? `${macroInfo.emoji} ${macroInfo.label}` : '—'}
|
||||
@@ -512,7 +514,7 @@ export default function Dashboard() {
|
||||
const isDom = key === dom
|
||||
return (
|
||||
<div key={key} className="flex items-center gap-1.5">
|
||||
<span className={clsx('text-[9px] w-16 truncate', isDom ? 'text-slate-200 font-semibold' : 'text-slate-500')}>
|
||||
<span className={clsx('text-[10px] w-16 truncate', isDom ? 'text-slate-200 font-semibold' : 'text-slate-400')}>
|
||||
{REGIME_LABELS[key] ?? key}
|
||||
</span>
|
||||
<div className="flex-1 h-1.5 bg-dark-700 rounded-full overflow-hidden">
|
||||
@@ -521,7 +523,7 @@ export default function Dashboard() {
|
||||
style={{ width: `${pct}%` }}
|
||||
/>
|
||||
</div>
|
||||
<span className={clsx('text-[9px] font-mono w-5 text-right', isDom ? 'text-blue-400' : 'text-slate-600')}>
|
||||
<span className={clsx('text-[10px] font-mono w-5 text-right', isDom ? 'text-blue-400' : 'text-slate-400')}>
|
||||
{score}
|
||||
</span>
|
||||
</div>
|
||||
@@ -542,11 +544,11 @@ export default function Dashboard() {
|
||||
const h = hint(val, chg)
|
||||
return (
|
||||
<div key={key} className="flex items-center gap-1.5">
|
||||
<span className="text-[9px] text-slate-600 w-16 shrink-0">{label}</span>
|
||||
<span className={clsx('text-[9px] font-mono font-semibold shrink-0', c)}>
|
||||
<span className="text-[10px] text-slate-400 w-16 shrink-0">{label}</span>
|
||||
<span className={clsx('text-[10px] font-mono font-semibold shrink-0', c)}>
|
||||
{fmt(val, chg)}
|
||||
</span>
|
||||
<span className="text-[8px] text-slate-700 truncate">{h}</span>
|
||||
<span className="text-[9px] text-slate-500 truncate">{h}</span>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
@@ -575,7 +577,7 @@ export default function Dashboard() {
|
||||
{todayEvents.length > 0 && (
|
||||
<div>
|
||||
<div className="flex items-center gap-1.5 text-[9px] font-semibold text-slate-300 bg-dark-700/50 rounded px-1.5 py-0.5 mb-1">
|
||||
Aujourd'hui <span className="badge-blue text-[8px] px-1 py-0">TODAY</span>
|
||||
Today <span className="badge-blue text-[8px] px-1 py-0">TODAY</span>
|
||||
</div>
|
||||
<div className="space-y-1 pl-0.5">
|
||||
{todayEvents.map((ev: any, i: number) => <EcoEventRow key={i} ev={ev} showActual />)}
|
||||
@@ -593,7 +595,7 @@ export default function Dashboard() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : <div className="text-slate-600 text-xs mt-2">No events this week</div>}
|
||||
) : <div className="text-slate-500 text-xs mt-2">No events this week</div>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user