refactor(web): extract repeated inline-style patterns to classes (UI audit #8)
Per-pattern, per-file analysis found 191 inline-style blocks across the
3 landing-view files (OverviewTab 72, MyStrategiesTab 64, HomeView 55).
155 are unique one-offs already using design tokens (var(--bl-*)) — those
stay inline since converting them to single-use classes would just relocate
code without reducing drift.
This commit extracts the **repeated patterns** (count >= 2 plus structural
container shapes) — 39 occurrences — into either Tailwind utilities or a
new web/src/styles/landing-views.css partial:
Tailwind replacements:
textAlign: 'right' → text-right
marginBottom: '32px' / '24px' → mb-8 / mb-6
fontWeight: 700 → font-bold
flex+justify-between+items-center → flex justify-between items-center
CSS partial (.lv-* classes, all token-driven):
.lv-card, .lv-card-lg, .lv-icon-tag, .lv-surface, .lv-eyebrow,
.lv-section-title, .lv-section-sub, .lv-empty-text,
.lv-divider-row, .lv-meta-faint
Per-file deltas:
tabs/OverviewTab.tsx 72 -> 53 inline blocks (19 conversions)
tabs/MyStrategiesTab.tsx 64 -> 55 inline blocks ( 9 conversions)
views/HomeView.tsx 55 -> 44 inline blocks (11 conversions)
The remaining 152 inline-style blocks are unique one-offs (one usage each)
and already token-driven — extracting them yields no drift reduction.
docs/ui/UI_AUDIT.md §5 #8 updated with this rationale.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
063afdbff6
commit
a48187da83
@ -4,6 +4,7 @@ import { Agentation } from 'agentation'
|
|||||||
import './index.css'
|
import './index.css'
|
||||||
import './App.css'
|
import './App.css'
|
||||||
import './layout-fixes.css'
|
import './layout-fixes.css'
|
||||||
|
import './styles/landing-views.css'
|
||||||
import App from './App.tsx'
|
import App from './App.tsx'
|
||||||
import { AuthProvider } from './components/AuthContext';
|
import { AuthProvider } from './components/AuthContext';
|
||||||
import { ProductAccessibilityGate } from './components/ProductAccessibilityGate';
|
import { ProductAccessibilityGate } from './components/ProductAccessibilityGate';
|
||||||
|
|||||||
91
web/src/styles/landing-views.css
Normal file
91
web/src/styles/landing-views.css
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/* ---------------------------------------------------------------------------
|
||||||
|
landing-views.css — extracted patterns from OverviewTab, HomeView, MyStrategiesTab
|
||||||
|
(UI audit #8, Pattern B). Keeps token-driven structural styles in CSS so they
|
||||||
|
can have @media queries and so consumers can override via class composition.
|
||||||
|
One-off styles remain inline (already var(--bl-*) driven).
|
||||||
|
--------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Card / panel container — used across overview metric cards, strategy
|
||||||
|
profile cards, and home preview panels. */
|
||||||
|
.lv-card {
|
||||||
|
background: var(--card);
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Larger structural card — overview "tile" / strategy profile shell. */
|
||||||
|
.lv-card-lg {
|
||||||
|
background: var(--bl-surface-overlay);
|
||||||
|
border: 1px solid var(--bl-border-subtle);
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Highlight chip / icon tag — small square holder for an icon + accent. */
|
||||||
|
.lv-icon-tag {
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--bl-surface-highlight);
|
||||||
|
border: 1px solid var(--bl-border-subtle);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Soft 24-radius surface — used by strategy profile sections, education panels. */
|
||||||
|
.lv-surface {
|
||||||
|
background: var(--bl-surface-highlight);
|
||||||
|
border: 1px solid var(--bl-border-subtle);
|
||||||
|
border-radius: 24px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Eyebrow / section label — small, bold, uppercase, letter-spaced. */
|
||||||
|
.lv-eyebrow {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 900;
|
||||||
|
color: var(--bl-text-quiet);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Section title — bold token-foreground at fixed metric size. */
|
||||||
|
.lv-section-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--foreground);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Section subtitle — muted, fixed metric size. */
|
||||||
|
.lv-section-sub {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--muted-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Empty-state text — italic, centered, padded, tertiary color. */
|
||||||
|
.lv-empty-text {
|
||||||
|
text-align: center;
|
||||||
|
padding: 16px;
|
||||||
|
color: var(--bl-text-tertiary);
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Top-bordered divider with breathing room — used for footer-like rows
|
||||||
|
inside cards (totals, last-updated stamps). */
|
||||||
|
.lv-divider-row {
|
||||||
|
margin-top: 12px;
|
||||||
|
padding-top: 10px;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tiny meta value — used for fine-print metrics next to the eyebrow. */
|
||||||
|
.lv-meta-faint {
|
||||||
|
font-size: 0.65rem;
|
||||||
|
color: var(--bl-text-faint);
|
||||||
|
}
|
||||||
@ -112,7 +112,7 @@ const ActiveStrategyCard: React.FC<{
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 3. Identity */}
|
{/* 3. Identity */}
|
||||||
<div style={{ marginBottom: '24px' }}>
|
<div className="mb-6">
|
||||||
<h3 style={{ fontSize: '24px', fontWeight: 950, color: 'white', letterSpacing: '-0.02em' }}>{profile.name}</h3>
|
<h3 style={{ fontSize: '24px', fontWeight: 950, color: 'white', letterSpacing: '-0.02em' }}>{profile.name}</h3>
|
||||||
<div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap', marginTop: '12px' }}>
|
<div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap', marginTop: '12px' }}>
|
||||||
<span style={{ background: 'var(--bl-success-muted)', color: 'var(--bl-success)', fontSize: '10px', fontWeight: 900, padding: '4px 10px', borderRadius: '6px', border: '1px solid var(--bl-success-muted)', textTransform: 'uppercase' }}>
|
<span style={{ background: 'var(--bl-success-muted)', color: 'var(--bl-success)', fontSize: '10px', fontWeight: 900, padding: '4px 10px', borderRadius: '6px', border: '1px solid var(--bl-success-muted)', textTransform: 'uppercase' }}>
|
||||||
@ -150,7 +150,7 @@ const ActiveStrategyCard: React.FC<{
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 5. Health Diagnostic (Education Layer) */}
|
{/* 5. Health Diagnostic (Education Layer) */}
|
||||||
<div style={{ marginBottom: '32px' }}>
|
<div className="mb-8">
|
||||||
<CardButton
|
<CardButton
|
||||||
onClick={() => onToggleExpand(profile.id)}
|
onClick={() => onToggleExpand(profile.id)}
|
||||||
style={{
|
style={{
|
||||||
@ -166,7 +166,7 @@ const ActiveStrategyCard: React.FC<{
|
|||||||
textAlign: 'left'
|
textAlign: 'left'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
<div className="flex justify-between items-center">
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', color: 'var(--bl-success)', fontSize: '10px', fontWeight: 900, textTransform: 'uppercase' }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', color: 'var(--bl-success)', fontSize: '10px', fontWeight: 900, textTransform: 'uppercase' }}>
|
||||||
<Fingerprint size={14} /> Diagnostic Intelligence {tier === 'free' && <Lock size={12} style={{ marginLeft: '4px', opacity: 0.5 }} />}
|
<Fingerprint size={14} /> Diagnostic Intelligence {tier === 'free' && <Lock size={12} style={{ marginLeft: '4px', opacity: 0.5 }} />}
|
||||||
</div>
|
</div>
|
||||||
@ -299,7 +299,7 @@ export const MyStrategiesTab: React.FC<{ botState: any; alerts?: any[]; previewA
|
|||||||
if (showWizard) {
|
if (showWizard) {
|
||||||
return (
|
return (
|
||||||
<div style={{ animation: 'fadeIn 0.5s ease-out' }}>
|
<div style={{ animation: 'fadeIn 0.5s ease-out' }}>
|
||||||
<div style={{ marginBottom: '24px' }}>
|
<div className="mb-6">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -368,7 +368,7 @@ export const MyStrategiesTab: React.FC<{ botState: any; alerts?: any[]; previewA
|
|||||||
<div style={{ background: 'var(--bl-surface-highlight)', border: '1px solid var(--bl-border-subtle)', borderRadius: '24px', padding: '24px 28px' }}>
|
<div style={{ background: 'var(--bl-surface-highlight)', border: '1px solid var(--bl-border-subtle)', borderRadius: '24px', padding: '24px 28px' }}>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '16px' }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '16px' }}>
|
||||||
<div style={{ width: '8px', height: '8px', borderRadius: '50%', background: 'var(--bl-success)', boxShadow: '0 0 8px var(--bl-success)' }} />
|
<div style={{ width: '8px', height: '8px', borderRadius: '50%', background: 'var(--bl-success)', boxShadow: '0 0 8px var(--bl-success)' }} />
|
||||||
<span style={{ fontSize: '11px', fontWeight: 900, color: 'var(--bl-text-quiet)', textTransform: 'uppercase', letterSpacing: '2px' }}>Recent Activity</span>
|
<span className="lv-eyebrow">Recent Activity</span>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
|
||||||
{recentAlerts.map((alert, i) => {
|
{recentAlerts.map((alert, i) => {
|
||||||
@ -383,7 +383,7 @@ export const MyStrategiesTab: React.FC<{ botState: any; alerts?: any[]; previewA
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{recentAlerts.length === 0 && <div style={{ textAlign: 'center', padding: '16px', color: 'var(--bl-text-tertiary)', fontSize: '12px', fontStyle: 'italic' }}>No activity yet...</div>}
|
{recentAlerts.length === 0 && <div className="lv-empty-text">No activity yet...</div>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -391,7 +391,7 @@ export const MyStrategiesTab: React.FC<{ botState: any; alerts?: any[]; previewA
|
|||||||
<div style={{ background: 'var(--bl-surface-highlight)', border: '1px solid var(--bl-border-subtle)', borderRadius: '24px', padding: '24px 28px' }}>
|
<div style={{ background: 'var(--bl-surface-highlight)', border: '1px solid var(--bl-border-subtle)', borderRadius: '24px', padding: '24px 28px' }}>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '16px' }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '16px' }}>
|
||||||
<TrendingUp size={15} color="var(--bl-info)" />
|
<TrendingUp size={15} color="var(--bl-info)" />
|
||||||
<span style={{ fontSize: '11px', fontWeight: 900, color: 'var(--bl-text-quiet)', textTransform: 'uppercase', letterSpacing: '2px' }}>Your Markets (24h)</span>
|
<span className="lv-eyebrow">Your Markets (24h)</span>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
||||||
{symbolVolatility.map(({ symbol, change }) => (
|
{symbolVolatility.map(({ symbol, change }) => (
|
||||||
@ -407,7 +407,7 @@ export const MyStrategiesTab: React.FC<{ botState: any; alerts?: any[]; previewA
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{symbolVolatility.length === 0 && <div style={{ textAlign: 'center', padding: '16px', color: 'var(--bl-text-tertiary)', fontSize: '12px', fontStyle: 'italic' }}>Deploy a strategy to see its market data</div>}
|
{symbolVolatility.length === 0 && <div className="lv-empty-text">Deploy a strategy to see its market data</div>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -462,7 +462,7 @@ export const MyStrategiesTab: React.FC<{ botState: any; alerts?: any[]; previewA
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
textAlign: 'center'
|
textAlign: 'center'
|
||||||
}}>
|
}}>
|
||||||
<Activity size={60} color="var(--bl-text-quiet)" style={{ marginBottom: '24px' }} />
|
<Activity size={60} color="var(--bl-text-quiet)" className="mb-6" />
|
||||||
<h3 style={{ color: 'var(--bl-text-quiet)', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '4px' }}>No strategies yet</h3>
|
<h3 style={{ color: 'var(--bl-text-quiet)', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '4px' }}>No strategies yet</h3>
|
||||||
<p style={{ color: 'var(--bl-text-quiet)', fontSize: '14px', marginTop: '12px', maxWidth: '300px' }}>Create your first strategy to start monitoring markets and testing automated execution.</p>
|
<p style={{ color: 'var(--bl-text-quiet)', fontSize: '14px', marginTop: '12px', maxWidth: '300px' }}>Create your first strategy to start monitoring markets and testing automated execution.</p>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -705,7 +705,7 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
|
|||||||
<span className="value" style={{ color: displayWindowAggregate.winRate >= 50 ? overviewSuccessText : overviewWarningText }}>
|
<span className="value" style={{ color: displayWindowAggregate.winRate >= 50 ? overviewSuccessText : overviewWarningText }}>
|
||||||
{displayWindowAggregate.winRate.toFixed(1)}%
|
{displayWindowAggregate.winRate.toFixed(1)}%
|
||||||
</span>
|
</span>
|
||||||
<span style={{ fontSize: '0.65rem', color: overviewMutedText }}>
|
<span className="lv-meta-faint">
|
||||||
{displayWindowAggregate.tradeCount} trades
|
{displayWindowAggregate.tradeCount} trades
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -719,7 +719,7 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
|
|||||||
>
|
>
|
||||||
{pnlWindow.durationLabel}
|
{pnlWindow.durationLabel}
|
||||||
</span>
|
</span>
|
||||||
<span style={{ fontSize: '0.65rem', color: overviewMutedText }}>
|
<span className="lv-meta-faint">
|
||||||
{pnlWindow.fromTs > 0
|
{pnlWindow.fromTs > 0
|
||||||
? `From ${new Date(pnlWindow.fromTs).toLocaleDateString()}`
|
? `From ${new Date(pnlWindow.fromTs).toLocaleDateString()}`
|
||||||
: 'Awaiting trade history'}
|
: 'Awaiting trade history'}
|
||||||
@ -737,7 +737,7 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
|
|||||||
: 'Waiting for snapshot...'}
|
: 'Waiting for snapshot...'}
|
||||||
</span>
|
</span>
|
||||||
{botState.accountSnapshot && (
|
{botState.accountSnapshot && (
|
||||||
<span style={{ fontSize: '0.65rem', color: overviewMutedText }}>
|
<span className="lv-meta-faint">
|
||||||
Cash: {formatUsd(botState.accountSnapshot.cash)} ({botState.accountSnapshot.currency})
|
Cash: {formatUsd(botState.accountSnapshot.cash)} ({botState.accountSnapshot.currency})
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@ -772,24 +772,24 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
|
|||||||
<div className="status-item" style={{ marginLeft: 'auto', borderLeft: overviewSoftBorder, paddingLeft: '16px' }}>
|
<div className="status-item" style={{ marginLeft: 'auto', borderLeft: overviewSoftBorder, paddingLeft: '16px' }}>
|
||||||
<span className="label" style={{ color: overviewDangerText }}>Recent Rejections:</span>
|
<span className="label" style={{ color: overviewDangerText }}>Recent Rejections:</span>
|
||||||
<span className="value" style={{ color: overviewDangerText }}>{(botState.orderFailures || []).length}</span>
|
<span className="value" style={{ color: overviewDangerText }}>{(botState.orderFailures || []).length}</span>
|
||||||
<span style={{ fontSize: '0.65rem', color: overviewMutedText }}>
|
<span className="lv-meta-faint">
|
||||||
Latest: {(botState.orderFailures || [])[0].symbol} ({(botState.orderFailures || [])[0].reason?.substring(0, 20)}...)
|
Latest: {(botState.orderFailures || [])[0].symbol} ({(botState.orderFailures || [])[0].reason?.substring(0, 20)}...)
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="table-container" style={{ marginBottom: '32px' }}>
|
<div className="table-container mb-8" >
|
||||||
<table className="pro-table w-full">
|
<table className="pro-table w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Capital Scope</th>
|
<th>Capital Scope</th>
|
||||||
<th style={{ textAlign: 'right' }}>Allocated</th>
|
<th className="text-right">Allocated</th>
|
||||||
<th style={{ textAlign: 'right' }}>Used</th>
|
<th className="text-right">Used</th>
|
||||||
<th style={{ textAlign: 'right' }}>Remaining</th>
|
<th className="text-right">Remaining</th>
|
||||||
<th style={{ textAlign: 'right' }}>Utilization</th>
|
<th className="text-right">Utilization</th>
|
||||||
<th style={{ textAlign: 'right' }}>Win Rate ({winRateWindowConfig.label})</th>
|
<th className="text-right">Win Rate ({winRateWindowConfig.label})</th>
|
||||||
<th style={{ textAlign: 'right' }}>Realized P&L</th>
|
<th className="text-right">Realized P&L</th>
|
||||||
<th>State</th>
|
<th>State</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -808,8 +808,8 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
|
|||||||
: overviewQuietText;
|
: overviewQuietText;
|
||||||
return (
|
return (
|
||||||
<tr key={row.id}>
|
<tr key={row.id}>
|
||||||
<td style={{ fontWeight: 700 }}>{row.name}</td>
|
<td className="font-bold">{row.name}</td>
|
||||||
<td style={{ textAlign: 'right' }}>{formatUsd(row.allocated)}</td>
|
<td className="text-right">{formatUsd(row.allocated)}</td>
|
||||||
<td style={{ textAlign: 'right', color: overviewInfoText }}>{formatUsd(row.used)}</td>
|
<td style={{ textAlign: 'right', color: overviewInfoText }}>{formatUsd(row.used)}</td>
|
||||||
<td style={{ textAlign: 'right', color: overAllocated ? overviewDangerText : overviewSuccessText }}>
|
<td style={{ textAlign: 'right', color: overAllocated ? overviewDangerText : overviewSuccessText }}>
|
||||||
{formatUsd(row.remaining)}
|
{formatUsd(row.remaining)}
|
||||||
@ -846,8 +846,8 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
|
|||||||
})
|
})
|
||||||
) : (
|
) : (
|
||||||
<tr>
|
<tr>
|
||||||
<td style={{ fontWeight: 700 }}>Account (Fallback)</td>
|
<td className="font-bold">Account (Fallback)</td>
|
||||||
<td style={{ textAlign: 'right' }}>{formatUsd(allocatedCapital)}</td>
|
<td className="text-right">{formatUsd(allocatedCapital)}</td>
|
||||||
<td style={{ textAlign: 'right', color: overviewInfoText }}>{formatUsd(capitalUsed)}</td>
|
<td style={{ textAlign: 'right', color: overviewInfoText }}>{formatUsd(capitalUsed)}</td>
|
||||||
<td style={{ textAlign: 'right', color: overAllocatedCapital > 1e-8 ? overviewDangerText : overviewSuccessText }}>
|
<td style={{ textAlign: 'right', color: overAllocatedCapital > 1e-8 ? overviewDangerText : overviewSuccessText }}>
|
||||||
{formatUsd(remainingCapital)}
|
{formatUsd(remainingCapital)}
|
||||||
@ -857,10 +857,10 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td style={{ textAlign: 'right' }}>
|
<td className="text-right">
|
||||||
{allocatedCapital > 0 ? ((capitalUsed / allocatedCapital) * 100).toFixed(1) : '0.0'}%
|
{allocatedCapital > 0 ? ((capitalUsed / allocatedCapital) * 100).toFixed(1) : '0.0'}%
|
||||||
</td>
|
</td>
|
||||||
<td style={{ textAlign: 'right' }}>-</td>
|
<td className="text-right">-</td>
|
||||||
<td style={{ textAlign: 'right', color: displayRealizedPnl >= 0 ? overviewSuccessText : overviewDangerText }}>{formatUsd(displayRealizedPnl)}</td>
|
<td style={{ textAlign: 'right', color: displayRealizedPnl >= 0 ? overviewSuccessText : overviewDangerText }}>{formatUsd(displayRealizedPnl)}</td>
|
||||||
<td>
|
<td>
|
||||||
<span style={{ color: overviewQuietText, fontWeight: 700 }}>No signal</span>
|
<span style={{ color: overviewQuietText, fontWeight: 700 }}>No signal</span>
|
||||||
@ -873,7 +873,7 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
|
|||||||
|
|
||||||
{/* NEW: Recent Order Rejections List */}
|
{/* NEW: Recent Order Rejections List */}
|
||||||
{botState.orderFailures && botState.orderFailures.length > 0 && (
|
{botState.orderFailures && botState.orderFailures.length > 0 && (
|
||||||
<div style={{ marginBottom: '32px' }}>
|
<div className="mb-8">
|
||||||
<h3 style={{ fontSize: '0.9rem', fontWeight: 700, marginBottom: '12px', color: overviewDangerText }}>Recent Order Rejections</h3>
|
<h3 style={{ fontSize: '0.9rem', fontWeight: 700, marginBottom: '12px', color: overviewDangerText }}>Recent Order Rejections</h3>
|
||||||
<div className="table-container">
|
<div className="table-container">
|
||||||
<table className="pro-table w-full">
|
<table className="pro-table w-full">
|
||||||
@ -1034,7 +1034,7 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
|
|||||||
{ label: 'Trading Window', value: sessionLabel, color: sessionColor },
|
{ label: 'Trading Window', value: sessionLabel, color: sessionColor },
|
||||||
{ label: 'Market Activity', value: volLabel, color: volColor },
|
{ label: 'Market Activity', value: volLabel, color: volColor },
|
||||||
].map(({ label, value, color }) => (
|
].map(({ label, value, color }) => (
|
||||||
<div key={label} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
<div key={label} className="flex justify-between items-center">
|
||||||
<span style={{ fontSize: '0.78rem', color: overviewBotMuted, fontWeight: 600 }}>{label}</span>
|
<span style={{ fontSize: '0.78rem', color: overviewBotMuted, fontWeight: 600 }}>{label}</span>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
|
||||||
<div style={{ width: '6px', height: '6px', borderRadius: '50%', background: color, boxShadow: `0 0 6px ${color}` }} />
|
<div style={{ width: '6px', height: '6px', borderRadius: '50%', background: color, boxShadow: `0 0 6px ${color}` }} />
|
||||||
|
|||||||
@ -523,7 +523,7 @@ function StockChart({
|
|||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
|
|
||||||
{enabledIndicators.rsi && (
|
{enabledIndicators.rsi && (
|
||||||
<div style={{ marginTop: 12, paddingTop: 10, borderTop: '1px solid var(--border)' }}>
|
<div className="lv-divider-row">
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4, fontSize: 11, color: 'var(--muted-foreground)', fontWeight: 700 }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4, fontSize: 11, color: 'var(--muted-foreground)', fontWeight: 700 }}>
|
||||||
<span>RSI (14)</span>
|
<span>RSI (14)</span>
|
||||||
<span style={{ color: 'var(--muted-foreground)', fontWeight: 500 }}>70 overbought · 30 oversold</span>
|
<span style={{ color: 'var(--muted-foreground)', fontWeight: 500 }}>70 overbought · 30 oversold</span>
|
||||||
@ -547,7 +547,7 @@ function StockChart({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{enabledIndicators.macd && (
|
{enabledIndicators.macd && (
|
||||||
<div style={{ marginTop: 12, paddingTop: 10, borderTop: '1px solid var(--border)' }}>
|
<div className="lv-divider-row">
|
||||||
<div style={{ marginBottom: 4, fontSize: 11, color: 'var(--muted-foreground)', fontWeight: 700 }}>
|
<div style={{ marginBottom: 4, fontSize: 11, color: 'var(--muted-foreground)', fontWeight: 700 }}>
|
||||||
MACD (12, 26, 9)
|
MACD (12, 26, 9)
|
||||||
</div>
|
</div>
|
||||||
@ -682,8 +682,8 @@ function ResearchCards({
|
|||||||
return (
|
return (
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 16 }}>
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 16 }}>
|
||||||
{/* Company Profile */}
|
{/* Company Profile */}
|
||||||
<div style={{ background: 'var(--card)', borderRadius: 12, border: '1px solid var(--border)', padding: 16 }}>
|
<div className="lv-card">
|
||||||
<div style={{ fontSize: 13, fontWeight: 700, color: 'var(--foreground)', marginBottom: 10 }}>
|
<div className="lv-section-title">
|
||||||
📋 Company
|
📋 Company
|
||||||
</div>
|
</div>
|
||||||
{profileLoading ? (
|
{profileLoading ? (
|
||||||
@ -713,13 +713,13 @@ function ResearchCards({
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ fontSize: 12, color: 'var(--muted-foreground)' }}>No profile data</div>
|
<div className="lv-section-sub">No profile data</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Financials */}
|
{/* Financials */}
|
||||||
<div style={{ background: 'var(--card)', borderRadius: 12, border: '1px solid var(--border)', padding: 16 }}>
|
<div className="lv-card">
|
||||||
<div style={{ fontSize: 13, fontWeight: 700, color: 'var(--foreground)', marginBottom: 10 }}>
|
<div className="lv-section-title">
|
||||||
📊 Financials
|
📊 Financials
|
||||||
</div>
|
</div>
|
||||||
{financialRows.map(([label, val]) => (
|
{financialRows.map(([label, val]) => (
|
||||||
@ -727,7 +727,7 @@ function ResearchCards({
|
|||||||
display: 'flex', justifyContent: 'space-between',
|
display: 'flex', justifyContent: 'space-between',
|
||||||
padding: '5px 0', borderBottom: '1px solid var(--border)',
|
padding: '5px 0', borderBottom: '1px solid var(--border)',
|
||||||
}}>
|
}}>
|
||||||
<span style={{ fontSize: 12, color: 'var(--muted-foreground)' }}>{label}</span>
|
<span className="lv-section-sub">{label}</span>
|
||||||
<span style={{ fontSize: 12, fontWeight: 600, color: 'var(--foreground)' }}>
|
<span style={{ fontSize: 12, fontWeight: 600, color: 'var(--foreground)' }}>
|
||||||
{loading || profileLoading ? <ValueSkeleton width={label.length > 10 ? 64 : 46} /> : val}
|
{loading || profileLoading ? <ValueSkeleton width={label.length > 10 ? 64 : 46} /> : val}
|
||||||
</span>
|
</span>
|
||||||
@ -736,8 +736,8 @@ function ResearchCards({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Events / Earnings */}
|
{/* Events / Earnings */}
|
||||||
<div style={{ background: 'var(--card)', borderRadius: 12, border: '1px solid var(--border)', padding: 16 }}>
|
<div className="lv-card">
|
||||||
<div style={{ fontSize: 13, fontWeight: 700, color: 'var(--foreground)', marginBottom: 10 }}>
|
<div className="lv-section-title">
|
||||||
📅 Events
|
📅 Events
|
||||||
</div>
|
</div>
|
||||||
{[
|
{[
|
||||||
@ -750,7 +750,7 @@ function ResearchCards({
|
|||||||
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
||||||
padding: '5px 0', borderBottom: '1px solid var(--border)',
|
padding: '5px 0', borderBottom: '1px solid var(--border)',
|
||||||
}}>
|
}}>
|
||||||
<span style={{ fontSize: 12, color: 'var(--muted-foreground)' }}>{label}</span>
|
<span className="lv-section-sub">{label}</span>
|
||||||
<span style={{ fontSize: 12, fontWeight: 600, color: 'var(--foreground)' }}>
|
<span style={{ fontSize: 12, fontWeight: 600, color: 'var(--foreground)' }}>
|
||||||
{val === '…' ? <ValueSkeleton width={label === 'Next Earnings' ? 82 : 52} /> : val}
|
{val === '…' ? <ValueSkeleton width={label === 'Next Earnings' ? 82 : 52} /> : val}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user