feat: denser market cards — fill the empty space
All checks were successful
deploy / deploy (push) Successful in 1m7s
All checks were successful
deploy / deploy (push) Successful in 1m7s
Each market panel gains a full-width depth-fill meter (depth vs target), an expanded stat column (spread est, fee/reward/net APR alongside the existing figures) and a micro-stat stack under the health dial (target, fill %, ends-in, boost). Fills the previously empty card interior. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
c05b185b99
commit
9dae780f30
1 changed files with 68 additions and 8 deletions
|
|
@ -6,9 +6,10 @@ import { Skeleton } from "@/components/ui/skeleton";
|
|||
import { HealthRadial } from "@/components/HealthRadial";
|
||||
import { SlippageCurve } from "@/components/SlippageCurve";
|
||||
import { DepthHistory } from "@/components/DepthHistory";
|
||||
import { DepthProgress } from "@/components/DepthProgress";
|
||||
import { rewardsRemainingUsd } from "@/hooks/useCampaigns";
|
||||
import { healthScore } from "@/lib/math";
|
||||
import { fmtUsd, fmtNum } from "@/lib/format";
|
||||
import { healthScore, feeApr, rewardApr, slippageFor } from "@/lib/math";
|
||||
import { fmtUsd, fmtNum, fmtAprPct, fmtCountdown } from "@/lib/format";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { CyberGrid } from "@/components/fx/CyberGrid";
|
||||
|
||||
|
|
@ -50,6 +51,12 @@ export default function Markets() {
|
|||
tvlUsd: c.tvlUsd,
|
||||
targetDepthUsd: c.targetDepthUsd,
|
||||
});
|
||||
const feeAprV = pair ? feeApr(pair.volume24h, pair.liquidityUsd) : 0;
|
||||
const rewardAprV = rewardApr(c.rewardBudgetUsd, c.durationDays, c.tvlUsd);
|
||||
const netApr = feeAprV + rewardAprV;
|
||||
const spreadPct = depth > 0 ? slippageFor(1_000, depth) * 2 * 100 : 0;
|
||||
const depthFill = c.targetDepthUsd > 0 ? depth / c.targetDepthUsd : 0;
|
||||
const boostX = c.status === "boost" ? c.boostBps / 10_000 : 1;
|
||||
return (
|
||||
<section
|
||||
key={c.meta.campaignId}
|
||||
|
|
@ -87,6 +94,19 @@ export default function Markets() {
|
|||
</Link>
|
||||
</div>
|
||||
|
||||
{/* depth-fill meter, full width */}
|
||||
<div className="border-b border-edge/60 px-5 py-3.5 md:px-7">
|
||||
<div className="mb-2 flex items-center justify-between font-mono text-[9.5px] uppercase tracking-[0.16em]">
|
||||
<span className="text-fog-dim">Depth fill // target {fmtUsd(c.targetDepthUsd)}</span>
|
||||
<span>
|
||||
<span className="text-snow">{fmtUsd(depth)}</span>
|
||||
<span className="text-fog-dim"> · </span>
|
||||
<span className="text-mint">{(depthFill * 100).toFixed(0)}%</span>
|
||||
</span>
|
||||
</div>
|
||||
<DepthProgress progress={depthFill} />
|
||||
</div>
|
||||
|
||||
<div className="grid gap-6 px-5 py-5 md:grid-cols-[1fr_1.25fr_auto] md:px-7">
|
||||
{pair ? (
|
||||
<div className="space-y-2 text-sm">
|
||||
|
|
@ -105,10 +125,28 @@ export default function Markets() {
|
|||
<span className="text-fog">24h volume</span>
|
||||
<span className="num font-semibold">{fmtUsd(pair.volume24h)}</span>
|
||||
</div>
|
||||
<div className="leader">
|
||||
<span className="text-fog">Spread est</span>
|
||||
<span className="num font-semibold">{spreadPct.toFixed(2)}%</span>
|
||||
</div>
|
||||
<div className="leader">
|
||||
<span className="text-fog">Total depth</span>
|
||||
<span className="num font-semibold text-mint">{fmtUsd(depth)}</span>
|
||||
</div>
|
||||
<div className="my-1 h-px bg-edge/60" />
|
||||
<div className="leader">
|
||||
<span className="text-fog">Fee APR</span>
|
||||
<span className="num font-semibold">{fmtAprPct(feeAprV)}</span>
|
||||
</div>
|
||||
<div className="leader">
|
||||
<span className="text-fog">Reward APR</span>
|
||||
<span className="num font-semibold text-lime">{fmtAprPct(rewardAprV)}</span>
|
||||
</div>
|
||||
<div className="leader">
|
||||
<span className="text-fog">Net APR</span>
|
||||
<span className="num font-semibold text-mint">{fmtAprPct(netApr)}</span>
|
||||
</div>
|
||||
<div className="my-1 h-px bg-edge/60" />
|
||||
<div className="leader">
|
||||
<span className="text-fog">Active LPs</span>
|
||||
<span className="num font-semibold">{c.activeLPs}</span>
|
||||
|
|
@ -133,12 +171,34 @@ export default function Markets() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center gap-4 md:flex-col md:items-end md:justify-start md:border-l md:border-edge md:pl-6">
|
||||
<HealthRadial score={score} />
|
||||
<span className="fig md:text-right">
|
||||
Fig. 03
|
||||
<br className="hidden md:block" /> Health
|
||||
</span>
|
||||
<div className="flex flex-col gap-4 md:border-l md:border-edge md:pl-6">
|
||||
<div className="flex flex-row items-center gap-4 md:flex-col md:items-end">
|
||||
<HealthRadial score={score} />
|
||||
<span className="fig md:text-right">
|
||||
Fig. 03
|
||||
<br className="hidden md:block" /> Health
|
||||
</span>
|
||||
</div>
|
||||
<dl className="hidden space-y-2 border-t border-edge/60 pt-3 text-[11px] md:block md:min-w-[152px]">
|
||||
<div className="leader">
|
||||
<span className="text-fog-dim">Target</span>
|
||||
<span className="num text-snow">{fmtUsd(c.targetDepthUsd)}</span>
|
||||
</div>
|
||||
<div className="leader">
|
||||
<span className="text-fog-dim">Fill</span>
|
||||
<span className="num text-mint">{(depthFill * 100).toFixed(0)}%</span>
|
||||
</div>
|
||||
<div className="leader">
|
||||
<span className="text-fog-dim">Ends</span>
|
||||
<span className="num text-snow">
|
||||
{c.status === "ended" ? "Closed" : fmtCountdown(c.end)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="leader">
|
||||
<span className="text-fog-dim">Boost</span>
|
||||
<span className="num text-lime">{boostX.toFixed(1)}×</span>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue