@medialane/ui 0.14.0 → 0.15.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.
- package/README.md +31 -5
- package/dist/components/coin-card.cjs +131 -0
- package/dist/components/coin-card.cjs.map +1 -0
- package/dist/components/coin-card.d.cts +19 -0
- package/dist/components/coin-card.d.ts +19 -0
- package/dist/components/coin-card.js +99 -0
- package/dist/components/coin-card.js.map +1 -0
- package/dist/components/coins-explorer.cjs +117 -0
- package/dist/components/coins-explorer.cjs.map +1 -0
- package/dist/components/coins-explorer.d.cts +23 -0
- package/dist/components/coins-explorer.d.ts +23 -0
- package/dist/components/coins-explorer.js +93 -0
- package/dist/components/coins-explorer.js.map +1 -0
- package/dist/data/coins.cjs +48 -0
- package/dist/data/coins.cjs.map +1 -0
- package/dist/data/coins.d.cts +33 -0
- package/dist/data/coins.d.ts +33 -0
- package/dist/data/coins.js +22 -0
- package/dist/data/coins.js.map +1 -0
- package/dist/index.cjs +17 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -173,16 +173,37 @@ import {
|
|
|
173
173
|
|
|
174
174
|
---
|
|
175
175
|
|
|
176
|
-
###
|
|
176
|
+
### Launchpad (single page-UI source since v0.8)
|
|
177
177
|
|
|
178
178
|
```ts
|
|
179
|
-
import {
|
|
179
|
+
import { LaunchpadGroupedSections, LaunchpadStrip, LAUNCHPAD_SERVICE_DEFINITIONS, SERVICE_HUES } from "@medialane/ui";
|
|
180
180
|
```
|
|
181
181
|
|
|
182
182
|
| Export | Description |
|
|
183
183
|
|---|---|
|
|
184
|
-
| `<
|
|
185
|
-
|
|
|
184
|
+
| `<LaunchpadGroupedSections overrides={...} />` | The full grouped launchpad page UI — apps inject only hrefs / per-app rollout flips |
|
|
185
|
+
| `<LaunchpadStrip hrefs={...} />` | Homepage launchpad carousel — cards derive from the shared service definitions |
|
|
186
|
+
| `LAUNCHPAD_SERVICE_DEFINITIONS` / `SERVICE_HUES` | Canonical service copy (titles, blurbs, examples) + one unique hue per service |
|
|
187
|
+
|
|
188
|
+
### Asset page modules (v0.13+)
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import { AssetOverviewContent, AssetMarketsTab, AssetMediaColumn, AssetHeaderBlock, ParentAttributionBanner, IPTypeDisplay } from "@medialane/ui";
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Shared presentation modules for the asset detail pages — both apps re-export
|
|
195
|
+
them as shims at their original paths and inject wallet hooks/dialogs locally.
|
|
196
|
+
|
|
197
|
+
### IP data layer (v0.13+)
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { IP_TYPES, LICENSE_TYPES, IP_TEMPLATES, DOC_UPLOAD, TEMPLATE_TRAIT_TYPES } from "@medialane/ui";
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Canonical IP types, license presets, and per-type templates (embeds, socials,
|
|
204
|
+
trait suggestions, and the `docUpload` config powering the document/PDF-to-IPFS
|
|
205
|
+
upload on Documents / Patents / Publications / Software). The apps' `types/ip`
|
|
206
|
+
and `lib/ip-templates` are re-export shims of this layer — edit here, never there.
|
|
186
207
|
|
|
187
208
|
---
|
|
188
209
|
|
|
@@ -212,7 +233,12 @@ The package uses [tsup](https://tsup.egoist.dev/) and outputs ESM + CJS + type d
|
|
|
212
233
|
|
|
213
234
|
| Version | Added |
|
|
214
235
|
|---|---|
|
|
215
|
-
| **v0.
|
|
236
|
+
| **v0.14.0** | `docUpload` template config + `DOC_UPLOAD` (document/PDF → IPFS for Documents/Patents/Publications/Software), `IPTypeDisplay` document card |
|
|
237
|
+
| **v0.13.x** | Asset-page modules lifted: `AssetOverviewContent`, `AssetMarketsTab`, `AssetMediaColumn`/`AssetHeaderBlock`, `ParentAttributionBanner`, `IPTypeDisplay`; IP data layer (`data/ip`, `data/ip-templates`); `timeUntil` |
|
|
238
|
+
| **v0.12.x** | `LaunchpadStrip` (homepage carousel from service defs); Discover strips restyled to the approved design; `CollectionCard` gated-content border + currency floor |
|
|
239
|
+
| **v0.11.x** | `DiscoverFeedSection` rebuilt as carousels; `ActivityCard`; coins live in shared service defaults |
|
|
240
|
+
| **v0.8–0.10** | `LaunchpadGroupedSections` + creator-first card redesign (chips, examples, gradient section titles); `PageContainer`, `NavCommandMenu`, `PortfolioSubnav` |
|
|
241
|
+
| **v0.4.0** | `LaunchpadServicesGrid` (removed in v0.8), `LAUNCHPAD_SERVICE_DEFINITIONS` |
|
|
216
242
|
| **v0.3.2** | `DiscoverHero`, `FeaturedCarousel`, `DiscoverCollectionsStrip`, `DiscoverCreatorsStrip`, `DiscoverFeedSection` |
|
|
217
243
|
| **v0.3.0** | `ActivityRow`, `ActivityFeedShell`, `ActivityTicker`, `HeroSlider`, `ListingCard`, `LaunchpadGrid`, `CtaCardGrid`, `timeAgo`, `ACTIVITY_TYPE_CONFIG` |
|
|
218
244
|
| **v0.2.0** | `MotionCard`, `FadeIn`, `Stagger`, `StaggerItem`, `KineticWords`, `ScrollSection`, `ShareButton`, `CollectionCard`, `TokenCard` |
|
|
@@ -0,0 +1,131 @@
|
|
|
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 coin_card_exports = {};
|
|
31
|
+
__export(coin_card_exports, {
|
|
32
|
+
CoinCard: () => CoinCard,
|
|
33
|
+
CoinCardSkeleton: () => CoinCardSkeleton,
|
|
34
|
+
CoinRow: () => CoinRow
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(coin_card_exports);
|
|
37
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
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_coins = require("../data/coins.js");
|
|
44
|
+
const KIND_TAG = {
|
|
45
|
+
creator: "border-brand-purple/30 bg-brand-purple/10 text-brand-purple",
|
|
46
|
+
memecoin: "border-brand-rose/30 bg-brand-rose/10 text-brand-rose"
|
|
47
|
+
};
|
|
48
|
+
function useTileModel({ collection, usePrice }) {
|
|
49
|
+
const { price, isLoading } = usePrice(collection);
|
|
50
|
+
const kind = (0, import_coins.coinKind)(collection.service);
|
|
51
|
+
const verified = collection.claimedBy != null || kind === "creator";
|
|
52
|
+
const logoUri = collection.profile?.image ?? collection.image;
|
|
53
|
+
const logo = logoUri ? (0, import_ipfs.ipfsToHttp)(logoUri) : null;
|
|
54
|
+
const initials = (collection.symbol ?? collection.name ?? "?").trim().slice(0, 2).toUpperCase();
|
|
55
|
+
const fdv = (0, import_coins.formatFdv)(price?.quotePerCoin, collection.totalSupply, price?.quoteSymbol ?? null);
|
|
56
|
+
const chain = (collection.chain ?? "").toString().toLowerCase();
|
|
57
|
+
return { price, isLoading, kind, verified, logo, initials, fdv, chain };
|
|
58
|
+
}
|
|
59
|
+
function PriceSkel({ wide }) {
|
|
60
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: (0, import_cn.cn)("inline-block h-4 rounded bg-muted-foreground/20 animate-pulse", wide ? "w-16" : "w-12") });
|
|
61
|
+
}
|
|
62
|
+
function CoinCard({ collection, usePrice, href }) {
|
|
63
|
+
const m = useTileModel({ collection, usePrice });
|
|
64
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_link.default, { href, className: "flex flex-col rounded-xl border border-border/60 bg-card overflow-hidden transition-transform active:scale-[0.99]", children: [
|
|
65
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-3 p-4", children: [
|
|
66
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative h-12 w-12 shrink-0 rounded-full overflow-hidden bg-muted", children: m.logo ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_image.default, { src: m.logo, alt: "", fill: true, sizes: "48px", className: "object-cover", unoptimized: true }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex h-full w-full items-center justify-center bg-gradient-to-br from-brand-blue to-brand-purple text-sm font-bold text-white", children: m.initials }) }),
|
|
67
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
68
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
69
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate font-semibold", children: collection.name ?? "Untitled coin" }),
|
|
70
|
+
m.verified && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.BadgeCheck, { className: "h-4 w-4 shrink-0 text-primary", "aria-label": "Verified" })
|
|
71
|
+
] }),
|
|
72
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm text-muted-foreground", children: collection.symbol ?? "\u2014" })
|
|
73
|
+
] }),
|
|
74
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: (0, import_cn.cn)("shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-medium", KIND_TAG[m.kind]), children: m.kind === "creator" ? "Creator Coin" : "Memecoin" })
|
|
75
|
+
] }),
|
|
76
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid grid-cols-3 gap-2 border-t border-border/60 px-4 py-3 text-sm", children: [
|
|
77
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Stat, { label: "Price", children: m.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PriceSkel, {}) : m.price ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-semibold", children: (0, import_coins.formatCoinPrice)(m.price.quotePerCoin) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-muted-foreground", children: "\u2014" }) }),
|
|
78
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Stat, { label: "FDV", children: m.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PriceSkel, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-semibold", children: m.fdv ?? "\u2014" }) }),
|
|
79
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Stat, { label: "Holders", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "inline-flex items-center gap-1 font-semibold", children: [
|
|
80
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Users, { className: "h-3 w-3 text-muted-foreground" }),
|
|
81
|
+
collection.holderCount || "\u2014"
|
|
82
|
+
] }) })
|
|
83
|
+
] }),
|
|
84
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between border-t border-border/60 px-4 py-2.5 text-sm", children: [
|
|
85
|
+
m.chain ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: m.chain }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {}),
|
|
86
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-medium text-primary", children: "Trade" })
|
|
87
|
+
] })
|
|
88
|
+
] });
|
|
89
|
+
}
|
|
90
|
+
function CoinRow({ collection, usePrice, href }) {
|
|
91
|
+
const m = useTileModel({ collection, usePrice });
|
|
92
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_link.default, { href, className: "flex items-center gap-3 rounded-lg border border-border/60 bg-card px-3 py-2.5 transition-colors hover:border-primary/40", children: [
|
|
93
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative h-9 w-9 shrink-0 overflow-hidden rounded-full bg-muted", children: m.logo ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_image.default, { src: m.logo, alt: "", fill: true, sizes: "36px", className: "object-cover", unoptimized: true }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex h-full w-full items-center justify-center bg-gradient-to-br from-brand-blue to-brand-purple text-[11px] font-bold text-white", children: m.initials }) }),
|
|
94
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
95
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
96
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate text-sm font-semibold", children: collection.name ?? "Untitled coin" }),
|
|
97
|
+
m.verified && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.BadgeCheck, { className: "h-3.5 w-3.5 shrink-0 text-primary", "aria-label": "Verified" })
|
|
98
|
+
] }),
|
|
99
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs text-muted-foreground", children: collection.symbol ?? "\u2014" })
|
|
100
|
+
] }),
|
|
101
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: (0, import_cn.cn)("hidden shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-medium sm:inline-block", KIND_TAG[m.kind]), children: m.kind === "creator" ? "Creator Coin" : "Memecoin" }),
|
|
102
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "w-24 shrink-0 text-right text-sm font-semibold tabular-nums", children: m.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-auto inline-block h-4 w-12 rounded bg-muted-foreground/20 animate-pulse" }) : m.price ? (0, import_coins.formatCoinPrice)(m.price.quotePerCoin) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-muted-foreground", children: "\u2014" }) }),
|
|
103
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hidden shrink-0 text-sm font-medium text-primary sm:inline-block", children: "Trade" })
|
|
104
|
+
] });
|
|
105
|
+
}
|
|
106
|
+
function Stat({ label, children }) {
|
|
107
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
|
|
108
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: label }),
|
|
109
|
+
children
|
|
110
|
+
] });
|
|
111
|
+
}
|
|
112
|
+
function CoinCardSkeleton() {
|
|
113
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col rounded-xl border border-border/60 bg-card overflow-hidden", children: [
|
|
114
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-3 p-4", children: [
|
|
115
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-12 w-12 rounded-full bg-muted animate-pulse" }),
|
|
116
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 space-y-1.5", children: [
|
|
117
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-4 w-24 rounded bg-muted-foreground/20 animate-pulse" }),
|
|
118
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-3 w-12 rounded bg-muted-foreground/20 animate-pulse" })
|
|
119
|
+
] })
|
|
120
|
+
] }),
|
|
121
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-3 gap-2 border-t border-border/60 px-4 py-3", children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-8 w-full rounded bg-muted-foreground/10 animate-pulse" }, i)) }),
|
|
122
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-9 w-full bg-muted-foreground/10 animate-pulse" })
|
|
123
|
+
] });
|
|
124
|
+
}
|
|
125
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
126
|
+
0 && (module.exports = {
|
|
127
|
+
CoinCard,
|
|
128
|
+
CoinCardSkeleton,
|
|
129
|
+
CoinRow
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=coin-card.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/coin-card.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * CoinCard / CoinRow — chain-agnostic coin discovery tiles.\n *\n * Pure presentation: the price read (`usePrice`) and the link target (`href`)\n * are injected by the consuming app, and the collection is typed structurally\n * (CoinCollectionLike) — so a coin on Starknet, Ethereum, or Solana renders the\n * same with zero changes here. `chain` is shown as a badge.\n */\n\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { BadgeCheck, Users } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport {\n coinKind, formatCoinPrice, formatFdv,\n type CoinCollectionLike, type CoinPriceLike,\n} from \"../data/coins.js\";\n\n/** Injected per-chain spot-price read. `price` is null while loading/unknown. */\nexport type UseCoinPrice = (collection: CoinCollectionLike) => {\n price: CoinPriceLike | null;\n isLoading: boolean;\n};\n\nexport interface CoinTileProps {\n collection: CoinCollectionLike;\n usePrice: UseCoinPrice;\n /** Link target — internal coin page or the per-chain trading app. */\n href: string;\n}\n\nconst KIND_TAG: Record<string, string> = {\n creator: \"border-brand-purple/30 bg-brand-purple/10 text-brand-purple\",\n memecoin: \"border-brand-rose/30 bg-brand-rose/10 text-brand-rose\",\n};\n\nfunction useTileModel({ collection, usePrice }: Omit<CoinTileProps, \"href\">) {\n const { price, isLoading } = usePrice(collection);\n const kind = coinKind(collection.service);\n const verified = collection.claimedBy != null || kind === \"creator\";\n const logoUri = collection.profile?.image ?? collection.image;\n const logo = logoUri ? ipfsToHttp(logoUri) : null;\n const initials = (collection.symbol ?? collection.name ?? \"?\").trim().slice(0, 2).toUpperCase();\n const fdv = formatFdv(price?.quotePerCoin, collection.totalSupply, price?.quoteSymbol ?? null);\n const chain = (collection.chain ?? \"\").toString().toLowerCase();\n return { price, isLoading, kind, verified, logo, initials, fdv, chain };\n}\n\nfunction PriceSkel({ wide }: { wide?: boolean }) {\n return <span className={cn(\"inline-block h-4 rounded bg-muted-foreground/20 animate-pulse\", wide ? \"w-16\" : \"w-12\")} />;\n}\n\nexport function CoinCard({ collection, usePrice, href }: CoinTileProps) {\n const m = useTileModel({ collection, usePrice });\n return (\n <Link href={href} className=\"flex flex-col rounded-xl border border-border/60 bg-card overflow-hidden transition-transform active:scale-[0.99]\">\n <div className=\"flex items-center gap-3 p-4\">\n <div className=\"relative h-12 w-12 shrink-0 rounded-full overflow-hidden bg-muted\">\n {m.logo ? (\n <Image src={m.logo} alt=\"\" fill sizes=\"48px\" className=\"object-cover\" unoptimized />\n ) : (\n <div className=\"flex h-full w-full items-center justify-center bg-gradient-to-br from-brand-blue to-brand-purple text-sm font-bold text-white\">{m.initials}</div>\n )}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-1\">\n <span className=\"truncate font-semibold\">{collection.name ?? \"Untitled coin\"}</span>\n {m.verified && <BadgeCheck className=\"h-4 w-4 shrink-0 text-primary\" aria-label=\"Verified\" />}\n </div>\n <span className=\"text-sm text-muted-foreground\">{collection.symbol ?? \"—\"}</span>\n </div>\n <span className={cn(\"shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-medium\", KIND_TAG[m.kind])}>\n {m.kind === \"creator\" ? \"Creator Coin\" : \"Memecoin\"}\n </span>\n </div>\n <div className=\"grid grid-cols-3 gap-2 border-t border-border/60 px-4 py-3 text-sm\">\n <Stat label=\"Price\">\n {m.isLoading ? <PriceSkel /> : m.price ? <span className=\"font-semibold\">{formatCoinPrice(m.price.quotePerCoin)}</span> : <span className=\"text-muted-foreground\">—</span>}\n </Stat>\n <Stat label=\"FDV\">\n {m.isLoading ? <PriceSkel /> : <span className=\"font-semibold\">{m.fdv ?? \"—\"}</span>}\n </Stat>\n <Stat label=\"Holders\">\n <span className=\"inline-flex items-center gap-1 font-semibold\">\n <Users className=\"h-3 w-3 text-muted-foreground\" />{collection.holderCount || \"—\"}\n </span>\n </Stat>\n </div>\n <div className=\"flex items-center justify-between border-t border-border/60 px-4 py-2.5 text-sm\">\n {m.chain ? <span className=\"text-[10px] uppercase tracking-wide text-muted-foreground\">{m.chain}</span> : <span />}\n <span className=\"font-medium text-primary\">Trade</span>\n </div>\n </Link>\n );\n}\n\nexport function CoinRow({ collection, usePrice, href }: CoinTileProps) {\n const m = useTileModel({ collection, usePrice });\n return (\n <Link href={href} className=\"flex items-center gap-3 rounded-lg border border-border/60 bg-card px-3 py-2.5 transition-colors hover:border-primary/40\">\n <div className=\"relative h-9 w-9 shrink-0 overflow-hidden rounded-full bg-muted\">\n {m.logo ? <Image src={m.logo} alt=\"\" fill sizes=\"36px\" className=\"object-cover\" unoptimized /> :\n <div className=\"flex h-full w-full items-center justify-center bg-gradient-to-br from-brand-blue to-brand-purple text-[11px] font-bold text-white\">{m.initials}</div>}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-1\">\n <span className=\"truncate text-sm font-semibold\">{collection.name ?? \"Untitled coin\"}</span>\n {m.verified && <BadgeCheck className=\"h-3.5 w-3.5 shrink-0 text-primary\" aria-label=\"Verified\" />}\n </div>\n <span className=\"text-xs text-muted-foreground\">{collection.symbol ?? \"—\"}</span>\n </div>\n <span className={cn(\"hidden shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-medium sm:inline-block\", KIND_TAG[m.kind])}>\n {m.kind === \"creator\" ? \"Creator Coin\" : \"Memecoin\"}\n </span>\n <span className=\"w-24 shrink-0 text-right text-sm font-semibold tabular-nums\">\n {m.isLoading ? <span className=\"ml-auto inline-block h-4 w-12 rounded bg-muted-foreground/20 animate-pulse\" /> : m.price ? formatCoinPrice(m.price.quotePerCoin) : <span className=\"text-muted-foreground\">—</span>}\n </span>\n <span className=\"hidden shrink-0 text-sm font-medium text-primary sm:inline-block\">Trade</span>\n </Link>\n );\n}\n\nfunction Stat({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"text-[10px] uppercase tracking-wide text-muted-foreground\">{label}</span>\n {children}\n </div>\n );\n}\n\nexport function CoinCardSkeleton() {\n return (\n <div className=\"flex flex-col rounded-xl border border-border/60 bg-card overflow-hidden\">\n <div className=\"flex items-center gap-3 p-4\">\n <div className=\"h-12 w-12 rounded-full bg-muted animate-pulse\" />\n <div className=\"flex-1 space-y-1.5\">\n <div className=\"h-4 w-24 rounded bg-muted-foreground/20 animate-pulse\" />\n <div className=\"h-3 w-12 rounded bg-muted-foreground/20 animate-pulse\" />\n </div>\n </div>\n <div className=\"grid grid-cols-3 gap-2 border-t border-border/60 px-4 py-3\">\n {[0, 1, 2].map((i) => <div key={i} className=\"h-8 w-full rounded bg-muted-foreground/10 animate-pulse\" />)}\n </div>\n <div className=\"h-9 w-full bg-muted-foreground/10 animate-pulse\" />\n </div>\n );\n}\n"],"mappings":"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","names":["Link","Image"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { CoinCollectionLike, CoinPriceLike } from '../data/coins.cjs';
|
|
3
|
+
|
|
4
|
+
/** Injected per-chain spot-price read. `price` is null while loading/unknown. */
|
|
5
|
+
type UseCoinPrice = (collection: CoinCollectionLike) => {
|
|
6
|
+
price: CoinPriceLike | null;
|
|
7
|
+
isLoading: boolean;
|
|
8
|
+
};
|
|
9
|
+
interface CoinTileProps {
|
|
10
|
+
collection: CoinCollectionLike;
|
|
11
|
+
usePrice: UseCoinPrice;
|
|
12
|
+
/** Link target — internal coin page or the per-chain trading app. */
|
|
13
|
+
href: string;
|
|
14
|
+
}
|
|
15
|
+
declare function CoinCard({ collection, usePrice, href }: CoinTileProps): react_jsx_runtime.JSX.Element;
|
|
16
|
+
declare function CoinRow({ collection, usePrice, href }: CoinTileProps): react_jsx_runtime.JSX.Element;
|
|
17
|
+
declare function CoinCardSkeleton(): react_jsx_runtime.JSX.Element;
|
|
18
|
+
|
|
19
|
+
export { CoinCard, CoinCardSkeleton, CoinRow, type CoinTileProps, type UseCoinPrice };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { CoinCollectionLike, CoinPriceLike } from '../data/coins.js';
|
|
3
|
+
|
|
4
|
+
/** Injected per-chain spot-price read. `price` is null while loading/unknown. */
|
|
5
|
+
type UseCoinPrice = (collection: CoinCollectionLike) => {
|
|
6
|
+
price: CoinPriceLike | null;
|
|
7
|
+
isLoading: boolean;
|
|
8
|
+
};
|
|
9
|
+
interface CoinTileProps {
|
|
10
|
+
collection: CoinCollectionLike;
|
|
11
|
+
usePrice: UseCoinPrice;
|
|
12
|
+
/** Link target — internal coin page or the per-chain trading app. */
|
|
13
|
+
href: string;
|
|
14
|
+
}
|
|
15
|
+
declare function CoinCard({ collection, usePrice, href }: CoinTileProps): react_jsx_runtime.JSX.Element;
|
|
16
|
+
declare function CoinRow({ collection, usePrice, href }: CoinTileProps): react_jsx_runtime.JSX.Element;
|
|
17
|
+
declare function CoinCardSkeleton(): react_jsx_runtime.JSX.Element;
|
|
18
|
+
|
|
19
|
+
export { CoinCard, CoinCardSkeleton, CoinRow, type CoinTileProps, type UseCoinPrice };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import Image from "next/image";
|
|
5
|
+
import { BadgeCheck, Users } from "lucide-react";
|
|
6
|
+
import { cn } from "../utils/cn.js";
|
|
7
|
+
import { ipfsToHttp } from "../utils/ipfs.js";
|
|
8
|
+
import {
|
|
9
|
+
coinKind,
|
|
10
|
+
formatCoinPrice,
|
|
11
|
+
formatFdv
|
|
12
|
+
} from "../data/coins.js";
|
|
13
|
+
const KIND_TAG = {
|
|
14
|
+
creator: "border-brand-purple/30 bg-brand-purple/10 text-brand-purple",
|
|
15
|
+
memecoin: "border-brand-rose/30 bg-brand-rose/10 text-brand-rose"
|
|
16
|
+
};
|
|
17
|
+
function useTileModel({ collection, usePrice }) {
|
|
18
|
+
const { price, isLoading } = usePrice(collection);
|
|
19
|
+
const kind = coinKind(collection.service);
|
|
20
|
+
const verified = collection.claimedBy != null || kind === "creator";
|
|
21
|
+
const logoUri = collection.profile?.image ?? collection.image;
|
|
22
|
+
const logo = logoUri ? ipfsToHttp(logoUri) : null;
|
|
23
|
+
const initials = (collection.symbol ?? collection.name ?? "?").trim().slice(0, 2).toUpperCase();
|
|
24
|
+
const fdv = formatFdv(price?.quotePerCoin, collection.totalSupply, price?.quoteSymbol ?? null);
|
|
25
|
+
const chain = (collection.chain ?? "").toString().toLowerCase();
|
|
26
|
+
return { price, isLoading, kind, verified, logo, initials, fdv, chain };
|
|
27
|
+
}
|
|
28
|
+
function PriceSkel({ wide }) {
|
|
29
|
+
return /* @__PURE__ */ jsx("span", { className: cn("inline-block h-4 rounded bg-muted-foreground/20 animate-pulse", wide ? "w-16" : "w-12") });
|
|
30
|
+
}
|
|
31
|
+
function CoinCard({ collection, usePrice, href }) {
|
|
32
|
+
const m = useTileModel({ collection, usePrice });
|
|
33
|
+
return /* @__PURE__ */ jsxs(Link, { href, className: "flex flex-col rounded-xl border border-border/60 bg-card overflow-hidden transition-transform active:scale-[0.99]", children: [
|
|
34
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 p-4", children: [
|
|
35
|
+
/* @__PURE__ */ jsx("div", { className: "relative h-12 w-12 shrink-0 rounded-full overflow-hidden bg-muted", children: m.logo ? /* @__PURE__ */ jsx(Image, { src: m.logo, alt: "", fill: true, sizes: "48px", className: "object-cover", unoptimized: true }) : /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center bg-gradient-to-br from-brand-blue to-brand-purple text-sm font-bold text-white", children: m.initials }) }),
|
|
36
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
37
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
38
|
+
/* @__PURE__ */ jsx("span", { className: "truncate font-semibold", children: collection.name ?? "Untitled coin" }),
|
|
39
|
+
m.verified && /* @__PURE__ */ jsx(BadgeCheck, { className: "h-4 w-4 shrink-0 text-primary", "aria-label": "Verified" })
|
|
40
|
+
] }),
|
|
41
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: collection.symbol ?? "\u2014" })
|
|
42
|
+
] }),
|
|
43
|
+
/* @__PURE__ */ jsx("span", { className: cn("shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-medium", KIND_TAG[m.kind]), children: m.kind === "creator" ? "Creator Coin" : "Memecoin" })
|
|
44
|
+
] }),
|
|
45
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-2 border-t border-border/60 px-4 py-3 text-sm", children: [
|
|
46
|
+
/* @__PURE__ */ jsx(Stat, { label: "Price", children: m.isLoading ? /* @__PURE__ */ jsx(PriceSkel, {}) : m.price ? /* @__PURE__ */ jsx("span", { className: "font-semibold", children: formatCoinPrice(m.price.quotePerCoin) }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" }) }),
|
|
47
|
+
/* @__PURE__ */ jsx(Stat, { label: "FDV", children: m.isLoading ? /* @__PURE__ */ jsx(PriceSkel, {}) : /* @__PURE__ */ jsx("span", { className: "font-semibold", children: m.fdv ?? "\u2014" }) }),
|
|
48
|
+
/* @__PURE__ */ jsx(Stat, { label: "Holders", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 font-semibold", children: [
|
|
49
|
+
/* @__PURE__ */ jsx(Users, { className: "h-3 w-3 text-muted-foreground" }),
|
|
50
|
+
collection.holderCount || "\u2014"
|
|
51
|
+
] }) })
|
|
52
|
+
] }),
|
|
53
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-t border-border/60 px-4 py-2.5 text-sm", children: [
|
|
54
|
+
m.chain ? /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: m.chain }) : /* @__PURE__ */ jsx("span", {}),
|
|
55
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-primary", children: "Trade" })
|
|
56
|
+
] })
|
|
57
|
+
] });
|
|
58
|
+
}
|
|
59
|
+
function CoinRow({ collection, usePrice, href }) {
|
|
60
|
+
const m = useTileModel({ collection, usePrice });
|
|
61
|
+
return /* @__PURE__ */ jsxs(Link, { href, className: "flex items-center gap-3 rounded-lg border border-border/60 bg-card px-3 py-2.5 transition-colors hover:border-primary/40", children: [
|
|
62
|
+
/* @__PURE__ */ jsx("div", { className: "relative h-9 w-9 shrink-0 overflow-hidden rounded-full bg-muted", children: m.logo ? /* @__PURE__ */ jsx(Image, { src: m.logo, alt: "", fill: true, sizes: "36px", className: "object-cover", unoptimized: true }) : /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center bg-gradient-to-br from-brand-blue to-brand-purple text-[11px] font-bold text-white", children: m.initials }) }),
|
|
63
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
64
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
65
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-sm font-semibold", children: collection.name ?? "Untitled coin" }),
|
|
66
|
+
m.verified && /* @__PURE__ */ jsx(BadgeCheck, { className: "h-3.5 w-3.5 shrink-0 text-primary", "aria-label": "Verified" })
|
|
67
|
+
] }),
|
|
68
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: collection.symbol ?? "\u2014" })
|
|
69
|
+
] }),
|
|
70
|
+
/* @__PURE__ */ jsx("span", { className: cn("hidden shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-medium sm:inline-block", KIND_TAG[m.kind]), children: m.kind === "creator" ? "Creator Coin" : "Memecoin" }),
|
|
71
|
+
/* @__PURE__ */ jsx("span", { className: "w-24 shrink-0 text-right text-sm font-semibold tabular-nums", children: m.isLoading ? /* @__PURE__ */ jsx("span", { className: "ml-auto inline-block h-4 w-12 rounded bg-muted-foreground/20 animate-pulse" }) : m.price ? formatCoinPrice(m.price.quotePerCoin) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" }) }),
|
|
72
|
+
/* @__PURE__ */ jsx("span", { className: "hidden shrink-0 text-sm font-medium text-primary sm:inline-block", children: "Trade" })
|
|
73
|
+
] });
|
|
74
|
+
}
|
|
75
|
+
function Stat({ label, children }) {
|
|
76
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
77
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: label }),
|
|
78
|
+
children
|
|
79
|
+
] });
|
|
80
|
+
}
|
|
81
|
+
function CoinCardSkeleton() {
|
|
82
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col rounded-xl border border-border/60 bg-card overflow-hidden", children: [
|
|
83
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 p-4", children: [
|
|
84
|
+
/* @__PURE__ */ jsx("div", { className: "h-12 w-12 rounded-full bg-muted animate-pulse" }),
|
|
85
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-1.5", children: [
|
|
86
|
+
/* @__PURE__ */ jsx("div", { className: "h-4 w-24 rounded bg-muted-foreground/20 animate-pulse" }),
|
|
87
|
+
/* @__PURE__ */ jsx("div", { className: "h-3 w-12 rounded bg-muted-foreground/20 animate-pulse" })
|
|
88
|
+
] })
|
|
89
|
+
] }),
|
|
90
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-2 border-t border-border/60 px-4 py-3", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx("div", { className: "h-8 w-full rounded bg-muted-foreground/10 animate-pulse" }, i)) }),
|
|
91
|
+
/* @__PURE__ */ jsx("div", { className: "h-9 w-full bg-muted-foreground/10 animate-pulse" })
|
|
92
|
+
] });
|
|
93
|
+
}
|
|
94
|
+
export {
|
|
95
|
+
CoinCard,
|
|
96
|
+
CoinCardSkeleton,
|
|
97
|
+
CoinRow
|
|
98
|
+
};
|
|
99
|
+
//# sourceMappingURL=coin-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/coin-card.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * CoinCard / CoinRow — chain-agnostic coin discovery tiles.\n *\n * Pure presentation: the price read (`usePrice`) and the link target (`href`)\n * are injected by the consuming app, and the collection is typed structurally\n * (CoinCollectionLike) — so a coin on Starknet, Ethereum, or Solana renders the\n * same with zero changes here. `chain` is shown as a badge.\n */\n\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { BadgeCheck, Users } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport {\n coinKind, formatCoinPrice, formatFdv,\n type CoinCollectionLike, type CoinPriceLike,\n} from \"../data/coins.js\";\n\n/** Injected per-chain spot-price read. `price` is null while loading/unknown. */\nexport type UseCoinPrice = (collection: CoinCollectionLike) => {\n price: CoinPriceLike | null;\n isLoading: boolean;\n};\n\nexport interface CoinTileProps {\n collection: CoinCollectionLike;\n usePrice: UseCoinPrice;\n /** Link target — internal coin page or the per-chain trading app. */\n href: string;\n}\n\nconst KIND_TAG: Record<string, string> = {\n creator: \"border-brand-purple/30 bg-brand-purple/10 text-brand-purple\",\n memecoin: \"border-brand-rose/30 bg-brand-rose/10 text-brand-rose\",\n};\n\nfunction useTileModel({ collection, usePrice }: Omit<CoinTileProps, \"href\">) {\n const { price, isLoading } = usePrice(collection);\n const kind = coinKind(collection.service);\n const verified = collection.claimedBy != null || kind === \"creator\";\n const logoUri = collection.profile?.image ?? collection.image;\n const logo = logoUri ? ipfsToHttp(logoUri) : null;\n const initials = (collection.symbol ?? collection.name ?? \"?\").trim().slice(0, 2).toUpperCase();\n const fdv = formatFdv(price?.quotePerCoin, collection.totalSupply, price?.quoteSymbol ?? null);\n const chain = (collection.chain ?? \"\").toString().toLowerCase();\n return { price, isLoading, kind, verified, logo, initials, fdv, chain };\n}\n\nfunction PriceSkel({ wide }: { wide?: boolean }) {\n return <span className={cn(\"inline-block h-4 rounded bg-muted-foreground/20 animate-pulse\", wide ? \"w-16\" : \"w-12\")} />;\n}\n\nexport function CoinCard({ collection, usePrice, href }: CoinTileProps) {\n const m = useTileModel({ collection, usePrice });\n return (\n <Link href={href} className=\"flex flex-col rounded-xl border border-border/60 bg-card overflow-hidden transition-transform active:scale-[0.99]\">\n <div className=\"flex items-center gap-3 p-4\">\n <div className=\"relative h-12 w-12 shrink-0 rounded-full overflow-hidden bg-muted\">\n {m.logo ? (\n <Image src={m.logo} alt=\"\" fill sizes=\"48px\" className=\"object-cover\" unoptimized />\n ) : (\n <div className=\"flex h-full w-full items-center justify-center bg-gradient-to-br from-brand-blue to-brand-purple text-sm font-bold text-white\">{m.initials}</div>\n )}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-1\">\n <span className=\"truncate font-semibold\">{collection.name ?? \"Untitled coin\"}</span>\n {m.verified && <BadgeCheck className=\"h-4 w-4 shrink-0 text-primary\" aria-label=\"Verified\" />}\n </div>\n <span className=\"text-sm text-muted-foreground\">{collection.symbol ?? \"—\"}</span>\n </div>\n <span className={cn(\"shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-medium\", KIND_TAG[m.kind])}>\n {m.kind === \"creator\" ? \"Creator Coin\" : \"Memecoin\"}\n </span>\n </div>\n <div className=\"grid grid-cols-3 gap-2 border-t border-border/60 px-4 py-3 text-sm\">\n <Stat label=\"Price\">\n {m.isLoading ? <PriceSkel /> : m.price ? <span className=\"font-semibold\">{formatCoinPrice(m.price.quotePerCoin)}</span> : <span className=\"text-muted-foreground\">—</span>}\n </Stat>\n <Stat label=\"FDV\">\n {m.isLoading ? <PriceSkel /> : <span className=\"font-semibold\">{m.fdv ?? \"—\"}</span>}\n </Stat>\n <Stat label=\"Holders\">\n <span className=\"inline-flex items-center gap-1 font-semibold\">\n <Users className=\"h-3 w-3 text-muted-foreground\" />{collection.holderCount || \"—\"}\n </span>\n </Stat>\n </div>\n <div className=\"flex items-center justify-between border-t border-border/60 px-4 py-2.5 text-sm\">\n {m.chain ? <span className=\"text-[10px] uppercase tracking-wide text-muted-foreground\">{m.chain}</span> : <span />}\n <span className=\"font-medium text-primary\">Trade</span>\n </div>\n </Link>\n );\n}\n\nexport function CoinRow({ collection, usePrice, href }: CoinTileProps) {\n const m = useTileModel({ collection, usePrice });\n return (\n <Link href={href} className=\"flex items-center gap-3 rounded-lg border border-border/60 bg-card px-3 py-2.5 transition-colors hover:border-primary/40\">\n <div className=\"relative h-9 w-9 shrink-0 overflow-hidden rounded-full bg-muted\">\n {m.logo ? <Image src={m.logo} alt=\"\" fill sizes=\"36px\" className=\"object-cover\" unoptimized /> :\n <div className=\"flex h-full w-full items-center justify-center bg-gradient-to-br from-brand-blue to-brand-purple text-[11px] font-bold text-white\">{m.initials}</div>}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-1\">\n <span className=\"truncate text-sm font-semibold\">{collection.name ?? \"Untitled coin\"}</span>\n {m.verified && <BadgeCheck className=\"h-3.5 w-3.5 shrink-0 text-primary\" aria-label=\"Verified\" />}\n </div>\n <span className=\"text-xs text-muted-foreground\">{collection.symbol ?? \"—\"}</span>\n </div>\n <span className={cn(\"hidden shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-medium sm:inline-block\", KIND_TAG[m.kind])}>\n {m.kind === \"creator\" ? \"Creator Coin\" : \"Memecoin\"}\n </span>\n <span className=\"w-24 shrink-0 text-right text-sm font-semibold tabular-nums\">\n {m.isLoading ? <span className=\"ml-auto inline-block h-4 w-12 rounded bg-muted-foreground/20 animate-pulse\" /> : m.price ? formatCoinPrice(m.price.quotePerCoin) : <span className=\"text-muted-foreground\">—</span>}\n </span>\n <span className=\"hidden shrink-0 text-sm font-medium text-primary sm:inline-block\">Trade</span>\n </Link>\n );\n}\n\nfunction Stat({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"text-[10px] uppercase tracking-wide text-muted-foreground\">{label}</span>\n {children}\n </div>\n );\n}\n\nexport function CoinCardSkeleton() {\n return (\n <div className=\"flex flex-col rounded-xl border border-border/60 bg-card overflow-hidden\">\n <div className=\"flex items-center gap-3 p-4\">\n <div className=\"h-12 w-12 rounded-full bg-muted animate-pulse\" />\n <div className=\"flex-1 space-y-1.5\">\n <div className=\"h-4 w-24 rounded bg-muted-foreground/20 animate-pulse\" />\n <div className=\"h-3 w-12 rounded bg-muted-foreground/20 animate-pulse\" />\n </div>\n </div>\n <div className=\"grid grid-cols-3 gap-2 border-t border-border/60 px-4 py-3\">\n {[0, 1, 2].map((i) => <div key={i} className=\"h-8 w-full rounded bg-muted-foreground/10 animate-pulse\" />)}\n </div>\n <div className=\"h-9 w-full bg-muted-foreground/10 animate-pulse\" />\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var coins_explorer_exports = {};
|
|
21
|
+
__export(coins_explorer_exports, {
|
|
22
|
+
CoinsExplorer: () => CoinsExplorer
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(coins_explorer_exports);
|
|
25
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
26
|
+
var import_react = require("react");
|
|
27
|
+
var import_lucide_react = require("lucide-react");
|
|
28
|
+
var import_cn = require("../utils/cn.js");
|
|
29
|
+
var import_coin_card = require("./coin-card.js");
|
|
30
|
+
const FILTER_TABS = [
|
|
31
|
+
{ label: "All", value: "all" },
|
|
32
|
+
{ label: "Creator Coins", value: "creator" },
|
|
33
|
+
{ label: "Memecoins", value: "memecoin" }
|
|
34
|
+
];
|
|
35
|
+
const SORT_OPTIONS = [
|
|
36
|
+
{ label: "Recently launched", value: "recent" },
|
|
37
|
+
{ label: "Name", value: "name" }
|
|
38
|
+
];
|
|
39
|
+
function CoinsExplorer({ useCoins, usePrice, coinHref, heading = true }) {
|
|
40
|
+
const [filter, setFilter] = (0, import_react.useState)("all");
|
|
41
|
+
const [sort, setSort] = (0, import_react.useState)("recent");
|
|
42
|
+
const [view, setView] = (0, import_react.useState)("grid");
|
|
43
|
+
const [query, setQuery] = (0, import_react.useState)("");
|
|
44
|
+
const { collections, isLoading } = useCoins({ filter, sort });
|
|
45
|
+
const items = (0, import_react.useMemo)(() => {
|
|
46
|
+
const q = query.trim().toLowerCase();
|
|
47
|
+
if (!q) return collections;
|
|
48
|
+
return collections.filter(
|
|
49
|
+
(c) => (c.name ?? "").toLowerCase().includes(q) || (c.symbol ?? "").toLowerCase().includes(q)
|
|
50
|
+
);
|
|
51
|
+
}, [collections, query]);
|
|
52
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-6", children: [
|
|
53
|
+
heading && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
54
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2 text-primary", children: [
|
|
55
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Coins, { className: "h-5 w-5" }),
|
|
56
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-semibold uppercase tracking-wider", children: "Tokens" })
|
|
57
|
+
] }),
|
|
58
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "text-3xl font-bold", children: "Creator coins & memecoins" }),
|
|
59
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-muted-foreground", children: "Discover creator-issued social tokens and claimed memecoins." })
|
|
60
|
+
] }),
|
|
61
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-3 border-b border-border/60 pb-3", children: [
|
|
62
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
|
|
63
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex gap-1.5", children: FILTER_TABS.map(({ label, value }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
64
|
+
"button",
|
|
65
|
+
{
|
|
66
|
+
onClick: () => setFilter(value),
|
|
67
|
+
className: (0, import_cn.cn)(
|
|
68
|
+
"rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors",
|
|
69
|
+
filter === value ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:border-primary/50 hover:text-foreground"
|
|
70
|
+
),
|
|
71
|
+
children: label
|
|
72
|
+
},
|
|
73
|
+
value
|
|
74
|
+
)) }),
|
|
75
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
76
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
77
|
+
"select",
|
|
78
|
+
{
|
|
79
|
+
value: sort,
|
|
80
|
+
onChange: (e) => setSort(e.target.value),
|
|
81
|
+
className: "rounded-lg border border-border bg-background px-3 py-1.5 text-xs font-medium text-foreground",
|
|
82
|
+
children: SORT_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: o.value, children: o.label }, o.value))
|
|
83
|
+
}
|
|
84
|
+
),
|
|
85
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "inline-flex rounded-lg border border-border p-0.5", children: [{ v: "grid", Icon: import_lucide_react.LayoutGrid }, { v: "table", Icon: import_lucide_react.List }].map(({ v, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
86
|
+
"button",
|
|
87
|
+
{
|
|
88
|
+
onClick: () => setView(v),
|
|
89
|
+
"aria-label": v === "grid" ? "Grid view" : "Table view",
|
|
90
|
+
className: (0, import_cn.cn)("rounded-md p-1.5 transition-colors", view === v ? "bg-primary/10 text-primary" : "text-muted-foreground hover:text-foreground"),
|
|
91
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { className: "h-4 w-4" })
|
|
92
|
+
},
|
|
93
|
+
v
|
|
94
|
+
)) })
|
|
95
|
+
] })
|
|
96
|
+
] }),
|
|
97
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative", children: [
|
|
98
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Search, { className: "pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
|
|
99
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
100
|
+
"input",
|
|
101
|
+
{
|
|
102
|
+
value: query,
|
|
103
|
+
onChange: (e) => setQuery(e.target.value),
|
|
104
|
+
placeholder: "Search coins by name or symbol\u2026",
|
|
105
|
+
className: "w-full rounded-lg border border-border bg-background py-2 pl-9 pr-3 text-sm outline-none focus:border-primary/50"
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
] })
|
|
109
|
+
] }),
|
|
110
|
+
isLoading && items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4", children: Array.from({ length: 8 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_coin_card.CoinCardSkeleton, {}, i)) }) : items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rounded-xl border border-border/60 py-16 text-center text-muted-foreground", children: query.trim() ? `No coins match "${query.trim()}".` : "No coins yet." }) : view === "table" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "space-y-2", children: items.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_coin_card.CoinRow, { collection: c, usePrice, href: coinHref(c) }, `${c.chain}-${c.contractAddress}`)) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4", children: items.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_coin_card.CoinCard, { collection: c, usePrice, href: coinHref(c) }, `${c.chain}-${c.contractAddress}`)) })
|
|
111
|
+
] });
|
|
112
|
+
}
|
|
113
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
114
|
+
0 && (module.exports = {
|
|
115
|
+
CoinsExplorer
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=coins-explorer.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/coins-explorer.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * CoinsExplorer — the shared coin-discovery surface (chain-agnostic).\n *\n * Owns view/search/filter/sort UI only. The data source (`useCoins`), the price\n * read (`usePrice`), and the link target (`coinHref`) are injected, so each app\n * (and each chain) wires its own without forking this component.\n */\n\nimport { useState, useMemo } from \"react\";\nimport { Coins, LayoutGrid, List, Search } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { CoinCard, CoinRow, CoinCardSkeleton, type UseCoinPrice } from \"./coin-card.js\";\nimport type { CoinCollectionLike } from \"../data/coins.js\";\n\nexport type CoinFilter = \"all\" | \"creator\" | \"memecoin\";\nexport type CoinSort = \"recent\" | \"name\";\nexport type UseCoins = (opts: { filter: CoinFilter; sort: CoinSort }) => {\n collections: CoinCollectionLike[];\n isLoading: boolean;\n};\n\nexport interface CoinsExplorerProps {\n useCoins: UseCoins;\n usePrice: UseCoinPrice;\n /** Build the link target for a coin (internal or per-chain trading app). */\n coinHref: (collection: CoinCollectionLike) => string;\n heading?: boolean;\n}\n\nconst FILTER_TABS: { label: string; value: CoinFilter }[] = [\n { label: \"All\", value: \"all\" },\n { label: \"Creator Coins\", value: \"creator\" },\n { label: \"Memecoins\", value: \"memecoin\" },\n];\n\n// Recency default — never raw swap volume (05 §11 anti-wash hygiene).\nconst SORT_OPTIONS: { label: string; value: CoinSort }[] = [\n { label: \"Recently launched\", value: \"recent\" },\n { label: \"Name\", value: \"name\" },\n];\n\nexport function CoinsExplorer({ useCoins, usePrice, coinHref, heading = true }: CoinsExplorerProps) {\n const [filter, setFilter] = useState<CoinFilter>(\"all\");\n const [sort, setSort] = useState<CoinSort>(\"recent\");\n const [view, setView] = useState<\"grid\" | \"table\">(\"grid\");\n const [query, setQuery] = useState(\"\");\n\n const { collections, isLoading } = useCoins({ filter, sort });\n const items = useMemo(() => {\n const q = query.trim().toLowerCase();\n if (!q) return collections;\n return collections.filter(\n (c) => (c.name ?? \"\").toLowerCase().includes(q) || (c.symbol ?? \"\").toLowerCase().includes(q)\n );\n }, [collections, query]);\n\n return (\n <div className=\"space-y-6\">\n {heading && (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2 text-primary\">\n <Coins className=\"h-5 w-5\" />\n <span className=\"text-sm font-semibold uppercase tracking-wider\">Tokens</span>\n </div>\n <h1 className=\"text-3xl font-bold\">Creator coins & memecoins</h1>\n <p className=\"text-muted-foreground\">Discover creator-issued social tokens and claimed memecoins.</p>\n </div>\n )}\n\n <div className=\"space-y-3 border-b border-border/60 pb-3\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex gap-1.5\">\n {FILTER_TABS.map(({ label, value }) => (\n <button\n key={value}\n onClick={() => setFilter(value)}\n className={cn(\n \"rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors\",\n filter === value\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50 hover:text-foreground\"\n )}\n >\n {label}\n </button>\n ))}\n </div>\n <div className=\"flex items-center gap-2\">\n <select\n value={sort}\n onChange={(e) => setSort(e.target.value as CoinSort)}\n className=\"rounded-lg border border-border bg-background px-3 py-1.5 text-xs font-medium text-foreground\"\n >\n {SORT_OPTIONS.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}\n </select>\n <div className=\"inline-flex rounded-lg border border-border p-0.5\">\n {([{ v: \"grid\", Icon: LayoutGrid }, { v: \"table\", Icon: List }] as const).map(({ v, Icon }) => (\n <button\n key={v}\n onClick={() => setView(v)}\n aria-label={v === \"grid\" ? \"Grid view\" : \"Table view\"}\n className={cn(\"rounded-md p-1.5 transition-colors\", view === v ? \"bg-primary/10 text-primary\" : \"text-muted-foreground hover:text-foreground\")}\n >\n <Icon className=\"h-4 w-4\" />\n </button>\n ))}\n </div>\n </div>\n </div>\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search coins by name or symbol…\"\n className=\"w-full rounded-lg border border-border bg-background py-2 pl-9 pr-3 text-sm outline-none focus:border-primary/50\"\n />\n </div>\n </div>\n\n {isLoading && items.length === 0 ? (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n {Array.from({ length: 8 }).map((_, i) => <CoinCardSkeleton key={i} />)}\n </div>\n ) : items.length === 0 ? (\n <div className=\"rounded-xl border border-border/60 py-16 text-center text-muted-foreground\">\n {query.trim() ? `No coins match \"${query.trim()}\".` : \"No coins yet.\"}\n </div>\n ) : view === \"table\" ? (\n <div className=\"space-y-2\">\n {items.map((c) => <CoinRow key={`${c.chain}-${c.contractAddress}`} collection={c} usePrice={usePrice} href={coinHref(c)} />)}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n {items.map((c) => <CoinCard key={`${c.chain}-${c.contractAddress}`} collection={c} usePrice={usePrice} href={coinHref(c)} />)}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { UseCoinPrice } from './coin-card.cjs';
|
|
3
|
+
import { CoinCollectionLike } from '../data/coins.cjs';
|
|
4
|
+
|
|
5
|
+
type CoinFilter = "all" | "creator" | "memecoin";
|
|
6
|
+
type CoinSort = "recent" | "name";
|
|
7
|
+
type UseCoins = (opts: {
|
|
8
|
+
filter: CoinFilter;
|
|
9
|
+
sort: CoinSort;
|
|
10
|
+
}) => {
|
|
11
|
+
collections: CoinCollectionLike[];
|
|
12
|
+
isLoading: boolean;
|
|
13
|
+
};
|
|
14
|
+
interface CoinsExplorerProps {
|
|
15
|
+
useCoins: UseCoins;
|
|
16
|
+
usePrice: UseCoinPrice;
|
|
17
|
+
/** Build the link target for a coin (internal or per-chain trading app). */
|
|
18
|
+
coinHref: (collection: CoinCollectionLike) => string;
|
|
19
|
+
heading?: boolean;
|
|
20
|
+
}
|
|
21
|
+
declare function CoinsExplorer({ useCoins, usePrice, coinHref, heading }: CoinsExplorerProps): react_jsx_runtime.JSX.Element;
|
|
22
|
+
|
|
23
|
+
export { type CoinFilter, type CoinSort, CoinsExplorer, type CoinsExplorerProps, type UseCoins };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { UseCoinPrice } from './coin-card.js';
|
|
3
|
+
import { CoinCollectionLike } from '../data/coins.js';
|
|
4
|
+
|
|
5
|
+
type CoinFilter = "all" | "creator" | "memecoin";
|
|
6
|
+
type CoinSort = "recent" | "name";
|
|
7
|
+
type UseCoins = (opts: {
|
|
8
|
+
filter: CoinFilter;
|
|
9
|
+
sort: CoinSort;
|
|
10
|
+
}) => {
|
|
11
|
+
collections: CoinCollectionLike[];
|
|
12
|
+
isLoading: boolean;
|
|
13
|
+
};
|
|
14
|
+
interface CoinsExplorerProps {
|
|
15
|
+
useCoins: UseCoins;
|
|
16
|
+
usePrice: UseCoinPrice;
|
|
17
|
+
/** Build the link target for a coin (internal or per-chain trading app). */
|
|
18
|
+
coinHref: (collection: CoinCollectionLike) => string;
|
|
19
|
+
heading?: boolean;
|
|
20
|
+
}
|
|
21
|
+
declare function CoinsExplorer({ useCoins, usePrice, coinHref, heading }: CoinsExplorerProps): react_jsx_runtime.JSX.Element;
|
|
22
|
+
|
|
23
|
+
export { type CoinFilter, type CoinSort, CoinsExplorer, type CoinsExplorerProps, type UseCoins };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useMemo } from "react";
|
|
4
|
+
import { Coins, LayoutGrid, List, Search } from "lucide-react";
|
|
5
|
+
import { cn } from "../utils/cn.js";
|
|
6
|
+
import { CoinCard, CoinRow, CoinCardSkeleton } from "./coin-card.js";
|
|
7
|
+
const FILTER_TABS = [
|
|
8
|
+
{ label: "All", value: "all" },
|
|
9
|
+
{ label: "Creator Coins", value: "creator" },
|
|
10
|
+
{ label: "Memecoins", value: "memecoin" }
|
|
11
|
+
];
|
|
12
|
+
const SORT_OPTIONS = [
|
|
13
|
+
{ label: "Recently launched", value: "recent" },
|
|
14
|
+
{ label: "Name", value: "name" }
|
|
15
|
+
];
|
|
16
|
+
function CoinsExplorer({ useCoins, usePrice, coinHref, heading = true }) {
|
|
17
|
+
const [filter, setFilter] = useState("all");
|
|
18
|
+
const [sort, setSort] = useState("recent");
|
|
19
|
+
const [view, setView] = useState("grid");
|
|
20
|
+
const [query, setQuery] = useState("");
|
|
21
|
+
const { collections, isLoading } = useCoins({ filter, sort });
|
|
22
|
+
const items = useMemo(() => {
|
|
23
|
+
const q = query.trim().toLowerCase();
|
|
24
|
+
if (!q) return collections;
|
|
25
|
+
return collections.filter(
|
|
26
|
+
(c) => (c.name ?? "").toLowerCase().includes(q) || (c.symbol ?? "").toLowerCase().includes(q)
|
|
27
|
+
);
|
|
28
|
+
}, [collections, query]);
|
|
29
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
30
|
+
heading && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
31
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-primary", children: [
|
|
32
|
+
/* @__PURE__ */ jsx(Coins, { className: "h-5 w-5" }),
|
|
33
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold uppercase tracking-wider", children: "Tokens" })
|
|
34
|
+
] }),
|
|
35
|
+
/* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold", children: "Creator coins & memecoins" }),
|
|
36
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "Discover creator-issued social tokens and claimed memecoins." })
|
|
37
|
+
] }),
|
|
38
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3 border-b border-border/60 pb-3", children: [
|
|
39
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
|
|
40
|
+
/* @__PURE__ */ jsx("div", { className: "flex gap-1.5", children: FILTER_TABS.map(({ label, value }) => /* @__PURE__ */ jsx(
|
|
41
|
+
"button",
|
|
42
|
+
{
|
|
43
|
+
onClick: () => setFilter(value),
|
|
44
|
+
className: cn(
|
|
45
|
+
"rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors",
|
|
46
|
+
filter === value ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:border-primary/50 hover:text-foreground"
|
|
47
|
+
),
|
|
48
|
+
children: label
|
|
49
|
+
},
|
|
50
|
+
value
|
|
51
|
+
)) }),
|
|
52
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
"select",
|
|
55
|
+
{
|
|
56
|
+
value: sort,
|
|
57
|
+
onChange: (e) => setSort(e.target.value),
|
|
58
|
+
className: "rounded-lg border border-border bg-background px-3 py-1.5 text-xs font-medium text-foreground",
|
|
59
|
+
children: SORT_OPTIONS.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
|
|
60
|
+
}
|
|
61
|
+
),
|
|
62
|
+
/* @__PURE__ */ jsx("div", { className: "inline-flex rounded-lg border border-border p-0.5", children: [{ v: "grid", Icon: LayoutGrid }, { v: "table", Icon: List }].map(({ v, Icon }) => /* @__PURE__ */ jsx(
|
|
63
|
+
"button",
|
|
64
|
+
{
|
|
65
|
+
onClick: () => setView(v),
|
|
66
|
+
"aria-label": v === "grid" ? "Grid view" : "Table view",
|
|
67
|
+
className: cn("rounded-md p-1.5 transition-colors", view === v ? "bg-primary/10 text-primary" : "text-muted-foreground hover:text-foreground"),
|
|
68
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" })
|
|
69
|
+
},
|
|
70
|
+
v
|
|
71
|
+
)) })
|
|
72
|
+
] })
|
|
73
|
+
] }),
|
|
74
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
75
|
+
/* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
|
|
76
|
+
/* @__PURE__ */ jsx(
|
|
77
|
+
"input",
|
|
78
|
+
{
|
|
79
|
+
value: query,
|
|
80
|
+
onChange: (e) => setQuery(e.target.value),
|
|
81
|
+
placeholder: "Search coins by name or symbol\u2026",
|
|
82
|
+
className: "w-full rounded-lg border border-border bg-background py-2 pl-9 pr-3 text-sm outline-none focus:border-primary/50"
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
] })
|
|
86
|
+
] }),
|
|
87
|
+
isLoading && items.length === 0 ? /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4", children: Array.from({ length: 8 }).map((_, i) => /* @__PURE__ */ jsx(CoinCardSkeleton, {}, i)) }) : items.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-border/60 py-16 text-center text-muted-foreground", children: query.trim() ? `No coins match "${query.trim()}".` : "No coins yet." }) : view === "table" ? /* @__PURE__ */ jsx("div", { className: "space-y-2", children: items.map((c) => /* @__PURE__ */ jsx(CoinRow, { collection: c, usePrice, href: coinHref(c) }, `${c.chain}-${c.contractAddress}`)) }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4", children: items.map((c) => /* @__PURE__ */ jsx(CoinCard, { collection: c, usePrice, href: coinHref(c) }, `${c.chain}-${c.contractAddress}`)) })
|
|
88
|
+
] });
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
CoinsExplorer
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=coins-explorer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/coins-explorer.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * CoinsExplorer — the shared coin-discovery surface (chain-agnostic).\n *\n * Owns view/search/filter/sort UI only. The data source (`useCoins`), the price\n * read (`usePrice`), and the link target (`coinHref`) are injected, so each app\n * (and each chain) wires its own without forking this component.\n */\n\nimport { useState, useMemo } from \"react\";\nimport { Coins, LayoutGrid, List, Search } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { CoinCard, CoinRow, CoinCardSkeleton, type UseCoinPrice } from \"./coin-card.js\";\nimport type { CoinCollectionLike } from \"../data/coins.js\";\n\nexport type CoinFilter = \"all\" | \"creator\" | \"memecoin\";\nexport type CoinSort = \"recent\" | \"name\";\nexport type UseCoins = (opts: { filter: CoinFilter; sort: CoinSort }) => {\n collections: CoinCollectionLike[];\n isLoading: boolean;\n};\n\nexport interface CoinsExplorerProps {\n useCoins: UseCoins;\n usePrice: UseCoinPrice;\n /** Build the link target for a coin (internal or per-chain trading app). */\n coinHref: (collection: CoinCollectionLike) => string;\n heading?: boolean;\n}\n\nconst FILTER_TABS: { label: string; value: CoinFilter }[] = [\n { label: \"All\", value: \"all\" },\n { label: \"Creator Coins\", value: \"creator\" },\n { label: \"Memecoins\", value: \"memecoin\" },\n];\n\n// Recency default — never raw swap volume (05 §11 anti-wash hygiene).\nconst SORT_OPTIONS: { label: string; value: CoinSort }[] = [\n { label: \"Recently launched\", value: \"recent\" },\n { label: \"Name\", value: \"name\" },\n];\n\nexport function CoinsExplorer({ useCoins, usePrice, coinHref, heading = true }: CoinsExplorerProps) {\n const [filter, setFilter] = useState<CoinFilter>(\"all\");\n const [sort, setSort] = useState<CoinSort>(\"recent\");\n const [view, setView] = useState<\"grid\" | \"table\">(\"grid\");\n const [query, setQuery] = useState(\"\");\n\n const { collections, isLoading } = useCoins({ filter, sort });\n const items = useMemo(() => {\n const q = query.trim().toLowerCase();\n if (!q) return collections;\n return collections.filter(\n (c) => (c.name ?? \"\").toLowerCase().includes(q) || (c.symbol ?? \"\").toLowerCase().includes(q)\n );\n }, [collections, query]);\n\n return (\n <div className=\"space-y-6\">\n {heading && (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2 text-primary\">\n <Coins className=\"h-5 w-5\" />\n <span className=\"text-sm font-semibold uppercase tracking-wider\">Tokens</span>\n </div>\n <h1 className=\"text-3xl font-bold\">Creator coins & memecoins</h1>\n <p className=\"text-muted-foreground\">Discover creator-issued social tokens and claimed memecoins.</p>\n </div>\n )}\n\n <div className=\"space-y-3 border-b border-border/60 pb-3\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex gap-1.5\">\n {FILTER_TABS.map(({ label, value }) => (\n <button\n key={value}\n onClick={() => setFilter(value)}\n className={cn(\n \"rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors\",\n filter === value\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50 hover:text-foreground\"\n )}\n >\n {label}\n </button>\n ))}\n </div>\n <div className=\"flex items-center gap-2\">\n <select\n value={sort}\n onChange={(e) => setSort(e.target.value as CoinSort)}\n className=\"rounded-lg border border-border bg-background px-3 py-1.5 text-xs font-medium text-foreground\"\n >\n {SORT_OPTIONS.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}\n </select>\n <div className=\"inline-flex rounded-lg border border-border p-0.5\">\n {([{ v: \"grid\", Icon: LayoutGrid }, { v: \"table\", Icon: List }] as const).map(({ v, Icon }) => (\n <button\n key={v}\n onClick={() => setView(v)}\n aria-label={v === \"grid\" ? \"Grid view\" : \"Table view\"}\n className={cn(\"rounded-md p-1.5 transition-colors\", view === v ? \"bg-primary/10 text-primary\" : \"text-muted-foreground hover:text-foreground\")}\n >\n <Icon className=\"h-4 w-4\" />\n </button>\n ))}\n </div>\n </div>\n </div>\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search coins by name or symbol…\"\n className=\"w-full rounded-lg border border-border bg-background py-2 pl-9 pr-3 text-sm outline-none focus:border-primary/50\"\n />\n </div>\n </div>\n\n {isLoading && items.length === 0 ? (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n {Array.from({ length: 8 }).map((_, i) => <CoinCardSkeleton key={i} />)}\n </div>\n ) : items.length === 0 ? (\n <div className=\"rounded-xl border border-border/60 py-16 text-center text-muted-foreground\">\n {query.trim() ? `No coins match \"${query.trim()}\".` : \"No coins yet.\"}\n </div>\n ) : view === \"table\" ? (\n <div className=\"space-y-2\">\n {items.map((c) => <CoinRow key={`${c.chain}-${c.contractAddress}`} collection={c} usePrice={usePrice} href={coinHref(c)} />)}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n {items.map((c) => <CoinCard key={`${c.chain}-${c.contractAddress}`} collection={c} usePrice={usePrice} href={coinHref(c)} />)}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";AA8DU,SACE,KADF;AApDV,SAAS,UAAU,eAAe;AAClC,SAAS,OAAO,YAAY,MAAM,cAAc;AAChD,SAAS,UAAU;AACnB,SAAS,UAAU,SAAS,wBAA2C;AAkBvE,MAAM,cAAsD;AAAA,EAC1D,EAAE,OAAO,OAAO,OAAO,MAAM;AAAA,EAC7B,EAAE,OAAO,iBAAiB,OAAO,UAAU;AAAA,EAC3C,EAAE,OAAO,aAAa,OAAO,WAAW;AAC1C;AAGA,MAAM,eAAqD;AAAA,EACzD,EAAE,OAAO,qBAAqB,OAAO,SAAS;AAAA,EAC9C,EAAE,OAAO,QAAQ,OAAO,OAAO;AACjC;AAEO,SAAS,cAAc,EAAE,UAAU,UAAU,UAAU,UAAU,KAAK,GAAuB;AAClG,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAqB,KAAK;AACtD,QAAM,CAAC,MAAM,OAAO,IAAI,SAAmB,QAAQ;AACnD,QAAM,CAAC,MAAM,OAAO,IAAI,SAA2B,MAAM;AACzD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AAErC,QAAM,EAAE,aAAa,UAAU,IAAI,SAAS,EAAE,QAAQ,KAAK,CAAC;AAC5D,QAAM,QAAQ,QAAQ,MAAM;AAC1B,UAAM,IAAI,MAAM,KAAK,EAAE,YAAY;AACnC,QAAI,CAAC,EAAG,QAAO;AACf,WAAO,YAAY;AAAA,MACjB,CAAC,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAE,SAAS,CAAC,MAAM,EAAE,UAAU,IAAI,YAAY,EAAE,SAAS,CAAC;AAAA,IAC9F;AAAA,EACF,GAAG,CAAC,aAAa,KAAK,CAAC;AAEvB,SACE,qBAAC,SAAI,WAAU,aACZ;AAAA,eACC,qBAAC,SAAI,WAAU,aACb;AAAA,2BAAC,SAAI,WAAU,wCACb;AAAA,4BAAC,SAAM,WAAU,WAAU;AAAA,QAC3B,oBAAC,UAAK,WAAU,kDAAiD,oBAAM;AAAA,SACzE;AAAA,MACA,oBAAC,QAAG,WAAU,sBAAqB,uCAA6B;AAAA,MAChE,oBAAC,OAAE,WAAU,yBAAwB,0EAA4D;AAAA,OACnG;AAAA,IAGF,qBAAC,SAAI,WAAU,4CACb;AAAA,2BAAC,SAAI,WAAU,qDACb;AAAA,4BAAC,SAAI,WAAU,gBACZ,sBAAY,IAAI,CAAC,EAAE,OAAO,MAAM,MAC/B;AAAA,UAAC;AAAA;AAAA,YAEC,SAAS,MAAM,UAAU,KAAK;AAAA,YAC9B,WAAW;AAAA,cACT;AAAA,cACA,WAAW,QACP,8CACA;AAAA,YACN;AAAA,YAEC;AAAA;AAAA,UATI;AAAA,QAUP,CACD,GACH;AAAA,QACA,qBAAC,SAAI,WAAU,2BACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAiB;AAAA,cACnD,WAAU;AAAA,cAET,uBAAa,IAAI,CAAC,MAAM,oBAAC,YAAqB,OAAO,EAAE,OAAQ,YAAE,SAA5B,EAAE,KAAgC,CAAS;AAAA;AAAA,UACnF;AAAA,UACA,oBAAC,SAAI,WAAU,qDACX,WAAC,EAAE,GAAG,QAAQ,MAAM,WAAW,GAAG,EAAE,GAAG,SAAS,MAAM,KAAK,CAAC,EAAY,IAAI,CAAC,EAAE,GAAG,KAAK,MACvF;AAAA,YAAC;AAAA;AAAA,cAEC,SAAS,MAAM,QAAQ,CAAC;AAAA,cACxB,cAAY,MAAM,SAAS,cAAc;AAAA,cACzC,WAAW,GAAG,sCAAsC,SAAS,IAAI,+BAA+B,6CAA6C;AAAA,cAE7I,8BAAC,QAAK,WAAU,WAAU;AAAA;AAAA,YALrB;AAAA,UAMP,CACD,GACH;AAAA,WACF;AAAA,SACF;AAAA,MACA,qBAAC,SAAI,WAAU,YACb;AAAA,4BAAC,UAAO,WAAU,kGAAiG;AAAA,QACnH;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,YACxC,aAAY;AAAA,YACZ,WAAU;AAAA;AAAA,QACZ;AAAA,SACF;AAAA,OACF;AAAA,IAEC,aAAa,MAAM,WAAW,IAC7B,oBAAC,SAAI,WAAU,uEACZ,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,oBAAC,sBAAsB,CAAG,CAAE,GACvE,IACE,MAAM,WAAW,IACnB,oBAAC,SAAI,WAAU,8EACZ,gBAAM,KAAK,IAAI,mBAAmB,MAAM,KAAK,CAAC,OAAO,iBACxD,IACE,SAAS,UACX,oBAAC,SAAI,WAAU,aACZ,gBAAM,IAAI,CAAC,MAAM,oBAAC,WAAgD,YAAY,GAAG,UAAoB,MAAM,SAAS,CAAC,KAAtF,GAAG,EAAE,KAAK,IAAI,EAAE,eAAe,EAA0D,CAAE,GAC7H,IAEA,oBAAC,SAAI,WAAU,uEACZ,gBAAM,IAAI,CAAC,MAAM,oBAAC,YAAiD,YAAY,GAAG,UAAoB,MAAM,SAAS,CAAC,KAAtF,GAAG,EAAE,KAAK,IAAI,EAAE,eAAe,EAA0D,CAAE,GAC9H;AAAA,KAEJ;AAEJ;","names":[]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var coins_exports = {};
|
|
20
|
+
__export(coins_exports, {
|
|
21
|
+
coinKind: () => coinKind,
|
|
22
|
+
formatCoinPrice: () => formatCoinPrice,
|
|
23
|
+
formatFdv: () => formatFdv
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(coins_exports);
|
|
26
|
+
function coinKind(service) {
|
|
27
|
+
return service === "external-erc20" ? "memecoin" : "creator";
|
|
28
|
+
}
|
|
29
|
+
function formatCoinPrice(n) {
|
|
30
|
+
if (n === 0) return "0";
|
|
31
|
+
if (n < 1e-6) return n.toExponential(2);
|
|
32
|
+
if (n < 1) return n.toPrecision(3);
|
|
33
|
+
return n.toLocaleString(void 0, { maximumFractionDigits: 4 });
|
|
34
|
+
}
|
|
35
|
+
function formatFdv(quotePerCoin, totalSupply, quoteSymbol) {
|
|
36
|
+
if (quotePerCoin == null || !totalSupply) return null;
|
|
37
|
+
const fdv = quotePerCoin * totalSupply;
|
|
38
|
+
const sym = quoteSymbol ?? "";
|
|
39
|
+
const abbr = fdv >= 1e9 ? `${(fdv / 1e9).toLocaleString(void 0, { maximumFractionDigits: 1 })}B` : fdv >= 1e6 ? `${(fdv / 1e6).toLocaleString(void 0, { maximumFractionDigits: 1 })}M` : fdv >= 1e3 ? `${(fdv / 1e3).toLocaleString(void 0, { maximumFractionDigits: 1 })}K` : fdv.toLocaleString(void 0, { maximumFractionDigits: 2 });
|
|
40
|
+
return sym ? `${abbr} ${sym}` : abbr;
|
|
41
|
+
}
|
|
42
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
43
|
+
0 && (module.exports = {
|
|
44
|
+
coinKind,
|
|
45
|
+
formatCoinPrice,
|
|
46
|
+
formatFdv
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=coins.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/data/coins.ts"],"sourcesContent":["// Coin discovery — pure, dependency-free helpers + the structural shapes the\n// coin components read. No @medialane/sdk import: ui types shared code\n// structurally (same pattern as CollectionCard's `ApiCollection & {…}`), so a\n// coin on any chain works without bumping ui's SDK. Registry-dependent logic\n// (isCoinCollection / COIN_SERVICE_IDS, price reads) lives in the apps and is\n// injected — see the CoinsExplorer/CoinCard props.\n\nexport type CoinKind = \"creator\" | \"memecoin\";\n\n/** The fields a coin tile reads. An app's `ApiCollection` structurally satisfies\n * this. `chain` is first-class — rendered as a badge; nothing assumes Starknet. */\nexport interface CoinCollectionLike {\n contractAddress: string;\n chain?: string | null;\n name?: string | null;\n symbol?: string | null;\n image?: string | null;\n service?: string | null;\n claimedBy?: string | null;\n holderCount?: number | null;\n totalSupply?: number | null;\n profile?: { image?: string | null } | null;\n}\n\n/** Minimal spot-price shape — the concrete read (Ekubo on Starknet, a DEX on\n * another chain) is injected by the app and structurally satisfies this. */\nexport interface CoinPriceLike {\n quotePerCoin: number;\n quoteSymbol: string | null;\n}\n\n/** Native creator coin vs claimed external memecoin. */\nexport function coinKind(service: string | null | undefined): CoinKind {\n return service === \"external-erc20\" ? \"memecoin\" : \"creator\";\n}\n\n/** Format a quote-per-coin spot price. */\nexport function formatCoinPrice(n: number): string {\n if (n === 0) return \"0\";\n if (n < 0.000001) return n.toExponential(2);\n if (n < 1) return n.toPrecision(3);\n return n.toLocaleString(undefined, { maximumFractionDigits: 4 });\n}\n\n/** Fully-diluted value = price × supply, abbreviated, in the quote symbol.\n * Returns null when price/supply is unknown or zero (external coins aren't\n * supply-indexed, so price × 0 must read \"—\", never \"0\"). */\nexport function formatFdv(\n quotePerCoin: number | null | undefined,\n totalSupply: number | null | undefined,\n quoteSymbol: string | null | undefined\n): string | null {\n if (quotePerCoin == null || !totalSupply) return null;\n const fdv = quotePerCoin * totalSupply;\n const sym = quoteSymbol ?? \"\";\n const abbr =\n fdv >= 1_000_000_000 ? `${(fdv / 1_000_000_000).toLocaleString(undefined, { maximumFractionDigits: 1 })}B` :\n fdv >= 1_000_000 ? `${(fdv / 1_000_000).toLocaleString(undefined, { maximumFractionDigits: 1 })}M` :\n fdv >= 1_000 ? `${(fdv / 1_000).toLocaleString(undefined, { maximumFractionDigits: 1 })}K` :\n fdv.toLocaleString(undefined, { maximumFractionDigits: 2 });\n return sym ? `${abbr} ${sym}` : abbr;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCO,SAAS,SAAS,SAA8C;AACrE,SAAO,YAAY,mBAAmB,aAAa;AACrD;AAGO,SAAS,gBAAgB,GAAmB;AACjD,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,IAAI,KAAU,QAAO,EAAE,cAAc,CAAC;AAC1C,MAAI,IAAI,EAAG,QAAO,EAAE,YAAY,CAAC;AACjC,SAAO,EAAE,eAAe,QAAW,EAAE,uBAAuB,EAAE,CAAC;AACjE;AAKO,SAAS,UACd,cACA,aACA,aACe;AACf,MAAI,gBAAgB,QAAQ,CAAC,YAAa,QAAO;AACjD,QAAM,MAAM,eAAe;AAC3B,QAAM,MAAM,eAAe;AAC3B,QAAM,OACJ,OAAO,MAAgB,IAAI,MAAM,KAAe,eAAe,QAAW,EAAE,uBAAuB,EAAE,CAAC,CAAC,MACvG,OAAO,MAAgB,IAAI,MAAM,KAAW,eAAe,QAAW,EAAE,uBAAuB,EAAE,CAAC,CAAC,MACnG,OAAO,MAAgB,IAAI,MAAM,KAAO,eAAe,QAAW,EAAE,uBAAuB,EAAE,CAAC,CAAC,MACxE,IAAI,eAAe,QAAW,EAAE,uBAAuB,EAAE,CAAC;AACnF,SAAO,MAAM,GAAG,IAAI,IAAI,GAAG,KAAK;AAClC;","names":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type CoinKind = "creator" | "memecoin";
|
|
2
|
+
/** The fields a coin tile reads. An app's `ApiCollection` structurally satisfies
|
|
3
|
+
* this. `chain` is first-class — rendered as a badge; nothing assumes Starknet. */
|
|
4
|
+
interface CoinCollectionLike {
|
|
5
|
+
contractAddress: string;
|
|
6
|
+
chain?: string | null;
|
|
7
|
+
name?: string | null;
|
|
8
|
+
symbol?: string | null;
|
|
9
|
+
image?: string | null;
|
|
10
|
+
service?: string | null;
|
|
11
|
+
claimedBy?: string | null;
|
|
12
|
+
holderCount?: number | null;
|
|
13
|
+
totalSupply?: number | null;
|
|
14
|
+
profile?: {
|
|
15
|
+
image?: string | null;
|
|
16
|
+
} | null;
|
|
17
|
+
}
|
|
18
|
+
/** Minimal spot-price shape — the concrete read (Ekubo on Starknet, a DEX on
|
|
19
|
+
* another chain) is injected by the app and structurally satisfies this. */
|
|
20
|
+
interface CoinPriceLike {
|
|
21
|
+
quotePerCoin: number;
|
|
22
|
+
quoteSymbol: string | null;
|
|
23
|
+
}
|
|
24
|
+
/** Native creator coin vs claimed external memecoin. */
|
|
25
|
+
declare function coinKind(service: string | null | undefined): CoinKind;
|
|
26
|
+
/** Format a quote-per-coin spot price. */
|
|
27
|
+
declare function formatCoinPrice(n: number): string;
|
|
28
|
+
/** Fully-diluted value = price × supply, abbreviated, in the quote symbol.
|
|
29
|
+
* Returns null when price/supply is unknown or zero (external coins aren't
|
|
30
|
+
* supply-indexed, so price × 0 must read "—", never "0"). */
|
|
31
|
+
declare function formatFdv(quotePerCoin: number | null | undefined, totalSupply: number | null | undefined, quoteSymbol: string | null | undefined): string | null;
|
|
32
|
+
|
|
33
|
+
export { type CoinCollectionLike, type CoinKind, type CoinPriceLike, coinKind, formatCoinPrice, formatFdv };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type CoinKind = "creator" | "memecoin";
|
|
2
|
+
/** The fields a coin tile reads. An app's `ApiCollection` structurally satisfies
|
|
3
|
+
* this. `chain` is first-class — rendered as a badge; nothing assumes Starknet. */
|
|
4
|
+
interface CoinCollectionLike {
|
|
5
|
+
contractAddress: string;
|
|
6
|
+
chain?: string | null;
|
|
7
|
+
name?: string | null;
|
|
8
|
+
symbol?: string | null;
|
|
9
|
+
image?: string | null;
|
|
10
|
+
service?: string | null;
|
|
11
|
+
claimedBy?: string | null;
|
|
12
|
+
holderCount?: number | null;
|
|
13
|
+
totalSupply?: number | null;
|
|
14
|
+
profile?: {
|
|
15
|
+
image?: string | null;
|
|
16
|
+
} | null;
|
|
17
|
+
}
|
|
18
|
+
/** Minimal spot-price shape — the concrete read (Ekubo on Starknet, a DEX on
|
|
19
|
+
* another chain) is injected by the app and structurally satisfies this. */
|
|
20
|
+
interface CoinPriceLike {
|
|
21
|
+
quotePerCoin: number;
|
|
22
|
+
quoteSymbol: string | null;
|
|
23
|
+
}
|
|
24
|
+
/** Native creator coin vs claimed external memecoin. */
|
|
25
|
+
declare function coinKind(service: string | null | undefined): CoinKind;
|
|
26
|
+
/** Format a quote-per-coin spot price. */
|
|
27
|
+
declare function formatCoinPrice(n: number): string;
|
|
28
|
+
/** Fully-diluted value = price × supply, abbreviated, in the quote symbol.
|
|
29
|
+
* Returns null when price/supply is unknown or zero (external coins aren't
|
|
30
|
+
* supply-indexed, so price × 0 must read "—", never "0"). */
|
|
31
|
+
declare function formatFdv(quotePerCoin: number | null | undefined, totalSupply: number | null | undefined, quoteSymbol: string | null | undefined): string | null;
|
|
32
|
+
|
|
33
|
+
export { type CoinCollectionLike, type CoinKind, type CoinPriceLike, coinKind, formatCoinPrice, formatFdv };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
function coinKind(service) {
|
|
2
|
+
return service === "external-erc20" ? "memecoin" : "creator";
|
|
3
|
+
}
|
|
4
|
+
function formatCoinPrice(n) {
|
|
5
|
+
if (n === 0) return "0";
|
|
6
|
+
if (n < 1e-6) return n.toExponential(2);
|
|
7
|
+
if (n < 1) return n.toPrecision(3);
|
|
8
|
+
return n.toLocaleString(void 0, { maximumFractionDigits: 4 });
|
|
9
|
+
}
|
|
10
|
+
function formatFdv(quotePerCoin, totalSupply, quoteSymbol) {
|
|
11
|
+
if (quotePerCoin == null || !totalSupply) return null;
|
|
12
|
+
const fdv = quotePerCoin * totalSupply;
|
|
13
|
+
const sym = quoteSymbol ?? "";
|
|
14
|
+
const abbr = fdv >= 1e9 ? `${(fdv / 1e9).toLocaleString(void 0, { maximumFractionDigits: 1 })}B` : fdv >= 1e6 ? `${(fdv / 1e6).toLocaleString(void 0, { maximumFractionDigits: 1 })}M` : fdv >= 1e3 ? `${(fdv / 1e3).toLocaleString(void 0, { maximumFractionDigits: 1 })}K` : fdv.toLocaleString(void 0, { maximumFractionDigits: 2 });
|
|
15
|
+
return sym ? `${abbr} ${sym}` : abbr;
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
coinKind,
|
|
19
|
+
formatCoinPrice,
|
|
20
|
+
formatFdv
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=coins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/data/coins.ts"],"sourcesContent":["// Coin discovery — pure, dependency-free helpers + the structural shapes the\n// coin components read. No @medialane/sdk import: ui types shared code\n// structurally (same pattern as CollectionCard's `ApiCollection & {…}`), so a\n// coin on any chain works without bumping ui's SDK. Registry-dependent logic\n// (isCoinCollection / COIN_SERVICE_IDS, price reads) lives in the apps and is\n// injected — see the CoinsExplorer/CoinCard props.\n\nexport type CoinKind = \"creator\" | \"memecoin\";\n\n/** The fields a coin tile reads. An app's `ApiCollection` structurally satisfies\n * this. `chain` is first-class — rendered as a badge; nothing assumes Starknet. */\nexport interface CoinCollectionLike {\n contractAddress: string;\n chain?: string | null;\n name?: string | null;\n symbol?: string | null;\n image?: string | null;\n service?: string | null;\n claimedBy?: string | null;\n holderCount?: number | null;\n totalSupply?: number | null;\n profile?: { image?: string | null } | null;\n}\n\n/** Minimal spot-price shape — the concrete read (Ekubo on Starknet, a DEX on\n * another chain) is injected by the app and structurally satisfies this. */\nexport interface CoinPriceLike {\n quotePerCoin: number;\n quoteSymbol: string | null;\n}\n\n/** Native creator coin vs claimed external memecoin. */\nexport function coinKind(service: string | null | undefined): CoinKind {\n return service === \"external-erc20\" ? \"memecoin\" : \"creator\";\n}\n\n/** Format a quote-per-coin spot price. */\nexport function formatCoinPrice(n: number): string {\n if (n === 0) return \"0\";\n if (n < 0.000001) return n.toExponential(2);\n if (n < 1) return n.toPrecision(3);\n return n.toLocaleString(undefined, { maximumFractionDigits: 4 });\n}\n\n/** Fully-diluted value = price × supply, abbreviated, in the quote symbol.\n * Returns null when price/supply is unknown or zero (external coins aren't\n * supply-indexed, so price × 0 must read \"—\", never \"0\"). */\nexport function formatFdv(\n quotePerCoin: number | null | undefined,\n totalSupply: number | null | undefined,\n quoteSymbol: string | null | undefined\n): string | null {\n if (quotePerCoin == null || !totalSupply) return null;\n const fdv = quotePerCoin * totalSupply;\n const sym = quoteSymbol ?? \"\";\n const abbr =\n fdv >= 1_000_000_000 ? `${(fdv / 1_000_000_000).toLocaleString(undefined, { maximumFractionDigits: 1 })}B` :\n fdv >= 1_000_000 ? `${(fdv / 1_000_000).toLocaleString(undefined, { maximumFractionDigits: 1 })}M` :\n fdv >= 1_000 ? `${(fdv / 1_000).toLocaleString(undefined, { maximumFractionDigits: 1 })}K` :\n fdv.toLocaleString(undefined, { maximumFractionDigits: 2 });\n return sym ? `${abbr} ${sym}` : abbr;\n}\n"],"mappings":"AAgCO,SAAS,SAAS,SAA8C;AACrE,SAAO,YAAY,mBAAmB,aAAa;AACrD;AAGO,SAAS,gBAAgB,GAAmB;AACjD,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,IAAI,KAAU,QAAO,EAAE,cAAc,CAAC;AAC1C,MAAI,IAAI,EAAG,QAAO,EAAE,YAAY,CAAC;AACjC,SAAO,EAAE,eAAe,QAAW,EAAE,uBAAuB,EAAE,CAAC;AACjE;AAKO,SAAS,UACd,cACA,aACA,aACe;AACf,MAAI,gBAAgB,QAAQ,CAAC,YAAa,QAAO;AACjD,QAAM,MAAM,eAAe;AAC3B,QAAM,MAAM,eAAe;AAC3B,QAAM,OACJ,OAAO,MAAgB,IAAI,MAAM,KAAe,eAAe,QAAW,EAAE,uBAAuB,EAAE,CAAC,CAAC,MACvG,OAAO,MAAgB,IAAI,MAAM,KAAW,eAAe,QAAW,EAAE,uBAAuB,EAAE,CAAC,CAAC,MACnG,OAAO,MAAgB,IAAI,MAAM,KAAO,eAAe,QAAW,EAAE,uBAAuB,EAAE,CAAC,CAAC,MACxE,IAAI,eAAe,QAAW,EAAE,uBAAuB,EAAE,CAAC;AACnF,SAAO,MAAM,GAAG,IAAI,IAAI,GAAG,KAAK;AAClC;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -32,6 +32,10 @@ __export(index_exports, {
|
|
|
32
32
|
AssetMediaColumn: () => import_asset_top_sections.AssetMediaColumn,
|
|
33
33
|
AssetOverviewContent: () => import_asset_overview_content.AssetOverviewContent,
|
|
34
34
|
BRAND: () => import_brand.BRAND,
|
|
35
|
+
CoinCard: () => import_coin_card.CoinCard,
|
|
36
|
+
CoinCardSkeleton: () => import_coin_card.CoinCardSkeleton,
|
|
37
|
+
CoinRow: () => import_coin_card.CoinRow,
|
|
38
|
+
CoinsExplorer: () => import_coins_explorer.CoinsExplorer,
|
|
35
39
|
CollectionCard: () => import_collection_card.CollectionCard,
|
|
36
40
|
CollectionCardSkeleton: () => import_collection_card.CollectionCardSkeleton,
|
|
37
41
|
CtaCardGrid: () => import_cta_card_grid.CtaCardGrid,
|
|
@@ -89,8 +93,11 @@ __export(index_exports, {
|
|
|
89
93
|
TokenCardSkeleton: () => import_token_card.TokenCardSkeleton,
|
|
90
94
|
buildEditionStats: () => import_asset_top_sections.buildEditionStats,
|
|
91
95
|
cn: () => import_cn.cn,
|
|
96
|
+
coinKind: () => import_coins.coinKind,
|
|
92
97
|
derivePortfolioCounts: () => import_portfolio_counts.derivePortfolioCounts,
|
|
98
|
+
formatCoinPrice: () => import_coins.formatCoinPrice,
|
|
93
99
|
formatDisplayPrice: () => import_format.formatDisplayPrice,
|
|
100
|
+
formatFdv: () => import_coins.formatFdv,
|
|
94
101
|
ipfsToHttp: () => import_ipfs.ipfsToHttp,
|
|
95
102
|
shortenAddress: () => import_address.shortenAddress,
|
|
96
103
|
timeAgo: () => import_time.timeAgo,
|
|
@@ -122,6 +129,9 @@ var import_scroll_section = require("./components/scroll-section.js");
|
|
|
122
129
|
var import_share_button = require("./components/share-button.js");
|
|
123
130
|
var import_collection_card = require("./components/collection-card.js");
|
|
124
131
|
var import_token_card = require("./components/token-card.js");
|
|
132
|
+
var import_coins = require("./data/coins.js");
|
|
133
|
+
var import_coin_card = require("./components/coin-card.js");
|
|
134
|
+
var import_coins_explorer = require("./components/coins-explorer.js");
|
|
125
135
|
var import_time = require("./utils/time.js");
|
|
126
136
|
var import_activity = require("./data/activity.js");
|
|
127
137
|
var import_hero_slider = require("./components/hero-slider.js");
|
|
@@ -158,6 +168,10 @@ var import_portfolio_counts = require("./utils/portfolio-counts.js");
|
|
|
158
168
|
AssetMediaColumn,
|
|
159
169
|
AssetOverviewContent,
|
|
160
170
|
BRAND,
|
|
171
|
+
CoinCard,
|
|
172
|
+
CoinCardSkeleton,
|
|
173
|
+
CoinRow,
|
|
174
|
+
CoinsExplorer,
|
|
161
175
|
CollectionCard,
|
|
162
176
|
CollectionCardSkeleton,
|
|
163
177
|
CtaCardGrid,
|
|
@@ -215,8 +229,11 @@ var import_portfolio_counts = require("./utils/portfolio-counts.js");
|
|
|
215
229
|
TokenCardSkeleton,
|
|
216
230
|
buildEditionStats,
|
|
217
231
|
cn,
|
|
232
|
+
coinKind,
|
|
218
233
|
derivePortfolioCounts,
|
|
234
|
+
formatCoinPrice,
|
|
219
235
|
formatDisplayPrice,
|
|
236
|
+
formatFdv,
|
|
220
237
|
ipfsToHttp,
|
|
221
238
|
shortenAddress,
|
|
222
239
|
timeAgo,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// ── Utils ─────────────────────────────────────────────────────────────────────\nexport { cn } from \"./utils/cn.js\";\nexport { formatDisplayPrice } from \"./utils/format.js\";\nexport { shortenAddress } from \"./utils/address.js\";\nexport { ipfsToHttp } from \"./utils/ipfs.js\";\n\n// ── Data (server-safe — no React, safe in Server Components) ──────────────────\nexport { IP_TYPE_DATA, IP_TYPE_DATA_MAP } from \"./data/ip-types.js\";\nexport type { IpTypeData } from \"./data/ip-types.js\";\nexport {\n IP_TYPES, LICENSE_TYPES, GEOGRAPHIC_SCOPES, AI_POLICIES,\n DERIVATIVES_OPTIONS, LICENSE_TRAIT_TYPES,\n} from \"./data/ip.js\";\nexport type { IPType, LicenseType } from \"./data/ip.js\";\nexport {\n IP_TEMPLATES, EMBED_PLATFORM_META, SOCIAL_PLATFORM_META, TEMPLATE_TRAIT_TYPES, DOC_UPLOAD,\n} from \"./data/ip-templates.js\";\nexport type { EmbedPlatform, SocialPlatform, TraitSuggestion, IPTemplate, DocUploadConfig } from \"./data/ip-templates.js\";\nexport { IPTypeDisplay } from \"./components/ip-type-display.js\";\nexport { AssetOverviewContent } from \"./components/asset-overview-content.js\";\nexport { AssetMarketsTab } from \"./components/asset-markets-tab.js\";\nexport { ParentAttributionBanner } from \"./components/parent-attribution-banner.js\";\nexport type { ParentBannerProps } from \"./components/parent-attribution-banner.js\";\nexport { AssetMediaColumn, AssetHeaderBlock, buildEditionStats } from \"./components/asset-top-sections.js\";\nexport { BRAND } from \"./data/brand.js\";\n\n// ── Components (client-only — all have \"use client\") ─────────────────────────\nexport { CurrencyIcon, CurrencyAmount } from \"./components/currency-icon.js\";\nexport type { CurrencyIconProps, CurrencyAmountProps } from \"./components/currency-icon.js\";\n\nexport { IpTypeBadge, IP_TYPE_CONFIG, IP_TYPE_MAP } from \"./components/ip-type-badge.js\";\nexport type { IpTypeBadgeProps, IpTypeConfig } from \"./components/ip-type-badge.js\";\n\nexport { AddressDisplay } from \"./components/address-display.js\";\nexport type { AddressDisplayProps } from \"./components/address-display.js\";\n\nexport { MedialaneIcon } from \"./components/brand-icon.js\";\nexport type { MedialaneIconProps } from \"./components/brand-icon.js\";\nexport { MedialaneLogoFull } from \"./components/brand-logo.js\";\nexport type { MedialaneLogoFullProps } from \"./components/brand-logo.js\";\n\n// ── v0.2 additions ────────────────────────────────────────────────────────────\nexport { MotionCard, FadeIn, Stagger, StaggerItem, KineticWords, SPRING, EASE_OUT } from \"./components/motion-primitives.js\";\nexport { PageContainer } from \"./components/page-container.js\";\nexport type { PageContainerProps } from \"./components/page-container.js\";\nexport { ScrollSection } from \"./components/scroll-section.js\";\nexport type { ScrollSectionProps } from \"./components/scroll-section.js\";\nexport { ShareButton } from \"./components/share-button.js\";\nexport type { ShareButtonProps } from \"./components/share-button.js\";\nexport { CollectionCard, CollectionCardSkeleton } from \"./components/collection-card.js\";\nexport type { CollectionCardProps } from \"./components/collection-card.js\";\nexport { TokenCard, TokenCardSkeleton } from \"./components/token-card.js\";\nexport type { TokenCardProps, RarityTier } from \"./components/token-card.js\";\n\n// ── v0.3 additions ────────────────────────────────────────────────────────────\nexport { timeAgo, timeUntil } from \"./utils/time.js\";\nexport { ACTIVITY_TYPE_CONFIG, TYPE_FILTERS } from \"./data/activity.js\";\nexport type { ActivityTypeConfig } from \"./data/activity.js\";\nexport { HeroSlider, HeroSliderSkeleton } from \"./components/hero-slider.js\";\nexport type { HeroSliderProps } from \"./components/hero-slider.js\";\nexport { ActivityTicker } from \"./components/activity-ticker.js\";\nexport type { ActivityTickerProps } from \"./components/activity-ticker.js\";\nexport { ListingCard, ListingCardSkeleton } from \"./components/listing-card.js\";\nexport type { ListingCardProps } from \"./components/listing-card.js\";\nexport { ActivityRow } from \"./components/activity-row.js\";\nexport type { ActivityRowProps } from \"./components/activity-row.js\";\nexport { ActivityFeedShell } from \"./components/activity-feed-shell.js\";\nexport type { ActivityFeedShellProps } from \"./components/activity-feed-shell.js\";\nexport { CtaCardGrid } from \"./components/cta-card-grid.js\";\nexport type { CtaCardGridProps, CtaCardItem } from \"./components/cta-card-grid.js\";\n\n// ── v0.3.2 additions ─────────────────────────────────────────────────────────\nexport { DiscoverHero } from \"./components/discover-hero.js\";\nexport type { DiscoverHeroProps } from \"./components/discover-hero.js\";\nexport { FeaturedCarousel, FeaturedCarouselSkeleton } from \"./components/featured-carousel.js\";\nexport type { FeaturedCarouselProps } from \"./components/featured-carousel.js\";\nexport { DiscoverCollectionsStrip } from \"./components/discover-collections-strip.js\";\nexport type { DiscoverCollectionsStripProps } from \"./components/discover-collections-strip.js\";\nexport { DiscoverCreatorsStrip } from \"./components/discover-creators-strip.js\";\nexport type { DiscoverCreatorsStripProps } from \"./components/discover-creators-strip.js\";\nexport { DiscoverFeedSection } from \"./components/discover-feed-section.js\";\nexport type { DiscoverFeedSectionProps } from \"./components/discover-feed-section.js\";\nexport { ActivityCard, ActivityCardSkeleton, ACTIVITY_MESSAGES } from \"./components/activity-card.js\";\nexport type { ActivityCardProps } from \"./components/activity-card.js\";\n\n// ── Launchpad (grouped sections — single page-UI source since 0.8.0) ─────────\nexport { LaunchpadGroupedSections, LaunchpadServiceCard, SERVICE_HUES } from \"./components/launchpad-services.js\";\nexport { LaunchpadStrip } from \"./components/launchpad-strip.js\";\nexport type { LaunchpadStripProps } from \"./components/launchpad-strip.js\";\nexport type { LaunchpadGroupedSectionsProps, LaunchpadServiceCardProps, ServiceOverride, ServiceOverrides } from \"./components/launchpad-services.js\";\nexport { LAUNCHPAD_SERVICE_DEFINITIONS, LAUNCHPAD_SERVICE_GROUPS } from \"./data/launchpad-services.js\";\nexport type { ServiceDefinition, ServiceStatus, ServiceCategory, ServiceGroup, ServiceGroupDefinition } from \"./data/launchpad-services.js\";\n\n// ── v0.5.0 additions ─────────────────────────────────────────────────────────\nexport { NavCommandMenu, useNavCommandMenu } from \"./components/nav-command-menu.js\";\nexport type { NavCommand, NavCommandGroup, NavCommandMenuProps } from \"./components/nav-command-menu.js\";\n\n// ── v0.6.0 additions — portfolio subnav + counts ────────────────────────────\nexport { PortfolioSubnav } from \"./components/portfolio-subnav.js\";\nexport type {\n PortfolioSubnavProps,\n PortfolioNavItem,\n PortfolioNavGroup,\n PortfolioBadgeVariant,\n} from \"./components/portfolio-subnav.js\";\nexport { derivePortfolioCounts } from \"./utils/portfolio-counts.js\";\nexport type { PortfolioCounts, CountableOrder } from \"./utils/portfolio-counts.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,gBAAmB;AACnB,oBAAmC;AACnC,qBAA+B;AAC/B,kBAA2B;AAG3B,sBAA+C;AAE/C,gBAGO;AAEP,0BAEO;AAEP,6BAA8B;AAC9B,oCAAqC;AACrC,+BAAgC;AAChC,uCAAwC;AAExC,gCAAsE;AACtE,mBAAsB;AAGtB,2BAA6C;AAG7C,2BAAyD;AAGzD,6BAA+B;AAG/B,wBAA8B;AAE9B,wBAAkC;AAIlC,+BAAyF;AACzF,4BAA8B;AAE9B,4BAA8B;AAE9B,0BAA4B;AAE5B,6BAAuD;AAEvD,wBAA6C;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// ── Utils ─────────────────────────────────────────────────────────────────────\nexport { cn } from \"./utils/cn.js\";\nexport { formatDisplayPrice } from \"./utils/format.js\";\nexport { shortenAddress } from \"./utils/address.js\";\nexport { ipfsToHttp } from \"./utils/ipfs.js\";\n\n// ── Data (server-safe — no React, safe in Server Components) ──────────────────\nexport { IP_TYPE_DATA, IP_TYPE_DATA_MAP } from \"./data/ip-types.js\";\nexport type { IpTypeData } from \"./data/ip-types.js\";\nexport {\n IP_TYPES, LICENSE_TYPES, GEOGRAPHIC_SCOPES, AI_POLICIES,\n DERIVATIVES_OPTIONS, LICENSE_TRAIT_TYPES,\n} from \"./data/ip.js\";\nexport type { IPType, LicenseType } from \"./data/ip.js\";\nexport {\n IP_TEMPLATES, EMBED_PLATFORM_META, SOCIAL_PLATFORM_META, TEMPLATE_TRAIT_TYPES, DOC_UPLOAD,\n} from \"./data/ip-templates.js\";\nexport type { EmbedPlatform, SocialPlatform, TraitSuggestion, IPTemplate, DocUploadConfig } from \"./data/ip-templates.js\";\nexport { IPTypeDisplay } from \"./components/ip-type-display.js\";\nexport { AssetOverviewContent } from \"./components/asset-overview-content.js\";\nexport { AssetMarketsTab } from \"./components/asset-markets-tab.js\";\nexport { ParentAttributionBanner } from \"./components/parent-attribution-banner.js\";\nexport type { ParentBannerProps } from \"./components/parent-attribution-banner.js\";\nexport { AssetMediaColumn, AssetHeaderBlock, buildEditionStats } from \"./components/asset-top-sections.js\";\nexport { BRAND } from \"./data/brand.js\";\n\n// ── Components (client-only — all have \"use client\") ─────────────────────────\nexport { CurrencyIcon, CurrencyAmount } from \"./components/currency-icon.js\";\nexport type { CurrencyIconProps, CurrencyAmountProps } from \"./components/currency-icon.js\";\n\nexport { IpTypeBadge, IP_TYPE_CONFIG, IP_TYPE_MAP } from \"./components/ip-type-badge.js\";\nexport type { IpTypeBadgeProps, IpTypeConfig } from \"./components/ip-type-badge.js\";\n\nexport { AddressDisplay } from \"./components/address-display.js\";\nexport type { AddressDisplayProps } from \"./components/address-display.js\";\n\nexport { MedialaneIcon } from \"./components/brand-icon.js\";\nexport type { MedialaneIconProps } from \"./components/brand-icon.js\";\nexport { MedialaneLogoFull } from \"./components/brand-logo.js\";\nexport type { MedialaneLogoFullProps } from \"./components/brand-logo.js\";\n\n// ── v0.2 additions ────────────────────────────────────────────────────────────\nexport { MotionCard, FadeIn, Stagger, StaggerItem, KineticWords, SPRING, EASE_OUT } from \"./components/motion-primitives.js\";\nexport { PageContainer } from \"./components/page-container.js\";\nexport type { PageContainerProps } from \"./components/page-container.js\";\nexport { ScrollSection } from \"./components/scroll-section.js\";\nexport type { ScrollSectionProps } from \"./components/scroll-section.js\";\nexport { ShareButton } from \"./components/share-button.js\";\nexport type { ShareButtonProps } from \"./components/share-button.js\";\nexport { CollectionCard, CollectionCardSkeleton } from \"./components/collection-card.js\";\nexport type { CollectionCardProps } from \"./components/collection-card.js\";\nexport { TokenCard, TokenCardSkeleton } from \"./components/token-card.js\";\nexport type { TokenCardProps, RarityTier } from \"./components/token-card.js\";\n// ── Coin discovery (chain-agnostic; price/data/href injected by the app) ─────\nexport {\n coinKind, formatCoinPrice, formatFdv,\n type CoinKind, type CoinCollectionLike, type CoinPriceLike,\n} from \"./data/coins.js\";\nexport { CoinCard, CoinRow, CoinCardSkeleton, type UseCoinPrice, type CoinTileProps } from \"./components/coin-card.js\";\nexport {\n CoinsExplorer,\n type CoinsExplorerProps, type CoinFilter, type CoinSort, type UseCoins,\n} from \"./components/coins-explorer.js\";\n\n// ── v0.3 additions ────────────────────────────────────────────────────────────\nexport { timeAgo, timeUntil } from \"./utils/time.js\";\nexport { ACTIVITY_TYPE_CONFIG, TYPE_FILTERS } from \"./data/activity.js\";\nexport type { ActivityTypeConfig } from \"./data/activity.js\";\nexport { HeroSlider, HeroSliderSkeleton } from \"./components/hero-slider.js\";\nexport type { HeroSliderProps } from \"./components/hero-slider.js\";\nexport { ActivityTicker } from \"./components/activity-ticker.js\";\nexport type { ActivityTickerProps } from \"./components/activity-ticker.js\";\nexport { ListingCard, ListingCardSkeleton } from \"./components/listing-card.js\";\nexport type { ListingCardProps } from \"./components/listing-card.js\";\nexport { ActivityRow } from \"./components/activity-row.js\";\nexport type { ActivityRowProps } from \"./components/activity-row.js\";\nexport { ActivityFeedShell } from \"./components/activity-feed-shell.js\";\nexport type { ActivityFeedShellProps } from \"./components/activity-feed-shell.js\";\nexport { CtaCardGrid } from \"./components/cta-card-grid.js\";\nexport type { CtaCardGridProps, CtaCardItem } from \"./components/cta-card-grid.js\";\n\n// ── v0.3.2 additions ─────────────────────────────────────────────────────────\nexport { DiscoverHero } from \"./components/discover-hero.js\";\nexport type { DiscoverHeroProps } from \"./components/discover-hero.js\";\nexport { FeaturedCarousel, FeaturedCarouselSkeleton } from \"./components/featured-carousel.js\";\nexport type { FeaturedCarouselProps } from \"./components/featured-carousel.js\";\nexport { DiscoverCollectionsStrip } from \"./components/discover-collections-strip.js\";\nexport type { DiscoverCollectionsStripProps } from \"./components/discover-collections-strip.js\";\nexport { DiscoverCreatorsStrip } from \"./components/discover-creators-strip.js\";\nexport type { DiscoverCreatorsStripProps } from \"./components/discover-creators-strip.js\";\nexport { DiscoverFeedSection } from \"./components/discover-feed-section.js\";\nexport type { DiscoverFeedSectionProps } from \"./components/discover-feed-section.js\";\nexport { ActivityCard, ActivityCardSkeleton, ACTIVITY_MESSAGES } from \"./components/activity-card.js\";\nexport type { ActivityCardProps } from \"./components/activity-card.js\";\n\n// ── Launchpad (grouped sections — single page-UI source since 0.8.0) ─────────\nexport { LaunchpadGroupedSections, LaunchpadServiceCard, SERVICE_HUES } from \"./components/launchpad-services.js\";\nexport { LaunchpadStrip } from \"./components/launchpad-strip.js\";\nexport type { LaunchpadStripProps } from \"./components/launchpad-strip.js\";\nexport type { LaunchpadGroupedSectionsProps, LaunchpadServiceCardProps, ServiceOverride, ServiceOverrides } from \"./components/launchpad-services.js\";\nexport { LAUNCHPAD_SERVICE_DEFINITIONS, LAUNCHPAD_SERVICE_GROUPS } from \"./data/launchpad-services.js\";\nexport type { ServiceDefinition, ServiceStatus, ServiceCategory, ServiceGroup, ServiceGroupDefinition } from \"./data/launchpad-services.js\";\n\n// ── v0.5.0 additions ─────────────────────────────────────────────────────────\nexport { NavCommandMenu, useNavCommandMenu } from \"./components/nav-command-menu.js\";\nexport type { NavCommand, NavCommandGroup, NavCommandMenuProps } from \"./components/nav-command-menu.js\";\n\n// ── v0.6.0 additions — portfolio subnav + counts ────────────────────────────\nexport { PortfolioSubnav } from \"./components/portfolio-subnav.js\";\nexport type {\n PortfolioSubnavProps,\n PortfolioNavItem,\n PortfolioNavGroup,\n PortfolioBadgeVariant,\n} from \"./components/portfolio-subnav.js\";\nexport { derivePortfolioCounts } from \"./utils/portfolio-counts.js\";\nexport type { PortfolioCounts, CountableOrder } from \"./utils/portfolio-counts.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,gBAAmB;AACnB,oBAAmC;AACnC,qBAA+B;AAC/B,kBAA2B;AAG3B,sBAA+C;AAE/C,gBAGO;AAEP,0BAEO;AAEP,6BAA8B;AAC9B,oCAAqC;AACrC,+BAAgC;AAChC,uCAAwC;AAExC,gCAAsE;AACtE,mBAAsB;AAGtB,2BAA6C;AAG7C,2BAAyD;AAGzD,6BAA+B;AAG/B,wBAA8B;AAE9B,wBAAkC;AAIlC,+BAAyF;AACzF,4BAA8B;AAE9B,4BAA8B;AAE9B,0BAA4B;AAE5B,6BAAuD;AAEvD,wBAA6C;AAG7C,mBAGO;AACP,uBAA2F;AAC3F,4BAGO;AAGP,kBAAmC;AACnC,sBAAmD;AAEnD,yBAA+C;AAE/C,6BAA+B;AAE/B,0BAAiD;AAEjD,0BAA4B;AAE5B,iCAAkC;AAElC,2BAA4B;AAI5B,2BAA6B;AAE7B,+BAA2D;AAE3D,wCAAyC;AAEzC,qCAAsC;AAEtC,mCAAoC;AAEpC,2BAAsE;AAItE,gCAA6E;AAC7E,6BAA+B;AAG/B,IAAAA,6BAAwE;AAIxE,8BAAkD;AAIlD,8BAAgC;AAOhC,8BAAsC;","names":["import_launchpad_services"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -22,6 +22,9 @@ export { ScrollSection, ScrollSectionProps } from './components/scroll-section.c
|
|
|
22
22
|
export { ShareButton, ShareButtonProps } from './components/share-button.cjs';
|
|
23
23
|
export { CollectionCard, CollectionCardProps, CollectionCardSkeleton } from './components/collection-card.cjs';
|
|
24
24
|
export { RarityTier, TokenCard, TokenCardProps, TokenCardSkeleton } from './components/token-card.cjs';
|
|
25
|
+
export { CoinCollectionLike, CoinKind, CoinPriceLike, coinKind, formatCoinPrice, formatFdv } from './data/coins.cjs';
|
|
26
|
+
export { CoinCard, CoinCardSkeleton, CoinRow, CoinTileProps, UseCoinPrice } from './components/coin-card.cjs';
|
|
27
|
+
export { CoinFilter, CoinSort, CoinsExplorer, CoinsExplorerProps, UseCoins } from './components/coins-explorer.cjs';
|
|
25
28
|
export { timeAgo, timeUntil } from './utils/time.cjs';
|
|
26
29
|
export { ACTIVITY_TYPE_CONFIG, ActivityTypeConfig, TYPE_FILTERS } from './data/activity.cjs';
|
|
27
30
|
export { HeroSlider, HeroSliderProps, HeroSliderSkeleton } from './components/hero-slider.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,9 @@ export { ScrollSection, ScrollSectionProps } from './components/scroll-section.j
|
|
|
22
22
|
export { ShareButton, ShareButtonProps } from './components/share-button.js';
|
|
23
23
|
export { CollectionCard, CollectionCardProps, CollectionCardSkeleton } from './components/collection-card.js';
|
|
24
24
|
export { RarityTier, TokenCard, TokenCardProps, TokenCardSkeleton } from './components/token-card.js';
|
|
25
|
+
export { CoinCollectionLike, CoinKind, CoinPriceLike, coinKind, formatCoinPrice, formatFdv } from './data/coins.js';
|
|
26
|
+
export { CoinCard, CoinCardSkeleton, CoinRow, CoinTileProps, UseCoinPrice } from './components/coin-card.js';
|
|
27
|
+
export { CoinFilter, CoinSort, CoinsExplorer, CoinsExplorerProps, UseCoins } from './components/coins-explorer.js';
|
|
25
28
|
export { timeAgo, timeUntil } from './utils/time.js';
|
|
26
29
|
export { ACTIVITY_TYPE_CONFIG, ActivityTypeConfig, TYPE_FILTERS } from './data/activity.js';
|
|
27
30
|
export { HeroSlider, HeroSliderProps, HeroSliderSkeleton } from './components/hero-slider.js';
|
package/dist/index.js
CHANGED
|
@@ -35,6 +35,15 @@ import { ScrollSection } from "./components/scroll-section.js";
|
|
|
35
35
|
import { ShareButton } from "./components/share-button.js";
|
|
36
36
|
import { CollectionCard, CollectionCardSkeleton } from "./components/collection-card.js";
|
|
37
37
|
import { TokenCard, TokenCardSkeleton } from "./components/token-card.js";
|
|
38
|
+
import {
|
|
39
|
+
coinKind,
|
|
40
|
+
formatCoinPrice,
|
|
41
|
+
formatFdv
|
|
42
|
+
} from "./data/coins.js";
|
|
43
|
+
import { CoinCard, CoinRow, CoinCardSkeleton } from "./components/coin-card.js";
|
|
44
|
+
import {
|
|
45
|
+
CoinsExplorer
|
|
46
|
+
} from "./components/coins-explorer.js";
|
|
38
47
|
import { timeAgo, timeUntil } from "./utils/time.js";
|
|
39
48
|
import { ACTIVITY_TYPE_CONFIG, TYPE_FILTERS } from "./data/activity.js";
|
|
40
49
|
import { HeroSlider, HeroSliderSkeleton } from "./components/hero-slider.js";
|
|
@@ -70,6 +79,10 @@ export {
|
|
|
70
79
|
AssetMediaColumn,
|
|
71
80
|
AssetOverviewContent,
|
|
72
81
|
BRAND,
|
|
82
|
+
CoinCard,
|
|
83
|
+
CoinCardSkeleton,
|
|
84
|
+
CoinRow,
|
|
85
|
+
CoinsExplorer,
|
|
73
86
|
CollectionCard,
|
|
74
87
|
CollectionCardSkeleton,
|
|
75
88
|
CtaCardGrid,
|
|
@@ -127,8 +140,11 @@ export {
|
|
|
127
140
|
TokenCardSkeleton,
|
|
128
141
|
buildEditionStats,
|
|
129
142
|
cn,
|
|
143
|
+
coinKind,
|
|
130
144
|
derivePortfolioCounts,
|
|
145
|
+
formatCoinPrice,
|
|
131
146
|
formatDisplayPrice,
|
|
147
|
+
formatFdv,
|
|
132
148
|
ipfsToHttp,
|
|
133
149
|
shortenAddress,
|
|
134
150
|
timeAgo,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// ── Utils ─────────────────────────────────────────────────────────────────────\nexport { cn } from \"./utils/cn.js\";\nexport { formatDisplayPrice } from \"./utils/format.js\";\nexport { shortenAddress } from \"./utils/address.js\";\nexport { ipfsToHttp } from \"./utils/ipfs.js\";\n\n// ── Data (server-safe — no React, safe in Server Components) ──────────────────\nexport { IP_TYPE_DATA, IP_TYPE_DATA_MAP } from \"./data/ip-types.js\";\nexport type { IpTypeData } from \"./data/ip-types.js\";\nexport {\n IP_TYPES, LICENSE_TYPES, GEOGRAPHIC_SCOPES, AI_POLICIES,\n DERIVATIVES_OPTIONS, LICENSE_TRAIT_TYPES,\n} from \"./data/ip.js\";\nexport type { IPType, LicenseType } from \"./data/ip.js\";\nexport {\n IP_TEMPLATES, EMBED_PLATFORM_META, SOCIAL_PLATFORM_META, TEMPLATE_TRAIT_TYPES, DOC_UPLOAD,\n} from \"./data/ip-templates.js\";\nexport type { EmbedPlatform, SocialPlatform, TraitSuggestion, IPTemplate, DocUploadConfig } from \"./data/ip-templates.js\";\nexport { IPTypeDisplay } from \"./components/ip-type-display.js\";\nexport { AssetOverviewContent } from \"./components/asset-overview-content.js\";\nexport { AssetMarketsTab } from \"./components/asset-markets-tab.js\";\nexport { ParentAttributionBanner } from \"./components/parent-attribution-banner.js\";\nexport type { ParentBannerProps } from \"./components/parent-attribution-banner.js\";\nexport { AssetMediaColumn, AssetHeaderBlock, buildEditionStats } from \"./components/asset-top-sections.js\";\nexport { BRAND } from \"./data/brand.js\";\n\n// ── Components (client-only — all have \"use client\") ─────────────────────────\nexport { CurrencyIcon, CurrencyAmount } from \"./components/currency-icon.js\";\nexport type { CurrencyIconProps, CurrencyAmountProps } from \"./components/currency-icon.js\";\n\nexport { IpTypeBadge, IP_TYPE_CONFIG, IP_TYPE_MAP } from \"./components/ip-type-badge.js\";\nexport type { IpTypeBadgeProps, IpTypeConfig } from \"./components/ip-type-badge.js\";\n\nexport { AddressDisplay } from \"./components/address-display.js\";\nexport type { AddressDisplayProps } from \"./components/address-display.js\";\n\nexport { MedialaneIcon } from \"./components/brand-icon.js\";\nexport type { MedialaneIconProps } from \"./components/brand-icon.js\";\nexport { MedialaneLogoFull } from \"./components/brand-logo.js\";\nexport type { MedialaneLogoFullProps } from \"./components/brand-logo.js\";\n\n// ── v0.2 additions ────────────────────────────────────────────────────────────\nexport { MotionCard, FadeIn, Stagger, StaggerItem, KineticWords, SPRING, EASE_OUT } from \"./components/motion-primitives.js\";\nexport { PageContainer } from \"./components/page-container.js\";\nexport type { PageContainerProps } from \"./components/page-container.js\";\nexport { ScrollSection } from \"./components/scroll-section.js\";\nexport type { ScrollSectionProps } from \"./components/scroll-section.js\";\nexport { ShareButton } from \"./components/share-button.js\";\nexport type { ShareButtonProps } from \"./components/share-button.js\";\nexport { CollectionCard, CollectionCardSkeleton } from \"./components/collection-card.js\";\nexport type { CollectionCardProps } from \"./components/collection-card.js\";\nexport { TokenCard, TokenCardSkeleton } from \"./components/token-card.js\";\nexport type { TokenCardProps, RarityTier } from \"./components/token-card.js\";\n\n// ── v0.3 additions ────────────────────────────────────────────────────────────\nexport { timeAgo, timeUntil } from \"./utils/time.js\";\nexport { ACTIVITY_TYPE_CONFIG, TYPE_FILTERS } from \"./data/activity.js\";\nexport type { ActivityTypeConfig } from \"./data/activity.js\";\nexport { HeroSlider, HeroSliderSkeleton } from \"./components/hero-slider.js\";\nexport type { HeroSliderProps } from \"./components/hero-slider.js\";\nexport { ActivityTicker } from \"./components/activity-ticker.js\";\nexport type { ActivityTickerProps } from \"./components/activity-ticker.js\";\nexport { ListingCard, ListingCardSkeleton } from \"./components/listing-card.js\";\nexport type { ListingCardProps } from \"./components/listing-card.js\";\nexport { ActivityRow } from \"./components/activity-row.js\";\nexport type { ActivityRowProps } from \"./components/activity-row.js\";\nexport { ActivityFeedShell } from \"./components/activity-feed-shell.js\";\nexport type { ActivityFeedShellProps } from \"./components/activity-feed-shell.js\";\nexport { CtaCardGrid } from \"./components/cta-card-grid.js\";\nexport type { CtaCardGridProps, CtaCardItem } from \"./components/cta-card-grid.js\";\n\n// ── v0.3.2 additions ─────────────────────────────────────────────────────────\nexport { DiscoverHero } from \"./components/discover-hero.js\";\nexport type { DiscoverHeroProps } from \"./components/discover-hero.js\";\nexport { FeaturedCarousel, FeaturedCarouselSkeleton } from \"./components/featured-carousel.js\";\nexport type { FeaturedCarouselProps } from \"./components/featured-carousel.js\";\nexport { DiscoverCollectionsStrip } from \"./components/discover-collections-strip.js\";\nexport type { DiscoverCollectionsStripProps } from \"./components/discover-collections-strip.js\";\nexport { DiscoverCreatorsStrip } from \"./components/discover-creators-strip.js\";\nexport type { DiscoverCreatorsStripProps } from \"./components/discover-creators-strip.js\";\nexport { DiscoverFeedSection } from \"./components/discover-feed-section.js\";\nexport type { DiscoverFeedSectionProps } from \"./components/discover-feed-section.js\";\nexport { ActivityCard, ActivityCardSkeleton, ACTIVITY_MESSAGES } from \"./components/activity-card.js\";\nexport type { ActivityCardProps } from \"./components/activity-card.js\";\n\n// ── Launchpad (grouped sections — single page-UI source since 0.8.0) ─────────\nexport { LaunchpadGroupedSections, LaunchpadServiceCard, SERVICE_HUES } from \"./components/launchpad-services.js\";\nexport { LaunchpadStrip } from \"./components/launchpad-strip.js\";\nexport type { LaunchpadStripProps } from \"./components/launchpad-strip.js\";\nexport type { LaunchpadGroupedSectionsProps, LaunchpadServiceCardProps, ServiceOverride, ServiceOverrides } from \"./components/launchpad-services.js\";\nexport { LAUNCHPAD_SERVICE_DEFINITIONS, LAUNCHPAD_SERVICE_GROUPS } from \"./data/launchpad-services.js\";\nexport type { ServiceDefinition, ServiceStatus, ServiceCategory, ServiceGroup, ServiceGroupDefinition } from \"./data/launchpad-services.js\";\n\n// ── v0.5.0 additions ─────────────────────────────────────────────────────────\nexport { NavCommandMenu, useNavCommandMenu } from \"./components/nav-command-menu.js\";\nexport type { NavCommand, NavCommandGroup, NavCommandMenuProps } from \"./components/nav-command-menu.js\";\n\n// ── v0.6.0 additions — portfolio subnav + counts ────────────────────────────\nexport { PortfolioSubnav } from \"./components/portfolio-subnav.js\";\nexport type {\n PortfolioSubnavProps,\n PortfolioNavItem,\n PortfolioNavGroup,\n PortfolioBadgeVariant,\n} from \"./components/portfolio-subnav.js\";\nexport { derivePortfolioCounts } from \"./utils/portfolio-counts.js\";\nexport type { PortfolioCounts, CountableOrder } from \"./utils/portfolio-counts.js\";\n"],"mappings":"AACA,SAAS,UAAU;AACnB,SAAS,0BAA0B;AACnC,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAG3B,SAAS,cAAc,wBAAwB;AAE/C;AAAA,EACE;AAAA,EAAU;AAAA,EAAe;AAAA,EAAmB;AAAA,EAC5C;AAAA,EAAqB;AAAA,OAChB;AAEP;AAAA,EACE;AAAA,EAAc;AAAA,EAAqB;AAAA,EAAsB;AAAA,EAAsB;AAAA,OAC1E;AAEP,SAAS,qBAAqB;AAC9B,SAAS,4BAA4B;AACrC,SAAS,uBAAuB;AAChC,SAAS,+BAA+B;AAExC,SAAS,kBAAkB,kBAAkB,yBAAyB;AACtE,SAAS,aAAa;AAGtB,SAAS,cAAc,sBAAsB;AAG7C,SAAS,aAAa,gBAAgB,mBAAmB;AAGzD,SAAS,sBAAsB;AAG/B,SAAS,qBAAqB;AAE9B,SAAS,yBAAyB;AAIlC,SAAS,YAAY,QAAQ,SAAS,aAAa,cAAc,QAAQ,gBAAgB;AACzF,SAAS,qBAAqB;AAE9B,SAAS,qBAAqB;AAE9B,SAAS,mBAAmB;AAE5B,SAAS,gBAAgB,8BAA8B;AAEvD,SAAS,WAAW,yBAAyB;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// ── Utils ─────────────────────────────────────────────────────────────────────\nexport { cn } from \"./utils/cn.js\";\nexport { formatDisplayPrice } from \"./utils/format.js\";\nexport { shortenAddress } from \"./utils/address.js\";\nexport { ipfsToHttp } from \"./utils/ipfs.js\";\n\n// ── Data (server-safe — no React, safe in Server Components) ──────────────────\nexport { IP_TYPE_DATA, IP_TYPE_DATA_MAP } from \"./data/ip-types.js\";\nexport type { IpTypeData } from \"./data/ip-types.js\";\nexport {\n IP_TYPES, LICENSE_TYPES, GEOGRAPHIC_SCOPES, AI_POLICIES,\n DERIVATIVES_OPTIONS, LICENSE_TRAIT_TYPES,\n} from \"./data/ip.js\";\nexport type { IPType, LicenseType } from \"./data/ip.js\";\nexport {\n IP_TEMPLATES, EMBED_PLATFORM_META, SOCIAL_PLATFORM_META, TEMPLATE_TRAIT_TYPES, DOC_UPLOAD,\n} from \"./data/ip-templates.js\";\nexport type { EmbedPlatform, SocialPlatform, TraitSuggestion, IPTemplate, DocUploadConfig } from \"./data/ip-templates.js\";\nexport { IPTypeDisplay } from \"./components/ip-type-display.js\";\nexport { AssetOverviewContent } from \"./components/asset-overview-content.js\";\nexport { AssetMarketsTab } from \"./components/asset-markets-tab.js\";\nexport { ParentAttributionBanner } from \"./components/parent-attribution-banner.js\";\nexport type { ParentBannerProps } from \"./components/parent-attribution-banner.js\";\nexport { AssetMediaColumn, AssetHeaderBlock, buildEditionStats } from \"./components/asset-top-sections.js\";\nexport { BRAND } from \"./data/brand.js\";\n\n// ── Components (client-only — all have \"use client\") ─────────────────────────\nexport { CurrencyIcon, CurrencyAmount } from \"./components/currency-icon.js\";\nexport type { CurrencyIconProps, CurrencyAmountProps } from \"./components/currency-icon.js\";\n\nexport { IpTypeBadge, IP_TYPE_CONFIG, IP_TYPE_MAP } from \"./components/ip-type-badge.js\";\nexport type { IpTypeBadgeProps, IpTypeConfig } from \"./components/ip-type-badge.js\";\n\nexport { AddressDisplay } from \"./components/address-display.js\";\nexport type { AddressDisplayProps } from \"./components/address-display.js\";\n\nexport { MedialaneIcon } from \"./components/brand-icon.js\";\nexport type { MedialaneIconProps } from \"./components/brand-icon.js\";\nexport { MedialaneLogoFull } from \"./components/brand-logo.js\";\nexport type { MedialaneLogoFullProps } from \"./components/brand-logo.js\";\n\n// ── v0.2 additions ────────────────────────────────────────────────────────────\nexport { MotionCard, FadeIn, Stagger, StaggerItem, KineticWords, SPRING, EASE_OUT } from \"./components/motion-primitives.js\";\nexport { PageContainer } from \"./components/page-container.js\";\nexport type { PageContainerProps } from \"./components/page-container.js\";\nexport { ScrollSection } from \"./components/scroll-section.js\";\nexport type { ScrollSectionProps } from \"./components/scroll-section.js\";\nexport { ShareButton } from \"./components/share-button.js\";\nexport type { ShareButtonProps } from \"./components/share-button.js\";\nexport { CollectionCard, CollectionCardSkeleton } from \"./components/collection-card.js\";\nexport type { CollectionCardProps } from \"./components/collection-card.js\";\nexport { TokenCard, TokenCardSkeleton } from \"./components/token-card.js\";\nexport type { TokenCardProps, RarityTier } from \"./components/token-card.js\";\n// ── Coin discovery (chain-agnostic; price/data/href injected by the app) ─────\nexport {\n coinKind, formatCoinPrice, formatFdv,\n type CoinKind, type CoinCollectionLike, type CoinPriceLike,\n} from \"./data/coins.js\";\nexport { CoinCard, CoinRow, CoinCardSkeleton, type UseCoinPrice, type CoinTileProps } from \"./components/coin-card.js\";\nexport {\n CoinsExplorer,\n type CoinsExplorerProps, type CoinFilter, type CoinSort, type UseCoins,\n} from \"./components/coins-explorer.js\";\n\n// ── v0.3 additions ────────────────────────────────────────────────────────────\nexport { timeAgo, timeUntil } from \"./utils/time.js\";\nexport { ACTIVITY_TYPE_CONFIG, TYPE_FILTERS } from \"./data/activity.js\";\nexport type { ActivityTypeConfig } from \"./data/activity.js\";\nexport { HeroSlider, HeroSliderSkeleton } from \"./components/hero-slider.js\";\nexport type { HeroSliderProps } from \"./components/hero-slider.js\";\nexport { ActivityTicker } from \"./components/activity-ticker.js\";\nexport type { ActivityTickerProps } from \"./components/activity-ticker.js\";\nexport { ListingCard, ListingCardSkeleton } from \"./components/listing-card.js\";\nexport type { ListingCardProps } from \"./components/listing-card.js\";\nexport { ActivityRow } from \"./components/activity-row.js\";\nexport type { ActivityRowProps } from \"./components/activity-row.js\";\nexport { ActivityFeedShell } from \"./components/activity-feed-shell.js\";\nexport type { ActivityFeedShellProps } from \"./components/activity-feed-shell.js\";\nexport { CtaCardGrid } from \"./components/cta-card-grid.js\";\nexport type { CtaCardGridProps, CtaCardItem } from \"./components/cta-card-grid.js\";\n\n// ── v0.3.2 additions ─────────────────────────────────────────────────────────\nexport { DiscoverHero } from \"./components/discover-hero.js\";\nexport type { DiscoverHeroProps } from \"./components/discover-hero.js\";\nexport { FeaturedCarousel, FeaturedCarouselSkeleton } from \"./components/featured-carousel.js\";\nexport type { FeaturedCarouselProps } from \"./components/featured-carousel.js\";\nexport { DiscoverCollectionsStrip } from \"./components/discover-collections-strip.js\";\nexport type { DiscoverCollectionsStripProps } from \"./components/discover-collections-strip.js\";\nexport { DiscoverCreatorsStrip } from \"./components/discover-creators-strip.js\";\nexport type { DiscoverCreatorsStripProps } from \"./components/discover-creators-strip.js\";\nexport { DiscoverFeedSection } from \"./components/discover-feed-section.js\";\nexport type { DiscoverFeedSectionProps } from \"./components/discover-feed-section.js\";\nexport { ActivityCard, ActivityCardSkeleton, ACTIVITY_MESSAGES } from \"./components/activity-card.js\";\nexport type { ActivityCardProps } from \"./components/activity-card.js\";\n\n// ── Launchpad (grouped sections — single page-UI source since 0.8.0) ─────────\nexport { LaunchpadGroupedSections, LaunchpadServiceCard, SERVICE_HUES } from \"./components/launchpad-services.js\";\nexport { LaunchpadStrip } from \"./components/launchpad-strip.js\";\nexport type { LaunchpadStripProps } from \"./components/launchpad-strip.js\";\nexport type { LaunchpadGroupedSectionsProps, LaunchpadServiceCardProps, ServiceOverride, ServiceOverrides } from \"./components/launchpad-services.js\";\nexport { LAUNCHPAD_SERVICE_DEFINITIONS, LAUNCHPAD_SERVICE_GROUPS } from \"./data/launchpad-services.js\";\nexport type { ServiceDefinition, ServiceStatus, ServiceCategory, ServiceGroup, ServiceGroupDefinition } from \"./data/launchpad-services.js\";\n\n// ── v0.5.0 additions ─────────────────────────────────────────────────────────\nexport { NavCommandMenu, useNavCommandMenu } from \"./components/nav-command-menu.js\";\nexport type { NavCommand, NavCommandGroup, NavCommandMenuProps } from \"./components/nav-command-menu.js\";\n\n// ── v0.6.0 additions — portfolio subnav + counts ────────────────────────────\nexport { PortfolioSubnav } from \"./components/portfolio-subnav.js\";\nexport type {\n PortfolioSubnavProps,\n PortfolioNavItem,\n PortfolioNavGroup,\n PortfolioBadgeVariant,\n} from \"./components/portfolio-subnav.js\";\nexport { derivePortfolioCounts } from \"./utils/portfolio-counts.js\";\nexport type { PortfolioCounts, CountableOrder } from \"./utils/portfolio-counts.js\";\n"],"mappings":"AACA,SAAS,UAAU;AACnB,SAAS,0BAA0B;AACnC,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAG3B,SAAS,cAAc,wBAAwB;AAE/C;AAAA,EACE;AAAA,EAAU;AAAA,EAAe;AAAA,EAAmB;AAAA,EAC5C;AAAA,EAAqB;AAAA,OAChB;AAEP;AAAA,EACE;AAAA,EAAc;AAAA,EAAqB;AAAA,EAAsB;AAAA,EAAsB;AAAA,OAC1E;AAEP,SAAS,qBAAqB;AAC9B,SAAS,4BAA4B;AACrC,SAAS,uBAAuB;AAChC,SAAS,+BAA+B;AAExC,SAAS,kBAAkB,kBAAkB,yBAAyB;AACtE,SAAS,aAAa;AAGtB,SAAS,cAAc,sBAAsB;AAG7C,SAAS,aAAa,gBAAgB,mBAAmB;AAGzD,SAAS,sBAAsB;AAG/B,SAAS,qBAAqB;AAE9B,SAAS,yBAAyB;AAIlC,SAAS,YAAY,QAAQ,SAAS,aAAa,cAAc,QAAQ,gBAAgB;AACzF,SAAS,qBAAqB;AAE9B,SAAS,qBAAqB;AAE9B,SAAS,mBAAmB;AAE5B,SAAS,gBAAgB,8BAA8B;AAEvD,SAAS,WAAW,yBAAyB;AAG7C;AAAA,EACE;AAAA,EAAU;AAAA,EAAiB;AAAA,OAEtB;AACP,SAAS,UAAU,SAAS,wBAA+D;AAC3F;AAAA,EACE;AAAA,OAEK;AAGP,SAAS,SAAS,iBAAiB;AACnC,SAAS,sBAAsB,oBAAoB;AAEnD,SAAS,YAAY,0BAA0B;AAE/C,SAAS,sBAAsB;AAE/B,SAAS,aAAa,2BAA2B;AAEjD,SAAS,mBAAmB;AAE5B,SAAS,yBAAyB;AAElC,SAAS,mBAAmB;AAI5B,SAAS,oBAAoB;AAE7B,SAAS,kBAAkB,gCAAgC;AAE3D,SAAS,gCAAgC;AAEzC,SAAS,6BAA6B;AAEtC,SAAS,2BAA2B;AAEpC,SAAS,cAAc,sBAAsB,yBAAyB;AAItE,SAAS,0BAA0B,sBAAsB,oBAAoB;AAC7E,SAAS,sBAAsB;AAG/B,SAAS,+BAA+B,gCAAgC;AAIxE,SAAS,gBAAgB,yBAAyB;AAIlD,SAAS,uBAAuB;AAOhC,SAAS,6BAA6B;","names":[]}
|