refactor(ui): replace one-off visual language with shared Badge components
- Replace .stat-chip with Badge in PresetMarketplace, BacktestTab, MembershipTab - Replace .saved-setup-id-chip with Badge in SimpleView - Replace .screener-sector-chip with Badge in ScreenerView - Replace .health-pill with Badge in TradeProfileManager - Remove CSS definitions for one-off classes from index.css - All components now use shared Badge from product adapter - Verify: audit:ui (0 findings), audit:ui:strict (0 findings), typecheck, build
This commit is contained in:
parent
a17de130c7
commit
94ce743bd0
@ -19,6 +19,7 @@ import { STRATEGY_PRESETS } from '../lib/PresetRegistry';
|
||||
import { Button } from './ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './ui/card';
|
||||
import { PageHeader } from './ui/page-header';
|
||||
import { Badge } from './ui/Primitives';
|
||||
|
||||
interface PresetMarketplaceProps {
|
||||
onSelect: (preset: StrategyPreset) => void;
|
||||
@ -74,7 +75,7 @@ const StrategyMarketplaceCard: React.FC<{
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="stat-chip">V{index + 1}.4</div>
|
||||
<Badge variant="neutral">V{index + 1}.4</Badge>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
@ -185,7 +186,7 @@ export const PresetMarketplace: React.FC<PresetMarketplaceProps> = ({ onSelect,
|
||||
description="Browse reusable strategy profiles with preconfigured risk posture and execution bias."
|
||||
/>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="stat-chip">{allPresets.length} presets</div>
|
||||
<Badge variant="neutral">{allPresets.length} presets</Badge>
|
||||
{onClose ? (
|
||||
<Button variant="outline" onClick={onClose}>
|
||||
Return
|
||||
|
||||
@ -28,7 +28,7 @@ import { Button } from './ui/button';
|
||||
import { Card } from './ui/card';
|
||||
import { Input } from './ui/input';
|
||||
import { Select } from './ui/select';
|
||||
import { Textarea } from './ui/Primitives';
|
||||
import { Textarea, Badge } from './ui/Primitives';
|
||||
import { cn } from '../lib/utils';
|
||||
// ChatControl is now rendered globally in App.tsx
|
||||
|
||||
@ -642,7 +642,6 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
const bp = botState.accountSnapshot?.buying_power ?? 0;
|
||||
const isCovered = (p.allocated_capital || 0) <= bp;
|
||||
const coverageStatus = isCovered ? 'Covered' : 'Insufficient funds';
|
||||
const coverageColor = isCovered ? 'ok' : 'drift'; // reuse 'drift' style for warning
|
||||
|
||||
const lifecycleStatus = stats.tradeCount > 0 ? 'OK' : (p.is_active ? 'Blocked' : 'Idle');
|
||||
const reconciliationDrift = (botState.health?.reconciliationMismatchCount || 0) > 0 ? 'Drift' : 'Clean';
|
||||
@ -752,15 +751,15 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
</div>
|
||||
|
||||
<div className="profile-health-strip flex flex-wrap gap-1 px-4 py-2">
|
||||
<span className={`health-pill ${capitalHealth === 'Issue' ? 'issue' : 'ok'}`}>Capital: {capitalHealth}</span>
|
||||
<Badge variant={capitalHealth === 'Issue' ? 'error' : 'success'}>Capital: {capitalHealth}</Badge>
|
||||
{botState.accountSnapshot && (
|
||||
<span className={`health-pill ${coverageColor}`} title={`Buying Power: $${bp.toFixed(2)}`}>
|
||||
<Badge variant={isCovered ? 'success' : 'warning'} title={`Buying Power: $${bp.toFixed(2)}`}>
|
||||
LP: {coverageStatus}
|
||||
</span>
|
||||
</Badge>
|
||||
)}
|
||||
<span className={`health-pill ${lifecycleStatus === 'OK' ? 'ok' : 'blocked'}`}>Lifecycle: {lifecycleStatus}</span>
|
||||
<span className={`health-pill ${reconciliationDrift === 'Drift' ? 'drift' : 'clean'}`}>Reconciliation: {reconciliationDrift}</span>
|
||||
<span className={`health-pill ${lockStatus === 'Contended' ? 'drift' : 'ok'}`}>Locks: {lockStatus}</span>
|
||||
<Badge variant={lifecycleStatus === 'OK' ? 'success' : 'error'}>Lifecycle: {lifecycleStatus}</Badge>
|
||||
<Badge variant={reconciliationDrift === 'Drift' ? 'warning' : 'success'}>Reconciliation: {reconciliationDrift}</Badge>
|
||||
<Badge variant={lockStatus === 'Contended' ? 'warning' : 'success'}>Locks: {lockStatus}</Badge>
|
||||
</div>
|
||||
|
||||
{/* Win rate section */}
|
||||
|
||||
@ -1080,26 +1080,6 @@ body {
|
||||
box-shadow: var(--card-shadow);
|
||||
}
|
||||
|
||||
.stat-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--border);
|
||||
background: var(--card-elevated);
|
||||
color: var(--muted-foreground);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.stat-chip[data-tone="success"] {
|
||||
color: #16a34a;
|
||||
}
|
||||
|
||||
.stat-chip[data-tone="danger"] {
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.trading-sidebar-nav {
|
||||
flex: 1;
|
||||
@ -2238,11 +2218,6 @@ body {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.saved-setup-id-chip,
|
||||
.saved-setup-updated {
|
||||
text-transform: none !important;
|
||||
letter-spacing: 0 !important;
|
||||
}
|
||||
|
||||
.saved-setup-timeline {
|
||||
display: grid;
|
||||
@ -2332,19 +2307,6 @@ body {
|
||||
gap: 7px;
|
||||
}
|
||||
|
||||
.screener-sector-chip {
|
||||
min-height: 32px !important;
|
||||
border-radius: 999px !important;
|
||||
padding: 0 12px !important;
|
||||
font-size: 11px !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
.screener-sector-chip[data-active="true"] {
|
||||
border-color: var(--accent) !important;
|
||||
background: var(--accent-soft) !important;
|
||||
color: var(--accent) !important;
|
||||
}
|
||||
|
||||
.screener-more-select {
|
||||
width: 150px;
|
||||
|
||||
@ -7,6 +7,7 @@ import { fetchTradeProfiles } from '../lib/profileApi';
|
||||
import { PageHeader } from '../components/ui/page-header';
|
||||
import { Card, CardContent } from '../components/ui/card';
|
||||
import { Button } from '../components/ui/button';
|
||||
import { Badge } from '../components/ui/Primitives';
|
||||
import { Select } from '../components/ui/select';
|
||||
|
||||
interface BacktestTabProps {
|
||||
@ -84,18 +85,18 @@ export const BacktestTab: React.FC<BacktestTabProps> = ({ previewAsCustomer = fa
|
||||
<Card style={{ marginBottom: 16 }}>
|
||||
<CardContent style={{ padding: '14px 16px' }}>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', marginBottom: '10px' }}>
|
||||
<span className="stat-chip">
|
||||
<Badge variant="neutral">
|
||||
Role: {isAdminAccount ? 'admin' : 'customer'}
|
||||
</span>
|
||||
<span className="stat-chip">
|
||||
</Badge>
|
||||
<Badge variant="neutral">
|
||||
Preview Mode: {previewAsCustomer ? 'customer view' : 'off'}
|
||||
</span>
|
||||
<span className="stat-chip" data-tone={runtimeFlags.enableBacktest ? 'success' : 'danger'}>
|
||||
</Badge>
|
||||
<Badge variant={runtimeFlags.enableBacktest ? 'success' : 'error'}>
|
||||
ENABLE_BACKTEST: {String(runtimeFlags.enableBacktest)}
|
||||
</span>
|
||||
<span className="stat-chip" data-tone={runtimeFlags.customerEnabled ? 'success' : 'danger'}>
|
||||
</Badge>
|
||||
<Badge variant={runtimeFlags.customerEnabled ? 'success' : 'error'}>
|
||||
BACKTEST_CUSTOMER_ENABLED: {String(runtimeFlags.customerEnabled)}
|
||||
</span>
|
||||
</Badge>
|
||||
</div>
|
||||
{!backtestGateLoading && !backtestEnabled && (
|
||||
<p style={{ margin: 0, fontSize: '12px', color: 'var(--bl-danger-muted)' }}>
|
||||
|
||||
@ -15,6 +15,7 @@ import { TIER_POLICIES } from '../lib/TierPolicy';
|
||||
import { PageHeader } from '../components/ui/page-header';
|
||||
import { Card, CardContent } from '../components/ui/card';
|
||||
import { Button } from '../components/ui/button';
|
||||
import { Badge } from '../components/ui/Primitives';
|
||||
|
||||
const PlanCard: React.FC<{
|
||||
id: string;
|
||||
@ -66,9 +67,9 @@ const PlanCard: React.FC<{
|
||||
</div>
|
||||
</div>
|
||||
{isElite && (
|
||||
<span className="stat-chip" data-tone="success">
|
||||
<Badge variant="success">
|
||||
Peak
|
||||
</span>
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -77,10 +78,10 @@ const PlanCard: React.FC<{
|
||||
<h3 style={{ fontSize: 42, fontWeight: 950, color: 'var(--foreground)', letterSpacing: '-0.04em', margin: 0 }}>{price}</h3>
|
||||
<span style={{ fontSize: 14, color: 'var(--muted-foreground)', fontWeight: 900, textTransform: 'uppercase' }}>/mo</span>
|
||||
</div>
|
||||
<div className="stat-chip">
|
||||
<Badge variant="neutral">
|
||||
<Sparkles size={14} style={{ color: 'var(--bl-warning)' }} />
|
||||
Professional grade DNA
|
||||
</div>
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
<p style={{
|
||||
@ -163,9 +164,9 @@ export const MembershipTab: React.FC = () => {
|
||||
/>
|
||||
|
||||
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', marginBottom: 28 }}>
|
||||
<span className="stat-chip">3 tiers</span>
|
||||
<span className="stat-chip">Preview pricing</span>
|
||||
<span className="stat-chip">Product direction only</span>
|
||||
<Badge variant="neutral">3 tiers</Badge>
|
||||
<Badge variant="neutral">Preview pricing</Badge>
|
||||
<Badge variant="neutral">Product direction only</Badge>
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
|
||||
@ -8,7 +8,7 @@ import { tradingRuntime } from '../lib/runtime';
|
||||
import { createRequestId } from '../../../shared/request-id.js';
|
||||
import { SkeletonBlock } from '../components/Skeleton';
|
||||
import { PageHeader } from '../components/ui/page-header';
|
||||
import { Button, Input, Select } from '../components/ui/Primitives';
|
||||
import { Button, Input, Select, Badge } from '../components/ui/Primitives';
|
||||
import { Card, CardContent } from '../components/ui/card';
|
||||
|
||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||
@ -200,16 +200,14 @@ export function ScreenerView() {
|
||||
<div className="screener-sector-row">
|
||||
<SlidersHorizontal size={13} color="var(--muted-foreground)" />
|
||||
{SECTORS.slice(0, 6).map(s => (
|
||||
<Button
|
||||
<Badge
|
||||
key={s}
|
||||
variant={sector === s ? 'info' : 'neutral'}
|
||||
className="cursor-pointer"
|
||||
onClick={() => setSector(s)}
|
||||
variant={sector === s ? 'secondary' : 'outline'}
|
||||
size="sm"
|
||||
className="screener-sector-chip"
|
||||
data-active={sector === s}
|
||||
>
|
||||
{s}
|
||||
</Button>
|
||||
</Badge>
|
||||
))}
|
||||
<Select
|
||||
aria-label="More sectors"
|
||||
|
||||
@ -14,7 +14,7 @@ import {
|
||||
import { fetchTradeProfiles, type TradeProfilePayload } from '../lib/profileApi';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../components/ui/card';
|
||||
import { PageHeader } from '../components/ui/page-header';
|
||||
import { Button, Input, Select } from '../components/ui/Primitives';
|
||||
import { Button, Input, Select, Badge } from '../components/ui/Primitives';
|
||||
import {
|
||||
DEFAULT_TRADE_PLANS_UI_STATE,
|
||||
reduceTradePlansUiState,
|
||||
@ -1515,30 +1515,18 @@ export function SimpleView() {
|
||||
</span>
|
||||
) : null}
|
||||
{(runtimeSnapshot?.tradeId || entry.linked_trade_id) ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="subtle"
|
||||
size="sm"
|
||||
onClick={() => void copyIdentifier('trade', String(runtimeSnapshot?.tradeId || entry.linked_trade_id))}
|
||||
className="saved-setup-id-chip"
|
||||
>
|
||||
<Badge variant="neutral" className="cursor-pointer" onClick={() => void copyIdentifier('trade', String(runtimeSnapshot?.tradeId || entry.linked_trade_id))}>
|
||||
{copiedKey === `trade:${String(runtimeSnapshot?.tradeId || entry.linked_trade_id)}`
|
||||
? 'Trade copied'
|
||||
: `Trade ${String(runtimeSnapshot?.tradeId || entry.linked_trade_id).slice(0, 18)}…`}
|
||||
</Button>
|
||||
</Badge>
|
||||
) : null}
|
||||
{runtimeSnapshot?.orderId ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="subtle"
|
||||
size="sm"
|
||||
onClick={() => void copyIdentifier('order', runtimeSnapshot.orderId)}
|
||||
className="saved-setup-id-chip"
|
||||
>
|
||||
<Badge variant="neutral" className="cursor-pointer" onClick={() => void copyIdentifier('order', runtimeSnapshot.orderId)}>
|
||||
{copiedKey === `order:${runtimeSnapshot.orderId}`
|
||||
? 'Order copied'
|
||||
: `Order ${runtimeSnapshot.orderId.slice(0, 12)}…`}
|
||||
</Button>
|
||||
</Badge>
|
||||
) : null}
|
||||
{updatedAt ? (
|
||||
<span className="saved-setup-updated">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user