From 92e717509d81309d2ecf25b2cd75b58826c56787 Mon Sep 17 00:00:00 2001 From: Saravana Achu Mac Date: Sat, 9 May 2026 01:04:50 -0700 Subject: [PATCH] refactor(ui): polish alert feed surface --- web/src/components/AlertFeed.css | 91 ++++++++++++++++++----- web/src/components/AlertFeed.dom.test.tsx | 11 +-- web/src/components/AlertFeed.tsx | 56 ++++++++------ 3 files changed, 110 insertions(+), 48 deletions(-) diff --git a/web/src/components/AlertFeed.css b/web/src/components/AlertFeed.css index d2814bc..a3cebf0 100644 --- a/web/src/components/AlertFeed.css +++ b/web/src/components/AlertFeed.css @@ -1,17 +1,43 @@ .alert-feed { - background: linear-gradient(135deg, var(--card) 0%, var(--card-elevated) 100%); - border-radius: 16px; - padding: 24px; - box-shadow: var(--card-shadow); border: 1px solid var(--border); + border-radius: 18px; + background: var(--card); + padding: 22px; + box-shadow: var(--card-shadow); +} + +.alert-feed-header { + display: flex; + align-items: flex-start; + gap: 12px; + margin-bottom: 20px; +} + +.alert-feed-title-icon { + display: grid; + width: 34px; + height: 34px; + flex: 0 0 auto; + place-items: center; + border: 1px solid color-mix(in oklab, var(--accent) 24%, var(--border)); + border-radius: 12px; + background: var(--accent-soft); + color: var(--accent); } .alert-feed h2 { + margin: 0; color: var(--foreground); - font-size: 20px; - font-weight: 700; - margin: 0 0 20px 0; - letter-spacing: 0.5px; + font-size: 18px; + font-weight: 820; + letter-spacing: 0; +} + +.alert-feed-header p { + margin: 4px 0 0; + color: var(--muted-foreground); + font-size: 13px; + line-height: 1.5; } .alerts-container { @@ -63,15 +89,16 @@ } .alert-item { - display: flex; + display: grid; + grid-template-columns: auto minmax(0, 1fr); gap: 12px; - padding: 16px; margin-bottom: 12px; + padding: 16px; border-radius: 12px; - background: color-mix(in oklab, var(--foreground) 3%, transparent); border: 1px solid var(--border); - transition: all 0.2s; + background: color-mix(in oklab, var(--muted) 42%, var(--card)); animation: slideIn 0.3s ease; + transition: background 0.16s ease, border-color 0.16s ease, transform 0.16s ease; } @keyframes slideIn { @@ -87,8 +114,9 @@ } .alert-item:hover { - background: var(--muted); - transform: translateX(4px); + border-color: var(--border-strong); + background: color-mix(in oklab, var(--accent-soft) 34%, var(--card)); + transform: translateY(-1px); } .alert-signal { @@ -108,27 +136,40 @@ } .alert-icon { - font-size: 24px; - flex-shrink: 0; + display: grid; + width: 34px; + height: 34px; + flex: 0 0 auto; + place-items: center; + border-radius: 12px; + background: var(--muted); + color: var(--muted-foreground); } .alert-content { - flex: 1; + min-width: 0; } .alert-header { display: flex; + align-items: center; justify-content: space-between; + gap: 12px; margin-bottom: 6px; } .alert-symbol { + min-width: 0; + overflow: hidden; color: var(--foreground); font-weight: 700; font-size: 14px; + text-overflow: ellipsis; + white-space: nowrap; } .alert-time { + flex: 0 0 auto; color: var(--muted-foreground); font-size: 12px; } @@ -137,4 +178,20 @@ color: var(--muted-foreground); font-size: 13px; line-height: 1.5; + overflow-wrap: anywhere; +} + +.alert-signal .alert-icon { + background: var(--bl-success-muted); + color: var(--bl-success); +} + +.alert-pulse .alert-icon { + background: var(--bl-info-muted); + color: var(--bl-info); +} + +.alert-error .alert-icon { + background: var(--bl-danger-muted); + color: var(--bl-danger); } diff --git a/web/src/components/AlertFeed.dom.test.tsx b/web/src/components/AlertFeed.dom.test.tsx index b6e821d..ef767a1 100644 --- a/web/src/components/AlertFeed.dom.test.tsx +++ b/web/src/components/AlertFeed.dom.test.tsx @@ -18,7 +18,7 @@ describe('AlertFeed DOM behavior', () => { expect(screen.getByText('Recent Activity')).toBeInTheDocument(); }); - it('renders different alert types with correct icons', () => { + it('renders different alert types with messages', () => { const alerts: any[] = [ { timestamp: Date.now(), type: 'signal', symbol: 'BTC', message: 'Signal Alert' }, { timestamp: Date.now(), type: 'pulse', symbol: 'ETH', message: 'Pulse Alert' }, @@ -28,13 +28,8 @@ describe('AlertFeed DOM behavior', () => { render(); - expect(screen.getByText('🚀')).toBeInTheDocument(); - expect(screen.getByText('⏰')).toBeInTheDocument(); - expect(screen.getByText('âš ī¸')).toBeInTheDocument(); - expect(screen.getByText('â„šī¸')).toBeInTheDocument(); - - expect(screen.getByText('Signal Alert')).toBeInTheDocument(); - expect(screen.getByText('Pulse Alert')).toBeInTheDocument(); + expect(screen.getByText('Signal Alert')).toBeInTheDocument(); + expect(screen.getByText('Pulse Alert')).toBeInTheDocument(); expect(screen.getByText('Error Alert')).toBeInTheDocument(); expect(screen.getByText('Info Alert')).toBeInTheDocument(); }); diff --git a/web/src/components/AlertFeed.tsx b/web/src/components/AlertFeed.tsx index 1c7069b..341d9a7 100644 --- a/web/src/components/AlertFeed.tsx +++ b/web/src/components/AlertFeed.tsx @@ -1,4 +1,5 @@ -import './AlertFeed.css'; +import { AlertCircle, Bell, Info, Rocket, Timer } from 'lucide-react'; +import './AlertFeed.css'; interface AlertFeedProps { alerts: Array<{ @@ -9,12 +10,12 @@ interface AlertFeedProps { }>; } -const alertTypeIcons: { [key: string]: string } = { - signal: '🚀', - pulse: '⏰', - error: 'âš ī¸', - info: 'â„šī¸' -}; +const alertTypeIcons = { + signal: Rocket, + pulse: Timer, + error: AlertCircle, + info: Info +}; export const AlertFeed = ({ alerts }: AlertFeedProps) => { const sortedAlerts = [...alerts].reverse().slice(0, 50); @@ -31,7 +32,13 @@ export const AlertFeed = ({ alerts }: AlertFeedProps) => { return (
-

Recent Activity

+
+
+
+

Recent Activity

+

{sortedAlerts.length} recent event{sortedAlerts.length === 1 ? '' : 's'} across signals, warnings, and execution.

+
+
{sortedAlerts.length === 0 && (
@@ -39,19 +46,22 @@ export const AlertFeed = ({ alerts }: AlertFeedProps) => { Signals, warnings, and execution events will appear here as they arrive.
)} - {sortedAlerts.map((alert, index) => ( + {sortedAlerts.map((alert, index) => { + const Icon = alertTypeIcons[alert.type] || Info; + return (
-
{alertTypeIcons[alert.type]}
-
-
- {alert.symbol} - {getTimeAgo(alert.timestamp)} -
-
{alert.message}
-
-
- ))} -
-
- ); -}; +
+
+
+ {alert.symbol || 'System'} + {getTimeAgo(alert.timestamp)} +
+
{alert.message}
+
+ + ); + })} + + + ); +};