202 lines
6.2 KiB
TypeScript
202 lines
6.2 KiB
TypeScript
import type { Decision } from '@/lib/types/agents'
|
|
|
|
type Props = { verdict: Decision | null; ticker: string; date: string }
|
|
|
|
const VERDICT_CONFIG: Record<Decision, {
|
|
color: string
|
|
colorBg: string
|
|
colorRing: string
|
|
colorGlow: string
|
|
label: string
|
|
sublabel: string
|
|
symbol: string
|
|
description: string
|
|
}> = {
|
|
BUY: {
|
|
color: 'var(--buy)',
|
|
colorBg: 'var(--buy-bg)',
|
|
colorRing: 'var(--buy-ring)',
|
|
colorGlow: 'rgba(0, 224, 120, 0.15)',
|
|
label: 'BUY',
|
|
sublabel: 'Long Position',
|
|
symbol: '↑',
|
|
description: 'AI consensus recommends entering a long position',
|
|
},
|
|
SELL: {
|
|
color: 'var(--sell)',
|
|
colorBg: 'var(--sell-bg)',
|
|
colorRing: 'var(--sell-ring)',
|
|
colorGlow: 'rgba(255, 31, 76, 0.15)',
|
|
label: 'SELL',
|
|
sublabel: 'Exit Position',
|
|
symbol: '↓',
|
|
description: 'AI consensus recommends exiting the position',
|
|
},
|
|
HOLD: {
|
|
color: 'var(--hold)',
|
|
colorBg: 'var(--hold-bg)',
|
|
colorRing: 'var(--hold-ring)',
|
|
colorGlow: 'rgba(255, 180, 0, 0.15)',
|
|
label: 'HOLD',
|
|
sublabel: 'Maintain Position',
|
|
symbol: '→',
|
|
description: 'AI consensus recommends maintaining current exposure',
|
|
},
|
|
}
|
|
|
|
export default function VerdictBanner({ verdict, ticker, date }: Props) {
|
|
if (!verdict || !VERDICT_CONFIG[verdict]) return null
|
|
const cfg = VERDICT_CONFIG[verdict]
|
|
|
|
return (
|
|
<div
|
|
className="relative overflow-hidden"
|
|
style={{
|
|
background: cfg.colorBg,
|
|
border: `1px solid ${cfg.colorRing}`,
|
|
borderRadius: '16px',
|
|
animation: 'verdict-reveal 0.55s cubic-bezier(0.16,1,0.3,1) both',
|
|
}}
|
|
>
|
|
{/* Background glow blobs */}
|
|
<div
|
|
className="absolute inset-0 pointer-events-none"
|
|
style={{
|
|
background: `radial-gradient(ellipse 70% 80% at 100% 50%, ${cfg.colorGlow} 0%, transparent 65%)`,
|
|
}}
|
|
/>
|
|
<div
|
|
className="absolute inset-0 pointer-events-none"
|
|
style={{
|
|
background: `radial-gradient(ellipse 40% 60% at 0% 50%, ${cfg.colorBg} 0%, transparent 70%)`,
|
|
}}
|
|
/>
|
|
|
|
{/* Scanline shimmer on active color */}
|
|
<div
|
|
className="absolute top-0 left-0 right-0 h-px pointer-events-none"
|
|
style={{
|
|
background: `linear-gradient(90deg, transparent 5%, ${cfg.color}60 50%, transparent 95%)`,
|
|
}}
|
|
/>
|
|
|
|
{/* Corner decorative mark */}
|
|
<div
|
|
className="absolute top-4 right-4 opacity-10 pointer-events-none"
|
|
style={{ color: cfg.color, fontFamily: 'var(--font-syne)', fontSize: '120px', fontWeight: 800, lineHeight: 1, letterSpacing: '-0.06em' }}
|
|
>
|
|
{cfg.symbol}
|
|
</div>
|
|
|
|
{/* Main content */}
|
|
<div className="relative px-7 py-6">
|
|
{/* Top row: label + meta */}
|
|
<div className="flex items-center justify-between mb-5">
|
|
<div className="apex-label" style={{ color: cfg.color, opacity: 0.7 }}>
|
|
Analysis Complete
|
|
</div>
|
|
<div
|
|
className="flex items-center gap-2 px-3 py-1 rounded-full text-[10px] font-bold"
|
|
style={{
|
|
fontFamily: 'var(--font-mono)',
|
|
letterSpacing: '0.1em',
|
|
background: `${cfg.colorRing}`,
|
|
color: cfg.color,
|
|
border: `1px solid ${cfg.colorRing}`,
|
|
}}
|
|
>
|
|
AI CONSENSUS
|
|
</div>
|
|
</div>
|
|
|
|
{/* Main verdict row */}
|
|
<div className="flex items-end justify-between gap-6">
|
|
{/* Left: ticker + description */}
|
|
<div className="flex-1 min-w-0">
|
|
<div
|
|
className="flex items-baseline gap-3 mb-2"
|
|
>
|
|
<span
|
|
className="terminal-text font-bold"
|
|
style={{
|
|
fontSize: '42px',
|
|
lineHeight: 1,
|
|
letterSpacing: '-0.02em',
|
|
color: 'var(--text-high)',
|
|
}}
|
|
>
|
|
{ticker}
|
|
</span>
|
|
<span
|
|
className="terminal-text text-sm font-medium"
|
|
style={{ color: 'var(--text-mid)', letterSpacing: '0.02em' }}
|
|
>
|
|
{date}
|
|
</span>
|
|
</div>
|
|
<p
|
|
className="text-sm"
|
|
style={{ color: 'var(--text-mid)', fontFamily: 'var(--font-manrope)', lineHeight: 1.5 }}
|
|
>
|
|
{cfg.description}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Right: big verdict badge */}
|
|
<div className="shrink-0 flex flex-col items-center gap-2">
|
|
<div
|
|
style={{
|
|
fontSize: '11px',
|
|
fontFamily: 'var(--font-mono)',
|
|
fontWeight: 700,
|
|
letterSpacing: '0.12em',
|
|
color: cfg.color,
|
|
opacity: 0.7,
|
|
textTransform: 'uppercase',
|
|
}}
|
|
>
|
|
{cfg.sublabel}
|
|
</div>
|
|
<div
|
|
className="flex items-center justify-center gap-2"
|
|
style={{
|
|
padding: '14px 32px',
|
|
borderRadius: '12px',
|
|
background: `${cfg.colorBg}`,
|
|
border: `2px solid ${cfg.color}`,
|
|
boxShadow: `0 0 32px ${cfg.colorGlow}, 0 0 64px ${cfg.colorBg}, inset 0 1px 0 rgba(255,255,255,0.06)`,
|
|
}}
|
|
>
|
|
<span
|
|
className="terminal-text"
|
|
style={{
|
|
fontSize: '48px',
|
|
fontWeight: 700,
|
|
lineHeight: 1,
|
|
color: cfg.color,
|
|
letterSpacing: '-0.02em',
|
|
}}
|
|
>
|
|
{cfg.symbol}
|
|
</span>
|
|
<span
|
|
style={{
|
|
fontFamily: 'var(--font-syne)',
|
|
fontSize: '48px',
|
|
fontWeight: 800,
|
|
lineHeight: 1,
|
|
color: cfg.color,
|
|
letterSpacing: '-0.02em',
|
|
textShadow: `0 0 30px ${cfg.color}80`,
|
|
}}
|
|
>
|
|
{cfg.label}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|