@medialane/ui 0.128.6 → 0.129.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -38,20 +38,29 @@ var import_link = __toESM(require("./link.js"), 1);
38
38
  var import_lucide_react = require("lucide-react");
39
39
  var import_address_display = require("./address-display.js");
40
40
  var import_currency_icon = require("./currency-icon.js");
41
+ var import_level_badge = require("./rewards/level-badge.js");
41
42
  var import_activity = require("../data/activity.js");
42
43
  var import_ipfs = require("../utils/ipfs.js");
43
44
  var import_time = require("../utils/time.js");
44
45
  var import_format = require("../utils/format.js");
45
46
  var import_cn = require("../utils/cn.js");
47
+ const ACTIVITY_MESSAGES = {
48
+ mint: "Newly minted",
49
+ listing: "Listed for sale",
50
+ sale: "Purchased",
51
+ offer: "Offer placed",
52
+ transfer: "Transferred",
53
+ cancelled: "Listing cancelled"
54
+ };
46
55
  function ActivityRow({
47
56
  activity,
48
- token,
49
57
  showActor = true,
50
58
  showExplorer = true,
51
59
  compact = false,
60
+ actorLevel,
52
61
  explorerUrl = "https://voyager.online",
53
- getAssetHref = (c, t) => `/asset/${c}/${t}`,
54
- getActorHref = (a) => `/creator/${a}`
62
+ getAssetHref = (contract, tokenId) => `/asset/STARKNET/${contract}/${tokenId}`,
63
+ getActorHref = (address) => `/creator/${address}`
55
64
  }) {
56
65
  const config = import_activity.ACTIVITY_TYPE_CONFIG[activity.type] ?? {
57
66
  label: activity.type,
@@ -65,28 +74,133 @@ function ActivityRow({
65
74
  const tokenId = activity.nftTokenId ?? activity.tokenId ?? null;
66
75
  const actor = activity.offerer ?? activity.fulfiller ?? (activity.type === "mint" ? activity.to : activity.from) ?? null;
67
76
  const txLink = activity.txHash ? `${explorerUrl}/tx/${activity.txHash}` : null;
68
- const tokenName = token?.name ?? (tokenId ? `#${tokenId}` : "\u2014");
69
- const tokenImage = token?.image ? (0, import_ipfs.ipfsToHttp)(token.image) : null;
70
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_cn.cn)("flex items-center gap-3 hover:bg-muted/30 transition-colors group", compact ? "pl-4 pr-5 py-2.5" : "pl-4 pr-5 py-3.5"), children: [
71
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_cn.cn)("rounded-lg flex items-center justify-center shrink-0", config.bgClass, compact ? "h-7 w-7" : "h-8 w-8"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { className: (0, import_cn.cn)("shrink-0", config.colorClass, compact ? "h-3.5 w-3.5" : "h-4 w-4") }) }),
72
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_cn.cn)("rounded-md overflow-hidden shrink-0 bg-muted", compact ? "h-7 w-7" : "h-9 w-9"), children: tokenImage ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_image.default, { src: tokenImage, alt: tokenName, width: compact ? 28 : 36, height: compact ? 28 : 36, className: "object-cover w-full h-full", unoptimized: true }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-full h-full bg-gradient-to-br from-muted-foreground/10 to-muted-foreground/5" }) }),
73
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-0", children: [
74
- contract && tokenId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_link.default, { href: getAssetHref(contract, tokenId), className: "text-sm font-semibold hover:text-primary transition-colors truncate block leading-tight", children: tokenName }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-semibold text-muted-foreground", children: "\u2014" }),
75
- showActor && actor && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_link.default, { href: getActorHref(actor), className: "text-xs text-muted-foreground hover:text-primary transition-colors font-mono leading-tight", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_address_display.AddressDisplay, { address: actor, chars: 4, showCopy: false }) })
76
- ] }),
77
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2.5 shrink-0", children: [
78
- !compact && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: (0, import_cn.cn)("text-2xs font-medium px-1.5 py-0.5 rounded hidden sm:inline-flex", config.bgClass, config.colorClass), children: config.label }),
79
- activity.price?.formatted && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "text-right", children: [
80
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-bold tabular-nums leading-tight", children: (0, import_format.formatDisplayPrice)(activity.price.formatted) }),
81
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-2xs text-muted-foreground leading-tight flex items-center justify-end gap-0.5", children: [
82
- activity.price.currency && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: activity.price.currency, size: 10 }),
83
- activity.price.currency
77
+ const tokenName = activity.token?.name ?? (tokenId ? `#${tokenId}` : "\u2014");
78
+ const rawImage = activity.token?.image ?? null;
79
+ const tokenImage = rawImage ? (0, import_ipfs.ipfsToHttp)(rawImage) : null;
80
+ const is1155 = activity.tokenStandard === "ERC1155" || (activity.type === "mint" || activity.type === "transfer") && Number(activity.amount ?? "1") > 1;
81
+ const amount = activity.amount && Number(activity.amount) > 1 ? activity.amount : null;
82
+ const message = ACTIVITY_MESSAGES[activity.type] ?? config.label;
83
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
84
+ "div",
85
+ {
86
+ className: (0, import_cn.cn)(
87
+ "flex items-center gap-3 hover:bg-muted/30 transition-colors group",
88
+ compact ? "pl-4 pr-5 py-2.5" : "pl-4 pr-5 py-3.5"
89
+ ),
90
+ children: [
91
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
92
+ "div",
93
+ {
94
+ className: (0, import_cn.cn)(
95
+ "rounded-lg flex items-center justify-center shrink-0",
96
+ config.bgClass,
97
+ compact ? "h-7 w-7" : "h-8 w-8"
98
+ ),
99
+ title: config.label,
100
+ "aria-label": config.label,
101
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
102
+ Icon,
103
+ {
104
+ className: (0, import_cn.cn)("shrink-0", config.colorClass, compact ? "h-3.5 w-3.5" : "h-4 w-4"),
105
+ "aria-hidden": true
106
+ }
107
+ )
108
+ }
109
+ ),
110
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
111
+ "div",
112
+ {
113
+ className: (0, import_cn.cn)(
114
+ "rounded-md overflow-hidden shrink-0 bg-muted relative",
115
+ compact ? "h-7 w-7" : "h-9 w-9"
116
+ ),
117
+ children: [
118
+ tokenImage ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
119
+ import_image.default,
120
+ {
121
+ src: tokenImage,
122
+ alt: tokenName,
123
+ width: compact ? 28 : 36,
124
+ height: compact ? 28 : 36,
125
+ className: "object-cover w-full h-full",
126
+ unoptimized: true
127
+ }
128
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-full h-full bg-gradient-to-br from-brand-purple/15 to-brand-blue/15", "aria-hidden": true }),
129
+ is1155 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "absolute -bottom-1 -right-1 text-[8px] font-bold bg-brand-purple text-white rounded px-0.5 leading-tight", children: "1155" })
130
+ ]
131
+ }
132
+ ),
133
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-0", children: [
134
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1.5 leading-tight", children: [
135
+ contract && tokenId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
136
+ import_link.default,
137
+ {
138
+ href: getAssetHref(contract, tokenId),
139
+ className: "text-sm font-semibold hover:text-primary transition-colors truncate block",
140
+ children: tokenName
141
+ }
142
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-semibold text-muted-foreground", children: "\u2014" }),
143
+ amount && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "text-[10px] font-medium text-brand-purple shrink-0", children: [
144
+ "\xD7",
145
+ amount
146
+ ] })
147
+ ] }),
148
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-xs text-muted-foreground leading-tight truncate mt-0.5 flex items-center gap-1", children: [
149
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate", children: message }),
150
+ showActor && actor && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
151
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
152
+ import_link.default,
153
+ {
154
+ href: getActorHref(actor),
155
+ className: "hover:text-primary transition-colors tabular-nums shrink-0",
156
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_address_display.AddressDisplay, { address: actor, chars: 4, showCopy: false })
157
+ }
158
+ ),
159
+ actorLevel && actorLevel.totalXp > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
160
+ import_level_badge.LevelBadge,
161
+ {
162
+ level: actorLevel.currentLevel,
163
+ name: actorLevel.currentLevelName,
164
+ badgeColor: actorLevel.badgeColor,
165
+ size: "sm",
166
+ className: "shrink-0"
167
+ }
168
+ )
169
+ ] })
170
+ ] })
171
+ ] }),
172
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2.5 shrink-0", children: [
173
+ activity.price?.formatted && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "text-right", children: [
174
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-bold tabular-nums leading-tight", children: (0, import_format.formatDisplayPrice)(activity.price.formatted) }),
175
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-[10px] text-muted-foreground leading-tight flex items-center justify-end gap-0.5", children: [
176
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: activity.price.currency, size: 10, "aria-hidden": true }),
177
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only", children: activity.price.currency })
178
+ ] })
179
+ ] }),
180
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
181
+ "span",
182
+ {
183
+ className: "text-[10px] text-muted-foreground tabular-nums hidden sm:block w-12 text-right",
184
+ title: new Date(activity.timestamp).toLocaleString(),
185
+ children: (0, import_time.timeAgo)(activity.timestamp)
186
+ }
187
+ ),
188
+ showExplorer && txLink && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
189
+ "a",
190
+ {
191
+ href: txLink,
192
+ target: "_blank",
193
+ rel: "noopener noreferrer",
194
+ className: "inline-flex items-center justify-center h-6 w-6 rounded-md hover:bg-muted transition-colors opacity-50 sm:opacity-0 sm:group-hover:opacity-100 shrink-0",
195
+ "aria-label": "View transaction on Voyager",
196
+ title: "View on Voyager",
197
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ExternalLink, { className: "h-3 w-3 text-muted-foreground", "aria-hidden": true })
198
+ }
199
+ )
84
200
  ] })
85
- ] }),
86
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-2xs text-muted-foreground tabular-nums hidden sm:block w-12 text-right", title: new Date(activity.timestamp).toLocaleString(), children: (0, import_time.timeAgo)(activity.timestamp) }),
87
- showExplorer && txLink && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: txLink, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center justify-center h-6 w-6 rounded-md hover:bg-muted transition-colors opacity-50 sm:opacity-0 sm:group-hover:opacity-100 shrink-0", "aria-label": "View on explorer", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ExternalLink, { className: "h-3 w-3 text-muted-foreground" }) })
88
- ] })
89
- ] });
201
+ ]
202
+ }
203
+ );
90
204
  }
91
205
  // Annotate the CommonJS export names for ESM import in node:
92
206
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/activity-row.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"./image.js\";\nimport Link from \"./link.js\";\nimport { ExternalLink } from \"lucide-react\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { ACTIVITY_TYPE_CONFIG } from \"../data/activity.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiActivity } from \"@medialane/sdk\";\n\nexport interface ActivityRowProps {\n activity: ApiActivity;\n\n token?: { name?: string; image?: string };\n showActor?: boolean;\n showExplorer?: boolean;\n compact?: boolean;\n explorerUrl?: string;\n getAssetHref?: (contract: string, tokenId: string) => string;\n getActorHref?: (address: string) => string;\n}\n\nexport function ActivityRow({\n activity,\n token,\n showActor = true,\n showExplorer = true,\n compact = false,\n explorerUrl = \"https://voyager.online\",\n getAssetHref = (c, t) => `/asset/${c}/${t}`,\n getActorHref = (a) => `/creator/${a}`,\n}: ActivityRowProps) {\n const config = ACTIVITY_TYPE_CONFIG[activity.type] ?? {\n label: activity.type,\n variant: \"outline\" as const,\n icon: ExternalLink,\n colorClass: \"text-muted-foreground\",\n bgClass: \"bg-muted\",\n };\n const Icon = config.icon;\n\n const contract = activity.nftContract ?? activity.contractAddress ?? null;\n const tokenId = activity.nftTokenId ?? activity.tokenId ?? null;\n const actor =\n activity.offerer ??\n activity.fulfiller ??\n ((activity.type as string) === \"mint\" ? activity.to : activity.from) ??\n null;\n const txLink = activity.txHash ? `${explorerUrl}/tx/${activity.txHash}` : null;\n\n const tokenName = token?.name ?? (tokenId ? `#${tokenId}` : \"—\");\n const tokenImage = token?.image ? ipfsToHttp(token.image) : null;\n\n return (\n <div className={cn(\"flex items-center gap-3 hover:bg-muted/30 transition-colors group\", compact ? \"pl-4 pr-5 py-2.5\" : \"pl-4 pr-5 py-3.5\")}>\n\n <div className={cn(\"rounded-lg flex items-center justify-center shrink-0\", config.bgClass, compact ? \"h-7 w-7\" : \"h-8 w-8\")}>\n <Icon className={cn(\"shrink-0\", config.colorClass, compact ? \"h-3.5 w-3.5\" : \"h-4 w-4\")} />\n </div>\n\n <div className={cn(\"rounded-md overflow-hidden shrink-0 bg-muted\", compact ? \"h-7 w-7\" : \"h-9 w-9\")}>\n {tokenImage ? (\n <Image src={tokenImage} alt={tokenName} width={compact ? 28 : 36} height={compact ? 28 : 36} className=\"object-cover w-full h-full\" unoptimized />\n ) : (\n <div className=\"w-full h-full bg-gradient-to-br from-muted-foreground/10 to-muted-foreground/5\" />\n )}\n </div>\n\n <div className=\"flex-1 min-w-0\">\n {contract && tokenId ? (\n <Link href={getAssetHref(contract, tokenId)} className=\"text-sm font-semibold hover:text-primary transition-colors truncate block leading-tight\">\n {tokenName}\n </Link>\n ) : (\n <span className=\"text-sm font-semibold text-muted-foreground\">—</span>\n )}\n {showActor && actor && (\n <Link href={getActorHref(actor)} className=\"text-xs text-muted-foreground hover:text-primary transition-colors font-mono leading-tight\">\n <AddressDisplay address={actor} chars={4} showCopy={false} />\n </Link>\n )}\n </div>\n\n <div className=\"flex items-center gap-2.5 shrink-0\">\n {!compact && (\n <span className={cn(\"text-2xs font-medium px-1.5 py-0.5 rounded hidden sm:inline-flex\", config.bgClass, config.colorClass)}>\n {config.label}\n </span>\n )}\n\n {activity.price?.formatted && (\n <div className=\"text-right\">\n <p className=\"text-sm font-bold tabular-nums leading-tight\">{formatDisplayPrice(activity.price.formatted)}</p>\n <p className=\"text-2xs text-muted-foreground leading-tight flex items-center justify-end gap-0.5\">\n {activity.price.currency && <CurrencyIcon symbol={activity.price.currency} size={10} />}\n {activity.price.currency}\n </p>\n </div>\n )}\n\n <span className=\"text-2xs text-muted-foreground tabular-nums hidden sm:block w-12 text-right\" title={new Date(activity.timestamp).toLocaleString()}>\n {timeAgo(activity.timestamp)}\n </span>\n\n {showExplorer && txLink && (\n <a href={txLink} target=\"_blank\" rel=\"noopener noreferrer\" className=\"inline-flex items-center justify-center h-6 w-6 rounded-md hover:bg-muted transition-colors opacity-50 sm:opacity-0 sm:group-hover:opacity-100 shrink-0\" aria-label=\"View on explorer\">\n <ExternalLink className=\"h-3 w-3 text-muted-foreground\" />\n </a>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA6DQ;AA3DR,mBAAkB;AAClB,kBAAiB;AACjB,0BAA6B;AAC7B,6BAA+B;AAC/B,2BAA6B;AAC7B,sBAAqC;AACrC,kBAA2B;AAC3B,kBAAwB;AACxB,oBAAmC;AACnC,gBAAmB;AAeZ,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,UAAU;AAAA,EACV,cAAc;AAAA,EACd,eAAe,CAAC,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC;AAAA,EACzC,eAAe,CAAC,MAAM,YAAY,CAAC;AACrC,GAAqB;AACnB,QAAM,SAAS,qCAAqB,SAAS,IAAI,KAAK;AAAA,IACpD,OAAO,SAAS;AAAA,IAChB,SAAS;AAAA,IACT,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,SAAS;AAAA,EACX;AACA,QAAM,OAAO,OAAO;AAEpB,QAAM,WAAW,SAAS,eAAe,SAAS,mBAAmB;AACrE,QAAM,UAAU,SAAS,cAAc,SAAS,WAAW;AAC3D,QAAM,QACJ,SAAS,WACT,SAAS,cACP,SAAS,SAAoB,SAAS,SAAS,KAAK,SAAS,SAC/D;AACF,QAAM,SAAS,SAAS,SAAS,GAAG,WAAW,OAAO,SAAS,MAAM,KAAK;AAE1E,QAAM,YAAY,OAAO,SAAS,UAAU,IAAI,OAAO,KAAK;AAC5D,QAAM,aAAa,OAAO,YAAQ,wBAAW,MAAM,KAAK,IAAI;AAE5D,SACE,6CAAC,SAAI,eAAW,cAAG,qEAAqE,UAAU,qBAAqB,kBAAkB,GAEvI;AAAA,gDAAC,SAAI,eAAW,cAAG,wDAAwD,OAAO,SAAS,UAAU,YAAY,SAAS,GACxH,sDAAC,QAAK,eAAW,cAAG,YAAY,OAAO,YAAY,UAAU,gBAAgB,SAAS,GAAG,GAC3F;AAAA,IAEA,4CAAC,SAAI,eAAW,cAAG,gDAAgD,UAAU,YAAY,SAAS,GAC/F,uBACC,4CAAC,aAAAA,SAAA,EAAM,KAAK,YAAY,KAAK,WAAW,OAAO,UAAU,KAAK,IAAI,QAAQ,UAAU,KAAK,IAAI,WAAU,8BAA6B,aAAW,MAAC,IAEhJ,4CAAC,SAAI,WAAU,kFAAiF,GAEpG;AAAA,IAEA,6CAAC,SAAI,WAAU,kBACZ;AAAA,kBAAY,UACX,4CAAC,YAAAC,SAAA,EAAK,MAAM,aAAa,UAAU,OAAO,GAAG,WAAU,2FACpD,qBACH,IAEA,4CAAC,UAAK,WAAU,+CAA8C,oBAAC;AAAA,MAEhE,aAAa,SACZ,4CAAC,YAAAA,SAAA,EAAK,MAAM,aAAa,KAAK,GAAG,WAAU,8FACzC,sDAAC,yCAAe,SAAS,OAAO,OAAO,GAAG,UAAU,OAAO,GAC7D;AAAA,OAEJ;AAAA,IAEA,6CAAC,SAAI,WAAU,sCACZ;AAAA,OAAC,WACA,4CAAC,UAAK,eAAW,cAAG,oEAAoE,OAAO,SAAS,OAAO,UAAU,GACtH,iBAAO,OACV;AAAA,MAGD,SAAS,OAAO,aACf,6CAAC,SAAI,WAAU,cACb;AAAA,oDAAC,OAAE,WAAU,gDAAgD,gDAAmB,SAAS,MAAM,SAAS,GAAE;AAAA,QAC1G,6CAAC,OAAE,WAAU,sFACV;AAAA,mBAAS,MAAM,YAAY,4CAAC,qCAAa,QAAQ,SAAS,MAAM,UAAU,MAAM,IAAI;AAAA,UACpF,SAAS,MAAM;AAAA,WAClB;AAAA,SACF;AAAA,MAGF,4CAAC,UAAK,WAAU,+EAA8E,OAAO,IAAI,KAAK,SAAS,SAAS,EAAE,eAAe,GAC9I,mCAAQ,SAAS,SAAS,GAC7B;AAAA,MAEC,gBAAgB,UACf,4CAAC,OAAE,MAAM,QAAQ,QAAO,UAAS,KAAI,uBAAsB,WAAU,2JAA0J,cAAW,oBACxO,sDAAC,oCAAa,WAAU,iCAAgC,GAC1D;AAAA,OAEJ;AAAA,KACF;AAEJ;","names":["Image","Link"]}
1
+ {"version":3,"sources":["../../src/components/activity-row.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"./image.js\";\nimport Link from \"./link.js\";\nimport { ExternalLink } from \"lucide-react\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { LevelBadge } from \"./rewards/level-badge.js\";\nimport { ACTIVITY_TYPE_CONFIG } from \"../data/activity.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiActivity, ApiRewardsBatchEntry } from \"@medialane/sdk\";\n\nconst ACTIVITY_MESSAGES: Record<string, string> = {\n mint: \"Newly minted\",\n listing: \"Listed for sale\",\n sale: \"Purchased\",\n offer: \"Offer placed\",\n transfer: \"Transferred\",\n cancelled: \"Listing cancelled\",\n};\n\nexport interface ActivityRowProps {\n activity: ApiActivity;\n showActor?: boolean;\n showExplorer?: boolean;\n compact?: boolean;\n actorLevel?: ApiRewardsBatchEntry;\n explorerUrl?: string;\n getAssetHref?: (contract: string, tokenId: string) => string;\n getActorHref?: (address: string) => string;\n}\n\nexport function ActivityRow({\n activity,\n showActor = true,\n showExplorer = true,\n compact = false,\n actorLevel,\n explorerUrl = \"https://voyager.online\",\n getAssetHref = (contract, tokenId) => `/asset/STARKNET/${contract}/${tokenId}`,\n getActorHref = (address) => `/creator/${address}`,\n}: ActivityRowProps) {\n const config = ACTIVITY_TYPE_CONFIG[activity.type] ?? {\n label: activity.type,\n variant: \"outline\" as const,\n icon: ExternalLink,\n colorClass: \"text-muted-foreground\",\n bgClass: \"bg-muted\",\n };\n const Icon = config.icon;\n\n const contract = activity.nftContract ?? activity.contractAddress ?? null;\n const tokenId = activity.nftTokenId ?? activity.tokenId ?? null;\n const actor =\n activity.offerer ??\n activity.fulfiller ??\n (activity.type === \"mint\" ? activity.to : activity.from) ??\n null;\n const txLink = activity.txHash ? `${explorerUrl}/tx/${activity.txHash}` : null;\n\n const tokenName = activity.token?.name ?? (tokenId ? `#${tokenId}` : \"—\");\n const rawImage = activity.token?.image ?? null;\n const tokenImage = rawImage ? ipfsToHttp(rawImage) : null;\n\n const is1155 = activity.tokenStandard === \"ERC1155\" ||\n (activity.type === \"mint\" || activity.type === \"transfer\") && Number(activity.amount ?? \"1\") > 1;\n const amount = activity.amount && Number(activity.amount) > 1 ? activity.amount : null;\n\n const message = ACTIVITY_MESSAGES[activity.type] ?? config.label;\n\n return (\n <div\n className={cn(\n \"flex items-center gap-3 hover:bg-muted/30 transition-colors group\",\n compact ? \"pl-4 pr-5 py-2.5\" : \"pl-4 pr-5 py-3.5\"\n )}\n >\n\n <div\n className={cn(\n \"rounded-lg flex items-center justify-center shrink-0\",\n config.bgClass,\n compact ? \"h-7 w-7\" : \"h-8 w-8\"\n )}\n title={config.label}\n aria-label={config.label}\n >\n <Icon\n className={cn(\"shrink-0\", config.colorClass, compact ? \"h-3.5 w-3.5\" : \"h-4 w-4\")}\n aria-hidden\n />\n </div>\n\n <div\n className={cn(\n \"rounded-md overflow-hidden shrink-0 bg-muted relative\",\n compact ? \"h-7 w-7\" : \"h-9 w-9\"\n )}\n >\n {tokenImage ? (\n <Image\n src={tokenImage}\n alt={tokenName}\n width={compact ? 28 : 36}\n height={compact ? 28 : 36}\n className=\"object-cover w-full h-full\"\n unoptimized\n />\n ) : (\n <div className=\"w-full h-full bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" aria-hidden />\n )}\n\n {is1155 && (\n <span className=\"absolute -bottom-1 -right-1 text-[8px] font-bold bg-brand-purple text-white rounded px-0.5 leading-tight\">\n 1155\n </span>\n )}\n </div>\n\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-1.5 leading-tight\">\n {contract && tokenId ? (\n <Link\n href={getAssetHref(contract, tokenId)}\n className=\"text-sm font-semibold hover:text-primary transition-colors truncate block\"\n >\n {tokenName}\n </Link>\n ) : (\n <span className=\"text-sm font-semibold text-muted-foreground\">—</span>\n )}\n {amount && (\n <span className=\"text-[10px] font-medium text-brand-purple shrink-0\">\n ×{amount}\n </span>\n )}\n </div>\n <p className=\"text-xs text-muted-foreground leading-tight truncate mt-0.5 flex items-center gap-1\">\n <span className=\"truncate\">{message}</span>\n {showActor && actor && (\n <>\n <Link\n href={getActorHref(actor)}\n className=\"hover:text-primary transition-colors tabular-nums shrink-0\"\n >\n <AddressDisplay address={actor} chars={4} showCopy={false} />\n </Link>\n {actorLevel && actorLevel.totalXp > 0 && (\n <LevelBadge\n level={actorLevel.currentLevel}\n name={actorLevel.currentLevelName}\n badgeColor={actorLevel.badgeColor}\n size=\"sm\"\n className=\"shrink-0\"\n />\n )}\n </>\n )}\n </p>\n </div>\n\n <div className=\"flex items-center gap-2.5 shrink-0\">\n {activity.price?.formatted && (\n <div className=\"text-right\">\n <p className=\"text-sm font-bold tabular-nums leading-tight\">\n {formatDisplayPrice(activity.price.formatted)}\n </p>\n <p className=\"text-[10px] text-muted-foreground leading-tight flex items-center justify-end gap-0.5\">\n <CurrencyIcon symbol={activity.price.currency} size={10} aria-hidden />\n <span className=\"sr-only\">{activity.price.currency}</span>\n </p>\n </div>\n )}\n\n <span\n className=\"text-[10px] text-muted-foreground tabular-nums hidden sm:block w-12 text-right\"\n title={new Date(activity.timestamp).toLocaleString()}\n >\n {timeAgo(activity.timestamp)}\n </span>\n\n {showExplorer && txLink && (\n <a\n href={txLink}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center justify-center h-6 w-6 rounded-md hover:bg-muted transition-colors opacity-50 sm:opacity-0 sm:group-hover:opacity-100 shrink-0\"\n aria-label=\"View transaction on Voyager\"\n title=\"View on Voyager\"\n >\n <ExternalLink className=\"h-3 w-3 text-muted-foreground\" aria-hidden />\n </a>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0FQ;AAxFR,mBAAkB;AAClB,kBAAiB;AACjB,0BAA6B;AAC7B,6BAA+B;AAC/B,2BAA6B;AAC7B,yBAA2B;AAC3B,sBAAqC;AACrC,kBAA2B;AAC3B,kBAAwB;AACxB,oBAAmC;AACnC,gBAAmB;AAGnB,MAAM,oBAA4C;AAAA,EAChD,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,OAAO;AAAA,EACP,UAAU;AAAA,EACV,WAAW;AACb;AAaO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,UAAU;AAAA,EACV;AAAA,EACA,cAAc;AAAA,EACd,eAAe,CAAC,UAAU,YAAY,mBAAmB,QAAQ,IAAI,OAAO;AAAA,EAC5E,eAAe,CAAC,YAAY,YAAY,OAAO;AACjD,GAAqB;AACnB,QAAM,SAAS,qCAAqB,SAAS,IAAI,KAAK;AAAA,IACpD,OAAO,SAAS;AAAA,IAChB,SAAS;AAAA,IACT,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,SAAS;AAAA,EACX;AACA,QAAM,OAAO,OAAO;AAEpB,QAAM,WAAW,SAAS,eAAe,SAAS,mBAAmB;AACrE,QAAM,UAAU,SAAS,cAAc,SAAS,WAAW;AAC3D,QAAM,QACJ,SAAS,WACT,SAAS,cACR,SAAS,SAAS,SAAS,SAAS,KAAK,SAAS,SACnD;AACF,QAAM,SAAS,SAAS,SAAS,GAAG,WAAW,OAAO,SAAS,MAAM,KAAK;AAE1E,QAAM,YAAY,SAAS,OAAO,SAAS,UAAU,IAAI,OAAO,KAAK;AACrE,QAAM,WAAW,SAAS,OAAO,SAAS;AAC1C,QAAM,aAAa,eAAW,wBAAW,QAAQ,IAAI;AAErD,QAAM,SAAS,SAAS,kBAAkB,cACvC,SAAS,SAAS,UAAU,SAAS,SAAS,eAAe,OAAO,SAAS,UAAU,GAAG,IAAI;AACjG,QAAM,SAAS,SAAS,UAAU,OAAO,SAAS,MAAM,IAAI,IAAI,SAAS,SAAS;AAElF,QAAM,UAAU,kBAAkB,SAAS,IAAI,KAAK,OAAO;AAE3D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW;AAAA,QACT;AAAA,QACA,UAAU,qBAAqB;AAAA,MACjC;AAAA,MAGA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,eAAW;AAAA,cACT;AAAA,cACA,OAAO;AAAA,cACP,UAAU,YAAY;AAAA,YACxB;AAAA,YACA,OAAO,OAAO;AAAA,YACd,cAAY,OAAO;AAAA,YAEnB;AAAA,cAAC;AAAA;AAAA,gBACC,eAAW,cAAG,YAAY,OAAO,YAAY,UAAU,gBAAgB,SAAS;AAAA,gBAChF,eAAW;AAAA;AAAA,YACb;AAAA;AAAA,QACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,eAAW;AAAA,cACT;AAAA,cACA,UAAU,YAAY;AAAA,YACxB;AAAA,YAEC;AAAA,2BACC;AAAA,gBAAC,aAAAA;AAAA,gBAAA;AAAA,kBACC,KAAK;AAAA,kBACL,KAAK;AAAA,kBACL,OAAO,UAAU,KAAK;AAAA,kBACtB,QAAQ,UAAU,KAAK;AAAA,kBACvB,WAAU;AAAA,kBACV,aAAW;AAAA;AAAA,cACb,IAEA,4CAAC,SAAI,WAAU,yEAAwE,eAAW,MAAC;AAAA,cAGpG,UACC,4CAAC,UAAK,WAAU,4GAA2G,kBAE3H;AAAA;AAAA;AAAA,QAEJ;AAAA,QAEA,6CAAC,SAAI,WAAU,kBACb;AAAA,uDAAC,SAAI,WAAU,2CACZ;AAAA,wBAAY,UACX;AAAA,cAAC,YAAAC;AAAA,cAAA;AAAA,gBACC,MAAM,aAAa,UAAU,OAAO;AAAA,gBACpC,WAAU;AAAA,gBAET;AAAA;AAAA,YACH,IAEA,4CAAC,UAAK,WAAU,+CAA8C,oBAAC;AAAA,YAEhE,UACC,6CAAC,UAAK,WAAU,sDAAqD;AAAA;AAAA,cACjE;AAAA,eACJ;AAAA,aAEJ;AAAA,UACA,6CAAC,OAAE,WAAU,uFACX;AAAA,wDAAC,UAAK,WAAU,YAAY,mBAAQ;AAAA,YACnC,aAAa,SACZ,4EACE;AAAA;AAAA,gBAAC,YAAAA;AAAA,gBAAA;AAAA,kBACC,MAAM,aAAa,KAAK;AAAA,kBACxB,WAAU;AAAA,kBAEV,sDAAC,yCAAe,SAAS,OAAO,OAAO,GAAG,UAAU,OAAO;AAAA;AAAA,cAC7D;AAAA,cACC,cAAc,WAAW,UAAU,KAClC;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO,WAAW;AAAA,kBAClB,MAAM,WAAW;AAAA,kBACjB,YAAY,WAAW;AAAA,kBACvB,MAAK;AAAA,kBACL,WAAU;AAAA;AAAA,cACZ;AAAA,eAEJ;AAAA,aAEJ;AAAA,WACF;AAAA,QAEA,6CAAC,SAAI,WAAU,sCACZ;AAAA,mBAAS,OAAO,aACf,6CAAC,SAAI,WAAU,cACb;AAAA,wDAAC,OAAE,WAAU,gDACV,gDAAmB,SAAS,MAAM,SAAS,GAC9C;AAAA,YACA,6CAAC,OAAE,WAAU,yFACX;AAAA,0DAAC,qCAAa,QAAQ,SAAS,MAAM,UAAU,MAAM,IAAI,eAAW,MAAC;AAAA,cACrE,4CAAC,UAAK,WAAU,WAAW,mBAAS,MAAM,UAAS;AAAA,eACrD;AAAA,aACF;AAAA,UAGF;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO,IAAI,KAAK,SAAS,SAAS,EAAE,eAAe;AAAA,cAElD,mCAAQ,SAAS,SAAS;AAAA;AAAA,UAC7B;AAAA,UAEC,gBAAgB,UACf;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN,QAAO;AAAA,cACP,KAAI;AAAA,cACJ,WAAU;AAAA,cACV,cAAW;AAAA,cACX,OAAM;AAAA,cAEN,sDAAC,oCAAa,WAAU,iCAAgC,eAAW,MAAC;AAAA;AAAA,UACtE;AAAA,WAEJ;AAAA;AAAA;AAAA,EACF;AAEJ;","names":["Image","Link"]}
@@ -1,19 +1,16 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ApiActivity } from '@medialane/sdk';
2
+ import { ApiActivity, ApiRewardsBatchEntry } from '@medialane/sdk';
3
3
 
4
4
  interface ActivityRowProps {
5
5
  activity: ApiActivity;
6
- token?: {
7
- name?: string;
8
- image?: string;
9
- };
10
6
  showActor?: boolean;
11
7
  showExplorer?: boolean;
12
8
  compact?: boolean;
9
+ actorLevel?: ApiRewardsBatchEntry;
13
10
  explorerUrl?: string;
14
11
  getAssetHref?: (contract: string, tokenId: string) => string;
15
12
  getActorHref?: (address: string) => string;
16
13
  }
17
- declare function ActivityRow({ activity, token, showActor, showExplorer, compact, explorerUrl, getAssetHref, getActorHref, }: ActivityRowProps): react_jsx_runtime.JSX.Element;
14
+ declare function ActivityRow({ activity, showActor, showExplorer, compact, actorLevel, explorerUrl, getAssetHref, getActorHref, }: ActivityRowProps): react_jsx_runtime.JSX.Element;
18
15
 
19
16
  export { ActivityRow, type ActivityRowProps };
@@ -1,19 +1,16 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ApiActivity } from '@medialane/sdk';
2
+ import { ApiActivity, ApiRewardsBatchEntry } from '@medialane/sdk';
3
3
 
4
4
  interface ActivityRowProps {
5
5
  activity: ApiActivity;
6
- token?: {
7
- name?: string;
8
- image?: string;
9
- };
10
6
  showActor?: boolean;
11
7
  showExplorer?: boolean;
12
8
  compact?: boolean;
9
+ actorLevel?: ApiRewardsBatchEntry;
13
10
  explorerUrl?: string;
14
11
  getAssetHref?: (contract: string, tokenId: string) => string;
15
12
  getActorHref?: (address: string) => string;
16
13
  }
17
- declare function ActivityRow({ activity, token, showActor, showExplorer, compact, explorerUrl, getAssetHref, getActorHref, }: ActivityRowProps): react_jsx_runtime.JSX.Element;
14
+ declare function ActivityRow({ activity, showActor, showExplorer, compact, actorLevel, explorerUrl, getAssetHref, getActorHref, }: ActivityRowProps): react_jsx_runtime.JSX.Element;
18
15
 
19
16
  export { ActivityRow, type ActivityRowProps };
@@ -1,24 +1,33 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import Image from "./image.js";
4
4
  import Link from "./link.js";
5
5
  import { ExternalLink } from "lucide-react";
6
6
  import { AddressDisplay } from "./address-display.js";
7
7
  import { CurrencyIcon } from "./currency-icon.js";
8
+ import { LevelBadge } from "./rewards/level-badge.js";
8
9
  import { ACTIVITY_TYPE_CONFIG } from "../data/activity.js";
9
10
  import { ipfsToHttp } from "../utils/ipfs.js";
10
11
  import { timeAgo } from "../utils/time.js";
11
12
  import { formatDisplayPrice } from "../utils/format.js";
12
13
  import { cn } from "../utils/cn.js";
14
+ const ACTIVITY_MESSAGES = {
15
+ mint: "Newly minted",
16
+ listing: "Listed for sale",
17
+ sale: "Purchased",
18
+ offer: "Offer placed",
19
+ transfer: "Transferred",
20
+ cancelled: "Listing cancelled"
21
+ };
13
22
  function ActivityRow({
14
23
  activity,
15
- token,
16
24
  showActor = true,
17
25
  showExplorer = true,
18
26
  compact = false,
27
+ actorLevel,
19
28
  explorerUrl = "https://voyager.online",
20
- getAssetHref = (c, t) => `/asset/${c}/${t}`,
21
- getActorHref = (a) => `/creator/${a}`
29
+ getAssetHref = (contract, tokenId) => `/asset/STARKNET/${contract}/${tokenId}`,
30
+ getActorHref = (address) => `/creator/${address}`
22
31
  }) {
23
32
  const config = ACTIVITY_TYPE_CONFIG[activity.type] ?? {
24
33
  label: activity.type,
@@ -32,28 +41,133 @@ function ActivityRow({
32
41
  const tokenId = activity.nftTokenId ?? activity.tokenId ?? null;
33
42
  const actor = activity.offerer ?? activity.fulfiller ?? (activity.type === "mint" ? activity.to : activity.from) ?? null;
34
43
  const txLink = activity.txHash ? `${explorerUrl}/tx/${activity.txHash}` : null;
35
- const tokenName = token?.name ?? (tokenId ? `#${tokenId}` : "\u2014");
36
- const tokenImage = token?.image ? ipfsToHttp(token.image) : null;
37
- return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-3 hover:bg-muted/30 transition-colors group", compact ? "pl-4 pr-5 py-2.5" : "pl-4 pr-5 py-3.5"), children: [
38
- /* @__PURE__ */ jsx("div", { className: cn("rounded-lg flex items-center justify-center shrink-0", config.bgClass, compact ? "h-7 w-7" : "h-8 w-8"), children: /* @__PURE__ */ jsx(Icon, { className: cn("shrink-0", config.colorClass, compact ? "h-3.5 w-3.5" : "h-4 w-4") }) }),
39
- /* @__PURE__ */ jsx("div", { className: cn("rounded-md overflow-hidden shrink-0 bg-muted", compact ? "h-7 w-7" : "h-9 w-9"), children: tokenImage ? /* @__PURE__ */ jsx(Image, { src: tokenImage, alt: tokenName, width: compact ? 28 : 36, height: compact ? 28 : 36, className: "object-cover w-full h-full", unoptimized: true }) : /* @__PURE__ */ jsx("div", { className: "w-full h-full bg-gradient-to-br from-muted-foreground/10 to-muted-foreground/5" }) }),
40
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
41
- contract && tokenId ? /* @__PURE__ */ jsx(Link, { href: getAssetHref(contract, tokenId), className: "text-sm font-semibold hover:text-primary transition-colors truncate block leading-tight", children: tokenName }) : /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-muted-foreground", children: "\u2014" }),
42
- showActor && actor && /* @__PURE__ */ jsx(Link, { href: getActorHref(actor), className: "text-xs text-muted-foreground hover:text-primary transition-colors font-mono leading-tight", children: /* @__PURE__ */ jsx(AddressDisplay, { address: actor, chars: 4, showCopy: false }) })
43
- ] }),
44
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 shrink-0", children: [
45
- !compact && /* @__PURE__ */ jsx("span", { className: cn("text-2xs font-medium px-1.5 py-0.5 rounded hidden sm:inline-flex", config.bgClass, config.colorClass), children: config.label }),
46
- activity.price?.formatted && /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
47
- /* @__PURE__ */ jsx("p", { className: "text-sm font-bold tabular-nums leading-tight", children: formatDisplayPrice(activity.price.formatted) }),
48
- /* @__PURE__ */ jsxs("p", { className: "text-2xs text-muted-foreground leading-tight flex items-center justify-end gap-0.5", children: [
49
- activity.price.currency && /* @__PURE__ */ jsx(CurrencyIcon, { symbol: activity.price.currency, size: 10 }),
50
- activity.price.currency
44
+ const tokenName = activity.token?.name ?? (tokenId ? `#${tokenId}` : "\u2014");
45
+ const rawImage = activity.token?.image ?? null;
46
+ const tokenImage = rawImage ? ipfsToHttp(rawImage) : null;
47
+ const is1155 = activity.tokenStandard === "ERC1155" || (activity.type === "mint" || activity.type === "transfer") && Number(activity.amount ?? "1") > 1;
48
+ const amount = activity.amount && Number(activity.amount) > 1 ? activity.amount : null;
49
+ const message = ACTIVITY_MESSAGES[activity.type] ?? config.label;
50
+ return /* @__PURE__ */ jsxs(
51
+ "div",
52
+ {
53
+ className: cn(
54
+ "flex items-center gap-3 hover:bg-muted/30 transition-colors group",
55
+ compact ? "pl-4 pr-5 py-2.5" : "pl-4 pr-5 py-3.5"
56
+ ),
57
+ children: [
58
+ /* @__PURE__ */ jsx(
59
+ "div",
60
+ {
61
+ className: cn(
62
+ "rounded-lg flex items-center justify-center shrink-0",
63
+ config.bgClass,
64
+ compact ? "h-7 w-7" : "h-8 w-8"
65
+ ),
66
+ title: config.label,
67
+ "aria-label": config.label,
68
+ children: /* @__PURE__ */ jsx(
69
+ Icon,
70
+ {
71
+ className: cn("shrink-0", config.colorClass, compact ? "h-3.5 w-3.5" : "h-4 w-4"),
72
+ "aria-hidden": true
73
+ }
74
+ )
75
+ }
76
+ ),
77
+ /* @__PURE__ */ jsxs(
78
+ "div",
79
+ {
80
+ className: cn(
81
+ "rounded-md overflow-hidden shrink-0 bg-muted relative",
82
+ compact ? "h-7 w-7" : "h-9 w-9"
83
+ ),
84
+ children: [
85
+ tokenImage ? /* @__PURE__ */ jsx(
86
+ Image,
87
+ {
88
+ src: tokenImage,
89
+ alt: tokenName,
90
+ width: compact ? 28 : 36,
91
+ height: compact ? 28 : 36,
92
+ className: "object-cover w-full h-full",
93
+ unoptimized: true
94
+ }
95
+ ) : /* @__PURE__ */ jsx("div", { className: "w-full h-full bg-gradient-to-br from-brand-purple/15 to-brand-blue/15", "aria-hidden": true }),
96
+ is1155 && /* @__PURE__ */ jsx("span", { className: "absolute -bottom-1 -right-1 text-[8px] font-bold bg-brand-purple text-white rounded px-0.5 leading-tight", children: "1155" })
97
+ ]
98
+ }
99
+ ),
100
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
101
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 leading-tight", children: [
102
+ contract && tokenId ? /* @__PURE__ */ jsx(
103
+ Link,
104
+ {
105
+ href: getAssetHref(contract, tokenId),
106
+ className: "text-sm font-semibold hover:text-primary transition-colors truncate block",
107
+ children: tokenName
108
+ }
109
+ ) : /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-muted-foreground", children: "\u2014" }),
110
+ amount && /* @__PURE__ */ jsxs("span", { className: "text-[10px] font-medium text-brand-purple shrink-0", children: [
111
+ "\xD7",
112
+ amount
113
+ ] })
114
+ ] }),
115
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground leading-tight truncate mt-0.5 flex items-center gap-1", children: [
116
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: message }),
117
+ showActor && actor && /* @__PURE__ */ jsxs(Fragment, { children: [
118
+ /* @__PURE__ */ jsx(
119
+ Link,
120
+ {
121
+ href: getActorHref(actor),
122
+ className: "hover:text-primary transition-colors tabular-nums shrink-0",
123
+ children: /* @__PURE__ */ jsx(AddressDisplay, { address: actor, chars: 4, showCopy: false })
124
+ }
125
+ ),
126
+ actorLevel && actorLevel.totalXp > 0 && /* @__PURE__ */ jsx(
127
+ LevelBadge,
128
+ {
129
+ level: actorLevel.currentLevel,
130
+ name: actorLevel.currentLevelName,
131
+ badgeColor: actorLevel.badgeColor,
132
+ size: "sm",
133
+ className: "shrink-0"
134
+ }
135
+ )
136
+ ] })
137
+ ] })
138
+ ] }),
139
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 shrink-0", children: [
140
+ activity.price?.formatted && /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
141
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-bold tabular-nums leading-tight", children: formatDisplayPrice(activity.price.formatted) }),
142
+ /* @__PURE__ */ jsxs("p", { className: "text-[10px] text-muted-foreground leading-tight flex items-center justify-end gap-0.5", children: [
143
+ /* @__PURE__ */ jsx(CurrencyIcon, { symbol: activity.price.currency, size: 10, "aria-hidden": true }),
144
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: activity.price.currency })
145
+ ] })
146
+ ] }),
147
+ /* @__PURE__ */ jsx(
148
+ "span",
149
+ {
150
+ className: "text-[10px] text-muted-foreground tabular-nums hidden sm:block w-12 text-right",
151
+ title: new Date(activity.timestamp).toLocaleString(),
152
+ children: timeAgo(activity.timestamp)
153
+ }
154
+ ),
155
+ showExplorer && txLink && /* @__PURE__ */ jsx(
156
+ "a",
157
+ {
158
+ href: txLink,
159
+ target: "_blank",
160
+ rel: "noopener noreferrer",
161
+ className: "inline-flex items-center justify-center h-6 w-6 rounded-md hover:bg-muted transition-colors opacity-50 sm:opacity-0 sm:group-hover:opacity-100 shrink-0",
162
+ "aria-label": "View transaction on Voyager",
163
+ title: "View on Voyager",
164
+ children: /* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3 text-muted-foreground", "aria-hidden": true })
165
+ }
166
+ )
51
167
  ] })
52
- ] }),
53
- /* @__PURE__ */ jsx("span", { className: "text-2xs text-muted-foreground tabular-nums hidden sm:block w-12 text-right", title: new Date(activity.timestamp).toLocaleString(), children: timeAgo(activity.timestamp) }),
54
- showExplorer && txLink && /* @__PURE__ */ jsx("a", { href: txLink, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center justify-center h-6 w-6 rounded-md hover:bg-muted transition-colors opacity-50 sm:opacity-0 sm:group-hover:opacity-100 shrink-0", "aria-label": "View on explorer", children: /* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3 text-muted-foreground" }) })
55
- ] })
56
- ] });
168
+ ]
169
+ }
170
+ );
57
171
  }
58
172
  export {
59
173
  ActivityRow
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/activity-row.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"./image.js\";\nimport Link from \"./link.js\";\nimport { ExternalLink } from \"lucide-react\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { ACTIVITY_TYPE_CONFIG } from \"../data/activity.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiActivity } from \"@medialane/sdk\";\n\nexport interface ActivityRowProps {\n activity: ApiActivity;\n\n token?: { name?: string; image?: string };\n showActor?: boolean;\n showExplorer?: boolean;\n compact?: boolean;\n explorerUrl?: string;\n getAssetHref?: (contract: string, tokenId: string) => string;\n getActorHref?: (address: string) => string;\n}\n\nexport function ActivityRow({\n activity,\n token,\n showActor = true,\n showExplorer = true,\n compact = false,\n explorerUrl = \"https://voyager.online\",\n getAssetHref = (c, t) => `/asset/${c}/${t}`,\n getActorHref = (a) => `/creator/${a}`,\n}: ActivityRowProps) {\n const config = ACTIVITY_TYPE_CONFIG[activity.type] ?? {\n label: activity.type,\n variant: \"outline\" as const,\n icon: ExternalLink,\n colorClass: \"text-muted-foreground\",\n bgClass: \"bg-muted\",\n };\n const Icon = config.icon;\n\n const contract = activity.nftContract ?? activity.contractAddress ?? null;\n const tokenId = activity.nftTokenId ?? activity.tokenId ?? null;\n const actor =\n activity.offerer ??\n activity.fulfiller ??\n ((activity.type as string) === \"mint\" ? activity.to : activity.from) ??\n null;\n const txLink = activity.txHash ? `${explorerUrl}/tx/${activity.txHash}` : null;\n\n const tokenName = token?.name ?? (tokenId ? `#${tokenId}` : \"—\");\n const tokenImage = token?.image ? ipfsToHttp(token.image) : null;\n\n return (\n <div className={cn(\"flex items-center gap-3 hover:bg-muted/30 transition-colors group\", compact ? \"pl-4 pr-5 py-2.5\" : \"pl-4 pr-5 py-3.5\")}>\n\n <div className={cn(\"rounded-lg flex items-center justify-center shrink-0\", config.bgClass, compact ? \"h-7 w-7\" : \"h-8 w-8\")}>\n <Icon className={cn(\"shrink-0\", config.colorClass, compact ? \"h-3.5 w-3.5\" : \"h-4 w-4\")} />\n </div>\n\n <div className={cn(\"rounded-md overflow-hidden shrink-0 bg-muted\", compact ? \"h-7 w-7\" : \"h-9 w-9\")}>\n {tokenImage ? (\n <Image src={tokenImage} alt={tokenName} width={compact ? 28 : 36} height={compact ? 28 : 36} className=\"object-cover w-full h-full\" unoptimized />\n ) : (\n <div className=\"w-full h-full bg-gradient-to-br from-muted-foreground/10 to-muted-foreground/5\" />\n )}\n </div>\n\n <div className=\"flex-1 min-w-0\">\n {contract && tokenId ? (\n <Link href={getAssetHref(contract, tokenId)} className=\"text-sm font-semibold hover:text-primary transition-colors truncate block leading-tight\">\n {tokenName}\n </Link>\n ) : (\n <span className=\"text-sm font-semibold text-muted-foreground\">—</span>\n )}\n {showActor && actor && (\n <Link href={getActorHref(actor)} className=\"text-xs text-muted-foreground hover:text-primary transition-colors font-mono leading-tight\">\n <AddressDisplay address={actor} chars={4} showCopy={false} />\n </Link>\n )}\n </div>\n\n <div className=\"flex items-center gap-2.5 shrink-0\">\n {!compact && (\n <span className={cn(\"text-2xs font-medium px-1.5 py-0.5 rounded hidden sm:inline-flex\", config.bgClass, config.colorClass)}>\n {config.label}\n </span>\n )}\n\n {activity.price?.formatted && (\n <div className=\"text-right\">\n <p className=\"text-sm font-bold tabular-nums leading-tight\">{formatDisplayPrice(activity.price.formatted)}</p>\n <p className=\"text-2xs text-muted-foreground leading-tight flex items-center justify-end gap-0.5\">\n {activity.price.currency && <CurrencyIcon symbol={activity.price.currency} size={10} />}\n {activity.price.currency}\n </p>\n </div>\n )}\n\n <span className=\"text-2xs text-muted-foreground tabular-nums hidden sm:block w-12 text-right\" title={new Date(activity.timestamp).toLocaleString()}>\n {timeAgo(activity.timestamp)}\n </span>\n\n {showExplorer && txLink && (\n <a href={txLink} target=\"_blank\" rel=\"noopener noreferrer\" className=\"inline-flex items-center justify-center h-6 w-6 rounded-md hover:bg-muted transition-colors opacity-50 sm:opacity-0 sm:group-hover:opacity-100 shrink-0\" aria-label=\"View on explorer\">\n <ExternalLink className=\"h-3 w-3 text-muted-foreground\" />\n </a>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/activity-row.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"./image.js\";\nimport Link from \"./link.js\";\nimport { ExternalLink } from \"lucide-react\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { LevelBadge } from \"./rewards/level-badge.js\";\nimport { ACTIVITY_TYPE_CONFIG } from \"../data/activity.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiActivity, ApiRewardsBatchEntry } from \"@medialane/sdk\";\n\nconst ACTIVITY_MESSAGES: Record<string, string> = {\n mint: \"Newly minted\",\n listing: \"Listed for sale\",\n sale: \"Purchased\",\n offer: \"Offer placed\",\n transfer: \"Transferred\",\n cancelled: \"Listing cancelled\",\n};\n\nexport interface ActivityRowProps {\n activity: ApiActivity;\n showActor?: boolean;\n showExplorer?: boolean;\n compact?: boolean;\n actorLevel?: ApiRewardsBatchEntry;\n explorerUrl?: string;\n getAssetHref?: (contract: string, tokenId: string) => string;\n getActorHref?: (address: string) => string;\n}\n\nexport function ActivityRow({\n activity,\n showActor = true,\n showExplorer = true,\n compact = false,\n actorLevel,\n explorerUrl = \"https://voyager.online\",\n getAssetHref = (contract, tokenId) => `/asset/STARKNET/${contract}/${tokenId}`,\n getActorHref = (address) => `/creator/${address}`,\n}: ActivityRowProps) {\n const config = ACTIVITY_TYPE_CONFIG[activity.type] ?? {\n label: activity.type,\n variant: \"outline\" as const,\n icon: ExternalLink,\n colorClass: \"text-muted-foreground\",\n bgClass: \"bg-muted\",\n };\n const Icon = config.icon;\n\n const contract = activity.nftContract ?? activity.contractAddress ?? null;\n const tokenId = activity.nftTokenId ?? activity.tokenId ?? null;\n const actor =\n activity.offerer ??\n activity.fulfiller ??\n (activity.type === \"mint\" ? activity.to : activity.from) ??\n null;\n const txLink = activity.txHash ? `${explorerUrl}/tx/${activity.txHash}` : null;\n\n const tokenName = activity.token?.name ?? (tokenId ? `#${tokenId}` : \"—\");\n const rawImage = activity.token?.image ?? null;\n const tokenImage = rawImage ? ipfsToHttp(rawImage) : null;\n\n const is1155 = activity.tokenStandard === \"ERC1155\" ||\n (activity.type === \"mint\" || activity.type === \"transfer\") && Number(activity.amount ?? \"1\") > 1;\n const amount = activity.amount && Number(activity.amount) > 1 ? activity.amount : null;\n\n const message = ACTIVITY_MESSAGES[activity.type] ?? config.label;\n\n return (\n <div\n className={cn(\n \"flex items-center gap-3 hover:bg-muted/30 transition-colors group\",\n compact ? \"pl-4 pr-5 py-2.5\" : \"pl-4 pr-5 py-3.5\"\n )}\n >\n\n <div\n className={cn(\n \"rounded-lg flex items-center justify-center shrink-0\",\n config.bgClass,\n compact ? \"h-7 w-7\" : \"h-8 w-8\"\n )}\n title={config.label}\n aria-label={config.label}\n >\n <Icon\n className={cn(\"shrink-0\", config.colorClass, compact ? \"h-3.5 w-3.5\" : \"h-4 w-4\")}\n aria-hidden\n />\n </div>\n\n <div\n className={cn(\n \"rounded-md overflow-hidden shrink-0 bg-muted relative\",\n compact ? \"h-7 w-7\" : \"h-9 w-9\"\n )}\n >\n {tokenImage ? (\n <Image\n src={tokenImage}\n alt={tokenName}\n width={compact ? 28 : 36}\n height={compact ? 28 : 36}\n className=\"object-cover w-full h-full\"\n unoptimized\n />\n ) : (\n <div className=\"w-full h-full bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" aria-hidden />\n )}\n\n {is1155 && (\n <span className=\"absolute -bottom-1 -right-1 text-[8px] font-bold bg-brand-purple text-white rounded px-0.5 leading-tight\">\n 1155\n </span>\n )}\n </div>\n\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-1.5 leading-tight\">\n {contract && tokenId ? (\n <Link\n href={getAssetHref(contract, tokenId)}\n className=\"text-sm font-semibold hover:text-primary transition-colors truncate block\"\n >\n {tokenName}\n </Link>\n ) : (\n <span className=\"text-sm font-semibold text-muted-foreground\">—</span>\n )}\n {amount && (\n <span className=\"text-[10px] font-medium text-brand-purple shrink-0\">\n ×{amount}\n </span>\n )}\n </div>\n <p className=\"text-xs text-muted-foreground leading-tight truncate mt-0.5 flex items-center gap-1\">\n <span className=\"truncate\">{message}</span>\n {showActor && actor && (\n <>\n <Link\n href={getActorHref(actor)}\n className=\"hover:text-primary transition-colors tabular-nums shrink-0\"\n >\n <AddressDisplay address={actor} chars={4} showCopy={false} />\n </Link>\n {actorLevel && actorLevel.totalXp > 0 && (\n <LevelBadge\n level={actorLevel.currentLevel}\n name={actorLevel.currentLevelName}\n badgeColor={actorLevel.badgeColor}\n size=\"sm\"\n className=\"shrink-0\"\n />\n )}\n </>\n )}\n </p>\n </div>\n\n <div className=\"flex items-center gap-2.5 shrink-0\">\n {activity.price?.formatted && (\n <div className=\"text-right\">\n <p className=\"text-sm font-bold tabular-nums leading-tight\">\n {formatDisplayPrice(activity.price.formatted)}\n </p>\n <p className=\"text-[10px] text-muted-foreground leading-tight flex items-center justify-end gap-0.5\">\n <CurrencyIcon symbol={activity.price.currency} size={10} aria-hidden />\n <span className=\"sr-only\">{activity.price.currency}</span>\n </p>\n </div>\n )}\n\n <span\n className=\"text-[10px] text-muted-foreground tabular-nums hidden sm:block w-12 text-right\"\n title={new Date(activity.timestamp).toLocaleString()}\n >\n {timeAgo(activity.timestamp)}\n </span>\n\n {showExplorer && txLink && (\n <a\n href={txLink}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center justify-center h-6 w-6 rounded-md hover:bg-muted transition-colors opacity-50 sm:opacity-0 sm:group-hover:opacity-100 shrink-0\"\n aria-label=\"View transaction on Voyager\"\n title=\"View on Voyager\"\n >\n <ExternalLink className=\"h-3 w-3 text-muted-foreground\" aria-hidden />\n </a>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -23,14 +23,15 @@ __export(medialane_collection_card_exports, {
23
23
  });
24
24
  module.exports = __toCommonJS(medialane_collection_card_exports);
25
25
  var import_jsx_runtime = require("react/jsx-runtime");
26
+ var import_lucide_react = require("lucide-react");
26
27
  var import_cn = require("../utils/cn.js");
27
- const FRAME_GRADIENT = "linear-gradient(135deg, #3b7bff, #8a5cf6 38%, #f6608f 70%, #fb8b46)";
28
28
  function MedialaneCollectionCard({
29
29
  image,
30
30
  name,
31
31
  collection,
32
32
  serial,
33
33
  creator,
34
+ creatorHref,
34
35
  className
35
36
  }) {
36
37
  const displayName = name?.trim() || "Untitled";
@@ -39,13 +40,7 @@ function MedialaneCollectionCard({
39
40
  {
40
41
  className: "ml-card-material relative rounded-[23px] overflow-hidden text-[#0a0e1f] dark:text-white",
41
42
  children: [
42
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "p-2.5 pb-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative aspect-[4/5] w-full overflow-hidden rounded-[16px] ring-1 ring-black/10 dark:ring-white/10", children: image ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: image, alt: displayName, className: "h-full w-full object-cover" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
43
- "div",
44
- {
45
- className: "h-full w-full",
46
- style: { background: FRAME_GRADIENT, opacity: 0.9 }
47
- }
48
- ) }) }),
43
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "p-2.5 pb-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative aspect-[4/5] w-full overflow-hidden rounded-[16px] ring-1 ring-black/10 dark:ring-white/10 bg-muted", children: image ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: image, alt: displayName, className: "h-full w-full object-cover" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-full w-full flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ImageIcon, { className: "h-8 w-8 text-muted-foreground/40" }) }) }) }),
49
44
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative px-4 pt-3 pb-4", children: [
50
45
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-start gap-2", children: [
51
46
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "min-w-0 flex-1 text-[18px] font-bold leading-snug truncate", children: displayName }),
@@ -55,7 +50,16 @@ function MedialaneCollectionCard({
55
50
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "my-3 h-px bg-black/10 dark:bg-white/10" }),
56
51
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
57
52
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[9px] font-bold tracking-[0.18em] text-[#0a0e1f]/50 dark:text-white/50", children: "STARKNET" }),
58
- creator && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-auto min-w-0 truncate text-2xs text-[#0a0e1f]/55 dark:text-white/55 tabular-nums", children: creator })
53
+ creator && (creatorHref ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
54
+ "a",
55
+ {
56
+ href: creatorHref,
57
+ target: "_blank",
58
+ rel: "noopener noreferrer",
59
+ className: "ml-auto min-w-0 truncate text-2xs text-[#0a0e1f]/55 dark:text-white/55 tabular-nums hover:text-[#0a0e1f]/80 dark:hover:text-white/80 transition-colors",
60
+ children: creator
61
+ }
62
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-auto min-w-0 truncate text-2xs text-[#0a0e1f]/55 dark:text-white/55 tabular-nums", children: creator }))
59
63
  ] })
60
64
  ] })
61
65
  ]
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/medialane-collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"../utils/cn.js\";\n\nexport interface MedialaneCollectionCardProps {\n\n image?: string | null;\n\n name?: string;\n\n collection?: string;\n\n serial?: string;\n\n creator?: string;\n className?: string;\n}\n\nconst FRAME_GRADIENT =\n \"linear-gradient(135deg, #3b7bff, #8a5cf6 38%, #f6608f 70%, #fb8b46)\";\n\nexport function MedialaneCollectionCard({\n image,\n name,\n collection,\n serial,\n creator,\n className,\n}: MedialaneCollectionCardProps) {\n const displayName = name?.trim() || \"Untitled\";\n\n return (\n <div className={cn(className)}>\n <div className=\"rounded-[24px] border border-border\">\n <div\n className=\"ml-card-material relative rounded-[23px] overflow-hidden text-[#0a0e1f] dark:text-white\"\n >\n\n <div className=\"p-2.5 pb-0\">\n <div className=\"relative aspect-[4/5] w-full overflow-hidden rounded-[16px] ring-1 ring-black/10 dark:ring-white/10\">\n {image ? (\n\n <img src={image} alt={displayName} className=\"h-full w-full object-cover\" />\n ) : (\n <div\n className=\"h-full w-full\"\n style={{ background: FRAME_GRADIENT, opacity: 0.9 }}\n />\n )}\n </div>\n </div>\n\n <div className=\"relative px-4 pt-3 pb-4\">\n <div className=\"flex items-start gap-2\">\n <p className=\"min-w-0 flex-1 text-[18px] font-bold leading-snug truncate\">\n {displayName}\n </p>\n {serial && (\n <span className=\"mt-0.5 shrink-0 rounded-full bg-black/5 dark:bg-white/10 px-2 py-0.5 text-2xs font-semibold text-[#0a0e1f]/80 dark:text-white/80 tabular-nums\">\n {serial}\n </span>\n )}\n </div>\n {collection && (\n <p className=\"mt-0.5 text-[12.5px] text-[#0a0e1f]/55 dark:text-white/55 truncate\">{collection}</p>\n )}\n <div className=\"my-3 h-px bg-black/10 dark:bg-white/10\" />\n <div className=\"flex items-center gap-2\">\n <span className=\"text-[9px] font-bold tracking-[0.18em] text-[#0a0e1f]/50 dark:text-white/50\">\n STARKNET\n </span>\n {creator && (\n <span className=\"ml-auto min-w-0 truncate text-2xs text-[#0a0e1f]/55 dark:text-white/55 tabular-nums\">\n {creator}\n </span>\n )}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0CgB;AAxChB,gBAAmB;AAgBnB,MAAM,iBACJ;AAEK,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiC;AAC/B,QAAM,cAAc,MAAM,KAAK,KAAK;AAEpC,SACE,4CAAC,SAAI,eAAW,cAAG,SAAS,GAC1B,sDAAC,SAAI,WAAU,uCACb;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MAGV;AAAA,oDAAC,SAAI,WAAU,cACb,sDAAC,SAAI,WAAU,uGACZ,kBAEC,4CAAC,SAAI,KAAK,OAAO,KAAK,aAAa,WAAU,8BAA6B,IAE1E;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,YAAY,gBAAgB,SAAS,IAAI;AAAA;AAAA,QACpD,GAEJ,GACF;AAAA,QAEA,6CAAC,SAAI,WAAU,2BACb;AAAA,uDAAC,SAAI,WAAU,0BACb;AAAA,wDAAC,OAAE,WAAU,8DACV,uBACH;AAAA,YACC,UACC,4CAAC,UAAK,WAAU,iJACb,kBACH;AAAA,aAEJ;AAAA,UACC,cACC,4CAAC,OAAE,WAAU,sEAAsE,sBAAW;AAAA,UAEhG,4CAAC,SAAI,WAAU,0CAAyC;AAAA,UACxD,6CAAC,SAAI,WAAU,2BACb;AAAA,wDAAC,UAAK,WAAU,+EAA8E,sBAE9F;AAAA,YACC,WACC,4CAAC,UAAK,WAAU,uFACb,mBACH;AAAA,aAEJ;AAAA,WACF;AAAA;AAAA;AAAA,EACF,GACF,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/medialane-collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { ImageIcon } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface MedialaneCollectionCardProps {\n\n image?: string | null;\n\n name?: string;\n\n collection?: string;\n\n serial?: string;\n\n creator?: string;\n\n /** Explorer/profile URL for the creator address makes the footer address a link. */\n creatorHref?: string;\n className?: string;\n}\n\nexport function MedialaneCollectionCard({\n image,\n name,\n collection,\n serial,\n creator,\n creatorHref,\n className,\n}: MedialaneCollectionCardProps) {\n const displayName = name?.trim() || \"Untitled\";\n\n return (\n <div className={cn(className)}>\n <div className=\"rounded-[24px] border border-border\">\n <div\n className=\"ml-card-material relative rounded-[23px] overflow-hidden text-[#0a0e1f] dark:text-white\"\n >\n\n <div className=\"p-2.5 pb-0\">\n <div className=\"relative aspect-[4/5] w-full overflow-hidden rounded-[16px] ring-1 ring-black/10 dark:ring-white/10 bg-muted\">\n {image ? (\n\n <img src={image} alt={displayName} className=\"h-full w-full object-cover\" />\n ) : (\n <div className=\"h-full w-full flex items-center justify-center\">\n <ImageIcon className=\"h-8 w-8 text-muted-foreground/40\" />\n </div>\n )}\n </div>\n </div>\n\n <div className=\"relative px-4 pt-3 pb-4\">\n <div className=\"flex items-start gap-2\">\n <p className=\"min-w-0 flex-1 text-[18px] font-bold leading-snug truncate\">\n {displayName}\n </p>\n {serial && (\n <span className=\"mt-0.5 shrink-0 rounded-full bg-black/5 dark:bg-white/10 px-2 py-0.5 text-2xs font-semibold text-[#0a0e1f]/80 dark:text-white/80 tabular-nums\">\n {serial}\n </span>\n )}\n </div>\n {collection && (\n <p className=\"mt-0.5 text-[12.5px] text-[#0a0e1f]/55 dark:text-white/55 truncate\">{collection}</p>\n )}\n <div className=\"my-3 h-px bg-black/10 dark:bg-white/10\" />\n <div className=\"flex items-center gap-2\">\n <span className=\"text-[9px] font-bold tracking-[0.18em] text-[#0a0e1f]/50 dark:text-white/50\">\n STARKNET\n </span>\n {creator && (\n creatorHref ? (\n <a\n href={creatorHref}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"ml-auto min-w-0 truncate text-2xs text-[#0a0e1f]/55 dark:text-white/55 tabular-nums hover:text-[#0a0e1f]/80 dark:hover:text-white/80 transition-colors\"\n >\n {creator}\n </a>\n ) : (\n <span className=\"ml-auto min-w-0 truncate text-2xs text-[#0a0e1f]/55 dark:text-white/55 tabular-nums\">\n {creator}\n </span>\n )\n )}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA4CgB;AA1ChB,0BAA0B;AAC1B,gBAAmB;AAmBZ,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiC;AAC/B,QAAM,cAAc,MAAM,KAAK,KAAK;AAEpC,SACE,4CAAC,SAAI,eAAW,cAAG,SAAS,GAC1B,sDAAC,SAAI,WAAU,uCACb;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MAGV;AAAA,oDAAC,SAAI,WAAU,cACb,sDAAC,SAAI,WAAU,gHACZ,kBAEC,4CAAC,SAAI,KAAK,OAAO,KAAK,aAAa,WAAU,8BAA6B,IAE1E,4CAAC,SAAI,WAAU,kDACb,sDAAC,iCAAU,WAAU,oCAAmC,GAC1D,GAEJ,GACF;AAAA,QAEA,6CAAC,SAAI,WAAU,2BACb;AAAA,uDAAC,SAAI,WAAU,0BACb;AAAA,wDAAC,OAAE,WAAU,8DACV,uBACH;AAAA,YACC,UACC,4CAAC,UAAK,WAAU,iJACb,kBACH;AAAA,aAEJ;AAAA,UACC,cACC,4CAAC,OAAE,WAAU,sEAAsE,sBAAW;AAAA,UAEhG,4CAAC,SAAI,WAAU,0CAAyC;AAAA,UACxD,6CAAC,SAAI,WAAU,2BACb;AAAA,wDAAC,UAAK,WAAU,+EAA8E,sBAE9F;AAAA,YACC,YACC,cACE;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM;AAAA,gBACN,QAAO;AAAA,gBACP,KAAI;AAAA,gBACJ,WAAU;AAAA,gBAET;AAAA;AAAA,YACH,IAEA,4CAAC,UAAK,WAAU,uFACb,mBACH;AAAA,aAGN;AAAA,WACF;AAAA;AAAA;AAAA,EACF,GACF,GACF;AAEJ;","names":[]}
@@ -6,8 +6,10 @@ interface MedialaneCollectionCardProps {
6
6
  collection?: string;
7
7
  serial?: string;
8
8
  creator?: string;
9
+ /** Explorer/profile URL for the creator address — makes the footer address a link. */
10
+ creatorHref?: string;
9
11
  className?: string;
10
12
  }
11
- declare function MedialaneCollectionCard({ image, name, collection, serial, creator, className, }: MedialaneCollectionCardProps): react_jsx_runtime.JSX.Element;
13
+ declare function MedialaneCollectionCard({ image, name, collection, serial, creator, creatorHref, className, }: MedialaneCollectionCardProps): react_jsx_runtime.JSX.Element;
12
14
 
13
15
  export { MedialaneCollectionCard, type MedialaneCollectionCardProps };
@@ -6,8 +6,10 @@ interface MedialaneCollectionCardProps {
6
6
  collection?: string;
7
7
  serial?: string;
8
8
  creator?: string;
9
+ /** Explorer/profile URL for the creator address — makes the footer address a link. */
10
+ creatorHref?: string;
9
11
  className?: string;
10
12
  }
11
- declare function MedialaneCollectionCard({ image, name, collection, serial, creator, className, }: MedialaneCollectionCardProps): react_jsx_runtime.JSX.Element;
13
+ declare function MedialaneCollectionCard({ image, name, collection, serial, creator, creatorHref, className, }: MedialaneCollectionCardProps): react_jsx_runtime.JSX.Element;
12
14
 
13
15
  export { MedialaneCollectionCard, type MedialaneCollectionCardProps };
@@ -1,13 +1,14 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { ImageIcon } from "lucide-react";
3
4
  import { cn } from "../utils/cn.js";
4
- const FRAME_GRADIENT = "linear-gradient(135deg, #3b7bff, #8a5cf6 38%, #f6608f 70%, #fb8b46)";
5
5
  function MedialaneCollectionCard({
6
6
  image,
7
7
  name,
8
8
  collection,
9
9
  serial,
10
10
  creator,
11
+ creatorHref,
11
12
  className
12
13
  }) {
13
14
  const displayName = name?.trim() || "Untitled";
@@ -16,13 +17,7 @@ function MedialaneCollectionCard({
16
17
  {
17
18
  className: "ml-card-material relative rounded-[23px] overflow-hidden text-[#0a0e1f] dark:text-white",
18
19
  children: [
19
- /* @__PURE__ */ jsx("div", { className: "p-2.5 pb-0", children: /* @__PURE__ */ jsx("div", { className: "relative aspect-[4/5] w-full overflow-hidden rounded-[16px] ring-1 ring-black/10 dark:ring-white/10", children: image ? /* @__PURE__ */ jsx("img", { src: image, alt: displayName, className: "h-full w-full object-cover" }) : /* @__PURE__ */ jsx(
20
- "div",
21
- {
22
- className: "h-full w-full",
23
- style: { background: FRAME_GRADIENT, opacity: 0.9 }
24
- }
25
- ) }) }),
20
+ /* @__PURE__ */ jsx("div", { className: "p-2.5 pb-0", children: /* @__PURE__ */ jsx("div", { className: "relative aspect-[4/5] w-full overflow-hidden rounded-[16px] ring-1 ring-black/10 dark:ring-white/10 bg-muted", children: image ? /* @__PURE__ */ jsx("img", { src: image, alt: displayName, className: "h-full w-full object-cover" }) : /* @__PURE__ */ jsx("div", { className: "h-full w-full flex items-center justify-center", children: /* @__PURE__ */ jsx(ImageIcon, { className: "h-8 w-8 text-muted-foreground/40" }) }) }) }),
26
21
  /* @__PURE__ */ jsxs("div", { className: "relative px-4 pt-3 pb-4", children: [
27
22
  /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
28
23
  /* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 text-[18px] font-bold leading-snug truncate", children: displayName }),
@@ -32,7 +27,16 @@ function MedialaneCollectionCard({
32
27
  /* @__PURE__ */ jsx("div", { className: "my-3 h-px bg-black/10 dark:bg-white/10" }),
33
28
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
34
29
  /* @__PURE__ */ jsx("span", { className: "text-[9px] font-bold tracking-[0.18em] text-[#0a0e1f]/50 dark:text-white/50", children: "STARKNET" }),
35
- creator && /* @__PURE__ */ jsx("span", { className: "ml-auto min-w-0 truncate text-2xs text-[#0a0e1f]/55 dark:text-white/55 tabular-nums", children: creator })
30
+ creator && (creatorHref ? /* @__PURE__ */ jsx(
31
+ "a",
32
+ {
33
+ href: creatorHref,
34
+ target: "_blank",
35
+ rel: "noopener noreferrer",
36
+ className: "ml-auto min-w-0 truncate text-2xs text-[#0a0e1f]/55 dark:text-white/55 tabular-nums hover:text-[#0a0e1f]/80 dark:hover:text-white/80 transition-colors",
37
+ children: creator
38
+ }
39
+ ) : /* @__PURE__ */ jsx("span", { className: "ml-auto min-w-0 truncate text-2xs text-[#0a0e1f]/55 dark:text-white/55 tabular-nums", children: creator }))
36
40
  ] })
37
41
  ] })
38
42
  ]
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/medialane-collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"../utils/cn.js\";\n\nexport interface MedialaneCollectionCardProps {\n\n image?: string | null;\n\n name?: string;\n\n collection?: string;\n\n serial?: string;\n\n creator?: string;\n className?: string;\n}\n\nconst FRAME_GRADIENT =\n \"linear-gradient(135deg, #3b7bff, #8a5cf6 38%, #f6608f 70%, #fb8b46)\";\n\nexport function MedialaneCollectionCard({\n image,\n name,\n collection,\n serial,\n creator,\n className,\n}: MedialaneCollectionCardProps) {\n const displayName = name?.trim() || \"Untitled\";\n\n return (\n <div className={cn(className)}>\n <div className=\"rounded-[24px] border border-border\">\n <div\n className=\"ml-card-material relative rounded-[23px] overflow-hidden text-[#0a0e1f] dark:text-white\"\n >\n\n <div className=\"p-2.5 pb-0\">\n <div className=\"relative aspect-[4/5] w-full overflow-hidden rounded-[16px] ring-1 ring-black/10 dark:ring-white/10\">\n {image ? (\n\n <img src={image} alt={displayName} className=\"h-full w-full object-cover\" />\n ) : (\n <div\n className=\"h-full w-full\"\n style={{ background: FRAME_GRADIENT, opacity: 0.9 }}\n />\n )}\n </div>\n </div>\n\n <div className=\"relative px-4 pt-3 pb-4\">\n <div className=\"flex items-start gap-2\">\n <p className=\"min-w-0 flex-1 text-[18px] font-bold leading-snug truncate\">\n {displayName}\n </p>\n {serial && (\n <span className=\"mt-0.5 shrink-0 rounded-full bg-black/5 dark:bg-white/10 px-2 py-0.5 text-2xs font-semibold text-[#0a0e1f]/80 dark:text-white/80 tabular-nums\">\n {serial}\n </span>\n )}\n </div>\n {collection && (\n <p className=\"mt-0.5 text-[12.5px] text-[#0a0e1f]/55 dark:text-white/55 truncate\">{collection}</p>\n )}\n <div className=\"my-3 h-px bg-black/10 dark:bg-white/10\" />\n <div className=\"flex items-center gap-2\">\n <span className=\"text-[9px] font-bold tracking-[0.18em] text-[#0a0e1f]/50 dark:text-white/50\">\n STARKNET\n </span>\n {creator && (\n <span className=\"ml-auto min-w-0 truncate text-2xs text-[#0a0e1f]/55 dark:text-white/55 tabular-nums\">\n {creator}\n </span>\n )}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";AA0CgB,cAWJ,YAXI;AAxChB,SAAS,UAAU;AAgBnB,MAAM,iBACJ;AAEK,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiC;AAC/B,QAAM,cAAc,MAAM,KAAK,KAAK;AAEpC,SACE,oBAAC,SAAI,WAAW,GAAG,SAAS,GAC1B,8BAAC,SAAI,WAAU,uCACb;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MAGV;AAAA,4BAAC,SAAI,WAAU,cACb,8BAAC,SAAI,WAAU,uGACZ,kBAEC,oBAAC,SAAI,KAAK,OAAO,KAAK,aAAa,WAAU,8BAA6B,IAE1E;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,YAAY,gBAAgB,SAAS,IAAI;AAAA;AAAA,QACpD,GAEJ,GACF;AAAA,QAEA,qBAAC,SAAI,WAAU,2BACb;AAAA,+BAAC,SAAI,WAAU,0BACb;AAAA,gCAAC,OAAE,WAAU,8DACV,uBACH;AAAA,YACC,UACC,oBAAC,UAAK,WAAU,iJACb,kBACH;AAAA,aAEJ;AAAA,UACC,cACC,oBAAC,OAAE,WAAU,sEAAsE,sBAAW;AAAA,UAEhG,oBAAC,SAAI,WAAU,0CAAyC;AAAA,UACxD,qBAAC,SAAI,WAAU,2BACb;AAAA,gCAAC,UAAK,WAAU,+EAA8E,sBAE9F;AAAA,YACC,WACC,oBAAC,UAAK,WAAU,uFACb,mBACH;AAAA,aAEJ;AAAA,WACF;AAAA;AAAA;AAAA,EACF,GACF,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/medialane-collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { ImageIcon } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface MedialaneCollectionCardProps {\n\n image?: string | null;\n\n name?: string;\n\n collection?: string;\n\n serial?: string;\n\n creator?: string;\n\n /** Explorer/profile URL for the creator address makes the footer address a link. */\n creatorHref?: string;\n className?: string;\n}\n\nexport function MedialaneCollectionCard({\n image,\n name,\n collection,\n serial,\n creator,\n creatorHref,\n className,\n}: MedialaneCollectionCardProps) {\n const displayName = name?.trim() || \"Untitled\";\n\n return (\n <div className={cn(className)}>\n <div className=\"rounded-[24px] border border-border\">\n <div\n className=\"ml-card-material relative rounded-[23px] overflow-hidden text-[#0a0e1f] dark:text-white\"\n >\n\n <div className=\"p-2.5 pb-0\">\n <div className=\"relative aspect-[4/5] w-full overflow-hidden rounded-[16px] ring-1 ring-black/10 dark:ring-white/10 bg-muted\">\n {image ? (\n\n <img src={image} alt={displayName} className=\"h-full w-full object-cover\" />\n ) : (\n <div className=\"h-full w-full flex items-center justify-center\">\n <ImageIcon className=\"h-8 w-8 text-muted-foreground/40\" />\n </div>\n )}\n </div>\n </div>\n\n <div className=\"relative px-4 pt-3 pb-4\">\n <div className=\"flex items-start gap-2\">\n <p className=\"min-w-0 flex-1 text-[18px] font-bold leading-snug truncate\">\n {displayName}\n </p>\n {serial && (\n <span className=\"mt-0.5 shrink-0 rounded-full bg-black/5 dark:bg-white/10 px-2 py-0.5 text-2xs font-semibold text-[#0a0e1f]/80 dark:text-white/80 tabular-nums\">\n {serial}\n </span>\n )}\n </div>\n {collection && (\n <p className=\"mt-0.5 text-[12.5px] text-[#0a0e1f]/55 dark:text-white/55 truncate\">{collection}</p>\n )}\n <div className=\"my-3 h-px bg-black/10 dark:bg-white/10\" />\n <div className=\"flex items-center gap-2\">\n <span className=\"text-[9px] font-bold tracking-[0.18em] text-[#0a0e1f]/50 dark:text-white/50\">\n STARKNET\n </span>\n {creator && (\n creatorHref ? (\n <a\n href={creatorHref}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"ml-auto min-w-0 truncate text-2xs text-[#0a0e1f]/55 dark:text-white/55 tabular-nums hover:text-[#0a0e1f]/80 dark:hover:text-white/80 transition-colors\"\n >\n {creator}\n </a>\n ) : (\n <span className=\"ml-auto min-w-0 truncate text-2xs text-[#0a0e1f]/55 dark:text-white/55 tabular-nums\">\n {creator}\n </span>\n )\n )}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";AA4CgB,cAUJ,YAVI;AA1ChB,SAAS,iBAAiB;AAC1B,SAAS,UAAU;AAmBZ,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiC;AAC/B,QAAM,cAAc,MAAM,KAAK,KAAK;AAEpC,SACE,oBAAC,SAAI,WAAW,GAAG,SAAS,GAC1B,8BAAC,SAAI,WAAU,uCACb;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MAGV;AAAA,4BAAC,SAAI,WAAU,cACb,8BAAC,SAAI,WAAU,gHACZ,kBAEC,oBAAC,SAAI,KAAK,OAAO,KAAK,aAAa,WAAU,8BAA6B,IAE1E,oBAAC,SAAI,WAAU,kDACb,8BAAC,aAAU,WAAU,oCAAmC,GAC1D,GAEJ,GACF;AAAA,QAEA,qBAAC,SAAI,WAAU,2BACb;AAAA,+BAAC,SAAI,WAAU,0BACb;AAAA,gCAAC,OAAE,WAAU,8DACV,uBACH;AAAA,YACC,UACC,oBAAC,UAAK,WAAU,iJACb,kBACH;AAAA,aAEJ;AAAA,UACC,cACC,oBAAC,OAAE,WAAU,sEAAsE,sBAAW;AAAA,UAEhG,oBAAC,SAAI,WAAU,0CAAyC;AAAA,UACxD,qBAAC,SAAI,WAAU,2BACb;AAAA,gCAAC,UAAK,WAAU,+EAA8E,sBAE9F;AAAA,YACC,YACC,cACE;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM;AAAA,gBACN,QAAO;AAAA,gBACP,KAAI;AAAA,gBACJ,WAAU;AAAA,gBAET;AAAA;AAAA,YACH,IAEA,oBAAC,UAAK,WAAU,uFACb,mBACH;AAAA,aAGN;AAAA,WACF;AAAA;AAAA;AAAA,EACF,GACF,GACF;AAEJ;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medialane/ui",
3
- "version": "0.128.6",
3
+ "version": "0.129.0",
4
4
  "description": "Shared UI components for Medialane apps",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -44,6 +44,7 @@
44
44
  ],
45
45
  "scripts": {
46
46
  "build": "tsup",
47
+ "test": "bun test",
47
48
  "prepublishOnly": "bun run typecheck && bun test && bun run build",
48
49
  "dev": "tsup --watch",
49
50
  "typecheck": "tsc --noEmit",