Overview: restore wide focus card and half-width positions
Deploy / lint (push) Successful in 7s
Deploy / test (push) Successful in 1m13s
Deploy / deploy (push) Successful in 38s

The focus|radar 3/5-2/5 pairing made the top-pick card cramped and the
full-width positions panel stretched its trade charts. Back to the
layout that worked: focus card full width, account ribbons, then
positions | radar side by side, performance chart at the bottom.

Kept from the rework: radar rows still swap the focus card - and now
reliably, because the ticker symbol inside a row is no longer a
navigation link (clicking anywhere in the row, symbol included,
selects it; the ticker page is reachable via the focus card's Ticker
details button). Below-gate inspection, badges, and the reset link
unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 18:47:40 +02:00
co-authored by Claude Fable 5
parent 06fdd92faa
commit 79010a5dae
+49 -55
View File
@@ -96,13 +96,7 @@ function RadarSetupRow({ setup, rank, reason, name, selected, onSelect }: RadarR
>
<span className="num text-[11px] text-gray-500">{rank}</span>
<span className="min-w-0">
<Link
to={`/ticker/${setup.symbol}`}
onClick={(e) => e.stopPropagation()}
className="block font-medium text-blue-300 transition-colors hover:text-blue-200"
>
{setup.symbol}
</Link>
<span className="block font-medium text-blue-300">{setup.symbol}</span>
{name && <span className="block truncate text-[10.5px] text-gray-500">{name}</span>}
</span>
<DirectionTag direction={setup.direction} />
@@ -413,9 +407,8 @@ export default function DashboardPage() {
)
)}
{/* Setup in focus | Radar — the decision pair */}
<div className="grid items-start gap-8 xl:grid-cols-5">
<div className="xl:col-span-3">
{/* Setup in focus — full width; select a radar row below to swap it */}
<div>
{(trades.isLoading || activation.isLoading) && <SkeletonCard />}
{trades.isError && <Callout variant="error">Failed to load setups</Callout>}
{trades.data && activation.data && (
@@ -446,7 +439,52 @@ export default function DashboardPage() {
)}
</div>
<div className="xl:col-span-2">
{/* Metric strip — the account ribbons, right above the positions they describe */}
{(trades.isLoading || openTrades.isLoading) ? (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
<SkeletonCard /><SkeletonCard /><SkeletonCard /><SkeletonCard />
</div>
) : (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
<Metric
label="Open Risk"
value={exposure.count > 0 ? `$${exposure.riskUsd.toFixed(0)}` : '—'}
sub={exposure.count > 0 ? `${exposure.count} open · distance to stops` : 'no open trades'}
/>
<Metric
label="Unrealized"
value={exposure.rPriced > 0 ? fmtR(exposure.unrealR) : '—'}
valueClass={rColor(exposure.rPriced > 0 ? exposure.unrealR : null)}
sub={
exposure.count > 0
? `${money(exposure.unrealUsd)} · ${exposure.winners}${exposure.losers}`
: 'mark-to-market'
}
/>
<Metric
label="Alpha vs S&P 500"
value={exposure.alphaPriced > 0 ? money(exposure.alphaUsd) : '—'}
valueClass={
exposure.alphaPriced > 0
? exposure.alphaUsd >= 0 ? 'text-emerald-300' : 'text-red-300'
: 'text-gray-100'
}
sub="open trades vs buy-and-hold SPY"
/>
<Metric
label="Gate"
value={trades.data ? `${qualifiedCount} / ${liveCount}` : '—'}
valueClass={qualifiedCount > 0 ? 'text-blue-300' : 'text-gray-100'}
sub={activation.data ? activationSummary(activation.data) : 'setups clearing the gate'}
/>
</div>
)}
{/* Open positions | Radar — side by side, half width each */}
<div className="grid items-start gap-8 xl:grid-cols-2">
<OpenTradesPanel />
<div>
<Section title="Radar" hint="ranked by strategy score · select a row to focus it">
{trades.isLoading && <SkeletonTable rows={5} cols={5} />}
{trades.data && radar.qualified.length === 0 && radar.below.length === 0 && (
@@ -535,50 +573,6 @@ export default function DashboardPage() {
</div>
</div>
{/* Metric strip — the account ribbons, right above the positions they describe */}
{(trades.isLoading || openTrades.isLoading) ? (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
<SkeletonCard /><SkeletonCard /><SkeletonCard /><SkeletonCard />
</div>
) : (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
<Metric
label="Open Risk"
value={exposure.count > 0 ? `$${exposure.riskUsd.toFixed(0)}` : ''}
sub={exposure.count > 0 ? `${exposure.count} open · distance to stops` : 'no open trades'}
/>
<Metric
label="Unrealized"
value={exposure.rPriced > 0 ? fmtR(exposure.unrealR) : ''}
valueClass={rColor(exposure.rPriced > 0 ? exposure.unrealR : null)}
sub={
exposure.count > 0
? `${money(exposure.unrealUsd)} · ${exposure.winners}▲ ${exposure.losers}▼`
: 'mark-to-market'
}
/>
<Metric
label="Alpha vs S&P 500"
value={exposure.alphaPriced > 0 ? money(exposure.alphaUsd) : ''}
valueClass={
exposure.alphaPriced > 0
? exposure.alphaUsd >= 0 ? 'text-emerald-300' : 'text-red-300'
: 'text-gray-100'
}
sub="open trades vs buy-and-hold SPY"
/>
<Metric
label="Gate"
value={trades.data ? `${qualifiedCount} / ${liveCount}` : ''}
valueClass={qualifiedCount > 0 ? 'text-blue-300' : 'text-gray-100'}
sub={activation.data ? activationSummary(activation.data) : 'setups clearing the gate'}
/>
</div>
)}
{/* Open positions — full width, right under their ribbons */}
<OpenTradesPanel />
{/* Performance — the paper book vs the same dollars in SPY */}
<PerfChart />
</div>