89 lines
4.5 KiB
TypeScript
89 lines
4.5 KiB
TypeScript
import React from 'react';
|
|
import type { BotState } from '../hooks/useWebSocket';
|
|
import { TrendingUp, Zap } from 'lucide-react';
|
|
|
|
interface LivePulseTickerProps {
|
|
botState: BotState;
|
|
}
|
|
|
|
export const LivePulseTicker: React.FC<LivePulseTickerProps> = ({ botState }) => {
|
|
const symbols = Object.keys(botState.symbols);
|
|
const volatileSymbols = symbols
|
|
.sort((a, b) => Math.abs(botState.symbols[b].change24h || 0) - Math.abs(botState.symbols[a].change24h || 0))
|
|
.slice(0, 8);
|
|
|
|
const aiSetups = symbols
|
|
.filter(s => botState.symbols[s].rules['AIAnalysisRule']?.metadata?.confidence !== undefined)
|
|
.sort((a, b) => (botState.symbols[b].rules['AIAnalysisRule']?.metadata?.confidence || 0) - (botState.symbols[a].rules['AIAnalysisRule']?.metadata?.confidence || 0))
|
|
.slice(0, 3);
|
|
|
|
return (
|
|
<div style={{
|
|
height: '40px',
|
|
background: 'rgba(10, 11, 13, 0.95)',
|
|
backdropFilter: 'blur(10px)',
|
|
borderTop: '1px solid rgba(255, 255, 255, 0.05)',
|
|
borderBottom: '1px solid rgba(255, 255, 255, 0.05)',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
overflow: 'hidden',
|
|
position: 'sticky',
|
|
top: '0',
|
|
zIndex: 1000,
|
|
padding: '0 24px'
|
|
}}>
|
|
{/* Market Ticker Section */}
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', borderRight: '1px solid rgba(255,255,255,0.1)', paddingRight: '16px', marginRight: '16px' }}>
|
|
<TrendingUp size={14} className="text-[#00ff88]" />
|
|
<span style={{ fontSize: '10px', fontWeight: 900, color: '#444', textTransform: 'uppercase', letterSpacing: '1px' }}>Market Pulse</span>
|
|
</div>
|
|
|
|
<div className="ticker-scroll" style={{ display: 'flex', gap: '24px', flex: 1 }}>
|
|
{volatileSymbols.map(s => {
|
|
const change = botState.symbols[s].change24h || 0;
|
|
return (
|
|
<div key={s} style={{ display: 'flex', alignItems: 'center', gap: '6px', whiteSpace: 'nowrap' }}>
|
|
<span style={{ fontSize: '11px', fontWeight: 800, color: '#aaa' }}>{s.split('/')[0]}</span>
|
|
<span style={{
|
|
fontSize: '11px',
|
|
fontWeight: 900,
|
|
color: change >= 0 ? '#00ff88' : '#ff3366',
|
|
fontFamily: 'monospace'
|
|
}}>
|
|
{change >= 0 ? '+' : ''}{change.toFixed(2)}%
|
|
</span>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{/* AI Highlight Section */}
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: '16px', marginLeft: 'auto', background: 'rgba(0, 255, 136, 0.03)', padding: '0 16px', height: '100%', borderLeft: '1px solid rgba(0, 255, 136, 0.1)' }}>
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
|
|
<Zap size={14} className="text-[#00ff88]" fill="#00ff88" style={{ filter: 'drop-shadow(0 0 4px #00ff88)' }} />
|
|
<span style={{ fontSize: '10px', fontWeight: 900, color: '#00ff88', textTransform: 'uppercase', letterSpacing: '1px' }}>AI Top Picks</span>
|
|
</div>
|
|
<div style={{ display: 'flex', gap: '12px' }}>
|
|
{aiSetups.map(s => (
|
|
<div key={s} style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>
|
|
<span style={{ fontSize: '11px', fontWeight: 800, color: '#fff' }}>{s.split('/')[0]}</span>
|
|
<span style={{ fontSize: '10px', fontWeight: 900, color: '#00ff88', opacity: 0.6 }}>{botState.symbols[s].rules['AIAnalysisRule']?.metadata?.confidence}%</span>
|
|
</div>
|
|
))}
|
|
{aiSetups.length === 0 && <span style={{ fontSize: '10px', fontWeight: 800, color: '#444' }}>SCANNING...</span>}
|
|
</div>
|
|
</div>
|
|
|
|
<style>{`
|
|
.ticker-scroll {
|
|
animation: ticker-slide 30s linear infinite;
|
|
}
|
|
@keyframes ticker-slide {
|
|
0% { transform: translateX(0); }
|
|
100% { transform: translateX(-20%); }
|
|
}
|
|
`}</style>
|
|
</div>
|
|
);
|
|
};
|