@medialane/ui 0.1.6 → 0.3.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.
Files changed (92) hide show
  1. package/dist/components/activity-feed-shell.cjs +90 -0
  2. package/dist/components/activity-feed-shell.cjs.map +1 -0
  3. package/dist/components/activity-feed-shell.d.cts +13 -0
  4. package/dist/components/activity-feed-shell.d.ts +13 -0
  5. package/dist/components/activity-feed-shell.js +56 -0
  6. package/dist/components/activity-feed-shell.js.map +1 -0
  7. package/dist/components/activity-row.cjs +95 -0
  8. package/dist/components/activity-row.cjs.map +1 -0
  9. package/dist/components/activity-row.d.cts +20 -0
  10. package/dist/components/activity-row.d.ts +20 -0
  11. package/dist/components/activity-row.js +61 -0
  12. package/dist/components/activity-row.js.map +1 -0
  13. package/dist/components/activity-ticker.cjs +92 -0
  14. package/dist/components/activity-ticker.cjs.map +1 -0
  15. package/dist/components/activity-ticker.d.cts +12 -0
  16. package/dist/components/activity-ticker.d.ts +12 -0
  17. package/dist/components/activity-ticker.js +58 -0
  18. package/dist/components/activity-ticker.js.map +1 -0
  19. package/dist/components/collection-card.cjs +124 -0
  20. package/dist/components/collection-card.cjs.map +1 -0
  21. package/dist/components/collection-card.d.cts +13 -0
  22. package/dist/components/collection-card.d.ts +13 -0
  23. package/dist/components/collection-card.js +89 -0
  24. package/dist/components/collection-card.js.map +1 -0
  25. package/dist/components/cta-card-grid.cjs +67 -0
  26. package/dist/components/cta-card-grid.cjs.map +1 -0
  27. package/dist/components/cta-card-grid.d.cts +23 -0
  28. package/dist/components/cta-card-grid.d.ts +23 -0
  29. package/dist/components/cta-card-grid.js +33 -0
  30. package/dist/components/cta-card-grid.js.map +1 -0
  31. package/dist/components/hero-slider.cjs +133 -0
  32. package/dist/components/hero-slider.cjs.map +1 -0
  33. package/dist/components/hero-slider.d.cts +12 -0
  34. package/dist/components/hero-slider.d.ts +12 -0
  35. package/dist/components/hero-slider.js +98 -0
  36. package/dist/components/hero-slider.js.map +1 -0
  37. package/dist/components/launchpad-grid.cjs +77 -0
  38. package/dist/components/launchpad-grid.cjs.map +1 -0
  39. package/dist/components/launchpad-grid.d.cts +20 -0
  40. package/dist/components/launchpad-grid.d.ts +20 -0
  41. package/dist/components/launchpad-grid.js +43 -0
  42. package/dist/components/launchpad-grid.js.map +1 -0
  43. package/dist/components/listing-card.cjs +146 -0
  44. package/dist/components/listing-card.cjs.map +1 -0
  45. package/dist/components/listing-card.d.cts +16 -0
  46. package/dist/components/listing-card.d.ts +16 -0
  47. package/dist/components/listing-card.js +111 -0
  48. package/dist/components/listing-card.js.map +1 -0
  49. package/dist/components/motion-primitives.cjs +126 -0
  50. package/dist/components/motion-primitives.cjs.map +1 -0
  51. package/dist/components/motion-primitives.d.cts +36 -0
  52. package/dist/components/motion-primitives.d.ts +36 -0
  53. package/dist/components/motion-primitives.js +96 -0
  54. package/dist/components/motion-primitives.js.map +1 -0
  55. package/dist/components/scroll-section.cjs +72 -0
  56. package/dist/components/scroll-section.cjs.map +1 -0
  57. package/dist/components/scroll-section.d.cts +18 -0
  58. package/dist/components/scroll-section.d.ts +18 -0
  59. package/dist/components/scroll-section.js +38 -0
  60. package/dist/components/scroll-section.js.map +1 -0
  61. package/dist/components/share-button.cjs +86 -0
  62. package/dist/components/share-button.cjs.map +1 -0
  63. package/dist/components/share-button.d.cts +12 -0
  64. package/dist/components/share-button.d.ts +12 -0
  65. package/dist/components/share-button.js +62 -0
  66. package/dist/components/share-button.js.map +1 -0
  67. package/dist/components/token-card.cjs +281 -0
  68. package/dist/components/token-card.cjs.map +1 -0
  69. package/dist/components/token-card.d.cts +31 -0
  70. package/dist/components/token-card.d.ts +31 -0
  71. package/dist/components/token-card.js +256 -0
  72. package/dist/components/token-card.js.map +1 -0
  73. package/dist/data/activity.cjs +48 -0
  74. package/dist/data/activity.cjs.map +1 -0
  75. package/dist/data/activity.d.cts +16 -0
  76. package/dist/data/activity.d.ts +16 -0
  77. package/dist/data/activity.js +23 -0
  78. package/dist/data/activity.js.map +1 -0
  79. package/dist/index.cjs +66 -2
  80. package/dist/index.cjs.map +1 -1
  81. package/dist/index.d.cts +18 -0
  82. package/dist/index.d.ts +18 -0
  83. package/dist/index.js +40 -1
  84. package/dist/index.js.map +1 -1
  85. package/dist/medialane.css +184 -0
  86. package/dist/utils/time.cjs +42 -0
  87. package/dist/utils/time.cjs.map +1 -0
  88. package/dist/utils/time.d.cts +7 -0
  89. package/dist/utils/time.d.ts +7 -0
  90. package/dist/utils/time.js +18 -0
  91. package/dist/utils/time.js.map +1 -0
  92. package/package.json +17 -10
@@ -0,0 +1,281 @@
1
+ "use strict";
2
+ "use client";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+ var token_card_exports = {};
31
+ __export(token_card_exports, {
32
+ TokenCard: () => TokenCard,
33
+ TokenCardSkeleton: () => TokenCardSkeleton
34
+ });
35
+ module.exports = __toCommonJS(token_card_exports);
36
+ var import_jsx_runtime = require("react/jsx-runtime");
37
+ var import_react = require("react");
38
+ var import_link = __toESM(require("next/link"), 1);
39
+ var import_image = __toESM(require("next/image"), 1);
40
+ var import_lucide_react = require("lucide-react");
41
+ var import_cn = require("../utils/cn.js");
42
+ var import_ipfs = require("../utils/ipfs.js");
43
+ var import_format = require("../utils/format.js");
44
+ var import_currency_icon = require("./currency-icon.js");
45
+ var import_ip_type_badge = require("./ip-type-badge.js");
46
+ var import_motion_primitives = require("./motion-primitives.js");
47
+ const RARITY_STYLE = {
48
+ legendary: { label: "Legendary", className: "bg-yellow-400/90 text-yellow-900" },
49
+ epic: { label: "Epic", className: "bg-purple-500/85 text-white" },
50
+ rare: { label: "Rare", className: "bg-blue-500/85 text-white" },
51
+ uncommon: { label: "Uncommon", className: "bg-emerald-500/85 text-white" },
52
+ common: null
53
+ };
54
+ const BTN_BASE = "h-8 rounded-[11px] flex items-center justify-center gap-1.5 text-xs font-semibold transition-all active:scale-[0.98] shadow-none border-0";
55
+ const BTN_SOLID = (0, import_cn.cn)(BTN_BASE, "text-white hover:brightness-110");
56
+ const BTN_OUTLINE = (0, import_cn.cn)(BTN_BASE, "border border-border/60 text-foreground hover:bg-muted/60");
57
+ function TokenCard({
58
+ token,
59
+ isOwner = false,
60
+ inCart = false,
61
+ showBuyButton = true,
62
+ rarityTier,
63
+ className,
64
+ onBuy,
65
+ onCart,
66
+ onOffer,
67
+ onList,
68
+ onCancel,
69
+ onTransfer,
70
+ overflowMenu
71
+ }) {
72
+ const [imgError, setImgError] = (0, import_react.useState)(false);
73
+ const name = token.metadata?.name || `Token #${token.tokenId}`;
74
+ const image = (0, import_ipfs.ipfsToHttp)(token.metadata?.image);
75
+ const activeOrder = token.activeOrders?.[0];
76
+ const assetHref = `/asset/${token.contractAddress}/${token.tokenId}`;
77
+ const renderActions = () => {
78
+ if (!isOwner && activeOrder && showBuyButton) {
79
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
80
+ onBuy && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
81
+ "button",
82
+ {
83
+ className: (0, import_cn.cn)(BTN_SOLID, "flex-1 bg-brand-purple"),
84
+ onClick: (e) => {
85
+ e.preventDefault();
86
+ e.stopPropagation();
87
+ onBuy(token);
88
+ },
89
+ children: [
90
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Zap, { className: "h-3.5 w-3.5 shrink-0" }),
91
+ "Buy"
92
+ ]
93
+ }
94
+ ),
95
+ onCart && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
96
+ "button",
97
+ {
98
+ className: (0, import_cn.cn)(
99
+ BTN_OUTLINE,
100
+ "w-8 shrink-0",
101
+ inCart && "border-brand-orange/50 bg-brand-orange/10 text-brand-orange"
102
+ ),
103
+ onClick: (e) => {
104
+ e.preventDefault();
105
+ e.stopPropagation();
106
+ onCart(token);
107
+ },
108
+ disabled: inCart,
109
+ "aria-label": inCart ? "In cart" : "Add to cart",
110
+ children: inCart ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ShoppingCart, { className: "h-3.5 w-3.5" })
111
+ }
112
+ ),
113
+ onOffer && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
114
+ "button",
115
+ {
116
+ className: (0, import_cn.cn)(BTN_OUTLINE, "w-8 shrink-0 text-brand-orange border-brand-orange/40 hover:bg-brand-orange/10"),
117
+ onClick: (e) => {
118
+ e.preventDefault();
119
+ e.stopPropagation();
120
+ onOffer(token);
121
+ },
122
+ "aria-label": "Make an offer",
123
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.HandCoins, { className: "h-3.5 w-3.5" })
124
+ }
125
+ )
126
+ ] });
127
+ }
128
+ if (!isOwner) {
129
+ if (!onOffer) return null;
130
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
131
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_link.default, { href: assetHref, className: (0, import_cn.cn)(BTN_OUTLINE, "flex-1"), children: [
132
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowUpRight, { className: "h-3.5 w-3.5 shrink-0" }),
133
+ "View"
134
+ ] }),
135
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
136
+ "button",
137
+ {
138
+ className: (0, import_cn.cn)(BTN_OUTLINE, "w-8 shrink-0 text-brand-orange border-brand-orange/40 hover:bg-brand-orange/10"),
139
+ onClick: (e) => {
140
+ e.preventDefault();
141
+ e.stopPropagation();
142
+ onOffer(token);
143
+ },
144
+ "aria-label": "Make an offer",
145
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.HandCoins, { className: "h-3.5 w-3.5" })
146
+ }
147
+ )
148
+ ] });
149
+ }
150
+ if (isOwner && activeOrder) {
151
+ if (!onCancel) return null;
152
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
153
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
154
+ "button",
155
+ {
156
+ className: (0, import_cn.cn)(BTN_SOLID, "flex-1 bg-brand-rose"),
157
+ onClick: (e) => {
158
+ e.preventDefault();
159
+ e.stopPropagation();
160
+ onCancel(token);
161
+ },
162
+ children: [
163
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "h-3.5 w-3.5 shrink-0" }),
164
+ "Cancel listing"
165
+ ]
166
+ }
167
+ ),
168
+ onTransfer && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
169
+ "button",
170
+ {
171
+ className: (0, import_cn.cn)(BTN_OUTLINE, "w-8 shrink-0"),
172
+ onClick: (e) => {
173
+ e.preventDefault();
174
+ e.stopPropagation();
175
+ onTransfer(token);
176
+ },
177
+ "aria-label": "Transfer",
178
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRightLeft, { className: "h-3.5 w-3.5" })
179
+ }
180
+ )
181
+ ] });
182
+ }
183
+ if (isOwner && !activeOrder) {
184
+ if (!onList) return null;
185
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
186
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
187
+ "button",
188
+ {
189
+ className: (0, import_cn.cn)(BTN_SOLID, "flex-1 bg-brand-blue"),
190
+ onClick: (e) => {
191
+ e.preventDefault();
192
+ e.stopPropagation();
193
+ onList(token);
194
+ },
195
+ children: [
196
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Tag, { className: "h-3.5 w-3.5 shrink-0" }),
197
+ "List for sale"
198
+ ]
199
+ }
200
+ ),
201
+ onTransfer && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
202
+ "button",
203
+ {
204
+ className: (0, import_cn.cn)(BTN_OUTLINE, "w-8 shrink-0"),
205
+ onClick: (e) => {
206
+ e.preventDefault();
207
+ e.stopPropagation();
208
+ onTransfer(token);
209
+ },
210
+ "aria-label": "Transfer",
211
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRightLeft, { className: "h-3.5 w-3.5" })
212
+ }
213
+ )
214
+ ] });
215
+ }
216
+ return null;
217
+ };
218
+ const actionContent = renderActions();
219
+ const showActionBar = actionContent != null || !!overflowMenu;
220
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_motion_primitives.MotionCard, { className: (0, import_cn.cn)("card-base group relative overflow-hidden flex flex-col", className), children: [
221
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_link.default, { href: assetHref, className: "block relative shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative aspect-square bg-muted overflow-hidden", children: [
222
+ !imgError ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
223
+ import_image.default,
224
+ {
225
+ src: image,
226
+ alt: name,
227
+ fill: true,
228
+ unoptimized: true,
229
+ sizes: "(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 22vw",
230
+ className: "object-cover transition-transform duration-500 group-hover:scale-105",
231
+ onError: () => setImgError(true)
232
+ }
233
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "text-2xl font-mono text-muted-foreground", children: [
234
+ "#",
235
+ token.tokenId
236
+ ] }) }),
237
+ token.metadata?.ipType && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute top-2 left-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ip_type_badge.IpTypeBadge, { ipType: token.metadata.ipType, size: "sm" }) }),
238
+ rarityTier && RARITY_STYLE[rarityTier] && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute top-2 right-2 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: (0, import_cn.cn)(
239
+ "inline-flex items-center px-1.5 py-0.5 rounded-md backdrop-blur-sm text-[10px] font-bold leading-none",
240
+ RARITY_STYLE[rarityTier].className
241
+ ), children: RARITY_STYLE[rarityTier].label }) }),
242
+ (token.metadataStatus === "PENDING" || token.metadataStatus === "FETCHING") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "absolute bottom-0 inset-x-0 flex items-center justify-center gap-1.5 bg-black/50 backdrop-blur-sm py-1.5", children: [
243
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Loader2, { className: "h-3 w-3 animate-spin text-white/70" }),
244
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[10px] text-white/70", children: "Indexing\u2026" })
245
+ ] })
246
+ ] }) }),
247
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "px-3 pt-2.5 pb-1 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_link.default, { href: assetHref, className: "block space-y-0.5 mb-2", children: [
248
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-xl font-bold line-clamp-2 leading-tight", children: name }),
249
+ activeOrder && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "flex items-center gap-1 text-[11px] font-semibold text-foreground/80", children: [
250
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: activeOrder.price.currency, size: 11 }),
251
+ (0, import_format.formatDisplayPrice)(activeOrder.price.formatted),
252
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-normal text-muted-foreground", children: activeOrder.price.currency })
253
+ ] }),
254
+ token.metadata?.description ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-[10px] text-muted-foreground truncate leading-snug", children: token.metadata.description }) : token.metadata?.ipType ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-[10px] text-muted-foreground opacity-70", children: token.metadata.ipType }) : null
255
+ ] }) }),
256
+ showActionBar && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1.5 px-2 pb-2", children: [
257
+ actionContent,
258
+ overflowMenu
259
+ ] })
260
+ ] });
261
+ }
262
+ function TokenCardSkeleton() {
263
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "card-base overflow-hidden", children: [
264
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "aspect-square w-full animate-pulse bg-muted" }),
265
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "px-3 pt-2.5 pb-2 space-y-1.5", children: [
266
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-5 w-3/4 rounded-md animate-pulse bg-muted" }),
267
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-2.5 w-2/5 rounded-md animate-pulse bg-muted" })
268
+ ] }),
269
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "px-2 pb-2 flex gap-1.5", children: [
270
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-8 flex-1 rounded-[11px] animate-pulse bg-muted" }),
271
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-8 w-8 rounded-[11px] animate-pulse bg-muted shrink-0" }),
272
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-8 w-8 rounded-[11px] animate-pulse bg-muted shrink-0" })
273
+ ] })
274
+ ] });
275
+ }
276
+ // Annotate the CommonJS export names for ESM import in node:
277
+ 0 && (module.exports = {
278
+ TokenCard,
279
+ TokenCardSkeleton
280
+ });
281
+ //# sourceMappingURL=token-card.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/token-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport {\n ShoppingCart, Tag, ArrowRightLeft, X, Loader2, HandCoins,\n Check, ArrowUpRight, Zap,\n} from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { MotionCard } from \"./motion-primitives.js\";\nimport type { ApiToken } from \"@medialane/sdk\";\n\nexport type RarityTier = \"legendary\" | \"epic\" | \"rare\" | \"uncommon\" | \"common\";\n\nconst RARITY_STYLE: Record<RarityTier, { label: string; className: string } | null> = {\n legendary: { label: \"Legendary\", className: \"bg-yellow-400/90 text-yellow-900\" },\n epic: { label: \"Epic\", className: \"bg-purple-500/85 text-white\" },\n rare: { label: \"Rare\", className: \"bg-blue-500/85 text-white\" },\n uncommon: { label: \"Uncommon\", className: \"bg-emerald-500/85 text-white\" },\n common: null,\n};\n\nconst BTN_BASE = \"h-8 rounded-[11px] flex items-center justify-center gap-1.5 text-xs font-semibold transition-all active:scale-[0.98] shadow-none border-0\";\nconst BTN_SOLID = cn(BTN_BASE, \"text-white hover:brightness-110\");\nconst BTN_OUTLINE = cn(BTN_BASE, \"border border-border/60 text-foreground hover:bg-muted/60\");\n\nexport interface TokenCardProps {\n token: ApiToken;\n /** Whether the current user owns this token. Default: false */\n isOwner?: boolean;\n /** Whether this token's listing is already in the cart. Default: false */\n inCart?: boolean;\n /** Show the Buy button for listed tokens. Default: true */\n showBuyButton?: boolean;\n /** Optional rarity label shown as an overlay badge */\n rarityTier?: RarityTier;\n className?: string;\n /** Callbacks — omit any to hide that button */\n onBuy?: (token: ApiToken) => void;\n onCart?: (token: ApiToken) => void;\n onOffer?: (token: ApiToken) => void;\n onList?: (token: ApiToken) => void;\n onCancel?: (token: ApiToken) => void;\n onTransfer?: (token: ApiToken) => void;\n onRemix?: (token: ApiToken) => void;\n onReport?: (token: ApiToken) => void;\n /** Slot for a DropdownMenu trigger — rendered after primary buttons */\n overflowMenu?: React.ReactNode;\n}\n\nexport function TokenCard({\n token,\n isOwner = false,\n inCart = false,\n showBuyButton = true,\n rarityTier,\n className,\n onBuy,\n onCart,\n onOffer,\n onList,\n onCancel,\n onTransfer,\n overflowMenu,\n}: TokenCardProps) {\n const [imgError, setImgError] = useState(false);\n\n const name = token.metadata?.name || `Token #${token.tokenId}`;\n const image = ipfsToHttp(token.metadata?.image);\n const activeOrder = token.activeOrders?.[0];\n const assetHref = `/asset/${token.contractAddress}/${token.tokenId}`;\n\n const renderActions = () => {\n // Non-owner + listed + showBuyButton\n if (!isOwner && activeOrder && showBuyButton) {\n return (\n <>\n {onBuy && (\n <button\n className={cn(BTN_SOLID, \"flex-1 bg-brand-purple\")}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onBuy(token); }}\n >\n <Zap className=\"h-3.5 w-3.5 shrink-0\" />\n Buy\n </button>\n )}\n {onCart && (\n <button\n className={cn(\n BTN_OUTLINE, \"w-8 shrink-0\",\n inCart && \"border-brand-orange/50 bg-brand-orange/10 text-brand-orange\"\n )}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onCart(token); }}\n disabled={inCart}\n aria-label={inCart ? \"In cart\" : \"Add to cart\"}\n >\n {inCart ? <Check className=\"h-3.5 w-3.5\" /> : <ShoppingCart className=\"h-3.5 w-3.5\" />}\n </button>\n )}\n {onOffer && (\n <button\n className={cn(BTN_OUTLINE, \"w-8 shrink-0 text-brand-orange border-brand-orange/40 hover:bg-brand-orange/10\")}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onOffer(token); }}\n aria-label=\"Make an offer\"\n >\n <HandCoins className=\"h-3.5 w-3.5\" />\n </button>\n )}\n </>\n );\n }\n\n // Non-owner + no listing (or showBuyButton=false)\n if (!isOwner) {\n if (!onOffer) return null;\n return (\n <>\n <Link href={assetHref} className={cn(BTN_OUTLINE, \"flex-1\")}>\n <ArrowUpRight className=\"h-3.5 w-3.5 shrink-0\" />\n View\n </Link>\n <button\n className={cn(BTN_OUTLINE, \"w-8 shrink-0 text-brand-orange border-brand-orange/40 hover:bg-brand-orange/10\")}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onOffer(token); }}\n aria-label=\"Make an offer\"\n >\n <HandCoins className=\"h-3.5 w-3.5\" />\n </button>\n </>\n );\n }\n\n // Owner + listed\n if (isOwner && activeOrder) {\n if (!onCancel) return null;\n return (\n <>\n <button\n className={cn(BTN_SOLID, \"flex-1 bg-brand-rose\")}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onCancel(token); }}\n >\n <X className=\"h-3.5 w-3.5 shrink-0\" />\n Cancel listing\n </button>\n {onTransfer && (\n <button\n className={cn(BTN_OUTLINE, \"w-8 shrink-0\")}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onTransfer(token); }}\n aria-label=\"Transfer\"\n >\n <ArrowRightLeft className=\"h-3.5 w-3.5\" />\n </button>\n )}\n </>\n );\n }\n\n // Owner + unlisted\n if (isOwner && !activeOrder) {\n if (!onList) return null;\n return (\n <>\n <button\n className={cn(BTN_SOLID, \"flex-1 bg-brand-blue\")}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onList(token); }}\n >\n <Tag className=\"h-3.5 w-3.5 shrink-0\" />\n List for sale\n </button>\n {onTransfer && (\n <button\n className={cn(BTN_OUTLINE, \"w-8 shrink-0\")}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onTransfer(token); }}\n aria-label=\"Transfer\"\n >\n <ArrowRightLeft className=\"h-3.5 w-3.5\" />\n </button>\n )}\n </>\n );\n }\n\n return null;\n };\n\n const actionContent = renderActions();\n const showActionBar = actionContent != null || !!overflowMenu;\n\n return (\n <MotionCard className={cn(\"card-base group relative overflow-hidden flex flex-col\", className)}>\n <Link href={assetHref} className=\"block relative shrink-0\">\n <div className=\"relative aspect-square bg-muted overflow-hidden\">\n {!imgError ? (\n <Image\n src={image}\n alt={name}\n fill\n unoptimized\n sizes=\"(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 22vw\"\n className=\"object-cover transition-transform duration-500 group-hover:scale-105\"\n onError={() => setImgError(true)}\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\">\n <span className=\"text-2xl font-mono text-muted-foreground\">#{token.tokenId}</span>\n </div>\n )}\n\n {token.metadata?.ipType && (\n <div className=\"absolute top-2 left-2\">\n <IpTypeBadge ipType={token.metadata.ipType as any} size=\"sm\" />\n </div>\n )}\n\n {rarityTier && RARITY_STYLE[rarityTier] && (\n <div className=\"absolute top-2 right-2 z-10\">\n <span className={cn(\n \"inline-flex items-center px-1.5 py-0.5 rounded-md backdrop-blur-sm text-[10px] font-bold leading-none\",\n RARITY_STYLE[rarityTier]!.className\n )}>\n {RARITY_STYLE[rarityTier]!.label}\n </span>\n </div>\n )}\n\n {(token.metadataStatus === \"PENDING\" || token.metadataStatus === \"FETCHING\") && (\n <div className=\"absolute bottom-0 inset-x-0 flex items-center justify-center gap-1.5 bg-black/50 backdrop-blur-sm py-1.5\">\n <Loader2 className=\"h-3 w-3 animate-spin text-white/70\" />\n <span className=\"text-[10px] text-white/70\">Indexing…</span>\n </div>\n )}\n </div>\n </Link>\n\n <div className=\"px-3 pt-2.5 pb-1 flex-1\">\n <Link href={assetHref} className=\"block space-y-0.5 mb-2\">\n <p className=\"text-xl font-bold line-clamp-2 leading-tight\">{name}</p>\n {activeOrder && (\n <p className=\"flex items-center gap-1 text-[11px] font-semibold text-foreground/80\">\n <CurrencyIcon symbol={activeOrder.price.currency} size={11} />\n {formatDisplayPrice(activeOrder.price.formatted)}\n <span className=\"font-normal text-muted-foreground\">{activeOrder.price.currency}</span>\n </p>\n )}\n {token.metadata?.description ? (\n <p className=\"text-[10px] text-muted-foreground truncate leading-snug\">\n {token.metadata.description}\n </p>\n ) : token.metadata?.ipType ? (\n <p className=\"text-[10px] text-muted-foreground opacity-70\">{token.metadata.ipType}</p>\n ) : null}\n </Link>\n </div>\n\n {showActionBar && (\n <div className=\"flex items-center gap-1.5 px-2 pb-2\">\n {actionContent}\n {overflowMenu}\n </div>\n )}\n </MotionCard>\n );\n}\n\nexport function TokenCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"aspect-square w-full animate-pulse bg-muted\" />\n <div className=\"px-3 pt-2.5 pb-2 space-y-1.5\">\n <div className=\"h-5 w-3/4 rounded-md animate-pulse bg-muted\" />\n <div className=\"h-2.5 w-2/5 rounded-md animate-pulse bg-muted\" />\n </div>\n <div className=\"px-2 pb-2 flex gap-1.5\">\n <div className=\"h-8 flex-1 rounded-[11px] animate-pulse bg-muted\" />\n <div className=\"h-8 w-8 rounded-[11px] animate-pulse bg-muted shrink-0\" />\n <div className=\"h-8 w-8 rounded-[11px] animate-pulse bg-muted shrink-0\" />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["Link","Image"]}
@@ -0,0 +1,31 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ApiToken } from '@medialane/sdk';
3
+
4
+ type RarityTier = "legendary" | "epic" | "rare" | "uncommon" | "common";
5
+ interface TokenCardProps {
6
+ token: ApiToken;
7
+ /** Whether the current user owns this token. Default: false */
8
+ isOwner?: boolean;
9
+ /** Whether this token's listing is already in the cart. Default: false */
10
+ inCart?: boolean;
11
+ /** Show the Buy button for listed tokens. Default: true */
12
+ showBuyButton?: boolean;
13
+ /** Optional rarity label shown as an overlay badge */
14
+ rarityTier?: RarityTier;
15
+ className?: string;
16
+ /** Callbacks — omit any to hide that button */
17
+ onBuy?: (token: ApiToken) => void;
18
+ onCart?: (token: ApiToken) => void;
19
+ onOffer?: (token: ApiToken) => void;
20
+ onList?: (token: ApiToken) => void;
21
+ onCancel?: (token: ApiToken) => void;
22
+ onTransfer?: (token: ApiToken) => void;
23
+ onRemix?: (token: ApiToken) => void;
24
+ onReport?: (token: ApiToken) => void;
25
+ /** Slot for a DropdownMenu trigger — rendered after primary buttons */
26
+ overflowMenu?: React.ReactNode;
27
+ }
28
+ declare function TokenCard({ token, isOwner, inCart, showBuyButton, rarityTier, className, onBuy, onCart, onOffer, onList, onCancel, onTransfer, overflowMenu, }: TokenCardProps): react_jsx_runtime.JSX.Element;
29
+ declare function TokenCardSkeleton(): react_jsx_runtime.JSX.Element;
30
+
31
+ export { type RarityTier, TokenCard, type TokenCardProps, TokenCardSkeleton };
@@ -0,0 +1,31 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ApiToken } from '@medialane/sdk';
3
+
4
+ type RarityTier = "legendary" | "epic" | "rare" | "uncommon" | "common";
5
+ interface TokenCardProps {
6
+ token: ApiToken;
7
+ /** Whether the current user owns this token. Default: false */
8
+ isOwner?: boolean;
9
+ /** Whether this token's listing is already in the cart. Default: false */
10
+ inCart?: boolean;
11
+ /** Show the Buy button for listed tokens. Default: true */
12
+ showBuyButton?: boolean;
13
+ /** Optional rarity label shown as an overlay badge */
14
+ rarityTier?: RarityTier;
15
+ className?: string;
16
+ /** Callbacks — omit any to hide that button */
17
+ onBuy?: (token: ApiToken) => void;
18
+ onCart?: (token: ApiToken) => void;
19
+ onOffer?: (token: ApiToken) => void;
20
+ onList?: (token: ApiToken) => void;
21
+ onCancel?: (token: ApiToken) => void;
22
+ onTransfer?: (token: ApiToken) => void;
23
+ onRemix?: (token: ApiToken) => void;
24
+ onReport?: (token: ApiToken) => void;
25
+ /** Slot for a DropdownMenu trigger — rendered after primary buttons */
26
+ overflowMenu?: React.ReactNode;
27
+ }
28
+ declare function TokenCard({ token, isOwner, inCart, showBuyButton, rarityTier, className, onBuy, onCart, onOffer, onList, onCancel, onTransfer, overflowMenu, }: TokenCardProps): react_jsx_runtime.JSX.Element;
29
+ declare function TokenCardSkeleton(): react_jsx_runtime.JSX.Element;
30
+
31
+ export { type RarityTier, TokenCard, type TokenCardProps, TokenCardSkeleton };
@@ -0,0 +1,256 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import Link from "next/link";
5
+ import Image from "next/image";
6
+ import {
7
+ ShoppingCart,
8
+ Tag,
9
+ ArrowRightLeft,
10
+ X,
11
+ Loader2,
12
+ HandCoins,
13
+ Check,
14
+ ArrowUpRight,
15
+ Zap
16
+ } from "lucide-react";
17
+ import { cn } from "../utils/cn.js";
18
+ import { ipfsToHttp } from "../utils/ipfs.js";
19
+ import { formatDisplayPrice } from "../utils/format.js";
20
+ import { CurrencyIcon } from "./currency-icon.js";
21
+ import { IpTypeBadge } from "./ip-type-badge.js";
22
+ import { MotionCard } from "./motion-primitives.js";
23
+ const RARITY_STYLE = {
24
+ legendary: { label: "Legendary", className: "bg-yellow-400/90 text-yellow-900" },
25
+ epic: { label: "Epic", className: "bg-purple-500/85 text-white" },
26
+ rare: { label: "Rare", className: "bg-blue-500/85 text-white" },
27
+ uncommon: { label: "Uncommon", className: "bg-emerald-500/85 text-white" },
28
+ common: null
29
+ };
30
+ const BTN_BASE = "h-8 rounded-[11px] flex items-center justify-center gap-1.5 text-xs font-semibold transition-all active:scale-[0.98] shadow-none border-0";
31
+ const BTN_SOLID = cn(BTN_BASE, "text-white hover:brightness-110");
32
+ const BTN_OUTLINE = cn(BTN_BASE, "border border-border/60 text-foreground hover:bg-muted/60");
33
+ function TokenCard({
34
+ token,
35
+ isOwner = false,
36
+ inCart = false,
37
+ showBuyButton = true,
38
+ rarityTier,
39
+ className,
40
+ onBuy,
41
+ onCart,
42
+ onOffer,
43
+ onList,
44
+ onCancel,
45
+ onTransfer,
46
+ overflowMenu
47
+ }) {
48
+ const [imgError, setImgError] = useState(false);
49
+ const name = token.metadata?.name || `Token #${token.tokenId}`;
50
+ const image = ipfsToHttp(token.metadata?.image);
51
+ const activeOrder = token.activeOrders?.[0];
52
+ const assetHref = `/asset/${token.contractAddress}/${token.tokenId}`;
53
+ const renderActions = () => {
54
+ if (!isOwner && activeOrder && showBuyButton) {
55
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
56
+ onBuy && /* @__PURE__ */ jsxs(
57
+ "button",
58
+ {
59
+ className: cn(BTN_SOLID, "flex-1 bg-brand-purple"),
60
+ onClick: (e) => {
61
+ e.preventDefault();
62
+ e.stopPropagation();
63
+ onBuy(token);
64
+ },
65
+ children: [
66
+ /* @__PURE__ */ jsx(Zap, { className: "h-3.5 w-3.5 shrink-0" }),
67
+ "Buy"
68
+ ]
69
+ }
70
+ ),
71
+ onCart && /* @__PURE__ */ jsx(
72
+ "button",
73
+ {
74
+ className: cn(
75
+ BTN_OUTLINE,
76
+ "w-8 shrink-0",
77
+ inCart && "border-brand-orange/50 bg-brand-orange/10 text-brand-orange"
78
+ ),
79
+ onClick: (e) => {
80
+ e.preventDefault();
81
+ e.stopPropagation();
82
+ onCart(token);
83
+ },
84
+ disabled: inCart,
85
+ "aria-label": inCart ? "In cart" : "Add to cart",
86
+ children: inCart ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(ShoppingCart, { className: "h-3.5 w-3.5" })
87
+ }
88
+ ),
89
+ onOffer && /* @__PURE__ */ jsx(
90
+ "button",
91
+ {
92
+ className: cn(BTN_OUTLINE, "w-8 shrink-0 text-brand-orange border-brand-orange/40 hover:bg-brand-orange/10"),
93
+ onClick: (e) => {
94
+ e.preventDefault();
95
+ e.stopPropagation();
96
+ onOffer(token);
97
+ },
98
+ "aria-label": "Make an offer",
99
+ children: /* @__PURE__ */ jsx(HandCoins, { className: "h-3.5 w-3.5" })
100
+ }
101
+ )
102
+ ] });
103
+ }
104
+ if (!isOwner) {
105
+ if (!onOffer) return null;
106
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
107
+ /* @__PURE__ */ jsxs(Link, { href: assetHref, className: cn(BTN_OUTLINE, "flex-1"), children: [
108
+ /* @__PURE__ */ jsx(ArrowUpRight, { className: "h-3.5 w-3.5 shrink-0" }),
109
+ "View"
110
+ ] }),
111
+ /* @__PURE__ */ jsx(
112
+ "button",
113
+ {
114
+ className: cn(BTN_OUTLINE, "w-8 shrink-0 text-brand-orange border-brand-orange/40 hover:bg-brand-orange/10"),
115
+ onClick: (e) => {
116
+ e.preventDefault();
117
+ e.stopPropagation();
118
+ onOffer(token);
119
+ },
120
+ "aria-label": "Make an offer",
121
+ children: /* @__PURE__ */ jsx(HandCoins, { className: "h-3.5 w-3.5" })
122
+ }
123
+ )
124
+ ] });
125
+ }
126
+ if (isOwner && activeOrder) {
127
+ if (!onCancel) return null;
128
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
129
+ /* @__PURE__ */ jsxs(
130
+ "button",
131
+ {
132
+ className: cn(BTN_SOLID, "flex-1 bg-brand-rose"),
133
+ onClick: (e) => {
134
+ e.preventDefault();
135
+ e.stopPropagation();
136
+ onCancel(token);
137
+ },
138
+ children: [
139
+ /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5 shrink-0" }),
140
+ "Cancel listing"
141
+ ]
142
+ }
143
+ ),
144
+ onTransfer && /* @__PURE__ */ jsx(
145
+ "button",
146
+ {
147
+ className: cn(BTN_OUTLINE, "w-8 shrink-0"),
148
+ onClick: (e) => {
149
+ e.preventDefault();
150
+ e.stopPropagation();
151
+ onTransfer(token);
152
+ },
153
+ "aria-label": "Transfer",
154
+ children: /* @__PURE__ */ jsx(ArrowRightLeft, { className: "h-3.5 w-3.5" })
155
+ }
156
+ )
157
+ ] });
158
+ }
159
+ if (isOwner && !activeOrder) {
160
+ if (!onList) return null;
161
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
162
+ /* @__PURE__ */ jsxs(
163
+ "button",
164
+ {
165
+ className: cn(BTN_SOLID, "flex-1 bg-brand-blue"),
166
+ onClick: (e) => {
167
+ e.preventDefault();
168
+ e.stopPropagation();
169
+ onList(token);
170
+ },
171
+ children: [
172
+ /* @__PURE__ */ jsx(Tag, { className: "h-3.5 w-3.5 shrink-0" }),
173
+ "List for sale"
174
+ ]
175
+ }
176
+ ),
177
+ onTransfer && /* @__PURE__ */ jsx(
178
+ "button",
179
+ {
180
+ className: cn(BTN_OUTLINE, "w-8 shrink-0"),
181
+ onClick: (e) => {
182
+ e.preventDefault();
183
+ e.stopPropagation();
184
+ onTransfer(token);
185
+ },
186
+ "aria-label": "Transfer",
187
+ children: /* @__PURE__ */ jsx(ArrowRightLeft, { className: "h-3.5 w-3.5" })
188
+ }
189
+ )
190
+ ] });
191
+ }
192
+ return null;
193
+ };
194
+ const actionContent = renderActions();
195
+ const showActionBar = actionContent != null || !!overflowMenu;
196
+ return /* @__PURE__ */ jsxs(MotionCard, { className: cn("card-base group relative overflow-hidden flex flex-col", className), children: [
197
+ /* @__PURE__ */ jsx(Link, { href: assetHref, className: "block relative shrink-0", children: /* @__PURE__ */ jsxs("div", { className: "relative aspect-square bg-muted overflow-hidden", children: [
198
+ !imgError ? /* @__PURE__ */ jsx(
199
+ Image,
200
+ {
201
+ src: image,
202
+ alt: name,
203
+ fill: true,
204
+ unoptimized: true,
205
+ sizes: "(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 22vw",
206
+ className: "object-cover transition-transform duration-500 group-hover:scale-105",
207
+ onError: () => setImgError(true)
208
+ }
209
+ ) : /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-gradient-to-br from-brand-purple/15 to-brand-blue/15", children: /* @__PURE__ */ jsxs("span", { className: "text-2xl font-mono text-muted-foreground", children: [
210
+ "#",
211
+ token.tokenId
212
+ ] }) }),
213
+ token.metadata?.ipType && /* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2", children: /* @__PURE__ */ jsx(IpTypeBadge, { ipType: token.metadata.ipType, size: "sm" }) }),
214
+ rarityTier && RARITY_STYLE[rarityTier] && /* @__PURE__ */ jsx("div", { className: "absolute top-2 right-2 z-10", children: /* @__PURE__ */ jsx("span", { className: cn(
215
+ "inline-flex items-center px-1.5 py-0.5 rounded-md backdrop-blur-sm text-[10px] font-bold leading-none",
216
+ RARITY_STYLE[rarityTier].className
217
+ ), children: RARITY_STYLE[rarityTier].label }) }),
218
+ (token.metadataStatus === "PENDING" || token.metadataStatus === "FETCHING") && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 inset-x-0 flex items-center justify-center gap-1.5 bg-black/50 backdrop-blur-sm py-1.5", children: [
219
+ /* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 animate-spin text-white/70" }),
220
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-white/70", children: "Indexing\u2026" })
221
+ ] })
222
+ ] }) }),
223
+ /* @__PURE__ */ jsx("div", { className: "px-3 pt-2.5 pb-1 flex-1", children: /* @__PURE__ */ jsxs(Link, { href: assetHref, className: "block space-y-0.5 mb-2", children: [
224
+ /* @__PURE__ */ jsx("p", { className: "text-xl font-bold line-clamp-2 leading-tight", children: name }),
225
+ activeOrder && /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-1 text-[11px] font-semibold text-foreground/80", children: [
226
+ /* @__PURE__ */ jsx(CurrencyIcon, { symbol: activeOrder.price.currency, size: 11 }),
227
+ formatDisplayPrice(activeOrder.price.formatted),
228
+ /* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: activeOrder.price.currency })
229
+ ] }),
230
+ token.metadata?.description ? /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground truncate leading-snug", children: token.metadata.description }) : token.metadata?.ipType ? /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground opacity-70", children: token.metadata.ipType }) : null
231
+ ] }) }),
232
+ showActionBar && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2 pb-2", children: [
233
+ actionContent,
234
+ overflowMenu
235
+ ] })
236
+ ] });
237
+ }
238
+ function TokenCardSkeleton() {
239
+ return /* @__PURE__ */ jsxs("div", { className: "card-base overflow-hidden", children: [
240
+ /* @__PURE__ */ jsx("div", { className: "aspect-square w-full animate-pulse bg-muted" }),
241
+ /* @__PURE__ */ jsxs("div", { className: "px-3 pt-2.5 pb-2 space-y-1.5", children: [
242
+ /* @__PURE__ */ jsx("div", { className: "h-5 w-3/4 rounded-md animate-pulse bg-muted" }),
243
+ /* @__PURE__ */ jsx("div", { className: "h-2.5 w-2/5 rounded-md animate-pulse bg-muted" })
244
+ ] }),
245
+ /* @__PURE__ */ jsxs("div", { className: "px-2 pb-2 flex gap-1.5", children: [
246
+ /* @__PURE__ */ jsx("div", { className: "h-8 flex-1 rounded-[11px] animate-pulse bg-muted" }),
247
+ /* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-[11px] animate-pulse bg-muted shrink-0" }),
248
+ /* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-[11px] animate-pulse bg-muted shrink-0" })
249
+ ] })
250
+ ] });
251
+ }
252
+ export {
253
+ TokenCard,
254
+ TokenCardSkeleton
255
+ };
256
+ //# sourceMappingURL=token-card.js.map