Overview: restore wide focus card and half-width positions
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:
@@ -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="num text-[11px] text-gray-500">{rank}</span>
|
||||||
<span className="min-w-0">
|
<span className="min-w-0">
|
||||||
<Link
|
<span className="block font-medium text-blue-300">{setup.symbol}</span>
|
||||||
to={`/ticker/${setup.symbol}`}
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
className="block font-medium text-blue-300 transition-colors hover:text-blue-200"
|
|
||||||
>
|
|
||||||
{setup.symbol}
|
|
||||||
</Link>
|
|
||||||
{name && <span className="block truncate text-[10.5px] text-gray-500">{name}</span>}
|
{name && <span className="block truncate text-[10.5px] text-gray-500">{name}</span>}
|
||||||
</span>
|
</span>
|
||||||
<DirectionTag direction={setup.direction} />
|
<DirectionTag direction={setup.direction} />
|
||||||
@@ -413,9 +407,8 @@ export default function DashboardPage() {
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Setup in focus | Radar — the decision pair */}
|
{/* Setup in focus — full width; select a radar row below to swap it */}
|
||||||
<div className="grid items-start gap-8 xl:grid-cols-5">
|
<div>
|
||||||
<div className="xl:col-span-3">
|
|
||||||
{(trades.isLoading || activation.isLoading) && <SkeletonCard />}
|
{(trades.isLoading || activation.isLoading) && <SkeletonCard />}
|
||||||
{trades.isError && <Callout variant="error">Failed to load setups</Callout>}
|
{trades.isError && <Callout variant="error">Failed to load setups</Callout>}
|
||||||
{trades.data && activation.data && (
|
{trades.data && activation.data && (
|
||||||
@@ -444,9 +437,54 @@ export default function DashboardPage() {
|
|||||||
</Callout>
|
</Callout>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</div>
|
</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">
|
<Section title="Radar" hint="ranked by strategy score · select a row to focus it">
|
||||||
{trades.isLoading && <SkeletonTable rows={5} cols={5} />}
|
{trades.isLoading && <SkeletonTable rows={5} cols={5} />}
|
||||||
{trades.data && radar.qualified.length === 0 && radar.below.length === 0 && (
|
{trades.data && radar.qualified.length === 0 && radar.below.length === 0 && (
|
||||||
@@ -535,50 +573,6 @@ export default function DashboardPage() {
|
|||||||
</div>
|
</div>
|
||||||
</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 */}
|
{/* Performance — the paper book vs the same dollars in SPY */}
|
||||||
<PerfChart />
|
<PerfChart />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user