From 9dae780f30795754659bf7b7c48fbbd74889ee80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B5=D0=BD=D0=B8=D1=81=20=D0=97=D0=B5=D1=84=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2?= Date: Sun, 12 Jul 2026 00:25:58 +0400 Subject: [PATCH] =?UTF-8?q?feat:=20denser=20market=20cards=20=E2=80=94=20f?= =?UTF-8?q?ill=20the=20empty=20space?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- apps/web/src/screens/Markets.tsx | 76 ++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/apps/web/src/screens/Markets.tsx b/apps/web/src/screens/Markets.tsx index e2ad156..68ac6ce 100644 --- a/apps/web/src/screens/Markets.tsx +++ b/apps/web/src/screens/Markets.tsx @@ -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 (
+ {/* depth-fill meter, full width */} +
+
+ Depth fill // target {fmtUsd(c.targetDepthUsd)} + + {fmtUsd(depth)} + · + {(depthFill * 100).toFixed(0)}% + +
+ +
+
{pair ? (
@@ -105,10 +125,28 @@ export default function Markets() { 24h volume {fmtUsd(pair.volume24h)}
+
+ Spread est + {spreadPct.toFixed(2)}% +
Total depth {fmtUsd(depth)}
+
+
+ Fee APR + {fmtAprPct(feeAprV)} +
+
+ Reward APR + {fmtAprPct(rewardAprV)} +
+
+ Net APR + {fmtAprPct(netApr)} +
+
Active LPs {c.activeLPs} @@ -133,12 +171,34 @@ export default function Markets() {
-
- - - Fig. 03 -
Health -
+
+
+ + + Fig. 03 +
Health +
+
+
+
+ Target + {fmtUsd(c.targetDepthUsd)} +
+
+ Fill + {(depthFill * 100).toFixed(0)}% +
+
+ Ends + + {c.status === "ended" ? "Closed" : fmtCountdown(c.end)} + +
+
+ Boost + {boostX.toFixed(1)}× +
+