From 97a65fe9496427af8f584c7fb1258fea8066b7ae Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Wed, 1 Apr 2026 16:34:52 +0100 Subject: [PATCH 1/3] =?UTF-8?q?[#728]=20Stories=20+=20Portfolio=20tab=20v5?= =?UTF-8?q?=20=E2=80=94=20polish=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Writer Stats: natural inline "Stories: 1" instead of wide grid gap 2. Storyline title: font-body (Lora), bold, accent color 3. Genre + active: tag badges with bg/border, not plain text 4. Deadline: regular row in stats section, no separate box 5. Royalties: ROYALTIES header, Claimable row + Claim button, Claimed row separate. Truncate to 4 decimals (digits=4) 6. Unified text-xs content font (no text-[11px] or text-[9px]) 7. Portfolio tab: same rules — natural inline labels, genre badges, Lora bold accent titles, unified text-xs Co-Authored-By: Claude Opus 4.6 (1M context) --- src/app/profile/[address]/page.tsx | 255 ++++++++++---------------- src/components/ClaimRoyalties.tsx | 144 +++++++-------- src/components/WriterTradingStats.tsx | 24 +-- 3 files changed, 176 insertions(+), 247 deletions(-) diff --git a/src/app/profile/[address]/page.tsx b/src/app/profile/[address]/page.tsx index 1366e610..64a1b20d 100644 --- a/src/app/profile/[address]/page.tsx +++ b/src/app/profile/[address]/page.tsx @@ -677,51 +677,35 @@ function StoriesTab({ return (
- {/* Writer Stats — structured grid */} + {/* Writer Stats — natural inline */}

Writer Stats

-
- Stories - {storylines.length} -
-
- Plots - {totalPlots} -
-
- Holders - {totalHolders !== undefined ? totalHolders : "—"} -
-
- Views - - {storylines.reduce((sum, s) => sum + (s.view_count ?? 0), 0)} - -
+ Stories: {storylines.length} + Plots: {totalPlots} + Holders: {totalHolders !== undefined ? totalHolders : "—"} + Views: {storylines.reduce((sum, s) => sum + (s.view_count ?? 0), 0)}
-
- Donated - - {totalDonations > BigInt(0) - ? `${formatPrice(formatUnits(totalDonations, 18))} ${RESERVE_LABEL}` - : "—"} +
+
+ Donated:{" "} + + {totalDonations > BigInt(0) ? `${formatPrice(formatUnits(totalDonations, 18))} ${RESERVE_LABEL}` : "—"} + {totalDonations > BigInt(0) && plotUsd != null && ( - ({formatUsdValue(Number(formatUnits(totalDonations, 18)) * plotUsd)}) + ({formatUsdValue(Number(formatUnits(totalDonations, 18)) * plotUsd)}) )} - +
{isOwnProfile && royaltyInfo && ( - <> - Claimable - - {royaltyInfo.unclaimed > BigInt(0) - ? `${formatPrice(formatUnits(royaltyInfo.unclaimed, 18))} ${RESERVE_LABEL}` - : "—"} - {royaltyInfo.unclaimed > BigInt(0) && plotUsd != null && ( - ({formatUsdValue(Number(formatUnits(royaltyInfo.unclaimed, 18)) * plotUsd)}) - )} +
+ Claimable:{" "} + + {royaltyInfo.unclaimed > BigInt(0) ? `${formatPrice(formatUnits(royaltyInfo.unclaimed, 18))} ${RESERVE_LABEL}` : "—"} - + {royaltyInfo.unclaimed > BigInt(0) && plotUsd != null && ( + ({formatUsdValue(Number(formatUnits(royaltyInfo.unclaimed, 18)) * plotUsd)}) + )} +
)}
@@ -830,62 +814,44 @@ function StoryRow({ return (
- {/* Title section */} + {/* Title + badges */}
{storyline.title} -
- {storyline.genre && {storyline.genre}} +
+ {storyline.genre && ( + {storyline.genre} + )} {storyline.sunset ? ( - complete + complete ) : ( - active + active )}
- {/* Stats grid */} + {/* Stats */}
{storyline.token_address && ( )} -
-
- Plots - {storyline.plot_count} -
-
- Holders - {holderCount ?? "—"} -
-
- Views - {formatViewCount(storyline.view_count)} -
-
- Created - - {storyline.block_timestamp - ? new Date(storyline.block_timestamp).toLocaleDateString("en-US", { month: "short", year: "2-digit" }) - : "—"} - -
+
+ Plots: {storyline.plot_count} + Holders: {holderCount ?? "—"} + Views: {formatViewCount(storyline.view_count)} + Created: {storyline.block_timestamp ? new Date(storyline.block_timestamp).toLocaleDateString("en-US", { month: "short", year: "2-digit" }) : "—"}
{storyline.token_address && ( )} -
- - {/* Deadline */} - {!storyline.sunset && storyline.last_plot_time && ( -
+ {!storyline.sunset && storyline.last_plot_time && ( -
- )} + )} +
{/* Genre prompt — own profile */} {isOwnProfile && !storyline.genre && ( @@ -1145,23 +1111,20 @@ function StoryDonationCount({ storylineId, tokenAddress }: { storylineId: number if (!data || data.count === 0) { return ( -
- Donations - +
+ Donations:
); } return ( -
- Donations - - {formatPrice(formatUnits(data.total, 18))} {RESERVE_LABEL} - {plotUsd != null && ( - ({formatUsdValue(Number(formatUnits(data.total, 18)) * plotUsd)}) - )} - ×{data.count} - +
+ Donations:{" "} + {formatPrice(formatUnits(data.total, 18))} {RESERVE_LABEL} + {plotUsd != null && ( + ({formatUsdValue(Number(formatUnits(data.total, 18)) * plotUsd)}) + )} + ×{data.count}
); } @@ -1374,24 +1337,23 @@ function PortfolioTab({ address, isOwnProfile }: { address: string; isOwnProfile {hasHoldings && (

Portfolio

-
- Value - - {formatPrice(formatUnits(totalValue, reserveDecimals))} {RESERVE_LABEL} - {plotUsd && ({formatUsdValue(Number(formatUnits(totalValue, reserveDecimals)) * plotUsd)})} - - Tokens - {holdings!.length} +
+
+ Value:{" "} + {formatPrice(formatUnits(totalValue, reserveDecimals))} {RESERVE_LABEL} + {plotUsd && ({formatUsdValue(Number(formatUnits(totalValue, reserveDecimals)) * plotUsd)})} +
+
Tokens: {holdings!.length}
{bestPick && bestPick.priceChange !== null && ( - <> - Best 24h - +
+ Best 24h:{" "} + {bestPick.storyline.title.slice(0, 20)}{bestPick.storyline.title.length > 20 ? "..." : ""} - = 0 ? "text-accent" : "text-error"}`}> - {bestPick.priceChange >= 0 ? "+" : ""}{bestPick.priceChange.toFixed(1)}% - - + = 0 ? "text-accent" : "text-error"}`}> + {bestPick.priceChange >= 0 ? "+" : ""}{bestPick.priceChange.toFixed(1)}% + +
)}
@@ -1404,52 +1366,41 @@ function PortfolioTab({ address, isOwnProfile }: { address: string; isOwnProfile
{h.storyline.title} {h.storyline.genre && ( - {h.storyline.genre} + {h.storyline.genre} )}
- {/* Stats grid */} -
- Value - - {formatPrice(formatUnits(h.value, h.reserveDecimals))} {RESERVE_LABEL} - {plotUsd && ({formatUsdValue(Number(formatUnits(h.value, h.reserveDecimals)) * plotUsd)})} - - {h.priceChange !== null && ( - <> - Change - = 0 ? "text-accent" : "text-error"}`}> + {/* Stats */} +
+
+ Value:{" "} + {formatPrice(formatUnits(h.value, h.reserveDecimals))} {RESERVE_LABEL} + {plotUsd && ({formatUsdValue(Number(formatUnits(h.value, h.reserveDecimals)) * plotUsd)})} + {h.priceChange !== null && ( + = 0 ? "text-accent" : "text-error"}`}> {h.priceChange >= 0 ? "+" : ""}{h.priceChange.toFixed(1)}% - - )} - Balance - {formatPrice(formatUnits(h.balance, 18))} tokens - Price - - {formatPrice(formatUnits(h.price, 18))} {RESERVE_LABEL} - {plotUsd != null && ({formatUsdValue(Number(formatUnits(h.price, 18)) * plotUsd)})} - + )} +
+
Balance: {formatPrice(formatUnits(h.balance, 18))} tokens
+
+ Price:{" "} + {formatPrice(formatUnits(h.price, 18))} {RESERVE_LABEL} + {plotUsd != null && ({formatUsdValue(Number(formatUnits(h.price, 18)) * plotUsd)})} +
{h.entryPrice !== null && h.entryPrice > 0 && ( - <> - Entry - - {formatPrice(h.entryPrice)} {RESERVE_LABEL} - {plotUsd != null && ({formatUsdValue(h.entryPrice * plotUsd)})} - - +
+ Entry:{" "} + {formatPrice(h.entryPrice)} {RESERVE_LABEL} + {plotUsd != null && ({formatUsdValue(h.entryPrice * plotUsd)})} +
)} {h.lastTraded && ( - <> - Traded - - {new Date(h.lastTraded).toLocaleDateString("en-US", { month: "short", day: "numeric" })} - - +
Traded: {new Date(h.lastTraded).toLocaleDateString("en-US", { month: "short", day: "numeric" })}
)}
@@ -1459,34 +1410,28 @@ function PortfolioTab({ address, isOwnProfile }: { address: string; isOwnProfile {(hasDonationsReceived || (isOwnProfile && hasDonationsGiven)) && (

Donations

-
+
{hasDonationsReceived && ( - <> - Received - - {formatPrice(formatUnits(donationsReceived!.total, 18))} {RESERVE_LABEL} - {plotUsd != null && ({formatUsdValue(Number(formatUnits(donationsReceived!.total, 18)) * plotUsd)})} - - - from {donationsReceived!.count} {donationsReceived!.count === 1 ? "donation" : "donations"} - +
+ Received:{" "} + {formatPrice(formatUnits(donationsReceived!.total, 18))} {RESERVE_LABEL} + {plotUsd != null && ({formatUsdValue(Number(formatUnits(donationsReceived!.total, 18)) * plotUsd)})} + from {donationsReceived!.count} {donationsReceived!.count === 1 ? "donation" : "donations"} +
)} {isOwnProfile && hasDonationsGiven && ( - <> - Given - - {formatPrice(formatUnits(totalDonated, 18))} {RESERVE_LABEL} - {plotUsd != null && totalDonated > BigInt(0) && ({formatUsdValue(Number(formatUnits(totalDonated, 18)) * plotUsd)})} - - - {donationTotalCount} {donationTotalCount === 1 ? "donation" : "donations"} - +
+ Given:{" "} + {formatPrice(formatUnits(totalDonated, 18))} {RESERVE_LABEL} + {plotUsd != null && totalDonated > BigInt(0) && ({formatUsdValue(Number(formatUnits(totalDonated, 18)) * plotUsd)})} + · {donationTotalCount} {donationTotalCount === 1 ? "donation" : "donations"} +
)}
{isOwnProfile && hasDonationsGiven && (
{donationsGiven.map((d) => ( -
+
{/* Row 2: tokens + amount */} -
+
{tokenCount > 0 ? `${formatSupply(tokenCount)} tokens` : ""} {formatPrice(t.reserve_amount)} {RESERVE_LABEL} diff --git a/src/components/ClaimRoyalties.tsx b/src/components/ClaimRoyalties.tsx index 4fe4d8b4..4f551dd4 100644 --- a/src/components/ClaimRoyalties.tsx +++ b/src/components/ClaimRoyalties.tsx @@ -9,7 +9,7 @@ import { mcv2BondAbi, getTokenTVL } from "../../lib/price"; import { MCV2_BOND, RESERVE_LABEL, EXPLORER_URL, PLOT_TOKEN } from "../../lib/contracts/constants"; import { formatUsdValue } from "../../lib/usd-price"; -function formatTruncated(value: bigint, decimals: number, digits = 10): string { +function formatTruncated(value: bigint, decimals: number, digits = 4): string { const raw = formatUnits(value, decimals); const dot = raw.indexOf("."); if (dot === -1 || raw.length - dot - 1 <= digits) return raw; @@ -109,97 +109,89 @@ export function ClaimRoyalties({ tokenAddress, plotCount, beneficiary, plotUsd } }, []); return ( -
-
-
- - Royalties - - {/* Info icon with tooltip */} -
- - {showTooltip && ( -
-

Royalties

-

- You earn a share of every trade on your storyline's token. -

-

To claim:

-
    -
  • - Chain at least 2 plots ({plotCount}/2) {eligible && "\u2713"} -
  • -
  • - Royalties accrue when readers trade your token ({formatTruncated(unclaimed, decimals)} {RESERVE_LABEL}{plotUsd != null ? ` ≈ ${formatUsdValue(parseFloat(formatUnits(unclaimed, decimals)) * plotUsd)}` : ""} unclaimed) -
  • -
-
- )} -
- BigInt(0) ? "text-accent" : "text-foreground"}`}> - {formatTruncated(unclaimed, decimals)} {RESERVE_LABEL} - - {plotUsd != null && ( - - (≈ {formatUsdValue(parseFloat(formatUnits(unclaimed, decimals)) * plotUsd)}) - - )} - {totalClaimed > BigInt(0) && ( - - (claimed: {formatTruncated(totalClaimed, decimals)} {RESERVE_LABEL}{plotUsd != null ? ` ≈ ${formatUsdValue(parseFloat(formatUnits(totalClaimed, decimals)) * plotUsd)}` : ""} so far) - - )} +
+

Royalties

+ {/* Claimable row */} +
+ Claimable:{" "} + BigInt(0) ? "text-accent" : "text-foreground"}`}> + {formatTruncated(unclaimed, decimals)} {RESERVE_LABEL} + + {plotUsd != null && unclaimed > BigInt(0) && ( + ({formatUsdValue(parseFloat(formatUnits(unclaimed, decimals)) * plotUsd)}) + )} +
+ {/* Claim button */} +
+ + {/* Info tooltip */} +
+ {showTooltip && ( +
+

Royalties

+

+ You earn a share of every trade on your storyline's token. +

+

Requires at least 2 plots ({plotCount}/2){eligible && " \u2713"}

+
+ )}
+ {/* Claimed row */} + {totalClaimed > BigInt(0) && ( +
+ Claimed:{" "} + + {formatTruncated(totalClaimed, decimals)} {RESERVE_LABEL} + + {plotUsd != null && ( + ({formatUsdValue(parseFloat(formatUnits(totalClaimed, decimals)) * plotUsd)}) + )} +
+ )} {!eligible && txState === "idle" && ( -

- Chain at least 2 plots to enable royalty claims ({plotCount}/2) +

+ Chain at least 2 plots to enable claims ({plotCount}/2)

)} {eligible && unclaimed === BigInt(0) && txState === "idle" && totalClaimed === BigInt(0) && ( -

- No royalties yet — royalties accrue when readers trade your token +

+ No royalties yet — accrue when readers trade your token

)} {txHash && txState === "done" && ( -

- Claimed {formatTruncated(claimedAmount, decimals)} {RESERVE_LABEL}{plotUsd != null ? ` (≈ ${formatUsdValue(parseFloat(formatUnits(claimedAmount, decimals)) * plotUsd)})` : ""} —{" "} - tx:{" "} - +

+ Claimed {formatTruncated(claimedAmount, decimals)} {RESERVE_LABEL} —{" "} + {txHash.slice(0, 10)}...{txHash.slice(-8)}

)} - {error &&

{error}

} + {error &&

{error}

}
); } diff --git a/src/components/WriterTradingStats.tsx b/src/components/WriterTradingStats.tsx index 09cba282..8e105692 100644 --- a/src/components/WriterTradingStats.tsx +++ b/src/components/WriterTradingStats.tsx @@ -44,23 +44,15 @@ export function WriterTradingStats({ storyline, plotUsd }: WriterTradingStatsPro return (
-
- Price - - {data ? `${formatPrice(data.price)} ${RESERVE_LABEL}` : "—"} - {data && plotUsd && ( - ({formatUsdValue(parseFloat(data.price) * plotUsd)}) - )} - +
+ Price:{" "} + {data ? `${formatPrice(data.price)} ${RESERVE_LABEL}` : "—"} + {data && plotUsd && ({formatUsdValue(parseFloat(data.price) * plotUsd)})}
-
- TVL - - {data ? `${formatPrice(data.tvl)} ${RESERVE_LABEL}` : "—"} - {data && plotUsd && ( - ({formatUsdValue(parseFloat(data.tvl) * plotUsd)}) - )} - +
+ TVL:{" "} + {data ? `${formatPrice(data.tvl)} ${RESERVE_LABEL}` : "—"} + {data && plotUsd && ({formatUsdValue(parseFloat(data.tvl) * plotUsd)})}
); From d8acb3381f645d50198cefeb64e055afdf0c6d3b Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Wed, 1 Apr 2026 16:41:05 +0100 Subject: [PATCH 2/3] [#728] Fix T2a review: deadline as plain row, claim right-aligned, text-xs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. DeadlineCountdown: removed bordered box, now plain "Deadline: Xd Xh" 2. ClaimRoyalties: Claim button row right-aligned (justify-end) 3. Donation history: text-[10px] → text-xs for content rows + load more Co-Authored-By: Claude Opus 4.6 (1M context) --- src/app/profile/[address]/page.tsx | 4 ++-- src/components/ClaimRoyalties.tsx | 2 +- src/components/DeadlineCountdown.tsx | 13 +++++++------ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/app/profile/[address]/page.tsx b/src/app/profile/[address]/page.tsx index 64a1b20d..d03f2308 100644 --- a/src/app/profile/[address]/page.tsx +++ b/src/app/profile/[address]/page.tsx @@ -1034,7 +1034,7 @@ function ProfileDonationHistory({ storylineId }: { storylineId: number }) { {donations.map((d) => (
{/* Claim button */} -
+
@@ -1565,7 +1565,7 @@ function PortfolioTradingHistory({ address, plotUsd }: { address: string; plotUs
{/* Row 3: date + tx link */} -
+
{t.block_timestamp && (
)} {!eligible && txState === "idle" && ( -

+

Chain at least 2 plots to enable claims ({plotCount}/2)

)} {eligible && unclaimed === BigInt(0) && txState === "idle" && totalClaimed === BigInt(0) && ( -

+

No royalties yet — accrue when readers trade your token

)} {txHash && txState === "done" && ( -

+

Claimed {formatTruncated(claimedAmount, decimals)} {RESERVE_LABEL} —{" "} {txHash.slice(0, 10)}...{txHash.slice(-8)}

)} - {error &&

{error}

} + {error &&

{error}

}
); }