@medialane/ui 0.87.0 → 0.89.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
@@ -233,6 +233,7 @@ The package uses [tsup](https://tsup.egoist.dev/) and outputs ESM + CJS + type d
233
233
 
234
234
  | Version | Added |
235
235
  |---|---|
236
+ | **v0.87.0** | `NavWalletTrigger` gains optional `disconnectedIcon` — overrides the default `Wallet` glyph in the disconnected-state ring, for apps whose real connect entry point isn't a wallet (e.g. a Google mark for an email/social-login app). Omitted = unchanged `Wallet` default |
236
237
  | **v0.86.0** | `NavWalletTrigger`'s disconnected state shows a plain `Wallet` glyph inside the rotating ring instead of an empty center — the bare ring wasn't being noticed as a connect entry point. Connected state unchanged |
237
238
  | **v0.85.0** | `NavCommandMenu` gains two optional props: `showKeyboardHints` (default `true` — hide the "↑↓ Navigate / ↵ Open" footer hint) and `brandSlot` (replace the static "medialane ⌘K" footer brandmark entirely, e.g. with a "Connect" button). Both default to the prior behavior — non-breaking |
238
239
  | **v0.84.0** | gol_starknet living-render support: `useIntersectionActive` + `AnimatedTokenMedia` swap a token's static image for a sandboxed iframe of its on-chain `animation_url` once visible, wired into `TokenCard`/`AssetCard`; SDK peer floor `>=0.73.0`. **Also replaces `AssetMediaColumn`** with the borderless/real-aspect-ratio/click-to-zoom design both apps had already forked locally |
@@ -63,9 +63,9 @@ function CoinsExplorer({ useCoins, usePrice, coinHref, heading = true }) {
63
63
  heading && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
64
64
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2 text-primary", children: [
65
65
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Coins, { className: "h-5 w-5" }),
66
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-semibold uppercase tracking-wider", children: "Tokens" })
66
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-semibold uppercase tracking-wider", children: "Coins" })
67
67
  ] }),
68
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "text-3xl font-bold", children: "Creator coins & memecoins" })
68
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "text-3xl", children: "Creator coins & memecoins" })
69
69
  ] }),
70
70
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-3 border-b border-border/60 pb-3", children: [
71
71
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
@@ -1 +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 * Type + sort live in a centered Filters dialog (the \"action focus\" pattern, and\n * matching the marketplace page); the header stays to two lines.\n */\n\nimport { useState, useMemo, useEffect } from \"react\";\nimport { Coins, LayoutGrid, List, Search, SlidersHorizontal, X } 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\nconst filterLabel = (v: CoinFilter) => FILTER_TABS.find((t) => t.value === v)?.label ?? \"\";\nconst sortLabel = (v: CoinSort) => SORT_OPTIONS.find((o) => o.value === v)?.label ?? \"\";\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 const [filtersOpen, setFiltersOpen] = useState(false);\n\n const filterCount = (filter !== \"all\" ? 1 : 0) + (sort !== \"recent\" ? 1 : 0);\n\n useEffect(() => {\n if (!filtersOpen) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setFiltersOpen(false);\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [filtersOpen]);\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 </div>\n )}\n\n {/* Controls — search + filters + view, kept lean. */}\n <div className=\"space-y-3 border-b border-border/60 pb-3\">\n <div className=\"flex items-center gap-2\">\n <div className=\"relative flex-1\">\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 <button\n onClick={() => setFiltersOpen(true)}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-border px-3 py-2 text-xs font-medium text-foreground hover:border-primary/50\"\n >\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n Filters\n {filterCount > 0 && (\n <span className=\"ml-0.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-semibold text-primary-foreground\">\n {filterCount}\n </span>\n )}\n </button>\n <div className=\"inline-flex shrink-0 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\n {/* Active-filter chips */}\n {filterCount > 0 && (\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {filter !== \"all\" && (\n <Chip onClear={() => setFilter(\"all\")}>{filterLabel(filter)}</Chip>\n )}\n {sort !== \"recent\" && (\n <Chip onClear={() => setSort(\"recent\")}>{sortLabel(sort)}</Chip>\n )}\n </div>\n )}\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\n {filtersOpen && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Filters\">\n <div className=\"absolute inset-0 bg-background/70 backdrop-blur-sm\" onClick={() => setFiltersOpen(false)} />\n <div className=\"card-base relative z-10 w-full max-w-sm space-y-5 p-5\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"flex items-center gap-2 text-base font-bold\">\n <SlidersHorizontal className=\"h-4 w-4 text-primary\" />\n Filters\n </h2>\n {filterCount > 0 && (\n <button\n onClick={() => { setFilter(\"all\"); setSort(\"recent\"); }}\n className=\"text-xs font-medium text-muted-foreground hover:text-foreground\"\n >\n Clear all\n </button>\n )}\n </div>\n\n <FilterGroup label=\"Type\">\n {FILTER_TABS.map(({ label, value }) => (\n <PillButton key={value} active={filter === value} onClick={() => setFilter(value)}>{label}</PillButton>\n ))}\n </FilterGroup>\n\n <FilterGroup label=\"Sort\">\n {SORT_OPTIONS.map(({ label, value }) => (\n <PillButton key={value} active={sort === value} onClick={() => setSort(value)}>{label}</PillButton>\n ))}\n </FilterGroup>\n\n <button\n onClick={() => setFiltersOpen(false)}\n className=\"w-full rounded-lg bg-gradient-to-r from-brand-blue to-brand-purple py-2.5 text-sm font-semibold text-white\"\n >\n Show {items.length} {items.length === 1 ? \"coin\" : \"coins\"}\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction FilterGroup({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"space-y-2\">\n <p className=\"text-[10px] font-semibold uppercase tracking-wider text-muted-foreground\">{label}</p>\n <div className=\"flex flex-wrap gap-1.5\">{children}</div>\n </div>\n );\n}\n\nfunction PillButton({ active, onClick, children }: { active: boolean; onClick: () => void; children: React.ReactNode }) {\n return (\n <button\n onClick={onClick}\n className={cn(\n \"rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors\",\n active ? \"border-primary bg-primary/10 text-primary\" : \"border-border text-muted-foreground hover:border-primary/50 hover:text-foreground\"\n )}\n >\n {children}\n </button>\n );\n}\n\nfunction Chip({ children, onClear }: { children: React.ReactNode; onClear: () => void }) {\n return (\n <span className=\"inline-flex items-center gap-1 rounded-full border border-primary/30 bg-primary/10 px-2.5 py-1 text-xs font-medium text-primary\">\n {children}\n <button onClick={onClear} aria-label=\"Clear filter\" className=\"hover:text-primary/60\">\n <X className=\"h-3 w-3\" />\n </button>\n </span>\n );\n}\n"],"mappings":"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","names":[]}
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 * Type + sort live in a centered Filters dialog (the \"action focus\" pattern, and\n * matching the marketplace page); the header stays to two lines.\n */\n\nimport { useState, useMemo, useEffect } from \"react\";\nimport { Coins, LayoutGrid, List, Search, SlidersHorizontal, X } 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\nconst filterLabel = (v: CoinFilter) => FILTER_TABS.find((t) => t.value === v)?.label ?? \"\";\nconst sortLabel = (v: CoinSort) => SORT_OPTIONS.find((o) => o.value === v)?.label ?? \"\";\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 const [filtersOpen, setFiltersOpen] = useState(false);\n\n const filterCount = (filter !== \"all\" ? 1 : 0) + (sort !== \"recent\" ? 1 : 0);\n\n useEffect(() => {\n if (!filtersOpen) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setFiltersOpen(false);\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [filtersOpen]);\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\">Coins</span>\n </div>\n <h1 className=\"text-3xl\">Creator coins &amp; memecoins</h1>\n </div>\n )}\n\n {/* Controls — search + filters + view, kept lean. */}\n <div className=\"space-y-3 border-b border-border/60 pb-3\">\n <div className=\"flex items-center gap-2\">\n <div className=\"relative flex-1\">\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 <button\n onClick={() => setFiltersOpen(true)}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-border px-3 py-2 text-xs font-medium text-foreground hover:border-primary/50\"\n >\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n Filters\n {filterCount > 0 && (\n <span className=\"ml-0.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-semibold text-primary-foreground\">\n {filterCount}\n </span>\n )}\n </button>\n <div className=\"inline-flex shrink-0 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\n {/* Active-filter chips */}\n {filterCount > 0 && (\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {filter !== \"all\" && (\n <Chip onClear={() => setFilter(\"all\")}>{filterLabel(filter)}</Chip>\n )}\n {sort !== \"recent\" && (\n <Chip onClear={() => setSort(\"recent\")}>{sortLabel(sort)}</Chip>\n )}\n </div>\n )}\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\n {filtersOpen && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Filters\">\n <div className=\"absolute inset-0 bg-background/70 backdrop-blur-sm\" onClick={() => setFiltersOpen(false)} />\n <div className=\"card-base relative z-10 w-full max-w-sm space-y-5 p-5\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"flex items-center gap-2 text-base font-bold\">\n <SlidersHorizontal className=\"h-4 w-4 text-primary\" />\n Filters\n </h2>\n {filterCount > 0 && (\n <button\n onClick={() => { setFilter(\"all\"); setSort(\"recent\"); }}\n className=\"text-xs font-medium text-muted-foreground hover:text-foreground\"\n >\n Clear all\n </button>\n )}\n </div>\n\n <FilterGroup label=\"Type\">\n {FILTER_TABS.map(({ label, value }) => (\n <PillButton key={value} active={filter === value} onClick={() => setFilter(value)}>{label}</PillButton>\n ))}\n </FilterGroup>\n\n <FilterGroup label=\"Sort\">\n {SORT_OPTIONS.map(({ label, value }) => (\n <PillButton key={value} active={sort === value} onClick={() => setSort(value)}>{label}</PillButton>\n ))}\n </FilterGroup>\n\n <button\n onClick={() => setFiltersOpen(false)}\n className=\"w-full rounded-lg bg-gradient-to-r from-brand-blue to-brand-purple py-2.5 text-sm font-semibold text-white\"\n >\n Show {items.length} {items.length === 1 ? \"coin\" : \"coins\"}\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction FilterGroup({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"space-y-2\">\n <p className=\"text-[10px] font-semibold uppercase tracking-wider text-muted-foreground\">{label}</p>\n <div className=\"flex flex-wrap gap-1.5\">{children}</div>\n </div>\n );\n}\n\nfunction PillButton({ active, onClick, children }: { active: boolean; onClick: () => void; children: React.ReactNode }) {\n return (\n <button\n onClick={onClick}\n className={cn(\n \"rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors\",\n active ? \"border-primary bg-primary/10 text-primary\" : \"border-border text-muted-foreground hover:border-primary/50 hover:text-foreground\"\n )}\n >\n {children}\n </button>\n );\n}\n\nfunction Chip({ children, onClear }: { children: React.ReactNode; onClear: () => void }) {\n return (\n <span className=\"inline-flex items-center gap-1 rounded-full border border-primary/30 bg-primary/10 px-2.5 py-1 text-xs font-medium text-primary\">\n {children}\n <button onClick={onClear} aria-label=\"Clear filter\" className=\"hover:text-primary/60\">\n <X className=\"h-3 w-3\" />\n </button>\n </span>\n );\n}\n"],"mappings":"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","names":[]}
@@ -40,9 +40,9 @@ function CoinsExplorer({ useCoins, usePrice, coinHref, heading = true }) {
40
40
  heading && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
41
41
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-primary", children: [
42
42
  /* @__PURE__ */ jsx(Coins, { className: "h-5 w-5" }),
43
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold uppercase tracking-wider", children: "Tokens" })
43
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold uppercase tracking-wider", children: "Coins" })
44
44
  ] }),
45
- /* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold", children: "Creator coins & memecoins" })
45
+ /* @__PURE__ */ jsx("h1", { className: "text-3xl", children: "Creator coins & memecoins" })
46
46
  ] }),
47
47
  /* @__PURE__ */ jsxs("div", { className: "space-y-3 border-b border-border/60 pb-3", children: [
48
48
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -1 +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 * Type + sort live in a centered Filters dialog (the \"action focus\" pattern, and\n * matching the marketplace page); the header stays to two lines.\n */\n\nimport { useState, useMemo, useEffect } from \"react\";\nimport { Coins, LayoutGrid, List, Search, SlidersHorizontal, X } 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\nconst filterLabel = (v: CoinFilter) => FILTER_TABS.find((t) => t.value === v)?.label ?? \"\";\nconst sortLabel = (v: CoinSort) => SORT_OPTIONS.find((o) => o.value === v)?.label ?? \"\";\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 const [filtersOpen, setFiltersOpen] = useState(false);\n\n const filterCount = (filter !== \"all\" ? 1 : 0) + (sort !== \"recent\" ? 1 : 0);\n\n useEffect(() => {\n if (!filtersOpen) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setFiltersOpen(false);\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [filtersOpen]);\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 </div>\n )}\n\n {/* Controls — search + filters + view, kept lean. */}\n <div className=\"space-y-3 border-b border-border/60 pb-3\">\n <div className=\"flex items-center gap-2\">\n <div className=\"relative flex-1\">\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 <button\n onClick={() => setFiltersOpen(true)}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-border px-3 py-2 text-xs font-medium text-foreground hover:border-primary/50\"\n >\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n Filters\n {filterCount > 0 && (\n <span className=\"ml-0.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-semibold text-primary-foreground\">\n {filterCount}\n </span>\n )}\n </button>\n <div className=\"inline-flex shrink-0 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\n {/* Active-filter chips */}\n {filterCount > 0 && (\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {filter !== \"all\" && (\n <Chip onClear={() => setFilter(\"all\")}>{filterLabel(filter)}</Chip>\n )}\n {sort !== \"recent\" && (\n <Chip onClear={() => setSort(\"recent\")}>{sortLabel(sort)}</Chip>\n )}\n </div>\n )}\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\n {filtersOpen && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Filters\">\n <div className=\"absolute inset-0 bg-background/70 backdrop-blur-sm\" onClick={() => setFiltersOpen(false)} />\n <div className=\"card-base relative z-10 w-full max-w-sm space-y-5 p-5\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"flex items-center gap-2 text-base font-bold\">\n <SlidersHorizontal className=\"h-4 w-4 text-primary\" />\n Filters\n </h2>\n {filterCount > 0 && (\n <button\n onClick={() => { setFilter(\"all\"); setSort(\"recent\"); }}\n className=\"text-xs font-medium text-muted-foreground hover:text-foreground\"\n >\n Clear all\n </button>\n )}\n </div>\n\n <FilterGroup label=\"Type\">\n {FILTER_TABS.map(({ label, value }) => (\n <PillButton key={value} active={filter === value} onClick={() => setFilter(value)}>{label}</PillButton>\n ))}\n </FilterGroup>\n\n <FilterGroup label=\"Sort\">\n {SORT_OPTIONS.map(({ label, value }) => (\n <PillButton key={value} active={sort === value} onClick={() => setSort(value)}>{label}</PillButton>\n ))}\n </FilterGroup>\n\n <button\n onClick={() => setFiltersOpen(false)}\n className=\"w-full rounded-lg bg-gradient-to-r from-brand-blue to-brand-purple py-2.5 text-sm font-semibold text-white\"\n >\n Show {items.length} {items.length === 1 ? \"coin\" : \"coins\"}\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction FilterGroup({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"space-y-2\">\n <p className=\"text-[10px] font-semibold uppercase tracking-wider text-muted-foreground\">{label}</p>\n <div className=\"flex flex-wrap gap-1.5\">{children}</div>\n </div>\n );\n}\n\nfunction PillButton({ active, onClick, children }: { active: boolean; onClick: () => void; children: React.ReactNode }) {\n return (\n <button\n onClick={onClick}\n className={cn(\n \"rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors\",\n active ? \"border-primary bg-primary/10 text-primary\" : \"border-border text-muted-foreground hover:border-primary/50 hover:text-foreground\"\n )}\n >\n {children}\n </button>\n );\n}\n\nfunction Chip({ children, onClear }: { children: React.ReactNode; onClear: () => void }) {\n return (\n <span className=\"inline-flex items-center gap-1 rounded-full border border-primary/30 bg-primary/10 px-2.5 py-1 text-xs font-medium text-primary\">\n {children}\n <button onClick={onClear} aria-label=\"Clear filter\" className=\"hover:text-primary/60\">\n <X className=\"h-3 w-3\" />\n </button>\n </span>\n );\n}\n"],"mappings":"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","names":[]}
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 * Type + sort live in a centered Filters dialog (the \"action focus\" pattern, and\n * matching the marketplace page); the header stays to two lines.\n */\n\nimport { useState, useMemo, useEffect } from \"react\";\nimport { Coins, LayoutGrid, List, Search, SlidersHorizontal, X } 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\nconst filterLabel = (v: CoinFilter) => FILTER_TABS.find((t) => t.value === v)?.label ?? \"\";\nconst sortLabel = (v: CoinSort) => SORT_OPTIONS.find((o) => o.value === v)?.label ?? \"\";\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 const [filtersOpen, setFiltersOpen] = useState(false);\n\n const filterCount = (filter !== \"all\" ? 1 : 0) + (sort !== \"recent\" ? 1 : 0);\n\n useEffect(() => {\n if (!filtersOpen) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setFiltersOpen(false);\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [filtersOpen]);\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\">Coins</span>\n </div>\n <h1 className=\"text-3xl\">Creator coins &amp; memecoins</h1>\n </div>\n )}\n\n {/* Controls — search + filters + view, kept lean. */}\n <div className=\"space-y-3 border-b border-border/60 pb-3\">\n <div className=\"flex items-center gap-2\">\n <div className=\"relative flex-1\">\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 <button\n onClick={() => setFiltersOpen(true)}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-border px-3 py-2 text-xs font-medium text-foreground hover:border-primary/50\"\n >\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n Filters\n {filterCount > 0 && (\n <span className=\"ml-0.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-semibold text-primary-foreground\">\n {filterCount}\n </span>\n )}\n </button>\n <div className=\"inline-flex shrink-0 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\n {/* Active-filter chips */}\n {filterCount > 0 && (\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {filter !== \"all\" && (\n <Chip onClear={() => setFilter(\"all\")}>{filterLabel(filter)}</Chip>\n )}\n {sort !== \"recent\" && (\n <Chip onClear={() => setSort(\"recent\")}>{sortLabel(sort)}</Chip>\n )}\n </div>\n )}\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\n {filtersOpen && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Filters\">\n <div className=\"absolute inset-0 bg-background/70 backdrop-blur-sm\" onClick={() => setFiltersOpen(false)} />\n <div className=\"card-base relative z-10 w-full max-w-sm space-y-5 p-5\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"flex items-center gap-2 text-base font-bold\">\n <SlidersHorizontal className=\"h-4 w-4 text-primary\" />\n Filters\n </h2>\n {filterCount > 0 && (\n <button\n onClick={() => { setFilter(\"all\"); setSort(\"recent\"); }}\n className=\"text-xs font-medium text-muted-foreground hover:text-foreground\"\n >\n Clear all\n </button>\n )}\n </div>\n\n <FilterGroup label=\"Type\">\n {FILTER_TABS.map(({ label, value }) => (\n <PillButton key={value} active={filter === value} onClick={() => setFilter(value)}>{label}</PillButton>\n ))}\n </FilterGroup>\n\n <FilterGroup label=\"Sort\">\n {SORT_OPTIONS.map(({ label, value }) => (\n <PillButton key={value} active={sort === value} onClick={() => setSort(value)}>{label}</PillButton>\n ))}\n </FilterGroup>\n\n <button\n onClick={() => setFiltersOpen(false)}\n className=\"w-full rounded-lg bg-gradient-to-r from-brand-blue to-brand-purple py-2.5 text-sm font-semibold text-white\"\n >\n Show {items.length} {items.length === 1 ? \"coin\" : \"coins\"}\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction FilterGroup({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"space-y-2\">\n <p className=\"text-[10px] font-semibold uppercase tracking-wider text-muted-foreground\">{label}</p>\n <div className=\"flex flex-wrap gap-1.5\">{children}</div>\n </div>\n );\n}\n\nfunction PillButton({ active, onClick, children }: { active: boolean; onClick: () => void; children: React.ReactNode }) {\n return (\n <button\n onClick={onClick}\n className={cn(\n \"rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors\",\n active ? \"border-primary bg-primary/10 text-primary\" : \"border-border text-muted-foreground hover:border-primary/50 hover:text-foreground\"\n )}\n >\n {children}\n </button>\n );\n}\n\nfunction Chip({ children, onClear }: { children: React.ReactNode; onClear: () => void }) {\n return (\n <span className=\"inline-flex items-center gap-1 rounded-full border border-primary/30 bg-primary/10 px-2.5 py-1 text-xs font-medium text-primary\">\n {children}\n <button onClick={onClear} aria-label=\"Clear filter\" className=\"hover:text-primary/60\">\n <X className=\"h-3 w-3\" />\n </button>\n </span>\n );\n}\n"],"mappings":"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","names":[]}
@@ -35,7 +35,7 @@ function CreatorChip({
35
35
  href
36
36
  }) {
37
37
  const [bannerError, setBannerError] = (0, import_react.useState)(false);
38
- const rawSrc = creator.bannerImage || creator.collectionImage || null;
38
+ const rawSrc = creator.avatarImage || creator.collectionImage || null;
39
39
  const bannerUrl = rawSrc && !bannerError ? (0, import_ipfs.ipfsToHttp)(rawSrc) : null;
40
40
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
41
41
  "a",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/discover-creators-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Users, ArrowRight } from \"lucide-react\";\nimport { FadeIn } from \"./motion-primitives.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport type { ApiCreatorProfile } from \"@medialane/sdk\";\n\nexport interface DiscoverCreatorsStripProps {\n creators: ApiCreatorProfile[];\n isLoading: boolean;\n getHref: (creator: ApiCreatorProfile) => string;\n allCreatorsHref?: string;\n sectionLabel?: string;\n title?: string;\n}\n\nfunction CreatorChipSkeleton() {\n return (\n <div className=\"shrink-0 w-64 aspect-[3/4] rounded-xl bg-muted animate-pulse\" />\n );\n}\n\nfunction CreatorChip({\n creator,\n href,\n}: {\n creator: ApiCreatorProfile;\n href: string;\n}) {\n const [bannerError, setBannerError] = useState(false);\n\n // bannerImage with collectionImage fallback — io-approved big-username design\n const rawSrc =\n creator.bannerImage ||\n (creator as ApiCreatorProfile & { collectionImage?: string | null }).collectionImage ||\n null;\n const bannerUrl = rawSrc && !bannerError ? ipfsToHttp(rawSrc) : null;\n\n return (\n <a\n href={href}\n className=\"block shrink-0 w-64 snap-start active:scale-[0.97] transition-transform duration-150 select-none\"\n >\n <div className=\"relative aspect-[3/4] rounded-xl overflow-hidden bg-muted\">\n {bannerUrl && (\n <img\n src={bannerUrl}\n alt=\"\"\n aria-hidden\n loading=\"lazy\"\n className=\"absolute inset-0 w-full h-full object-cover\"\n onError={() => setBannerError(true)}\n />\n )}\n <div className=\"absolute bottom-0 inset-x-0 px-3 py-3\">\n <p className=\"font-bold text-2xl text-white truncate\">{creator.username}</p>\n </div>\n </div>\n </a>\n );\n}\n\nexport function DiscoverCreatorsStrip({\n creators,\n isLoading,\n getHref,\n allCreatorsHref = \"/creators\",\n sectionLabel = \"Explore\",\n title = \"Creators\",\n}: DiscoverCreatorsStripProps) {\n if (!isLoading && creators.length === 0) return null;\n\n return (\n <FadeIn>\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"section-label\">{sectionLabel}</p>\n <div className=\"flex items-center gap-2 mt-0.5\">\n <Users className=\"h-4 w-4 text-brand-purple\" />\n <h2 className=\"text-lg font-bold\">{title}</h2>\n </div>\n </div>\n <a\n href={allCreatorsHref}\n className=\"inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground px-3 py-1.5 rounded-md hover:bg-accent transition-colors\"\n >\n View all <ArrowRight className=\"h-3.5 w-3.5\" />\n </a>\n </div>\n <div className=\"overflow-x-auto scrollbar-hide snap-x snap-mandatory -mx-4 px-4 md:mx-0 md:px-0\">\n <div className=\"flex gap-5 sm:gap-6 w-max pb-2\">\n {isLoading\n ? Array.from({ length: 6 }).map((_, i) => <CreatorChipSkeleton key={i} />)\n : creators.map((c) => (\n <CreatorChip key={c.walletAddress} creator={c} href={getHref(c)} />\n ))}\n </div>\n </div>\n </div>\n </FadeIn>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBI;AAjBJ,mBAAyB;AACzB,0BAAkC;AAClC,+BAAuB;AACvB,kBAA2B;AAY3B,SAAS,sBAAsB;AAC7B,SACE,4CAAC,SAAI,WAAU,gEAA+D;AAElF;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,KAAK;AAGpD,QAAM,SACJ,QAAQ,eACP,QAAoE,mBACrE;AACF,QAAM,YAAY,UAAU,CAAC,kBAAc,wBAAW,MAAM,IAAI;AAEhE,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAU;AAAA,MAEV,uDAAC,SAAI,WAAU,6DACZ;AAAA,qBACC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAI;AAAA,YACJ,eAAW;AAAA,YACX,SAAQ;AAAA,YACR,WAAU;AAAA,YACV,SAAS,MAAM,eAAe,IAAI;AAAA;AAAA,QACpC;AAAA,QAEF,4CAAC,SAAI,WAAU,yCACb,sDAAC,OAAE,WAAU,0CAA0C,kBAAQ,UAAS,GAC1E;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,QAAQ;AACV,GAA+B;AAC7B,MAAI,CAAC,aAAa,SAAS,WAAW,EAAG,QAAO;AAEhD,SACE,4CAAC,mCACC,uDAAC,SAAI,WAAU,aACb;AAAA,iDAAC,SAAI,WAAU,qCACb;AAAA,mDAAC,SACC;AAAA,oDAAC,OAAE,WAAU,iBAAiB,wBAAa;AAAA,QAC3C,6CAAC,SAAI,WAAU,kCACb;AAAA,sDAAC,6BAAM,WAAU,6BAA4B;AAAA,UAC7C,4CAAC,QAAG,WAAU,qBAAqB,iBAAM;AAAA,WAC3C;AAAA,SACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN,WAAU;AAAA,UACX;AAAA;AAAA,YACU,4CAAC,kCAAW,WAAU,eAAc;AAAA;AAAA;AAAA,MAC/C;AAAA,OACF;AAAA,IACA,4CAAC,SAAI,WAAU,mFACb,sDAAC,SAAI,WAAU,kCACZ,sBACG,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,4CAAC,yBAAyB,CAAG,CAAE,IACvE,SAAS,IAAI,CAAC,MACZ,4CAAC,eAAkC,SAAS,GAAG,MAAM,QAAQ,CAAC,KAA5C,EAAE,aAA6C,CAClE,GACP,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/discover-creators-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Users, ArrowRight } from \"lucide-react\";\nimport { FadeIn } from \"./motion-primitives.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport type { ApiCreatorProfile } from \"@medialane/sdk\";\n\nexport interface DiscoverCreatorsStripProps {\n creators: ApiCreatorProfile[];\n isLoading: boolean;\n getHref: (creator: ApiCreatorProfile) => string;\n allCreatorsHref?: string;\n sectionLabel?: string;\n title?: string;\n}\n\nfunction CreatorChipSkeleton() {\n return (\n <div className=\"shrink-0 w-64 aspect-[3/4] rounded-xl bg-muted animate-pulse\" />\n );\n}\n\nfunction CreatorChip({\n creator,\n href,\n}: {\n creator: ApiCreatorProfile;\n href: string;\n}) {\n const [bannerError, setBannerError] = useState(false);\n\n // avatarImage (the creator's chosen NFT) with collectionImage fallback — io-approved big-username design\n const rawSrc = creator.avatarImage || creator.collectionImage || null;\n const bannerUrl = rawSrc && !bannerError ? ipfsToHttp(rawSrc) : null;\n\n return (\n <a\n href={href}\n className=\"block shrink-0 w-64 snap-start active:scale-[0.97] transition-transform duration-150 select-none\"\n >\n <div className=\"relative aspect-[3/4] rounded-xl overflow-hidden bg-muted\">\n {bannerUrl && (\n <img\n src={bannerUrl}\n alt=\"\"\n aria-hidden\n loading=\"lazy\"\n className=\"absolute inset-0 w-full h-full object-cover\"\n onError={() => setBannerError(true)}\n />\n )}\n <div className=\"absolute bottom-0 inset-x-0 px-3 py-3\">\n <p className=\"font-bold text-2xl text-white truncate\">{creator.username}</p>\n </div>\n </div>\n </a>\n );\n}\n\nexport function DiscoverCreatorsStrip({\n creators,\n isLoading,\n getHref,\n allCreatorsHref = \"/creators\",\n sectionLabel = \"Explore\",\n title = \"Creators\",\n}: DiscoverCreatorsStripProps) {\n if (!isLoading && creators.length === 0) return null;\n\n return (\n <FadeIn>\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"section-label\">{sectionLabel}</p>\n <div className=\"flex items-center gap-2 mt-0.5\">\n <Users className=\"h-4 w-4 text-brand-purple\" />\n <h2 className=\"text-lg font-bold\">{title}</h2>\n </div>\n </div>\n <a\n href={allCreatorsHref}\n className=\"inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground px-3 py-1.5 rounded-md hover:bg-accent transition-colors\"\n >\n View all <ArrowRight className=\"h-3.5 w-3.5\" />\n </a>\n </div>\n <div className=\"overflow-x-auto scrollbar-hide snap-x snap-mandatory -mx-4 px-4 md:mx-0 md:px-0\">\n <div className=\"flex gap-5 sm:gap-6 w-max pb-2\">\n {isLoading\n ? Array.from({ length: 6 }).map((_, i) => <CreatorChipSkeleton key={i} />)\n : creators.map((c) => (\n <CreatorChip key={c.walletAddress} creator={c} href={getHref(c)} />\n ))}\n </div>\n </div>\n </div>\n </FadeIn>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBI;AAjBJ,mBAAyB;AACzB,0BAAkC;AAClC,+BAAuB;AACvB,kBAA2B;AAY3B,SAAS,sBAAsB;AAC7B,SACE,4CAAC,SAAI,WAAU,gEAA+D;AAElF;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,KAAK;AAGpD,QAAM,SAAS,QAAQ,eAAe,QAAQ,mBAAmB;AACjE,QAAM,YAAY,UAAU,CAAC,kBAAc,wBAAW,MAAM,IAAI;AAEhE,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAU;AAAA,MAEV,uDAAC,SAAI,WAAU,6DACZ;AAAA,qBACC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAI;AAAA,YACJ,eAAW;AAAA,YACX,SAAQ;AAAA,YACR,WAAU;AAAA,YACV,SAAS,MAAM,eAAe,IAAI;AAAA;AAAA,QACpC;AAAA,QAEF,4CAAC,SAAI,WAAU,yCACb,sDAAC,OAAE,WAAU,0CAA0C,kBAAQ,UAAS,GAC1E;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,QAAQ;AACV,GAA+B;AAC7B,MAAI,CAAC,aAAa,SAAS,WAAW,EAAG,QAAO;AAEhD,SACE,4CAAC,mCACC,uDAAC,SAAI,WAAU,aACb;AAAA,iDAAC,SAAI,WAAU,qCACb;AAAA,mDAAC,SACC;AAAA,oDAAC,OAAE,WAAU,iBAAiB,wBAAa;AAAA,QAC3C,6CAAC,SAAI,WAAU,kCACb;AAAA,sDAAC,6BAAM,WAAU,6BAA4B;AAAA,UAC7C,4CAAC,QAAG,WAAU,qBAAqB,iBAAM;AAAA,WAC3C;AAAA,SACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN,WAAU;AAAA,UACX;AAAA;AAAA,YACU,4CAAC,kCAAW,WAAU,eAAc;AAAA;AAAA;AAAA,MAC/C;AAAA,OACF;AAAA,IACA,4CAAC,SAAI,WAAU,mFACb,sDAAC,SAAI,WAAU,kCACZ,sBACG,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,4CAAC,yBAAyB,CAAG,CAAE,IACvE,SAAS,IAAI,CAAC,MACZ,4CAAC,eAAkC,SAAS,GAAG,MAAM,QAAQ,CAAC,KAA5C,EAAE,aAA6C,CAClE,GACP,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}
@@ -12,7 +12,7 @@ function CreatorChip({
12
12
  href
13
13
  }) {
14
14
  const [bannerError, setBannerError] = useState(false);
15
- const rawSrc = creator.bannerImage || creator.collectionImage || null;
15
+ const rawSrc = creator.avatarImage || creator.collectionImage || null;
16
16
  const bannerUrl = rawSrc && !bannerError ? ipfsToHttp(rawSrc) : null;
17
17
  return /* @__PURE__ */ jsx(
18
18
  "a",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/discover-creators-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Users, ArrowRight } from \"lucide-react\";\nimport { FadeIn } from \"./motion-primitives.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport type { ApiCreatorProfile } from \"@medialane/sdk\";\n\nexport interface DiscoverCreatorsStripProps {\n creators: ApiCreatorProfile[];\n isLoading: boolean;\n getHref: (creator: ApiCreatorProfile) => string;\n allCreatorsHref?: string;\n sectionLabel?: string;\n title?: string;\n}\n\nfunction CreatorChipSkeleton() {\n return (\n <div className=\"shrink-0 w-64 aspect-[3/4] rounded-xl bg-muted animate-pulse\" />\n );\n}\n\nfunction CreatorChip({\n creator,\n href,\n}: {\n creator: ApiCreatorProfile;\n href: string;\n}) {\n const [bannerError, setBannerError] = useState(false);\n\n // bannerImage with collectionImage fallback — io-approved big-username design\n const rawSrc =\n creator.bannerImage ||\n (creator as ApiCreatorProfile & { collectionImage?: string | null }).collectionImage ||\n null;\n const bannerUrl = rawSrc && !bannerError ? ipfsToHttp(rawSrc) : null;\n\n return (\n <a\n href={href}\n className=\"block shrink-0 w-64 snap-start active:scale-[0.97] transition-transform duration-150 select-none\"\n >\n <div className=\"relative aspect-[3/4] rounded-xl overflow-hidden bg-muted\">\n {bannerUrl && (\n <img\n src={bannerUrl}\n alt=\"\"\n aria-hidden\n loading=\"lazy\"\n className=\"absolute inset-0 w-full h-full object-cover\"\n onError={() => setBannerError(true)}\n />\n )}\n <div className=\"absolute bottom-0 inset-x-0 px-3 py-3\">\n <p className=\"font-bold text-2xl text-white truncate\">{creator.username}</p>\n </div>\n </div>\n </a>\n );\n}\n\nexport function DiscoverCreatorsStrip({\n creators,\n isLoading,\n getHref,\n allCreatorsHref = \"/creators\",\n sectionLabel = \"Explore\",\n title = \"Creators\",\n}: DiscoverCreatorsStripProps) {\n if (!isLoading && creators.length === 0) return null;\n\n return (\n <FadeIn>\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"section-label\">{sectionLabel}</p>\n <div className=\"flex items-center gap-2 mt-0.5\">\n <Users className=\"h-4 w-4 text-brand-purple\" />\n <h2 className=\"text-lg font-bold\">{title}</h2>\n </div>\n </div>\n <a\n href={allCreatorsHref}\n className=\"inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground px-3 py-1.5 rounded-md hover:bg-accent transition-colors\"\n >\n View all <ArrowRight className=\"h-3.5 w-3.5\" />\n </a>\n </div>\n <div className=\"overflow-x-auto scrollbar-hide snap-x snap-mandatory -mx-4 px-4 md:mx-0 md:px-0\">\n <div className=\"flex gap-5 sm:gap-6 w-max pb-2\">\n {isLoading\n ? Array.from({ length: 6 }).map((_, i) => <CreatorChipSkeleton key={i} />)\n : creators.map((c) => (\n <CreatorChip key={c.walletAddress} creator={c} href={getHref(c)} />\n ))}\n </div>\n </div>\n </div>\n </FadeIn>\n );\n}\n"],"mappings":";AAmBI,cAyBE,YAzBF;AAjBJ,SAAS,gBAAgB;AACzB,SAAS,OAAO,kBAAkB;AAClC,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAY3B,SAAS,sBAAsB;AAC7B,SACE,oBAAC,SAAI,WAAU,gEAA+D;AAElF;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AAGpD,QAAM,SACJ,QAAQ,eACP,QAAoE,mBACrE;AACF,QAAM,YAAY,UAAU,CAAC,cAAc,WAAW,MAAM,IAAI;AAEhE,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAU;AAAA,MAEV,+BAAC,SAAI,WAAU,6DACZ;AAAA,qBACC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAI;AAAA,YACJ,eAAW;AAAA,YACX,SAAQ;AAAA,YACR,WAAU;AAAA,YACV,SAAS,MAAM,eAAe,IAAI;AAAA;AAAA,QACpC;AAAA,QAEF,oBAAC,SAAI,WAAU,yCACb,8BAAC,OAAE,WAAU,0CAA0C,kBAAQ,UAAS,GAC1E;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,QAAQ;AACV,GAA+B;AAC7B,MAAI,CAAC,aAAa,SAAS,WAAW,EAAG,QAAO;AAEhD,SACE,oBAAC,UACC,+BAAC,SAAI,WAAU,aACb;AAAA,yBAAC,SAAI,WAAU,qCACb;AAAA,2BAAC,SACC;AAAA,4BAAC,OAAE,WAAU,iBAAiB,wBAAa;AAAA,QAC3C,qBAAC,SAAI,WAAU,kCACb;AAAA,8BAAC,SAAM,WAAU,6BAA4B;AAAA,UAC7C,oBAAC,QAAG,WAAU,qBAAqB,iBAAM;AAAA,WAC3C;AAAA,SACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN,WAAU;AAAA,UACX;AAAA;AAAA,YACU,oBAAC,cAAW,WAAU,eAAc;AAAA;AAAA;AAAA,MAC/C;AAAA,OACF;AAAA,IACA,oBAAC,SAAI,WAAU,mFACb,8BAAC,SAAI,WAAU,kCACZ,sBACG,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,oBAAC,yBAAyB,CAAG,CAAE,IACvE,SAAS,IAAI,CAAC,MACZ,oBAAC,eAAkC,SAAS,GAAG,MAAM,QAAQ,CAAC,KAA5C,EAAE,aAA6C,CAClE,GACP,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/discover-creators-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Users, ArrowRight } from \"lucide-react\";\nimport { FadeIn } from \"./motion-primitives.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport type { ApiCreatorProfile } from \"@medialane/sdk\";\n\nexport interface DiscoverCreatorsStripProps {\n creators: ApiCreatorProfile[];\n isLoading: boolean;\n getHref: (creator: ApiCreatorProfile) => string;\n allCreatorsHref?: string;\n sectionLabel?: string;\n title?: string;\n}\n\nfunction CreatorChipSkeleton() {\n return (\n <div className=\"shrink-0 w-64 aspect-[3/4] rounded-xl bg-muted animate-pulse\" />\n );\n}\n\nfunction CreatorChip({\n creator,\n href,\n}: {\n creator: ApiCreatorProfile;\n href: string;\n}) {\n const [bannerError, setBannerError] = useState(false);\n\n // avatarImage (the creator's chosen NFT) with collectionImage fallback — io-approved big-username design\n const rawSrc = creator.avatarImage || creator.collectionImage || null;\n const bannerUrl = rawSrc && !bannerError ? ipfsToHttp(rawSrc) : null;\n\n return (\n <a\n href={href}\n className=\"block shrink-0 w-64 snap-start active:scale-[0.97] transition-transform duration-150 select-none\"\n >\n <div className=\"relative aspect-[3/4] rounded-xl overflow-hidden bg-muted\">\n {bannerUrl && (\n <img\n src={bannerUrl}\n alt=\"\"\n aria-hidden\n loading=\"lazy\"\n className=\"absolute inset-0 w-full h-full object-cover\"\n onError={() => setBannerError(true)}\n />\n )}\n <div className=\"absolute bottom-0 inset-x-0 px-3 py-3\">\n <p className=\"font-bold text-2xl text-white truncate\">{creator.username}</p>\n </div>\n </div>\n </a>\n );\n}\n\nexport function DiscoverCreatorsStrip({\n creators,\n isLoading,\n getHref,\n allCreatorsHref = \"/creators\",\n sectionLabel = \"Explore\",\n title = \"Creators\",\n}: DiscoverCreatorsStripProps) {\n if (!isLoading && creators.length === 0) return null;\n\n return (\n <FadeIn>\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"section-label\">{sectionLabel}</p>\n <div className=\"flex items-center gap-2 mt-0.5\">\n <Users className=\"h-4 w-4 text-brand-purple\" />\n <h2 className=\"text-lg font-bold\">{title}</h2>\n </div>\n </div>\n <a\n href={allCreatorsHref}\n className=\"inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground px-3 py-1.5 rounded-md hover:bg-accent transition-colors\"\n >\n View all <ArrowRight className=\"h-3.5 w-3.5\" />\n </a>\n </div>\n <div className=\"overflow-x-auto scrollbar-hide snap-x snap-mandatory -mx-4 px-4 md:mx-0 md:px-0\">\n <div className=\"flex gap-5 sm:gap-6 w-max pb-2\">\n {isLoading\n ? Array.from({ length: 6 }).map((_, i) => <CreatorChipSkeleton key={i} />)\n : creators.map((c) => (\n <CreatorChip key={c.walletAddress} creator={c} href={getHref(c)} />\n ))}\n </div>\n </div>\n </div>\n </FadeIn>\n );\n}\n"],"mappings":";AAmBI,cAsBE,YAtBF;AAjBJ,SAAS,gBAAgB;AACzB,SAAS,OAAO,kBAAkB;AAClC,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAY3B,SAAS,sBAAsB;AAC7B,SACE,oBAAC,SAAI,WAAU,gEAA+D;AAElF;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AAGpD,QAAM,SAAS,QAAQ,eAAe,QAAQ,mBAAmB;AACjE,QAAM,YAAY,UAAU,CAAC,cAAc,WAAW,MAAM,IAAI;AAEhE,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAU;AAAA,MAEV,+BAAC,SAAI,WAAU,6DACZ;AAAA,qBACC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAI;AAAA,YACJ,eAAW;AAAA,YACX,SAAQ;AAAA,YACR,WAAU;AAAA,YACV,SAAS,MAAM,eAAe,IAAI;AAAA;AAAA,QACpC;AAAA,QAEF,oBAAC,SAAI,WAAU,yCACb,8BAAC,OAAE,WAAU,0CAA0C,kBAAQ,UAAS,GAC1E;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,QAAQ;AACV,GAA+B;AAC7B,MAAI,CAAC,aAAa,SAAS,WAAW,EAAG,QAAO;AAEhD,SACE,oBAAC,UACC,+BAAC,SAAI,WAAU,aACb;AAAA,yBAAC,SAAI,WAAU,qCACb;AAAA,2BAAC,SACC;AAAA,4BAAC,OAAE,WAAU,iBAAiB,wBAAa;AAAA,QAC3C,qBAAC,SAAI,WAAU,kCACb;AAAA,8BAAC,SAAM,WAAU,6BAA4B;AAAA,UAC7C,oBAAC,QAAG,WAAU,qBAAqB,iBAAM;AAAA,WAC3C;AAAA,SACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN,WAAU;AAAA,UACX;AAAA;AAAA,YACU,oBAAC,cAAW,WAAU,eAAc;AAAA;AAAA;AAAA,MAC/C;AAAA,OACF;AAAA,IACA,oBAAC,SAAI,WAAU,mFACb,8BAAC,SAAI,WAAU,kCACZ,sBACG,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,oBAAC,yBAAyB,CAAG,CAAE,IACvE,SAAS,IAAI,CAAC,MACZ,oBAAC,eAAkC,SAAS,GAAG,MAAM,QAAQ,CAAC,KAA5C,EAAE,aAA6C,CAClE,GACP,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}
@@ -0,0 +1,47 @@
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 gradient_button_exports = {};
21
+ __export(gradient_button_exports, {
22
+ GradientButton: () => GradientButton
23
+ });
24
+ module.exports = __toCommonJS(gradient_button_exports);
25
+ var import_jsx_runtime = require("react/jsx-runtime");
26
+ var import_cn = require("../utils/cn.js");
27
+ function GradientButton({ big, children, className, wrapperClassName, ...rest }) {
28
+ const sizeClass = big ? "h-[54px] px-5 rounded-[15px] text-[15px]" : "h-12 px-5 rounded-[11px] text-sm";
29
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_cn.cn)("btn-border-animated w-full", big ? "rounded-2xl" : "rounded-xl", wrapperClassName), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
30
+ "button",
31
+ {
32
+ ...rest,
33
+ className: (0, import_cn.cn)(
34
+ "inline-flex w-full items-center justify-center gap-2 whitespace-nowrap font-semibold text-white",
35
+ "border-none bg-transparent transition-all hover:brightness-110 active:scale-[0.98]",
36
+ sizeClass,
37
+ className
38
+ ),
39
+ children
40
+ }
41
+ ) });
42
+ }
43
+ // Annotate the CommonJS export names for ESM import in node:
44
+ 0 && (module.exports = {
45
+ GradientButton
46
+ });
47
+ //# sourceMappingURL=gradient-button.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/gradient-button.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"../utils/cn.js\";\n\nexport interface GradientButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Tall 54px variant for hero contexts (onboarding, primary page CTAs). */\n big?: boolean;\n /** Outer wrapper class (the `.btn-border-animated` ring) — rarely needed. */\n wrapperClassName?: string;\n}\n\n/**\n * The full-spectrum animated-gradient CTA — `.btn-border-animated` as a 1px\n * wrapper around a transparent-fill button, so the ring reads as a solid,\n * continuously shifting brand-gradient fill (blue → purple → rose → orange).\n * This is the primary-action treatment used across medialane.io/starknet.medialane.io\n * (e.g. \"Connect wallet\", \"Buy now\") — previously hand-copied per call site;\n * this component is the single source.\n *\n * For the secondary animated-border treatment (a neutral `bg-card` fill with\n * only the border animated), use `ActionButton` instead.\n */\nexport function GradientButton({ big, children, className, wrapperClassName, ...rest }: GradientButtonProps) {\n const sizeClass = big\n ? \"h-[54px] px-5 rounded-[15px] text-[15px]\"\n : \"h-12 px-5 rounded-[11px] text-sm\";\n\n return (\n <div className={cn(\"btn-border-animated w-full\", big ? \"rounded-2xl\" : \"rounded-xl\", wrapperClassName)}>\n <button\n {...rest}\n className={cn(\n \"inline-flex w-full items-center justify-center gap-2 whitespace-nowrap font-semibold text-white\",\n \"border-none bg-transparent transition-all hover:brightness-110 active:scale-[0.98]\",\n sizeClass,\n className,\n )}\n >\n {children}\n </button>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BM;AA3BN,gBAAmB;AAoBZ,SAAS,eAAe,EAAE,KAAK,UAAU,WAAW,kBAAkB,GAAG,KAAK,GAAwB;AAC3G,QAAM,YAAY,MACd,6CACA;AAEJ,SACE,4CAAC,SAAI,eAAW,cAAG,8BAA8B,MAAM,gBAAgB,cAAc,gBAAgB,GACnG;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,eAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH,GACF;AAEJ;","names":[]}
@@ -0,0 +1,22 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ interface GradientButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
4
+ /** Tall 54px variant for hero contexts (onboarding, primary page CTAs). */
5
+ big?: boolean;
6
+ /** Outer wrapper class (the `.btn-border-animated` ring) — rarely needed. */
7
+ wrapperClassName?: string;
8
+ }
9
+ /**
10
+ * The full-spectrum animated-gradient CTA — `.btn-border-animated` as a 1px
11
+ * wrapper around a transparent-fill button, so the ring reads as a solid,
12
+ * continuously shifting brand-gradient fill (blue → purple → rose → orange).
13
+ * This is the primary-action treatment used across medialane.io/starknet.medialane.io
14
+ * (e.g. "Connect wallet", "Buy now") — previously hand-copied per call site;
15
+ * this component is the single source.
16
+ *
17
+ * For the secondary animated-border treatment (a neutral `bg-card` fill with
18
+ * only the border animated), use `ActionButton` instead.
19
+ */
20
+ declare function GradientButton({ big, children, className, wrapperClassName, ...rest }: GradientButtonProps): react_jsx_runtime.JSX.Element;
21
+
22
+ export { GradientButton, type GradientButtonProps };
@@ -0,0 +1,22 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ interface GradientButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
4
+ /** Tall 54px variant for hero contexts (onboarding, primary page CTAs). */
5
+ big?: boolean;
6
+ /** Outer wrapper class (the `.btn-border-animated` ring) — rarely needed. */
7
+ wrapperClassName?: string;
8
+ }
9
+ /**
10
+ * The full-spectrum animated-gradient CTA — `.btn-border-animated` as a 1px
11
+ * wrapper around a transparent-fill button, so the ring reads as a solid,
12
+ * continuously shifting brand-gradient fill (blue → purple → rose → orange).
13
+ * This is the primary-action treatment used across medialane.io/starknet.medialane.io
14
+ * (e.g. "Connect wallet", "Buy now") — previously hand-copied per call site;
15
+ * this component is the single source.
16
+ *
17
+ * For the secondary animated-border treatment (a neutral `bg-card` fill with
18
+ * only the border animated), use `ActionButton` instead.
19
+ */
20
+ declare function GradientButton({ big, children, className, wrapperClassName, ...rest }: GradientButtonProps): react_jsx_runtime.JSX.Element;
21
+
22
+ export { GradientButton, type GradientButtonProps };
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { cn } from "../utils/cn.js";
4
+ function GradientButton({ big, children, className, wrapperClassName, ...rest }) {
5
+ const sizeClass = big ? "h-[54px] px-5 rounded-[15px] text-[15px]" : "h-12 px-5 rounded-[11px] text-sm";
6
+ return /* @__PURE__ */ jsx("div", { className: cn("btn-border-animated w-full", big ? "rounded-2xl" : "rounded-xl", wrapperClassName), children: /* @__PURE__ */ jsx(
7
+ "button",
8
+ {
9
+ ...rest,
10
+ className: cn(
11
+ "inline-flex w-full items-center justify-center gap-2 whitespace-nowrap font-semibold text-white",
12
+ "border-none bg-transparent transition-all hover:brightness-110 active:scale-[0.98]",
13
+ sizeClass,
14
+ className
15
+ ),
16
+ children
17
+ }
18
+ ) });
19
+ }
20
+ export {
21
+ GradientButton
22
+ };
23
+ //# sourceMappingURL=gradient-button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/gradient-button.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"../utils/cn.js\";\n\nexport interface GradientButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Tall 54px variant for hero contexts (onboarding, primary page CTAs). */\n big?: boolean;\n /** Outer wrapper class (the `.btn-border-animated` ring) — rarely needed. */\n wrapperClassName?: string;\n}\n\n/**\n * The full-spectrum animated-gradient CTA — `.btn-border-animated` as a 1px\n * wrapper around a transparent-fill button, so the ring reads as a solid,\n * continuously shifting brand-gradient fill (blue → purple → rose → orange).\n * This is the primary-action treatment used across medialane.io/starknet.medialane.io\n * (e.g. \"Connect wallet\", \"Buy now\") — previously hand-copied per call site;\n * this component is the single source.\n *\n * For the secondary animated-border treatment (a neutral `bg-card` fill with\n * only the border animated), use `ActionButton` instead.\n */\nexport function GradientButton({ big, children, className, wrapperClassName, ...rest }: GradientButtonProps) {\n const sizeClass = big\n ? \"h-[54px] px-5 rounded-[15px] text-[15px]\"\n : \"h-12 px-5 rounded-[11px] text-sm\";\n\n return (\n <div className={cn(\"btn-border-animated w-full\", big ? \"rounded-2xl\" : \"rounded-xl\", wrapperClassName)}>\n <button\n {...rest}\n className={cn(\n \"inline-flex w-full items-center justify-center gap-2 whitespace-nowrap font-semibold text-white\",\n \"border-none bg-transparent transition-all hover:brightness-110 active:scale-[0.98]\",\n sizeClass,\n className,\n )}\n >\n {children}\n </button>\n </div>\n );\n}\n"],"mappings":";AA6BM;AA3BN,SAAS,UAAU;AAoBZ,SAAS,eAAe,EAAE,KAAK,UAAU,WAAW,kBAAkB,GAAG,KAAK,GAAwB;AAC3G,QAAM,YAAY,MACd,6CACA;AAEJ,SACE,oBAAC,SAAI,WAAW,GAAG,8BAA8B,MAAM,gBAAgB,cAAc,gBAAgB,GACnG;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH,GACF;AAEJ;","names":[]}
@@ -65,7 +65,6 @@ function HeroSlide({ collection, active, getHref }) {
65
65
  const supply = collection.totalSupply;
66
66
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_cn.cn)("absolute inset-0 transition-opacity duration-700", active ? "opacity-100" : "opacity-0 pointer-events-none"), children: [
67
67
  imageUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "animate-kenburns absolute inset-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_image.default, { src: imageUrl, alt: name, fill: true, className: "object-cover", priority: active, unoptimized: true }) }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 bg-gradient-to-br from-brand-purple/40 via-brand-blue/20 to-brand-navy/60" }),
68
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 bg-gradient-to-t from-black/40 via-black/30 to-black/0" }),
69
68
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "absolute bottom-0 left-0 right-0 p-6 sm:p-10 flex flex-col gap-3", children: [
70
69
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_link.default, { href: getHref(collection), className: "hover:opacity-90 transition-opacity", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-4xl lg:text-5xl font-semibold text-white leading-tight", children: name }) }),
71
70
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-4 text-sm text-white/70", children: [
@@ -103,8 +102,8 @@ function HeroSlider({ collections, isLoading, getHref, placeholderHrefs = {} })
103
102
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", { className: "relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] overflow-hidden bg-muted", children: count === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HeroPlaceholder, { hrefs }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
104
103
  collections.map((col, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HeroSlide, { collection: col, active: i === current, getHref }, col.contractAddress)),
105
104
  count > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
106
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: prev, "aria-label": "Previous slide", className: "absolute left-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronLeft, { className: "h-5 w-5 text-white" }) }),
107
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: next, "aria-label": "Next slide", className: "absolute right-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronRight, { className: "h-5 w-5 text-white" }) }),
105
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: prev, "aria-label": "Previous slide", className: "absolute left-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-white/10 backdrop-blur-md hover:bg-white/20 flex items-center justify-center transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronLeft, { className: "h-5 w-5 text-white" }) }),
106
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: next, "aria-label": "Next slide", className: "absolute right-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-white/10 backdrop-blur-md hover:bg-white/20 flex items-center justify-center transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronRight, { className: "h-5 w-5 text-white" }) }),
108
107
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-1.5 z-10", children: collections.map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: () => setCurrent(i), "aria-label": `Go to slide ${i + 1}`, className: (0, import_cn.cn)("h-1.5 rounded-full transition-all", i === current ? "w-6 bg-white" : "w-1.5 bg-white/40") }, i)) })
109
108
  ] })
110
109
  ] }) });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/hero-slider.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\nexport interface HeroSliderProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n /** Optional placeholder CTA hrefs — defaults to \"/marketplace\" and \"/create/asset\" */\n placeholderHrefs?: { markets?: string; create?: string };\n}\n\nfunction formatFloorPrice(price: string | null | undefined): string {\n if (!price) return \"\";\n const n = parseFloat(price);\n if (isNaN(n)) return price;\n if (n >= 1000) return `${(n / 1000).toFixed(1)}K`;\n if (n >= 1) return n.toFixed(2);\n return n.toPrecision(3);\n}\n\nfunction HeroPlaceholder({ hrefs }: { hrefs: Required<HeroSliderProps>[\"placeholderHrefs\"] }) {\n return (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/50 flex flex-col items-center justify-center gap-4 text-center px-6 overflow-hidden\">\n\n <h2 className=\"text-4xl sm:text-6xl font-black gradient-text relative z-10\">Medialane</h2>\n <p className=\"text-muted-foreground text-lg relative z-10 max-w-md\">\n New monetization revenues for creative works\n </p>\n <div className=\"flex gap-3 relative z-10\">\n <Link href={hrefs.markets!} className=\"inline-flex items-center justify-center rounded-[11px] bg-brand-blue px-4 py-2 text-sm font-semibold text-white hover:brightness-110 active:scale-[0.98] transition-all\">\n Markets\n </Link>\n <Link href={hrefs.create!} className=\"inline-flex items-center justify-center rounded-[11px] border border-white/20 bg-background/20 backdrop-blur-sm px-4 py-2 text-sm font-semibold text-white hover:bg-white/10 transition-all\">\n Create\n </Link>\n </div>\n </div>\n );\n}\n\nfunction HeroSlide({ collection, active, getHref }: { collection: ApiCollection; active: boolean; getHref: (col: ApiCollection) => string }) {\n const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;\n const name = collection.name ?? \"Collection\";\n const floor = collection.floorPrice;\n const supply = collection.totalSupply;\n\n return (\n <div className={cn(\"absolute inset-0 transition-opacity duration-700\", active ? \"opacity-100\" : \"opacity-0 pointer-events-none\")}>\n {imageUrl ? (\n <div className=\"absolute inset-0 overflow-hidden\">\n <div className=\"animate-kenburns absolute inset-0\">\n <Image src={imageUrl} alt={name} fill className=\"object-cover\" priority={active} unoptimized />\n </div>\n </div>\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/40 via-brand-blue/20 to-brand-navy/60\" />\n )}\n <div className=\"absolute inset-0 bg-gradient-to-t from-black/40 via-black/30 to-black/0\" />\n <div className=\"absolute bottom-0 left-0 right-0 p-6 sm:p-10 flex flex-col gap-3\">\n <Link href={getHref(collection)} className=\"hover:opacity-90 transition-opacity\">\n <h2 className=\"text-4xl lg:text-5xl font-semibold text-white leading-tight\">{name}</h2>\n </Link>\n <div className=\"flex items-center gap-4 text-sm text-white/70\">\n {supply != null && <span>{supply.toLocaleString()} items</span>}\n {floor && <span className=\"text-white font-semibold\">Floor {formatFloorPrice(floor)}</span>}\n </div>\n </div>\n </div>\n );\n}\n\nexport function HeroSliderSkeleton() {\n return <section className=\"relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] bg-muted animate-pulse\" />;\n}\n\nexport function HeroSlider({ collections, isLoading, getHref, placeholderHrefs = {} }: HeroSliderProps) {\n const hrefs = { markets: \"/marketplace\", create: \"/create/asset\", ...placeholderHrefs };\n const [current, setCurrent] = useState(0);\n const count = collections.length;\n\n const next = useCallback(() => { if (count > 1) setCurrent((c) => (c + 1) % count); }, [count]);\n const prev = useCallback(() => { if (count > 1) setCurrent((c) => (c - 1 + count) % count); }, [count]);\n\n useEffect(() => {\n if (count <= 1) return;\n const id = setInterval(next, 7000);\n return () => clearInterval(id);\n }, [count, next]);\n\n if (isLoading) return <HeroSliderSkeleton />;\n\n return (\n <section className=\"relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] overflow-hidden bg-muted\">\n {count === 0 ? (\n <HeroPlaceholder hrefs={hrefs} />\n ) : (\n <>\n {collections.map((col, i) => (\n <HeroSlide key={col.contractAddress} collection={col} active={i === current} getHref={getHref} />\n ))}\n {count > 1 && (\n <>\n <button onClick={prev} aria-label=\"Previous slide\" className=\"absolute left-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors\">\n <ChevronLeft className=\"h-5 w-5 text-white\" />\n </button>\n <button onClick={next} aria-label=\"Next slide\" className=\"absolute right-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors\">\n <ChevronRight className=\"h-5 w-5 text-white\" />\n </button>\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-1.5 z-10\">\n {collections.map((_, i) => (\n <button key={i} onClick={() => setCurrent(i)} aria-label={`Go to slide ${i + 1}`} className={cn(\"h-1.5 rounded-full transition-all\", i === current ? \"w-6 bg-white\" : \"w-1.5 bg-white/40\")} />\n ))}\n </div>\n </>\n )}\n </>\n )}\n </section>\n );\n}\n"],"mappings":"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","names":["Link","Image"]}
1
+ {"version":3,"sources":["../../src/components/hero-slider.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\nexport interface HeroSliderProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n /** Optional placeholder CTA hrefs — defaults to \"/marketplace\" and \"/create/asset\" */\n placeholderHrefs?: { markets?: string; create?: string };\n}\n\nfunction formatFloorPrice(price: string | null | undefined): string {\n if (!price) return \"\";\n const n = parseFloat(price);\n if (isNaN(n)) return price;\n if (n >= 1000) return `${(n / 1000).toFixed(1)}K`;\n if (n >= 1) return n.toFixed(2);\n return n.toPrecision(3);\n}\n\nfunction HeroPlaceholder({ hrefs }: { hrefs: Required<HeroSliderProps>[\"placeholderHrefs\"] }) {\n return (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/50 flex flex-col items-center justify-center gap-4 text-center px-6 overflow-hidden\">\n\n <h2 className=\"text-4xl sm:text-6xl font-black gradient-text relative z-10\">Medialane</h2>\n <p className=\"text-muted-foreground text-lg relative z-10 max-w-md\">\n New monetization revenues for creative works\n </p>\n <div className=\"flex gap-3 relative z-10\">\n <Link href={hrefs.markets!} className=\"inline-flex items-center justify-center rounded-[11px] bg-brand-blue px-4 py-2 text-sm font-semibold text-white hover:brightness-110 active:scale-[0.98] transition-all\">\n Markets\n </Link>\n <Link href={hrefs.create!} className=\"inline-flex items-center justify-center rounded-[11px] border border-white/20 bg-background/20 backdrop-blur-sm px-4 py-2 text-sm font-semibold text-white hover:bg-white/10 transition-all\">\n Create\n </Link>\n </div>\n </div>\n );\n}\n\nfunction HeroSlide({ collection, active, getHref }: { collection: ApiCollection; active: boolean; getHref: (col: ApiCollection) => string }) {\n const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;\n const name = collection.name ?? \"Collection\";\n const floor = collection.floorPrice;\n const supply = collection.totalSupply;\n\n return (\n <div className={cn(\"absolute inset-0 transition-opacity duration-700\", active ? \"opacity-100\" : \"opacity-0 pointer-events-none\")}>\n {imageUrl ? (\n <div className=\"absolute inset-0 overflow-hidden\">\n <div className=\"animate-kenburns absolute inset-0\">\n <Image src={imageUrl} alt={name} fill className=\"object-cover\" priority={active} unoptimized />\n </div>\n </div>\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/40 via-brand-blue/20 to-brand-navy/60\" />\n )}\n <div className=\"absolute bottom-0 left-0 right-0 p-6 sm:p-10 flex flex-col gap-3\">\n <Link href={getHref(collection)} className=\"hover:opacity-90 transition-opacity\">\n <h2 className=\"text-4xl lg:text-5xl font-semibold text-white leading-tight\">{name}</h2>\n </Link>\n <div className=\"flex items-center gap-4 text-sm text-white/70\">\n {supply != null && <span>{supply.toLocaleString()} items</span>}\n {floor && <span className=\"text-white font-semibold\">Floor {formatFloorPrice(floor)}</span>}\n </div>\n </div>\n </div>\n );\n}\n\nexport function HeroSliderSkeleton() {\n return <section className=\"relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] bg-muted animate-pulse\" />;\n}\n\nexport function HeroSlider({ collections, isLoading, getHref, placeholderHrefs = {} }: HeroSliderProps) {\n const hrefs = { markets: \"/marketplace\", create: \"/create/asset\", ...placeholderHrefs };\n const [current, setCurrent] = useState(0);\n const count = collections.length;\n\n const next = useCallback(() => { if (count > 1) setCurrent((c) => (c + 1) % count); }, [count]);\n const prev = useCallback(() => { if (count > 1) setCurrent((c) => (c - 1 + count) % count); }, [count]);\n\n useEffect(() => {\n if (count <= 1) return;\n const id = setInterval(next, 7000);\n return () => clearInterval(id);\n }, [count, next]);\n\n if (isLoading) return <HeroSliderSkeleton />;\n\n return (\n <section className=\"relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] overflow-hidden bg-muted\">\n {count === 0 ? (\n <HeroPlaceholder hrefs={hrefs} />\n ) : (\n <>\n {collections.map((col, i) => (\n <HeroSlide key={col.contractAddress} collection={col} active={i === current} getHref={getHref} />\n ))}\n {count > 1 && (\n <>\n <button onClick={prev} aria-label=\"Previous slide\" className=\"absolute left-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-white/10 backdrop-blur-md hover:bg-white/20 flex items-center justify-center transition-colors\">\n <ChevronLeft className=\"h-5 w-5 text-white\" />\n </button>\n <button onClick={next} aria-label=\"Next slide\" className=\"absolute right-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-white/10 backdrop-blur-md hover:bg-white/20 flex items-center justify-center transition-colors\">\n <ChevronRight className=\"h-5 w-5 text-white\" />\n </button>\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-1.5 z-10\">\n {collections.map((_, i) => (\n <button key={i} onClick={() => setCurrent(i)} aria-label={`Go to slide ${i + 1}`} className={cn(\"h-1.5 rounded-full transition-all\", i === current ? \"w-6 bg-white\" : \"w-1.5 bg-white/40\")} />\n ))}\n </div>\n </>\n )}\n </>\n )}\n </section>\n );\n}\n"],"mappings":"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","names":["Link","Image"]}
@@ -31,7 +31,6 @@ function HeroSlide({ collection, active, getHref }) {
31
31
  const supply = collection.totalSupply;
32
32
  return /* @__PURE__ */ jsxs("div", { className: cn("absolute inset-0 transition-opacity duration-700", active ? "opacity-100" : "opacity-0 pointer-events-none"), children: [
33
33
  imageUrl ? /* @__PURE__ */ jsx("div", { className: "absolute inset-0 overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "animate-kenburns absolute inset-0", children: /* @__PURE__ */ jsx(Image, { src: imageUrl, alt: name, fill: true, className: "object-cover", priority: active, unoptimized: true }) }) }) : /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-br from-brand-purple/40 via-brand-blue/20 to-brand-navy/60" }),
34
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/40 via-black/30 to-black/0" }),
35
34
  /* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 left-0 right-0 p-6 sm:p-10 flex flex-col gap-3", children: [
36
35
  /* @__PURE__ */ jsx(Link, { href: getHref(collection), className: "hover:opacity-90 transition-opacity", children: /* @__PURE__ */ jsx("h2", { className: "text-4xl lg:text-5xl font-semibold text-white leading-tight", children: name }) }),
37
36
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 text-sm text-white/70", children: [
@@ -69,8 +68,8 @@ function HeroSlider({ collections, isLoading, getHref, placeholderHrefs = {} })
69
68
  return /* @__PURE__ */ jsx("section", { className: "relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] overflow-hidden bg-muted", children: count === 0 ? /* @__PURE__ */ jsx(HeroPlaceholder, { hrefs }) : /* @__PURE__ */ jsxs(Fragment, { children: [
70
69
  collections.map((col, i) => /* @__PURE__ */ jsx(HeroSlide, { collection: col, active: i === current, getHref }, col.contractAddress)),
71
70
  count > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
72
- /* @__PURE__ */ jsx("button", { onClick: prev, "aria-label": "Previous slide", className: "absolute left-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors", children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-5 w-5 text-white" }) }),
73
- /* @__PURE__ */ jsx("button", { onClick: next, "aria-label": "Next slide", className: "absolute right-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors", children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-5 w-5 text-white" }) }),
71
+ /* @__PURE__ */ jsx("button", { onClick: prev, "aria-label": "Previous slide", className: "absolute left-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-white/10 backdrop-blur-md hover:bg-white/20 flex items-center justify-center transition-colors", children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-5 w-5 text-white" }) }),
72
+ /* @__PURE__ */ jsx("button", { onClick: next, "aria-label": "Next slide", className: "absolute right-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-white/10 backdrop-blur-md hover:bg-white/20 flex items-center justify-center transition-colors", children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-5 w-5 text-white" }) }),
74
73
  /* @__PURE__ */ jsx("div", { className: "absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-1.5 z-10", children: collections.map((_, i) => /* @__PURE__ */ jsx("button", { onClick: () => setCurrent(i), "aria-label": `Go to slide ${i + 1}`, className: cn("h-1.5 rounded-full transition-all", i === current ? "w-6 bg-white" : "w-1.5 bg-white/40") }, i)) })
75
74
  ] })
76
75
  ] }) });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/hero-slider.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\nexport interface HeroSliderProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n /** Optional placeholder CTA hrefs — defaults to \"/marketplace\" and \"/create/asset\" */\n placeholderHrefs?: { markets?: string; create?: string };\n}\n\nfunction formatFloorPrice(price: string | null | undefined): string {\n if (!price) return \"\";\n const n = parseFloat(price);\n if (isNaN(n)) return price;\n if (n >= 1000) return `${(n / 1000).toFixed(1)}K`;\n if (n >= 1) return n.toFixed(2);\n return n.toPrecision(3);\n}\n\nfunction HeroPlaceholder({ hrefs }: { hrefs: Required<HeroSliderProps>[\"placeholderHrefs\"] }) {\n return (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/50 flex flex-col items-center justify-center gap-4 text-center px-6 overflow-hidden\">\n\n <h2 className=\"text-4xl sm:text-6xl font-black gradient-text relative z-10\">Medialane</h2>\n <p className=\"text-muted-foreground text-lg relative z-10 max-w-md\">\n New monetization revenues for creative works\n </p>\n <div className=\"flex gap-3 relative z-10\">\n <Link href={hrefs.markets!} className=\"inline-flex items-center justify-center rounded-[11px] bg-brand-blue px-4 py-2 text-sm font-semibold text-white hover:brightness-110 active:scale-[0.98] transition-all\">\n Markets\n </Link>\n <Link href={hrefs.create!} className=\"inline-flex items-center justify-center rounded-[11px] border border-white/20 bg-background/20 backdrop-blur-sm px-4 py-2 text-sm font-semibold text-white hover:bg-white/10 transition-all\">\n Create\n </Link>\n </div>\n </div>\n );\n}\n\nfunction HeroSlide({ collection, active, getHref }: { collection: ApiCollection; active: boolean; getHref: (col: ApiCollection) => string }) {\n const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;\n const name = collection.name ?? \"Collection\";\n const floor = collection.floorPrice;\n const supply = collection.totalSupply;\n\n return (\n <div className={cn(\"absolute inset-0 transition-opacity duration-700\", active ? \"opacity-100\" : \"opacity-0 pointer-events-none\")}>\n {imageUrl ? (\n <div className=\"absolute inset-0 overflow-hidden\">\n <div className=\"animate-kenburns absolute inset-0\">\n <Image src={imageUrl} alt={name} fill className=\"object-cover\" priority={active} unoptimized />\n </div>\n </div>\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/40 via-brand-blue/20 to-brand-navy/60\" />\n )}\n <div className=\"absolute inset-0 bg-gradient-to-t from-black/40 via-black/30 to-black/0\" />\n <div className=\"absolute bottom-0 left-0 right-0 p-6 sm:p-10 flex flex-col gap-3\">\n <Link href={getHref(collection)} className=\"hover:opacity-90 transition-opacity\">\n <h2 className=\"text-4xl lg:text-5xl font-semibold text-white leading-tight\">{name}</h2>\n </Link>\n <div className=\"flex items-center gap-4 text-sm text-white/70\">\n {supply != null && <span>{supply.toLocaleString()} items</span>}\n {floor && <span className=\"text-white font-semibold\">Floor {formatFloorPrice(floor)}</span>}\n </div>\n </div>\n </div>\n );\n}\n\nexport function HeroSliderSkeleton() {\n return <section className=\"relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] bg-muted animate-pulse\" />;\n}\n\nexport function HeroSlider({ collections, isLoading, getHref, placeholderHrefs = {} }: HeroSliderProps) {\n const hrefs = { markets: \"/marketplace\", create: \"/create/asset\", ...placeholderHrefs };\n const [current, setCurrent] = useState(0);\n const count = collections.length;\n\n const next = useCallback(() => { if (count > 1) setCurrent((c) => (c + 1) % count); }, [count]);\n const prev = useCallback(() => { if (count > 1) setCurrent((c) => (c - 1 + count) % count); }, [count]);\n\n useEffect(() => {\n if (count <= 1) return;\n const id = setInterval(next, 7000);\n return () => clearInterval(id);\n }, [count, next]);\n\n if (isLoading) return <HeroSliderSkeleton />;\n\n return (\n <section className=\"relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] overflow-hidden bg-muted\">\n {count === 0 ? (\n <HeroPlaceholder hrefs={hrefs} />\n ) : (\n <>\n {collections.map((col, i) => (\n <HeroSlide key={col.contractAddress} collection={col} active={i === current} getHref={getHref} />\n ))}\n {count > 1 && (\n <>\n <button onClick={prev} aria-label=\"Previous slide\" className=\"absolute left-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors\">\n <ChevronLeft className=\"h-5 w-5 text-white\" />\n </button>\n <button onClick={next} aria-label=\"Next slide\" className=\"absolute right-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors\">\n <ChevronRight className=\"h-5 w-5 text-white\" />\n </button>\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-1.5 z-10\">\n {collections.map((_, i) => (\n <button key={i} onClick={() => setCurrent(i)} aria-label={`Go to slide ${i + 1}`} className={cn(\"h-1.5 rounded-full transition-all\", i === current ? \"w-6 bg-white\" : \"w-1.5 bg-white/40\")} />\n ))}\n </div>\n </>\n )}\n </>\n )}\n </section>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/hero-slider.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\nexport interface HeroSliderProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n /** Optional placeholder CTA hrefs — defaults to \"/marketplace\" and \"/create/asset\" */\n placeholderHrefs?: { markets?: string; create?: string };\n}\n\nfunction formatFloorPrice(price: string | null | undefined): string {\n if (!price) return \"\";\n const n = parseFloat(price);\n if (isNaN(n)) return price;\n if (n >= 1000) return `${(n / 1000).toFixed(1)}K`;\n if (n >= 1) return n.toFixed(2);\n return n.toPrecision(3);\n}\n\nfunction HeroPlaceholder({ hrefs }: { hrefs: Required<HeroSliderProps>[\"placeholderHrefs\"] }) {\n return (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/50 flex flex-col items-center justify-center gap-4 text-center px-6 overflow-hidden\">\n\n <h2 className=\"text-4xl sm:text-6xl font-black gradient-text relative z-10\">Medialane</h2>\n <p className=\"text-muted-foreground text-lg relative z-10 max-w-md\">\n New monetization revenues for creative works\n </p>\n <div className=\"flex gap-3 relative z-10\">\n <Link href={hrefs.markets!} className=\"inline-flex items-center justify-center rounded-[11px] bg-brand-blue px-4 py-2 text-sm font-semibold text-white hover:brightness-110 active:scale-[0.98] transition-all\">\n Markets\n </Link>\n <Link href={hrefs.create!} className=\"inline-flex items-center justify-center rounded-[11px] border border-white/20 bg-background/20 backdrop-blur-sm px-4 py-2 text-sm font-semibold text-white hover:bg-white/10 transition-all\">\n Create\n </Link>\n </div>\n </div>\n );\n}\n\nfunction HeroSlide({ collection, active, getHref }: { collection: ApiCollection; active: boolean; getHref: (col: ApiCollection) => string }) {\n const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;\n const name = collection.name ?? \"Collection\";\n const floor = collection.floorPrice;\n const supply = collection.totalSupply;\n\n return (\n <div className={cn(\"absolute inset-0 transition-opacity duration-700\", active ? \"opacity-100\" : \"opacity-0 pointer-events-none\")}>\n {imageUrl ? (\n <div className=\"absolute inset-0 overflow-hidden\">\n <div className=\"animate-kenburns absolute inset-0\">\n <Image src={imageUrl} alt={name} fill className=\"object-cover\" priority={active} unoptimized />\n </div>\n </div>\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/40 via-brand-blue/20 to-brand-navy/60\" />\n )}\n <div className=\"absolute bottom-0 left-0 right-0 p-6 sm:p-10 flex flex-col gap-3\">\n <Link href={getHref(collection)} className=\"hover:opacity-90 transition-opacity\">\n <h2 className=\"text-4xl lg:text-5xl font-semibold text-white leading-tight\">{name}</h2>\n </Link>\n <div className=\"flex items-center gap-4 text-sm text-white/70\">\n {supply != null && <span>{supply.toLocaleString()} items</span>}\n {floor && <span className=\"text-white font-semibold\">Floor {formatFloorPrice(floor)}</span>}\n </div>\n </div>\n </div>\n );\n}\n\nexport function HeroSliderSkeleton() {\n return <section className=\"relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] bg-muted animate-pulse\" />;\n}\n\nexport function HeroSlider({ collections, isLoading, getHref, placeholderHrefs = {} }: HeroSliderProps) {\n const hrefs = { markets: \"/marketplace\", create: \"/create/asset\", ...placeholderHrefs };\n const [current, setCurrent] = useState(0);\n const count = collections.length;\n\n const next = useCallback(() => { if (count > 1) setCurrent((c) => (c + 1) % count); }, [count]);\n const prev = useCallback(() => { if (count > 1) setCurrent((c) => (c - 1 + count) % count); }, [count]);\n\n useEffect(() => {\n if (count <= 1) return;\n const id = setInterval(next, 7000);\n return () => clearInterval(id);\n }, [count, next]);\n\n if (isLoading) return <HeroSliderSkeleton />;\n\n return (\n <section className=\"relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] overflow-hidden bg-muted\">\n {count === 0 ? (\n <HeroPlaceholder hrefs={hrefs} />\n ) : (\n <>\n {collections.map((col, i) => (\n <HeroSlide key={col.contractAddress} collection={col} active={i === current} getHref={getHref} />\n ))}\n {count > 1 && (\n <>\n <button onClick={prev} aria-label=\"Previous slide\" className=\"absolute left-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-white/10 backdrop-blur-md hover:bg-white/20 flex items-center justify-center transition-colors\">\n <ChevronLeft className=\"h-5 w-5 text-white\" />\n </button>\n <button onClick={next} aria-label=\"Next slide\" className=\"absolute right-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-white/10 backdrop-blur-md hover:bg-white/20 flex items-center justify-center transition-colors\">\n <ChevronRight className=\"h-5 w-5 text-white\" />\n </button>\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-1.5 z-10\">\n {collections.map((_, i) => (\n <button key={i} onClick={() => setCurrent(i)} aria-label={`Go to slide ${i + 1}`} className={cn(\"h-1.5 rounded-full transition-all\", i === current ? \"w-6 bg-white\" : \"w-1.5 bg-white/40\")} />\n ))}\n </div>\n </>\n )}\n </>\n )}\n </section>\n );\n}\n"],"mappings":"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","names":[]}
package/dist/index.cjs CHANGED
@@ -90,6 +90,7 @@ __export(index_exports, {
90
90
  FeaturedCarousel: () => import_featured_carousel.FeaturedCarousel,
91
91
  FeaturedCarouselSkeleton: () => import_featured_carousel.FeaturedCarouselSkeleton,
92
92
  GEOGRAPHIC_SCOPES: () => import_ip.GEOGRAPHIC_SCOPES,
93
+ GradientButton: () => import_gradient_button.GradientButton,
93
94
  HeroSlider: () => import_hero_slider.HeroSlider,
94
95
  HeroSliderSkeleton: () => import_hero_slider.HeroSliderSkeleton,
95
96
  IPTypeDisplay: () => import_ip_type_display.IPTypeDisplay,
@@ -258,6 +259,7 @@ var import_load_more_sentinel = require("./components/load-more-sentinel.js");
258
259
  var import_community_rewards_section = require("./components/community-rewards-section.js");
259
260
  var import_creator_airdrop_banner = require("./components/creator-airdrop-banner.js");
260
261
  var import_action_button = require("./components/action-button.js");
262
+ var import_gradient_button = require("./components/gradient-button.js");
261
263
  var import_coin_launch_preview = require("./components/coin-launch-preview.js");
262
264
  var import_medialane_collection_card = require("./components/medialane-collection-card.js");
263
265
  var import_token_glyph = require("./components/token-glyph.js");
@@ -337,6 +339,7 @@ var import_action_dialog = require("./components/action-dialog.js");
337
339
  FeaturedCarousel,
338
340
  FeaturedCarouselSkeleton,
339
341
  GEOGRAPHIC_SCOPES,
342
+ GradientButton,
340
343
  HeroSlider,
341
344
  HeroSliderSkeleton,
342
345
  IPTypeDisplay,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// ── Utils ─────────────────────────────────────────────────────────────────────\nexport { cn } from \"./utils/cn.js\";\nexport { formatDisplayPrice, parsePriceDisplay } from \"./utils/format.js\";\nexport { shortenAddress } from \"./utils/address.js\";\nexport { ipfsToHttp } from \"./utils/ipfs.js\";\nexport { useIntersectionActive } from \"./utils/use-intersection-active.js\";\nexport { licenseSummary } from \"./utils/license-summary.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 { AssetLicenseSummary } from \"./components/asset-license-summary.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, AssetOwnerRow, buildEditionStats } from \"./components/asset-top-sections.js\";\nexport type { AssetOwnerRowProps } from \"./components/asset-top-sections.js\";\nexport { AssetCollectionBar } from \"./components/asset-collection-bar.js\";\nexport type { AssetCollectionBarProps, AssetCollectionBarSibling } from \"./components/asset-collection-bar.js\";\nexport { AssetUtilityIcons } from \"./components/asset-utility-icons.js\";\nexport type { AssetUtilityIconsProps } from \"./components/asset-utility-icons.js\";\nexport { AssetMarketplacePanel } from \"./components/asset-marketplace-panel.js\";\nexport type { AssetMarketplacePanelProps, ApiOrderLike } from \"./components/asset-marketplace-panel.js\";\nexport { BRAND } from \"./data/brand.js\";\nexport { LIVING_RENDER_COLLECTIONS, isLivingRenderCollection } from \"./data/living-render-collections.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 { 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 } from \"./components/token-card.js\";\nexport { AnimatedTokenMedia } from \"./components/animated-token-media.js\";\nexport type { AnimatedTokenMediaProps } from \"./components/animated-token-media.js\";\nexport { ThemeAmbientBackground } from \"./components/theme-ambient-background.js\";\nexport {\n useCollectionFilters, SORT_OPTIONS, CollectionFiltersTrigger, CollectionFiltersBody,\n} from \"./components/collection-filters.js\";\nexport type { TraitSection, CollectionFiltersTriggerProps, CollectionFiltersBodyProps } from \"./components/collection-filters.js\";\nexport {\n DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem,\n DropdownMenuCheckboxItem, DropdownMenuRadioItem, DropdownMenuLabel,\n DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuGroup,\n DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent,\n DropdownMenuSubTrigger, DropdownMenuRadioGroup,\n} from \"./components/dropdown-menu.js\";\nexport { AssetCard, AssetCardSkeleton } from \"./components/asset-card.js\";\nexport type { AssetCardProps, AssetCardPrice } from \"./components/asset-card.js\";\nexport { AssetPicker } from \"./components/asset-picker.js\";\nexport type { AssetPickerProps, OwnedAsset } from \"./components/asset-picker.js\";\nexport { AssetSearchPicker } from \"./components/asset-search-picker.js\";\nexport type { AssetSearchPickerProps } from \"./components/asset-search-picker.js\";\nexport { LicenseTermsBuilder, EMPTY_SPONSORSHIP_TERMS, MEDIA_TYPES, DURATION_UNITS, toLicenseMetadata, toDurationDays } from \"./components/license-terms-builder.js\";\nexport type { LicenseTermsBuilderProps, SponsorshipTerms, DurationUnit } from \"./components/license-terms-builder.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, DiscoverActivityStrip } from \"./components/discover-feed-section.js\";\nexport type { DiscoverFeedSectionProps, DiscoverActivityStripProps } 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, useLaunchpadFilter } from \"./components/launchpad-services.js\";\nexport { LaunchpadFilterBar } from \"./components/launchpad-filter-bar.js\";\nexport type { LaunchpadFilterBarProps } from \"./components/launchpad-filter-bar.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, 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.62.0 — nav shell (brand trigger + header buttons + account sheet) ─────\nexport {\n NavBrandButton,\n NavIconButton,\n NavWalletTrigger,\n NavAccountSheet,\n useNavAccountSheet,\n} from \"./components/nav-shell.js\";\nexport type {\n NavBrandButtonProps,\n NavIconButtonProps,\n NavWalletTriggerProps,\n NavAccountSheetProps,\n} from \"./components/nav-shell.js\";\n\n// ── v0.59.0 — portfolio shell (two-level nav + header + overview) ────────────\nexport { PortfolioNav } from \"./components/portfolio-nav.js\";\nexport type {\n PortfolioNavProps,\n PortfolioNavSection,\n PortfolioNavChild,\n PortfolioBadgeVariant,\n} from \"./components/portfolio-nav.js\";\nexport { PortfolioHeader } from \"./components/portfolio-header.js\";\nexport type {\n PortfolioHeaderProps,\n PortfolioHeaderScore,\n} from \"./components/portfolio-header.js\";\nexport { PortfolioOverview } from \"./components/portfolio-overview.js\";\nexport type {\n PortfolioOverviewProps,\n PortfolioOverviewStat,\n PortfolioAttentionItem,\n PortfolioQuickAction,\n} from \"./components/portfolio-overview.js\";\nexport { derivePortfolioCounts } from \"./utils/portfolio-counts.js\";\nexport type { PortfolioCounts, CountableOrder } from \"./utils/portfolio-counts.js\";\n\n// ── v0.22.0 additions — launchpad/claim form template primitives ─────────────\n// Pure-presentation header + rail shared by every launchpad/claim form. The\n// app supplies its own gate, back button, and form logic. Requires the\n// `.btn-border-animated` class (in @medialane/ui/styles) for the form shell.\nexport { ServiceHeader } from \"./components/service-header.js\";\nexport type { ServiceHeaderProps } from \"./components/service-header.js\";\nexport { ClaimRail } from \"./components/claim-rail.js\";\nexport type { ClaimRailProps } from \"./components/claim-rail.js\";\n\n// ── v0.23.0 additions — slot-based form shell ────────────────────────────────\n// Pure layout (back slot + header + animated-border compartment + 8/4 bento).\n// No auth/router — the app injects its own gate (around children) + back button.\nexport { ServiceFormShell } from \"./components/service-form-shell.js\";\nexport type { ServiceFormShellProps } from \"./components/service-form-shell.js\";\nexport { StepNav } from \"./components/step-nav.js\";\nexport type { StepNavProps, StepNavStep } from \"./components/step-nav.js\";\n\n// Rewards score kit (v0.36.0)\nexport { LevelBadge } from \"./components/rewards/level-badge.js\";\nexport type { LevelBadgeProps } from \"./components/rewards/level-badge.js\";\nexport { XpProgress } from \"./components/rewards/xp-progress.js\";\nexport type { XpProgressProps } from \"./components/rewards/xp-progress.js\";\nexport { BadgeShelf } from \"./components/rewards/badge-shelf.js\";\nexport type { BadgeShelfProps, BadgeShelfBadge } from \"./components/rewards/badge-shelf.js\";\nexport { ScoreSummaryCard } from \"./components/rewards/score-summary-card.js\";\nexport type { ScoreSummaryCardProps } from \"./components/rewards/score-summary-card.js\";\nexport { LeaderboardTable, LeaderboardWidget } from \"./components/rewards/leaderboard-table.js\";\nexport type { LeaderboardTableProps, LeaderboardWidgetProps, LeaderboardEntryLike } from \"./components/rewards/leaderboard-table.js\";\nexport { LevelLadder } from \"./components/rewards/level-ladder.js\";\nexport type { LevelLadderProps } from \"./components/rewards/level-ladder.js\";\nexport { XpToastContent } from \"./components/rewards/xp-toast-content.js\";\nexport type { XpToastContentProps } from \"./components/rewards/xp-toast-content.js\";\n\n// ── v0.37.0 additions — infinite-scroll trigger ──────────────────────────────\nexport { LoadMoreSentinel } from \"./components/load-more-sentinel.js\";\nexport type { LoadMoreSentinelProps } from \"./components/load-more-sentinel.js\";\n\n// ── v0.47.0 additions — community rewards section ────────────────────────────\nexport { CommunityRewardsSection } from \"./components/community-rewards-section.js\";\nexport type { CommunityRewardsSectionProps, CommunityRewardsEntry } from \"./components/community-rewards-section.js\";\nexport { CreatorAirdropBanner } from \"./components/creator-airdrop-banner.js\";\nexport type { CreatorAirdropBannerProps } from \"./components/creator-airdrop-banner.js\";\n\n// ── Design system primitives — action-focus pattern, tokens, data display ────\nexport { ActionButton } from \"./components/action-button.js\";\nexport type { ActionButtonProps, ActionKey, ToneKey } from \"./components/action-button.js\";\n\nexport { CoinLaunchPreview } from \"./components/coin-launch-preview.js\";\nexport type { CoinPreviewData } from \"./components/coin-launch-preview.js\";\nexport { MedialaneCollectionCard } from \"./components/medialane-collection-card.js\";\nexport type { MedialaneCollectionCardProps } from \"./components/medialane-collection-card.js\";\nexport { TokenGlyph, TokenAmount } from \"./components/token-glyph.js\";\nexport type { TokenGlyphProps, TokenAmountProps, TokenSymbol } from \"./components/token-glyph.js\";\n\nexport { StatTile, StatPill } from \"./components/stat-tile.js\";\nexport type { StatTileProps, StatPillProps } from \"./components/stat-tile.js\";\n\nexport { ActionDialog } from \"./components/action-dialog.js\";\nexport type { ActionDialogProps } from \"./components/action-dialog.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;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,oBAAsD;AACtD,qBAA+B;AAC/B,kBAA2B;AAC3B,qCAAsC;AACtC,6BAA+B;AAG/B,sBAA+C;AAE/C,gBAGO;AAEP,0BAEO;AAEP,6BAA8B;AAC9B,oCAAqC;AACrC,mCAAoC;AACpC,+BAAgC;AAChC,uCAAwC;AAExC,gCAAqF;AAErF,kCAAmC;AAEnC,iCAAkC;AAElC,qCAAsC;AAEtC,mBAAsB;AACtB,uCAAoE;AAGpE,2BAA6C;AAG7C,2BAAyD;AAGzD,6BAA+B;AAG/B,wBAAkC;AAIlC,+BAAyF;AACzF,4BAA8B;AAE9B,4BAA8B;AAE9B,0BAA4B;AAE5B,6BAAuD;AAEvD,wBAA6C;AAE7C,kCAAmC;AAEnC,sCAAuC;AACvC,gCAEO;AAEP,2BAMO;AACP,wBAA6C;AAE7C,0BAA4B;AAE5B,iCAAkC;AAElC,mCAA6H;AAG7H,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,mCAA2D;AAE3D,2BAAsE;AAItE,gCAAiG;AACjG,kCAAmC;AAEnC,6BAA+B;AAG/B,IAAAA,6BAAwE;AAIxE,8BAAkD;AAIlD,uBAMO;AASP,2BAA6B;AAO7B,8BAAgC;AAKhC,gCAAkC;AAOlC,8BAAsC;AAOtC,4BAA8B;AAE9B,wBAA0B;AAM1B,gCAAiC;AAEjC,sBAAwB;AAIxB,yBAA2B;AAE3B,yBAA2B;AAE3B,yBAA2B;AAE3B,gCAAiC;AAEjC,+BAAoD;AAEpD,0BAA4B;AAE5B,8BAA+B;AAI/B,gCAAiC;AAIjC,uCAAwC;AAExC,oCAAqC;AAIrC,2BAA6B;AAG7B,iCAAkC;AAElC,uCAAwC;AAExC,yBAAwC;AAGxC,uBAAmC;AAGnC,2BAA6B;","names":["import_launchpad_services"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// ── Utils ─────────────────────────────────────────────────────────────────────\nexport { cn } from \"./utils/cn.js\";\nexport { formatDisplayPrice, parsePriceDisplay } from \"./utils/format.js\";\nexport { shortenAddress } from \"./utils/address.js\";\nexport { ipfsToHttp } from \"./utils/ipfs.js\";\nexport { useIntersectionActive } from \"./utils/use-intersection-active.js\";\nexport { licenseSummary } from \"./utils/license-summary.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 { AssetLicenseSummary } from \"./components/asset-license-summary.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, AssetOwnerRow, buildEditionStats } from \"./components/asset-top-sections.js\";\nexport type { AssetOwnerRowProps } from \"./components/asset-top-sections.js\";\nexport { AssetCollectionBar } from \"./components/asset-collection-bar.js\";\nexport type { AssetCollectionBarProps, AssetCollectionBarSibling } from \"./components/asset-collection-bar.js\";\nexport { AssetUtilityIcons } from \"./components/asset-utility-icons.js\";\nexport type { AssetUtilityIconsProps } from \"./components/asset-utility-icons.js\";\nexport { AssetMarketplacePanel } from \"./components/asset-marketplace-panel.js\";\nexport type { AssetMarketplacePanelProps, ApiOrderLike } from \"./components/asset-marketplace-panel.js\";\nexport { BRAND } from \"./data/brand.js\";\nexport { LIVING_RENDER_COLLECTIONS, isLivingRenderCollection } from \"./data/living-render-collections.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 { 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 } from \"./components/token-card.js\";\nexport { AnimatedTokenMedia } from \"./components/animated-token-media.js\";\nexport type { AnimatedTokenMediaProps } from \"./components/animated-token-media.js\";\nexport { ThemeAmbientBackground } from \"./components/theme-ambient-background.js\";\nexport {\n useCollectionFilters, SORT_OPTIONS, CollectionFiltersTrigger, CollectionFiltersBody,\n} from \"./components/collection-filters.js\";\nexport type { TraitSection, CollectionFiltersTriggerProps, CollectionFiltersBodyProps } from \"./components/collection-filters.js\";\nexport {\n DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem,\n DropdownMenuCheckboxItem, DropdownMenuRadioItem, DropdownMenuLabel,\n DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuGroup,\n DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent,\n DropdownMenuSubTrigger, DropdownMenuRadioGroup,\n} from \"./components/dropdown-menu.js\";\nexport { AssetCard, AssetCardSkeleton } from \"./components/asset-card.js\";\nexport type { AssetCardProps, AssetCardPrice } from \"./components/asset-card.js\";\nexport { AssetPicker } from \"./components/asset-picker.js\";\nexport type { AssetPickerProps, OwnedAsset } from \"./components/asset-picker.js\";\nexport { AssetSearchPicker } from \"./components/asset-search-picker.js\";\nexport type { AssetSearchPickerProps } from \"./components/asset-search-picker.js\";\nexport { LicenseTermsBuilder, EMPTY_SPONSORSHIP_TERMS, MEDIA_TYPES, DURATION_UNITS, toLicenseMetadata, toDurationDays } from \"./components/license-terms-builder.js\";\nexport type { LicenseTermsBuilderProps, SponsorshipTerms, DurationUnit } from \"./components/license-terms-builder.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, DiscoverActivityStrip } from \"./components/discover-feed-section.js\";\nexport type { DiscoverFeedSectionProps, DiscoverActivityStripProps } 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, useLaunchpadFilter } from \"./components/launchpad-services.js\";\nexport { LaunchpadFilterBar } from \"./components/launchpad-filter-bar.js\";\nexport type { LaunchpadFilterBarProps } from \"./components/launchpad-filter-bar.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, 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.62.0 — nav shell (brand trigger + header buttons + account sheet) ─────\nexport {\n NavBrandButton,\n NavIconButton,\n NavWalletTrigger,\n NavAccountSheet,\n useNavAccountSheet,\n} from \"./components/nav-shell.js\";\nexport type {\n NavBrandButtonProps,\n NavIconButtonProps,\n NavWalletTriggerProps,\n NavAccountSheetProps,\n} from \"./components/nav-shell.js\";\n\n// ── v0.59.0 — portfolio shell (two-level nav + header + overview) ────────────\nexport { PortfolioNav } from \"./components/portfolio-nav.js\";\nexport type {\n PortfolioNavProps,\n PortfolioNavSection,\n PortfolioNavChild,\n PortfolioBadgeVariant,\n} from \"./components/portfolio-nav.js\";\nexport { PortfolioHeader } from \"./components/portfolio-header.js\";\nexport type {\n PortfolioHeaderProps,\n PortfolioHeaderScore,\n} from \"./components/portfolio-header.js\";\nexport { PortfolioOverview } from \"./components/portfolio-overview.js\";\nexport type {\n PortfolioOverviewProps,\n PortfolioOverviewStat,\n PortfolioAttentionItem,\n PortfolioQuickAction,\n} from \"./components/portfolio-overview.js\";\nexport { derivePortfolioCounts } from \"./utils/portfolio-counts.js\";\nexport type { PortfolioCounts, CountableOrder } from \"./utils/portfolio-counts.js\";\n\n// ── v0.22.0 additions — launchpad/claim form template primitives ─────────────\n// Pure-presentation header + rail shared by every launchpad/claim form. The\n// app supplies its own gate, back button, and form logic. Requires the\n// `.btn-border-animated` class (in @medialane/ui/styles) for the form shell.\nexport { ServiceHeader } from \"./components/service-header.js\";\nexport type { ServiceHeaderProps } from \"./components/service-header.js\";\nexport { ClaimRail } from \"./components/claim-rail.js\";\nexport type { ClaimRailProps } from \"./components/claim-rail.js\";\n\n// ── v0.23.0 additions — slot-based form shell ────────────────────────────────\n// Pure layout (back slot + header + animated-border compartment + 8/4 bento).\n// No auth/router — the app injects its own gate (around children) + back button.\nexport { ServiceFormShell } from \"./components/service-form-shell.js\";\nexport type { ServiceFormShellProps } from \"./components/service-form-shell.js\";\nexport { StepNav } from \"./components/step-nav.js\";\nexport type { StepNavProps, StepNavStep } from \"./components/step-nav.js\";\n\n// Rewards score kit (v0.36.0)\nexport { LevelBadge } from \"./components/rewards/level-badge.js\";\nexport type { LevelBadgeProps } from \"./components/rewards/level-badge.js\";\nexport { XpProgress } from \"./components/rewards/xp-progress.js\";\nexport type { XpProgressProps } from \"./components/rewards/xp-progress.js\";\nexport { BadgeShelf } from \"./components/rewards/badge-shelf.js\";\nexport type { BadgeShelfProps, BadgeShelfBadge } from \"./components/rewards/badge-shelf.js\";\nexport { ScoreSummaryCard } from \"./components/rewards/score-summary-card.js\";\nexport type { ScoreSummaryCardProps } from \"./components/rewards/score-summary-card.js\";\nexport { LeaderboardTable, LeaderboardWidget } from \"./components/rewards/leaderboard-table.js\";\nexport type { LeaderboardTableProps, LeaderboardWidgetProps, LeaderboardEntryLike } from \"./components/rewards/leaderboard-table.js\";\nexport { LevelLadder } from \"./components/rewards/level-ladder.js\";\nexport type { LevelLadderProps } from \"./components/rewards/level-ladder.js\";\nexport { XpToastContent } from \"./components/rewards/xp-toast-content.js\";\nexport type { XpToastContentProps } from \"./components/rewards/xp-toast-content.js\";\n\n// ── v0.37.0 additions — infinite-scroll trigger ──────────────────────────────\nexport { LoadMoreSentinel } from \"./components/load-more-sentinel.js\";\nexport type { LoadMoreSentinelProps } from \"./components/load-more-sentinel.js\";\n\n// ── v0.47.0 additions — community rewards section ────────────────────────────\nexport { CommunityRewardsSection } from \"./components/community-rewards-section.js\";\nexport type { CommunityRewardsSectionProps, CommunityRewardsEntry } from \"./components/community-rewards-section.js\";\nexport { CreatorAirdropBanner } from \"./components/creator-airdrop-banner.js\";\nexport type { CreatorAirdropBannerProps } from \"./components/creator-airdrop-banner.js\";\n\n// ── Design system primitives — action-focus pattern, tokens, data display ────\nexport { ActionButton } from \"./components/action-button.js\";\nexport type { ActionButtonProps, ActionKey, ToneKey } from \"./components/action-button.js\";\nexport { GradientButton } from \"./components/gradient-button.js\";\nexport type { GradientButtonProps } from \"./components/gradient-button.js\";\n\nexport { CoinLaunchPreview } from \"./components/coin-launch-preview.js\";\nexport type { CoinPreviewData } from \"./components/coin-launch-preview.js\";\nexport { MedialaneCollectionCard } from \"./components/medialane-collection-card.js\";\nexport type { MedialaneCollectionCardProps } from \"./components/medialane-collection-card.js\";\nexport { TokenGlyph, TokenAmount } from \"./components/token-glyph.js\";\nexport type { TokenGlyphProps, TokenAmountProps, TokenSymbol } from \"./components/token-glyph.js\";\n\nexport { StatTile, StatPill } from \"./components/stat-tile.js\";\nexport type { StatTileProps, StatPillProps } from \"./components/stat-tile.js\";\n\nexport { ActionDialog } from \"./components/action-dialog.js\";\nexport type { ActionDialogProps } from \"./components/action-dialog.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;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,oBAAsD;AACtD,qBAA+B;AAC/B,kBAA2B;AAC3B,qCAAsC;AACtC,6BAA+B;AAG/B,sBAA+C;AAE/C,gBAGO;AAEP,0BAEO;AAEP,6BAA8B;AAC9B,oCAAqC;AACrC,mCAAoC;AACpC,+BAAgC;AAChC,uCAAwC;AAExC,gCAAqF;AAErF,kCAAmC;AAEnC,iCAAkC;AAElC,qCAAsC;AAEtC,mBAAsB;AACtB,uCAAoE;AAGpE,2BAA6C;AAG7C,2BAAyD;AAGzD,6BAA+B;AAG/B,wBAAkC;AAIlC,+BAAyF;AACzF,4BAA8B;AAE9B,4BAA8B;AAE9B,0BAA4B;AAE5B,6BAAuD;AAEvD,wBAA6C;AAE7C,kCAAmC;AAEnC,sCAAuC;AACvC,gCAEO;AAEP,2BAMO;AACP,wBAA6C;AAE7C,0BAA4B;AAE5B,iCAAkC;AAElC,mCAA6H;AAG7H,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,mCAA2D;AAE3D,2BAAsE;AAItE,gCAAiG;AACjG,kCAAmC;AAEnC,6BAA+B;AAG/B,IAAAA,6BAAwE;AAIxE,8BAAkD;AAIlD,uBAMO;AASP,2BAA6B;AAO7B,8BAAgC;AAKhC,gCAAkC;AAOlC,8BAAsC;AAOtC,4BAA8B;AAE9B,wBAA0B;AAM1B,gCAAiC;AAEjC,sBAAwB;AAIxB,yBAA2B;AAE3B,yBAA2B;AAE3B,yBAA2B;AAE3B,gCAAiC;AAEjC,+BAAoD;AAEpD,0BAA4B;AAE5B,8BAA+B;AAI/B,gCAAiC;AAIjC,uCAAwC;AAExC,oCAAqC;AAIrC,2BAA6B;AAE7B,6BAA+B;AAG/B,iCAAkC;AAElC,uCAAwC;AAExC,yBAAwC;AAGxC,uBAAmC;AAGnC,2BAA6B;","names":["import_launchpad_services"]}
package/dist/index.d.cts CHANGED
@@ -78,6 +78,7 @@ export { LoadMoreSentinel, LoadMoreSentinelProps } from './components/load-more-
78
78
  export { CommunityRewardsEntry, CommunityRewardsSection, CommunityRewardsSectionProps } from './components/community-rewards-section.cjs';
79
79
  export { CreatorAirdropBanner, CreatorAirdropBannerProps } from './components/creator-airdrop-banner.cjs';
80
80
  export { ActionButton, ActionButtonProps, ActionKey, ToneKey } from './components/action-button.cjs';
81
+ export { GradientButton, GradientButtonProps } from './components/gradient-button.cjs';
81
82
  export { CoinLaunchPreview, CoinPreviewData } from './components/coin-launch-preview.cjs';
82
83
  export { MedialaneCollectionCard, MedialaneCollectionCardProps } from './components/medialane-collection-card.cjs';
83
84
  export { TokenAmount, TokenAmountProps, TokenGlyph, TokenGlyphProps, TokenSymbol } from './components/token-glyph.cjs';
package/dist/index.d.ts CHANGED
@@ -78,6 +78,7 @@ export { LoadMoreSentinel, LoadMoreSentinelProps } from './components/load-more-
78
78
  export { CommunityRewardsEntry, CommunityRewardsSection, CommunityRewardsSectionProps } from './components/community-rewards-section.js';
79
79
  export { CreatorAirdropBanner, CreatorAirdropBannerProps } from './components/creator-airdrop-banner.js';
80
80
  export { ActionButton, ActionButtonProps, ActionKey, ToneKey } from './components/action-button.js';
81
+ export { GradientButton, GradientButtonProps } from './components/gradient-button.js';
81
82
  export { CoinLaunchPreview, CoinPreviewData } from './components/coin-launch-preview.js';
82
83
  export { MedialaneCollectionCard, MedialaneCollectionCardProps } from './components/medialane-collection-card.js';
83
84
  export { TokenAmount, TokenAmountProps, TokenGlyph, TokenGlyphProps, TokenSymbol } from './components/token-glyph.js';
package/dist/index.js CHANGED
@@ -124,6 +124,7 @@ import { LoadMoreSentinel } from "./components/load-more-sentinel.js";
124
124
  import { CommunityRewardsSection } from "./components/community-rewards-section.js";
125
125
  import { CreatorAirdropBanner } from "./components/creator-airdrop-banner.js";
126
126
  import { ActionButton } from "./components/action-button.js";
127
+ import { GradientButton } from "./components/gradient-button.js";
127
128
  import { CoinLaunchPreview } from "./components/coin-launch-preview.js";
128
129
  import { MedialaneCollectionCard } from "./components/medialane-collection-card.js";
129
130
  import { TokenGlyph, TokenAmount } from "./components/token-glyph.js";
@@ -202,6 +203,7 @@ export {
202
203
  FeaturedCarousel,
203
204
  FeaturedCarouselSkeleton,
204
205
  GEOGRAPHIC_SCOPES,
206
+ GradientButton,
205
207
  HeroSlider,
206
208
  HeroSliderSkeleton,
207
209
  IPTypeDisplay,
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, parsePriceDisplay } from \"./utils/format.js\";\nexport { shortenAddress } from \"./utils/address.js\";\nexport { ipfsToHttp } from \"./utils/ipfs.js\";\nexport { useIntersectionActive } from \"./utils/use-intersection-active.js\";\nexport { licenseSummary } from \"./utils/license-summary.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 { AssetLicenseSummary } from \"./components/asset-license-summary.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, AssetOwnerRow, buildEditionStats } from \"./components/asset-top-sections.js\";\nexport type { AssetOwnerRowProps } from \"./components/asset-top-sections.js\";\nexport { AssetCollectionBar } from \"./components/asset-collection-bar.js\";\nexport type { AssetCollectionBarProps, AssetCollectionBarSibling } from \"./components/asset-collection-bar.js\";\nexport { AssetUtilityIcons } from \"./components/asset-utility-icons.js\";\nexport type { AssetUtilityIconsProps } from \"./components/asset-utility-icons.js\";\nexport { AssetMarketplacePanel } from \"./components/asset-marketplace-panel.js\";\nexport type { AssetMarketplacePanelProps, ApiOrderLike } from \"./components/asset-marketplace-panel.js\";\nexport { BRAND } from \"./data/brand.js\";\nexport { LIVING_RENDER_COLLECTIONS, isLivingRenderCollection } from \"./data/living-render-collections.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 { 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 } from \"./components/token-card.js\";\nexport { AnimatedTokenMedia } from \"./components/animated-token-media.js\";\nexport type { AnimatedTokenMediaProps } from \"./components/animated-token-media.js\";\nexport { ThemeAmbientBackground } from \"./components/theme-ambient-background.js\";\nexport {\n useCollectionFilters, SORT_OPTIONS, CollectionFiltersTrigger, CollectionFiltersBody,\n} from \"./components/collection-filters.js\";\nexport type { TraitSection, CollectionFiltersTriggerProps, CollectionFiltersBodyProps } from \"./components/collection-filters.js\";\nexport {\n DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem,\n DropdownMenuCheckboxItem, DropdownMenuRadioItem, DropdownMenuLabel,\n DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuGroup,\n DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent,\n DropdownMenuSubTrigger, DropdownMenuRadioGroup,\n} from \"./components/dropdown-menu.js\";\nexport { AssetCard, AssetCardSkeleton } from \"./components/asset-card.js\";\nexport type { AssetCardProps, AssetCardPrice } from \"./components/asset-card.js\";\nexport { AssetPicker } from \"./components/asset-picker.js\";\nexport type { AssetPickerProps, OwnedAsset } from \"./components/asset-picker.js\";\nexport { AssetSearchPicker } from \"./components/asset-search-picker.js\";\nexport type { AssetSearchPickerProps } from \"./components/asset-search-picker.js\";\nexport { LicenseTermsBuilder, EMPTY_SPONSORSHIP_TERMS, MEDIA_TYPES, DURATION_UNITS, toLicenseMetadata, toDurationDays } from \"./components/license-terms-builder.js\";\nexport type { LicenseTermsBuilderProps, SponsorshipTerms, DurationUnit } from \"./components/license-terms-builder.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, DiscoverActivityStrip } from \"./components/discover-feed-section.js\";\nexport type { DiscoverFeedSectionProps, DiscoverActivityStripProps } 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, useLaunchpadFilter } from \"./components/launchpad-services.js\";\nexport { LaunchpadFilterBar } from \"./components/launchpad-filter-bar.js\";\nexport type { LaunchpadFilterBarProps } from \"./components/launchpad-filter-bar.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, 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.62.0 — nav shell (brand trigger + header buttons + account sheet) ─────\nexport {\n NavBrandButton,\n NavIconButton,\n NavWalletTrigger,\n NavAccountSheet,\n useNavAccountSheet,\n} from \"./components/nav-shell.js\";\nexport type {\n NavBrandButtonProps,\n NavIconButtonProps,\n NavWalletTriggerProps,\n NavAccountSheetProps,\n} from \"./components/nav-shell.js\";\n\n// ── v0.59.0 — portfolio shell (two-level nav + header + overview) ────────────\nexport { PortfolioNav } from \"./components/portfolio-nav.js\";\nexport type {\n PortfolioNavProps,\n PortfolioNavSection,\n PortfolioNavChild,\n PortfolioBadgeVariant,\n} from \"./components/portfolio-nav.js\";\nexport { PortfolioHeader } from \"./components/portfolio-header.js\";\nexport type {\n PortfolioHeaderProps,\n PortfolioHeaderScore,\n} from \"./components/portfolio-header.js\";\nexport { PortfolioOverview } from \"./components/portfolio-overview.js\";\nexport type {\n PortfolioOverviewProps,\n PortfolioOverviewStat,\n PortfolioAttentionItem,\n PortfolioQuickAction,\n} from \"./components/portfolio-overview.js\";\nexport { derivePortfolioCounts } from \"./utils/portfolio-counts.js\";\nexport type { PortfolioCounts, CountableOrder } from \"./utils/portfolio-counts.js\";\n\n// ── v0.22.0 additions — launchpad/claim form template primitives ─────────────\n// Pure-presentation header + rail shared by every launchpad/claim form. The\n// app supplies its own gate, back button, and form logic. Requires the\n// `.btn-border-animated` class (in @medialane/ui/styles) for the form shell.\nexport { ServiceHeader } from \"./components/service-header.js\";\nexport type { ServiceHeaderProps } from \"./components/service-header.js\";\nexport { ClaimRail } from \"./components/claim-rail.js\";\nexport type { ClaimRailProps } from \"./components/claim-rail.js\";\n\n// ── v0.23.0 additions — slot-based form shell ────────────────────────────────\n// Pure layout (back slot + header + animated-border compartment + 8/4 bento).\n// No auth/router — the app injects its own gate (around children) + back button.\nexport { ServiceFormShell } from \"./components/service-form-shell.js\";\nexport type { ServiceFormShellProps } from \"./components/service-form-shell.js\";\nexport { StepNav } from \"./components/step-nav.js\";\nexport type { StepNavProps, StepNavStep } from \"./components/step-nav.js\";\n\n// Rewards score kit (v0.36.0)\nexport { LevelBadge } from \"./components/rewards/level-badge.js\";\nexport type { LevelBadgeProps } from \"./components/rewards/level-badge.js\";\nexport { XpProgress } from \"./components/rewards/xp-progress.js\";\nexport type { XpProgressProps } from \"./components/rewards/xp-progress.js\";\nexport { BadgeShelf } from \"./components/rewards/badge-shelf.js\";\nexport type { BadgeShelfProps, BadgeShelfBadge } from \"./components/rewards/badge-shelf.js\";\nexport { ScoreSummaryCard } from \"./components/rewards/score-summary-card.js\";\nexport type { ScoreSummaryCardProps } from \"./components/rewards/score-summary-card.js\";\nexport { LeaderboardTable, LeaderboardWidget } from \"./components/rewards/leaderboard-table.js\";\nexport type { LeaderboardTableProps, LeaderboardWidgetProps, LeaderboardEntryLike } from \"./components/rewards/leaderboard-table.js\";\nexport { LevelLadder } from \"./components/rewards/level-ladder.js\";\nexport type { LevelLadderProps } from \"./components/rewards/level-ladder.js\";\nexport { XpToastContent } from \"./components/rewards/xp-toast-content.js\";\nexport type { XpToastContentProps } from \"./components/rewards/xp-toast-content.js\";\n\n// ── v0.37.0 additions — infinite-scroll trigger ──────────────────────────────\nexport { LoadMoreSentinel } from \"./components/load-more-sentinel.js\";\nexport type { LoadMoreSentinelProps } from \"./components/load-more-sentinel.js\";\n\n// ── v0.47.0 additions — community rewards section ────────────────────────────\nexport { CommunityRewardsSection } from \"./components/community-rewards-section.js\";\nexport type { CommunityRewardsSectionProps, CommunityRewardsEntry } from \"./components/community-rewards-section.js\";\nexport { CreatorAirdropBanner } from \"./components/creator-airdrop-banner.js\";\nexport type { CreatorAirdropBannerProps } from \"./components/creator-airdrop-banner.js\";\n\n// ── Design system primitives — action-focus pattern, tokens, data display ────\nexport { ActionButton } from \"./components/action-button.js\";\nexport type { ActionButtonProps, ActionKey, ToneKey } from \"./components/action-button.js\";\n\nexport { CoinLaunchPreview } from \"./components/coin-launch-preview.js\";\nexport type { CoinPreviewData } from \"./components/coin-launch-preview.js\";\nexport { MedialaneCollectionCard } from \"./components/medialane-collection-card.js\";\nexport type { MedialaneCollectionCardProps } from \"./components/medialane-collection-card.js\";\nexport { TokenGlyph, TokenAmount } from \"./components/token-glyph.js\";\nexport type { TokenGlyphProps, TokenAmountProps, TokenSymbol } from \"./components/token-glyph.js\";\n\nexport { StatTile, StatPill } from \"./components/stat-tile.js\";\nexport type { StatTileProps, StatPillProps } from \"./components/stat-tile.js\";\n\nexport { ActionDialog } from \"./components/action-dialog.js\";\nexport type { ActionDialogProps } from \"./components/action-dialog.js\";\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// ── Utils ─────────────────────────────────────────────────────────────────────\nexport { cn } from \"./utils/cn.js\";\nexport { formatDisplayPrice, parsePriceDisplay } from \"./utils/format.js\";\nexport { shortenAddress } from \"./utils/address.js\";\nexport { ipfsToHttp } from \"./utils/ipfs.js\";\nexport { useIntersectionActive } from \"./utils/use-intersection-active.js\";\nexport { licenseSummary } from \"./utils/license-summary.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 { AssetLicenseSummary } from \"./components/asset-license-summary.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, AssetOwnerRow, buildEditionStats } from \"./components/asset-top-sections.js\";\nexport type { AssetOwnerRowProps } from \"./components/asset-top-sections.js\";\nexport { AssetCollectionBar } from \"./components/asset-collection-bar.js\";\nexport type { AssetCollectionBarProps, AssetCollectionBarSibling } from \"./components/asset-collection-bar.js\";\nexport { AssetUtilityIcons } from \"./components/asset-utility-icons.js\";\nexport type { AssetUtilityIconsProps } from \"./components/asset-utility-icons.js\";\nexport { AssetMarketplacePanel } from \"./components/asset-marketplace-panel.js\";\nexport type { AssetMarketplacePanelProps, ApiOrderLike } from \"./components/asset-marketplace-panel.js\";\nexport { BRAND } from \"./data/brand.js\";\nexport { LIVING_RENDER_COLLECTIONS, isLivingRenderCollection } from \"./data/living-render-collections.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 { 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 } from \"./components/token-card.js\";\nexport { AnimatedTokenMedia } from \"./components/animated-token-media.js\";\nexport type { AnimatedTokenMediaProps } from \"./components/animated-token-media.js\";\nexport { ThemeAmbientBackground } from \"./components/theme-ambient-background.js\";\nexport {\n useCollectionFilters, SORT_OPTIONS, CollectionFiltersTrigger, CollectionFiltersBody,\n} from \"./components/collection-filters.js\";\nexport type { TraitSection, CollectionFiltersTriggerProps, CollectionFiltersBodyProps } from \"./components/collection-filters.js\";\nexport {\n DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem,\n DropdownMenuCheckboxItem, DropdownMenuRadioItem, DropdownMenuLabel,\n DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuGroup,\n DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent,\n DropdownMenuSubTrigger, DropdownMenuRadioGroup,\n} from \"./components/dropdown-menu.js\";\nexport { AssetCard, AssetCardSkeleton } from \"./components/asset-card.js\";\nexport type { AssetCardProps, AssetCardPrice } from \"./components/asset-card.js\";\nexport { AssetPicker } from \"./components/asset-picker.js\";\nexport type { AssetPickerProps, OwnedAsset } from \"./components/asset-picker.js\";\nexport { AssetSearchPicker } from \"./components/asset-search-picker.js\";\nexport type { AssetSearchPickerProps } from \"./components/asset-search-picker.js\";\nexport { LicenseTermsBuilder, EMPTY_SPONSORSHIP_TERMS, MEDIA_TYPES, DURATION_UNITS, toLicenseMetadata, toDurationDays } from \"./components/license-terms-builder.js\";\nexport type { LicenseTermsBuilderProps, SponsorshipTerms, DurationUnit } from \"./components/license-terms-builder.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, DiscoverActivityStrip } from \"./components/discover-feed-section.js\";\nexport type { DiscoverFeedSectionProps, DiscoverActivityStripProps } 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, useLaunchpadFilter } from \"./components/launchpad-services.js\";\nexport { LaunchpadFilterBar } from \"./components/launchpad-filter-bar.js\";\nexport type { LaunchpadFilterBarProps } from \"./components/launchpad-filter-bar.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, 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.62.0 — nav shell (brand trigger + header buttons + account sheet) ─────\nexport {\n NavBrandButton,\n NavIconButton,\n NavWalletTrigger,\n NavAccountSheet,\n useNavAccountSheet,\n} from \"./components/nav-shell.js\";\nexport type {\n NavBrandButtonProps,\n NavIconButtonProps,\n NavWalletTriggerProps,\n NavAccountSheetProps,\n} from \"./components/nav-shell.js\";\n\n// ── v0.59.0 — portfolio shell (two-level nav + header + overview) ────────────\nexport { PortfolioNav } from \"./components/portfolio-nav.js\";\nexport type {\n PortfolioNavProps,\n PortfolioNavSection,\n PortfolioNavChild,\n PortfolioBadgeVariant,\n} from \"./components/portfolio-nav.js\";\nexport { PortfolioHeader } from \"./components/portfolio-header.js\";\nexport type {\n PortfolioHeaderProps,\n PortfolioHeaderScore,\n} from \"./components/portfolio-header.js\";\nexport { PortfolioOverview } from \"./components/portfolio-overview.js\";\nexport type {\n PortfolioOverviewProps,\n PortfolioOverviewStat,\n PortfolioAttentionItem,\n PortfolioQuickAction,\n} from \"./components/portfolio-overview.js\";\nexport { derivePortfolioCounts } from \"./utils/portfolio-counts.js\";\nexport type { PortfolioCounts, CountableOrder } from \"./utils/portfolio-counts.js\";\n\n// ── v0.22.0 additions — launchpad/claim form template primitives ─────────────\n// Pure-presentation header + rail shared by every launchpad/claim form. The\n// app supplies its own gate, back button, and form logic. Requires the\n// `.btn-border-animated` class (in @medialane/ui/styles) for the form shell.\nexport { ServiceHeader } from \"./components/service-header.js\";\nexport type { ServiceHeaderProps } from \"./components/service-header.js\";\nexport { ClaimRail } from \"./components/claim-rail.js\";\nexport type { ClaimRailProps } from \"./components/claim-rail.js\";\n\n// ── v0.23.0 additions — slot-based form shell ────────────────────────────────\n// Pure layout (back slot + header + animated-border compartment + 8/4 bento).\n// No auth/router — the app injects its own gate (around children) + back button.\nexport { ServiceFormShell } from \"./components/service-form-shell.js\";\nexport type { ServiceFormShellProps } from \"./components/service-form-shell.js\";\nexport { StepNav } from \"./components/step-nav.js\";\nexport type { StepNavProps, StepNavStep } from \"./components/step-nav.js\";\n\n// Rewards score kit (v0.36.0)\nexport { LevelBadge } from \"./components/rewards/level-badge.js\";\nexport type { LevelBadgeProps } from \"./components/rewards/level-badge.js\";\nexport { XpProgress } from \"./components/rewards/xp-progress.js\";\nexport type { XpProgressProps } from \"./components/rewards/xp-progress.js\";\nexport { BadgeShelf } from \"./components/rewards/badge-shelf.js\";\nexport type { BadgeShelfProps, BadgeShelfBadge } from \"./components/rewards/badge-shelf.js\";\nexport { ScoreSummaryCard } from \"./components/rewards/score-summary-card.js\";\nexport type { ScoreSummaryCardProps } from \"./components/rewards/score-summary-card.js\";\nexport { LeaderboardTable, LeaderboardWidget } from \"./components/rewards/leaderboard-table.js\";\nexport type { LeaderboardTableProps, LeaderboardWidgetProps, LeaderboardEntryLike } from \"./components/rewards/leaderboard-table.js\";\nexport { LevelLadder } from \"./components/rewards/level-ladder.js\";\nexport type { LevelLadderProps } from \"./components/rewards/level-ladder.js\";\nexport { XpToastContent } from \"./components/rewards/xp-toast-content.js\";\nexport type { XpToastContentProps } from \"./components/rewards/xp-toast-content.js\";\n\n// ── v0.37.0 additions — infinite-scroll trigger ──────────────────────────────\nexport { LoadMoreSentinel } from \"./components/load-more-sentinel.js\";\nexport type { LoadMoreSentinelProps } from \"./components/load-more-sentinel.js\";\n\n// ── v0.47.0 additions — community rewards section ────────────────────────────\nexport { CommunityRewardsSection } from \"./components/community-rewards-section.js\";\nexport type { CommunityRewardsSectionProps, CommunityRewardsEntry } from \"./components/community-rewards-section.js\";\nexport { CreatorAirdropBanner } from \"./components/creator-airdrop-banner.js\";\nexport type { CreatorAirdropBannerProps } from \"./components/creator-airdrop-banner.js\";\n\n// ── Design system primitives — action-focus pattern, tokens, data display ────\nexport { ActionButton } from \"./components/action-button.js\";\nexport type { ActionButtonProps, ActionKey, ToneKey } from \"./components/action-button.js\";\nexport { GradientButton } from \"./components/gradient-button.js\";\nexport type { GradientButtonProps } from \"./components/gradient-button.js\";\n\nexport { CoinLaunchPreview } from \"./components/coin-launch-preview.js\";\nexport type { CoinPreviewData } from \"./components/coin-launch-preview.js\";\nexport { MedialaneCollectionCard } from \"./components/medialane-collection-card.js\";\nexport type { MedialaneCollectionCardProps } from \"./components/medialane-collection-card.js\";\nexport { TokenGlyph, TokenAmount } from \"./components/token-glyph.js\";\nexport type { TokenGlyphProps, TokenAmountProps, TokenSymbol } from \"./components/token-glyph.js\";\n\nexport { StatTile, StatPill } from \"./components/stat-tile.js\";\nexport type { StatTileProps, StatPillProps } from \"./components/stat-tile.js\";\n\nexport { ActionDialog } from \"./components/action-dialog.js\";\nexport type { ActionDialogProps } from \"./components/action-dialog.js\";\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medialane/ui",
3
- "version": "0.87.0",
3
+ "version": "0.89.0",
4
4
  "description": "Shared UI components for Medialane apps",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -46,7 +46,7 @@
46
46
  "tailwind-merge": ">=2.0.0"
47
47
  },
48
48
  "devDependencies": {
49
- "@medialane/sdk": "0.73.0",
49
+ "@medialane/sdk": "0.74.0",
50
50
  "@radix-ui/react-dropdown-menu": "^2.1.16",
51
51
  "@types/bun": "^1.3.14",
52
52
  "@types/react": "^19.0.0",