From 9521ad329434f965c8e849293a57bc944434b4d1 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Wed, 25 Mar 2026 10:01:56 +0000 Subject: [PATCH 1/2] =?UTF-8?q?[#530]=20Fix=20OG=20image=20=E2=80=94=20mat?= =?UTF-8?q?ch=20home=20page=20moleskine=20layout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Redesign to single centered moleskine card (was notebook left + metadata right) - Top-left inside: genre tag - Center inside: story title - Bottom inside: plot count + TVL with USD value - Below moleskine: author name + plotlink.xyz branding - Bump version to 0.1.8 Fixes #530 Co-Authored-By: Claude Opus 4.6 (1M context) --- package.json | 2 +- src/app/story/[storylineId]/og/route.tsx | 210 ++++++++--------------- 2 files changed, 68 insertions(+), 144 deletions(-) diff --git a/package.json b/package.json index 367cedef..08b5fa60 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plotlink", - "version": "0.1.7", + "version": "0.1.8", "private": true, "workspaces": [ "packages/*" diff --git a/src/app/story/[storylineId]/og/route.tsx b/src/app/story/[storylineId]/og/route.tsx index 1bef4a54..b174e82a 100644 --- a/src/app/story/[storylineId]/og/route.tsx +++ b/src/app/story/[storylineId]/og/route.tsx @@ -1,18 +1,17 @@ import { ImageResponse } from "next/og"; import { type Address } from "viem"; import { createServerClient, type Storyline } from "../../../../../lib/supabase"; -import { getTokenPrice } from "../../../../../lib/price"; +import { getTokenTVL } from "../../../../../lib/price"; import { lookupByAddress } from "../../../../../lib/farcaster"; import { RESERVE_LABEL, STORY_FACTORY } from "../../../../../lib/contracts/constants"; import { formatPrice } from "../../../../../lib/format"; import { truncateAddress } from "../../../../../lib/utils"; +import { getPlotUsdPrice, formatUsdValue } from "../../../../../lib/usd-price"; export const runtime = "edge"; async function loadFont(): Promise { try { - // Fetch with no User-Agent → Google returns TTF (truetype) format - // ImageResponse supports ttf/otf/woff but NOT woff2 const res = await fetch( "https://fonts.googleapis.com/css2?family=Lora:wght@700&display=swap", ); @@ -58,22 +57,30 @@ export async function GET( const sl = storyline as Storyline; - const [priceInfo, farcasterProfile, fontData] = await Promise.all([ - sl.token_address ? getTokenPrice(sl.token_address as Address) : null, + const [tvlInfo, plotUsd, farcasterProfile, fontData] = await Promise.all([ + sl.token_address ? getTokenTVL(sl.token_address as Address) : null, + getPlotUsdPrice(), lookupByAddress(sl.writer_address).catch(() => null), loadFont(), ]); const reserveLabel = RESERVE_LABEL; - const priceDisplay = priceInfo - ? `${formatPrice(priceInfo.pricePerToken)} ${reserveLabel}` - : null; const authorName = farcasterProfile ? `@${farcasterProfile.username}` : truncateAddress(sl.writer_address); - const plotLabel = sl.plot_count === 1 ? "plot" : "plots"; + const plotLabel = `${sl.plot_count} ${sl.plot_count === 1 ? "plot" : "plots"}`; const titleDisplay = - sl.title.length > 60 ? `${sl.title.slice(0, 57)}...` : sl.title; + sl.title.length > 50 ? `${sl.title.slice(0, 47)}...` : sl.title; + + // TVL display with USD + let tvlDisplay: string | null = null; + if (tvlInfo) { + const tvlNum = parseFloat(tvlInfo.tvl); + tvlDisplay = `TVL: ${formatPrice(tvlInfo.tvl)} ${reserveLabel}`; + if (plotUsd && tvlNum > 0) { + tvlDisplay += ` (${formatUsdValue(tvlNum * plotUsd)})`; + } + } const fonts = fontData ? [{ name: "Lora", data: fontData, weight: 700 as const }] @@ -86,18 +93,18 @@ export async function GET( width: "100%", height: "100%", display: "flex", + flexDirection: "column", alignItems: "center", justifyContent: "center", backgroundColor: "#DDD3C2", - padding: "40px 60px", fontFamily: fontData ? "Lora" : "Georgia, serif", }} > - {/* Left: Moleskine notebook cover */} + {/* Centered moleskine card */}
{/* Elastic band */} @@ -116,7 +122,7 @@ export async function GET( position: "absolute", top: "-1px", bottom: "-1px", - right: "22px", + right: "28px", width: "8px", borderRadius: "2px", background: "rgba(139, 69, 19, 0.18)", @@ -124,33 +130,35 @@ export async function GET( }} /> - {/* Ruled lines background */} + {/* Top-left: genre tag */}
- {Array.from({ length: 18 }).map((_, i) => ( + {sl.genre ? (
- ))} + > + {sl.genre} +
+ ) : ( +
+ )}
- {/* Content inside notebook: title + author */} + {/* Center: title */}
35 ? "32px" : "38px", + fontSize: titleDisplay.length > 30 ? "32px" : "38px", fontWeight: 700, color: "#8B4513", lineHeight: 1.25, display: "flex", textAlign: "center", justifyContent: "center", - maxWidth: "290px", + maxWidth: "380px", }} > {titleDisplay}
-
- by {authorName} -
-
-
- - {/* Right: Metadata on dark background */} -
- {/* Top: PlotLink branding */} -
-
- PlotLink -
-
- Tokenised collaborative fiction -
- {/* Middle: genre + stats */} + {/* Bottom: plot count + TVL */}
- {sl.genre ? ( -
- {sl.genre} +
{plotLabel}
+ {tvlDisplay && ( +
+ {tvlDisplay}
- ) : ( -
)} -
- - {sl.plot_count} {plotLabel} - - {priceDisplay && ( - - {priceDisplay} - - )} -
+
- {/* Bottom: domain */} -
- plotlink.xyz -
+ {/* Below moleskine: author + branding */} +
+
by {authorName}
+
plotlink.xyz
), From 11e82fdb85c07bb7f138411e474a012803b52db9 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Wed, 25 Mar 2026 10:07:35 +0000 Subject: [PATCH 2/2] [#530] Fix: use 2:3 portrait aspect ratio to match home page StoryCard Changed OG moleskine from 440x440 square to 360x540 (2:3 aspect-ratio). Co-Authored-By: Claude Opus 4.6 (1M context) --- src/app/story/[storylineId]/og/route.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/story/[storylineId]/og/route.tsx b/src/app/story/[storylineId]/og/route.tsx index b174e82a..c5fdfe3b 100644 --- a/src/app/story/[storylineId]/og/route.tsx +++ b/src/app/story/[storylineId]/og/route.tsx @@ -103,8 +103,8 @@ export async function GET( {/* Centered moleskine card */}