| 'use client' |
| import { Bell, Search, Globe, Wifi, Zap } from 'lucide-react' |
| import { useState, useEffect } from 'react' |
|
|
| interface TorqueStatus { configured: boolean; status: string; sessionEvents: number } |
|
|
| export function Topbar() { |
| const [time, setTime] = useState('') |
| const [torque, setTorque] = useState<TorqueStatus | null>(null) |
|
|
| useEffect(() => { |
| const u = () => setTime(new Date().toLocaleTimeString('en-US', { hour12: false })) |
| u(); const i = setInterval(u, 1000); return () => clearInterval(i) |
| }, []) |
|
|
| useEffect(() => { |
| const fetchStatus = async () => { |
| try { |
| const res = await fetch('/api/torque/status') |
| if (res.ok) setTorque(await res.json()) |
| } catch {} |
| } |
| fetchStatus() |
| const i = setInterval(fetchStatus, 8000) |
| return () => clearInterval(i) |
| }, []) |
|
|
| const isLive = torque?.configured && torque?.status === 'connected' |
|
|
| return ( |
| <header className="h-14 border-b border-hairline-dark bg-surface-card/80 backdrop-blur-sm flex items-center justify-between px-6"> |
| <div className="relative"> |
| <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted" /> |
| <input type="text" placeholder="Search wallets, campaigns..." className="w-64 h-9 pl-9 pr-4 rounded-lg bg-surface-elevated border border-hairline-dark text-body-sm text-[#eaecef] placeholder:text-muted focus:outline-none focus:ring-1 focus:ring-brand-yellow/50 transition" /> |
| </div> |
| <div className="flex items-center gap-4"> |
| {torque && ( |
| <div className={`flex items-center gap-2 px-3 py-1.5 rounded-pill border ${isLive ? 'bg-trading-up/10 border-trading-up/20' : 'bg-trading-down/10 border-trading-down/20'}`}> |
| <div className={`w-2 h-2 rounded-full ${isLive ? 'bg-trading-up animate-pulse' : 'bg-trading-down'}`} /> |
| <span className={`text-caption font-semibold ${isLive ? 'text-trading-up' : 'text-trading-down'}`}> |
| TORQUE {isLive ? 'LIVE' : 'OFFLINE'} |
| </span> |
| </div> |
| )} |
| {!torque && ( |
| <div className="flex items-center gap-2 px-3 py-1.5 rounded-pill bg-muted/10 border border-muted/20"> |
| <div className="w-2 h-2 rounded-full bg-muted animate-pulse" /> |
| <span className="text-caption text-muted font-semibold">CONNECTING...</span> |
| </div> |
| )} |
| {torque && torque.sessionEvents > 0 && ( |
| <div className="flex items-center gap-1.5 px-2.5 py-1 rounded-pill bg-brand-yellow/10 border border-brand-yellow/20"> |
| <Zap className="w-3 h-3 text-brand-yellow" /> |
| <span className="font-mono text-caption text-brand-yellow font-semibold">{torque.sessionEvents}</span> |
| </div> |
| )} |
| <span className="font-mono text-num-sm text-muted tabular-nums">{time}</span> |
| <button className="flex items-center gap-1.5 text-muted hover:text-[#eaecef] transition"> |
| <Wifi className={`w-4 h-4 ${isLive ? 'text-trading-up' : 'text-muted'}`} /><span className="text-caption">Solana</span> |
| </button> |
| <button className="relative p-2 rounded-lg hover:bg-surface-elevated transition"> |
| <Bell className="w-4 h-4 text-muted" /> |
| <span className="absolute top-1 right-1 w-2 h-2 bg-brand-yellow rounded-full" /> |
| </button> |
| <button className="flex items-center gap-2 px-4 py-2 rounded-md bg-brand-yellow text-ink text-button font-semibold hover:bg-brand-yellow-active transition"> |
| <Globe className="w-4 h-4" />Connect |
| </button> |
| </div> |
| </header> |
| ) |
| } |
|
|