feat(market): render listing imageUrl on contract card

The buzz-market/v0 listing gains an optional imageUrl. The channel
projection carries it into the scenario, and MarketContractCard renders
it in the left media square (relay URLs proxied via rewriteRelayUrl),
falling back to the existing placeholder icon.

Full desktop suite: 5,833 pass.

Signed-off-by: Moneypennie <62d0caca1ee9c3ce3a753262374b3b794f0e1196cfa8b1294b0affbc90130307@buzz.block.builderlab.xyz>
This commit is contained in:
Moneypennie
2026-09-01 18:57:00 -04:00
committed by Wintermute
parent 88461dde46
commit b8339ca0ef
3 changed files with 15 additions and 2 deletions

View File

@@ -36,6 +36,7 @@ const AnnouncementEnvelope = BaseEnvelope.extend({
closesAt: PositiveInteger.optional(),
deliveryMinutes: PositiveInteger.optional(),
minimumDecrementSats: PositiveInteger.optional(),
imageUrl: z.string().url().max(500).optional(),
}),
});
@@ -522,6 +523,7 @@ export function projectMarketChannel(
eyebrow: `${listing.listing.direction === "offer" ? "Offer" : "Request"} · ${listing.listing.mechanism.replace("-", " ")} · ${quantity === "unlimited" ? "unlimited" : "finite"}`,
title: listing.listing.title,
summary: listing.listing.summary,
imageUrl: listing.listing.imageUrl,
direction:
listing.listing.direction === "offer"
? `Buyer pays ${listingPrice(listing.listing)} · Seller delivers`

View File

@@ -26,6 +26,7 @@ export type MarketScenario = {
direction: string;
eyebrow: string;
id: MarketScenarioId;
imageUrl?: string;
liveMetrics: MarketTerm[];
mode: string;
primaryAction: string;

View File

@@ -1,6 +1,7 @@
import { Bot, PackageCheck, Radio, Store } from "lucide-react";
import type { MarketScenario } from "@/features/market/lib/marketPrototypeData";
import { rewriteRelayUrl } from "@/shared/lib/mediaUrl";
import { Badge } from "@/shared/ui/badge";
const COMMERCIAL_TERM_LABELS = new Set(["Price", "Reward", "Initial quantity"]);
@@ -20,8 +21,17 @@ export function MarketContractCard({ scenario }: { scenario: MarketScenario }) {
data-testid="market-contract-card"
>
<div className="grid sm:grid-cols-[11rem_minmax(0,1fr)]">
<div className="flex aspect-square items-center justify-center border-b bg-muted/60 text-muted-foreground sm:border-b-0 sm:border-r">
<PackageCheck className="h-8 w-8" strokeWidth={1.5} />
<div className="flex aspect-square items-center justify-center overflow-hidden border-b bg-muted/60 text-muted-foreground sm:border-b-0 sm:border-r">
{scenario.imageUrl ? (
<img
alt={scenario.title}
className="h-full w-full object-cover"
data-testid="market-contract-image"
src={rewriteRelayUrl(scenario.imageUrl)}
/>
) : (
<PackageCheck className="h-8 w-8" strokeWidth={1.5} />
)}
</div>
<div className="min-w-0 p-5">
<div className="flex flex-wrap items-center gap-2">