@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 CHANGED
@@ -173,16 +173,37 @@ import {
173
173
 
174
174
  ---
175
175
 
176
- ### v0.4 Launchpad Services
176
+ ### Launchpad (single page-UI source since v0.8)
177
177
 
178
178
  ```ts
179
- import { LaunchpadServicesGrid, LAUNCHPAD_SERVICE_DEFINITIONS } from "@medialane/ui";
179
+ import { LaunchpadGroupedSections, LaunchpadStrip, LAUNCHPAD_SERVICE_DEFINITIONS, SERVICE_HUES } from "@medialane/ui";
180
180
  ```
181
181
 
182
182
  | Export | Description |
183
183
  |---|---|
184
- | `<LaunchpadServicesGrid services={LAUNCHPAD_SERVICE_DEFINITIONS} />` | Launchpad services grid with live/coming-soon badges |
185
- | `LAUNCHPAD_SERVICE_DEFINITIONS` | Pre-built service definitions for all launchpad products |
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.4.0** | `LaunchpadServicesGrid`, `LAUNCHPAD_SERVICE_DEFINITIONS` |
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 &amp; 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 &amp; 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,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,
@@ -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;AAI7C,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"]}
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;AAI7C,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":[]}
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":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medialane/ui",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "Shared UI components for Medialane apps",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",