From aa954c0da44454287f5108ea7ef75df7ab5b32a1 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Mon, 4 May 2026 22:40:24 +0900 Subject: [PATCH 1/2] [#1043] Fix MCap chart label overlap, log scale, and accent color Co-Authored-By: Claude Opus 4.6 (1M context) --- src/components/airdrop/CampaignHero.tsx | 33 ++++++++++++++++--------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/components/airdrop/CampaignHero.tsx b/src/components/airdrop/CampaignHero.tsx index 7a78aa4..ee1835f 100644 --- a/src/components/airdrop/CampaignHero.tsx +++ b/src/components/airdrop/CampaignHero.tsx @@ -32,6 +32,16 @@ const MILESTONES = [ ]; const MAX_MCAP = 100_000_000; +const ACCENT = "#8B4513"; + +/** Map MCap to 0–1 using a log scale (base at $100K for visual spread) */ +const LOG_MIN = Math.log10(100_000); +const LOG_MAX = Math.log10(MAX_MCAP); +function logScale(mcap: number): number { + if (mcap <= 0) return 0; + const clamped = Math.min(Math.max(mcap, 100_000), MAX_MCAP); + return (Math.log10(clamped) - LOG_MIN) / (LOG_MAX - LOG_MIN); +} /* ─── Helpers ─── */ @@ -74,10 +84,10 @@ function useCountdown(endDateStr: string) { /* ─── MCap Chart ─── */ function MCapChart({ currentFdv }: { currentFdv: number }) { - const progress = Math.min(currentFdv / MAX_MCAP, 1); + const progress = logScale(currentFdv); const svgW = 600; const svgH = 80; - const pad = { left: 0, right: 0 }; + const pad = { left: 10, right: 10 }; const chartW = svgW - pad.left - pad.right; const fillX = pad.left + progress * chartW; @@ -86,7 +96,7 @@ function MCapChart({ currentFdv }: { currentFdv: number }) { {/* Desktop labels above chart */}
{MILESTONES.map((ms) => { - const x = (ms.mcap / MAX_MCAP) * 100; + const x = logScale(ms.mcap) * 100; return (
- - + + @@ -140,7 +150,7 @@ function MCapChart({ currentFdv }: { currentFdv: number }) { {/* Milestone vertical dashed lines */} {MILESTONES.map((ms) => { - const mx = pad.left + (ms.mcap / MAX_MCAP) * chartW; + const mx = pad.left + logScale(ms.mcap) * chartW; return ( { - const mx = pad.left + (ms.mcap / MAX_MCAP) * chartW; + const mx = pad.left + logScale(ms.mcap) * chartW; return ( )} @@ -190,7 +200,7 @@ function MCapChart({ currentFdv }: { currentFdv: number }) { {/* Heartbeat dot — inside SVG for pixel-perfect alignment */} {progress > 0 && ( <> - + - + )} {/* Scale labels */}
- $0 - $50M + $100K $100M
From da073a7e2f1483b5f54d6bbf2d7fb426914e9e90 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Mon, 4 May 2026 22:43:14 +0900 Subject: [PATCH 2/2] [#1043] Switch to fixed equal spacing with edge-aware label alignment Co-Authored-By: Claude Opus 4.6 (1M context) --- src/components/airdrop/CampaignHero.tsx | 43 +++++++++++++++++-------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/components/airdrop/CampaignHero.tsx b/src/components/airdrop/CampaignHero.tsx index ee1835f..3941b8a 100644 --- a/src/components/airdrop/CampaignHero.tsx +++ b/src/components/airdrop/CampaignHero.tsx @@ -34,13 +34,27 @@ const MILESTONES = [ const MAX_MCAP = 100_000_000; const ACCENT = "#8B4513"; -/** Map MCap to 0–1 using a log scale (base at $100K for visual spread) */ -const LOG_MIN = Math.log10(100_000); -const LOG_MAX = Math.log10(MAX_MCAP); -function logScale(mcap: number): number { +/** Fixed milestone positions at 25/50/75/100% for even visual spacing */ +const MILESTONE_POS = new Map([ + [1_000_000, 0.25], + [10_000_000, 0.50], + [50_000_000, 0.75], + [100_000_000, 1.0], +]); + +/** Map MCap to 0–1 using piecewise linear interpolation between milestones */ +function mcapToX(mcap: number): number { if (mcap <= 0) return 0; - const clamped = Math.min(Math.max(mcap, 100_000), MAX_MCAP); - return (Math.log10(clamped) - LOG_MIN) / (LOG_MAX - LOG_MIN); + if (mcap >= MAX_MCAP) return 1; + const thresholds = [0, 1_000_000, 10_000_000, 50_000_000, 100_000_000]; + const positions = [0, 0.25, 0.50, 0.75, 1.0]; + for (let i = 1; i < thresholds.length; i++) { + if (mcap <= thresholds[i]) { + const t = (mcap - thresholds[i - 1]) / (thresholds[i] - thresholds[i - 1]); + return positions[i - 1] + t * (positions[i] - positions[i - 1]); + } + } + return 1; } /* ─── Helpers ─── */ @@ -84,7 +98,7 @@ function useCountdown(endDateStr: string) { /* ─── MCap Chart ─── */ function MCapChart({ currentFdv }: { currentFdv: number }) { - const progress = logScale(currentFdv); + const progress = mcapToX(currentFdv); const svgW = 600; const svgH = 80; const pad = { left: 10, right: 10 }; @@ -95,13 +109,14 @@ function MCapChart({ currentFdv }: { currentFdv: number }) {
{/* Desktop labels above chart */}
- {MILESTONES.map((ms) => { - const x = logScale(ms.mcap) * 100; + {MILESTONES.map((ms, i) => { + const x = (MILESTONE_POS.get(ms.mcap) ?? 0) * 100; + const isLast = i === MILESTONES.length - 1; return (
{ms.label}
unlocks {ms.pct}%
@@ -150,7 +165,7 @@ function MCapChart({ currentFdv }: { currentFdv: number }) { {/* Milestone vertical dashed lines */} {MILESTONES.map((ms) => { - const mx = pad.left + logScale(ms.mcap) * chartW; + const mx = pad.left + (MILESTONE_POS.get(ms.mcap) ?? 0) * chartW; return ( { - const mx = pad.left + logScale(ms.mcap) * chartW; + const mx = pad.left + (MILESTONE_POS.get(ms.mcap) ?? 0) * chartW; return ( - $100K + $0 $100M