@medialane/ui 0.4.0 → 0.4.2
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 +219 -0
- package/dist/components/activity-ticker.cjs +1 -2
- package/dist/components/activity-ticker.cjs.map +1 -1
- package/dist/components/activity-ticker.d.cts +2 -1
- package/dist/components/activity-ticker.d.ts +2 -1
- package/dist/components/activity-ticker.js +1 -2
- package/dist/components/activity-ticker.js.map +1 -1
- package/dist/components/discover-collections-strip.cjs +5 -3
- package/dist/components/discover-collections-strip.cjs.map +1 -1
- package/dist/components/discover-collections-strip.d.cts +3 -1
- package/dist/components/discover-collections-strip.d.ts +3 -1
- package/dist/components/discover-collections-strip.js +5 -3
- package/dist/components/discover-collections-strip.js.map +1 -1
- package/dist/components/discover-creators-strip.cjs +7 -5
- package/dist/components/discover-creators-strip.cjs.map +1 -1
- package/dist/components/discover-creators-strip.d.cts +3 -1
- package/dist/components/discover-creators-strip.d.ts +3 -1
- package/dist/components/discover-creators-strip.js +7 -5
- package/dist/components/discover-creators-strip.js.map +1 -1
- package/dist/components/discover-hero.cjs +3 -2
- package/dist/components/discover-hero.cjs.map +1 -1
- package/dist/components/discover-hero.d.cts +2 -1
- package/dist/components/discover-hero.d.ts +2 -1
- package/dist/components/discover-hero.js +3 -2
- package/dist/components/discover-hero.js.map +1 -1
- package/dist/components/hero-slider.cjs +8 -11
- package/dist/components/hero-slider.cjs.map +1 -1
- package/dist/components/hero-slider.d.cts +6 -1
- package/dist/components/hero-slider.d.ts +6 -1
- package/dist/components/hero-slider.js +7 -10
- package/dist/components/hero-slider.js.map +1 -1
- package/dist/data/launchpad-services.cjs +38 -38
- package/dist/data/launchpad-services.cjs.map +1 -1
- package/dist/data/launchpad-services.js +38 -38
- package/dist/data/launchpad-services.js.map +1 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# @medialane/ui
|
|
2
|
+
|
|
3
|
+
Shared UI component library for Medialane apps. Used by `medialane-dapp`, `medialane-io`, and `medialane-portal`.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@medialane/ui)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @medialane/ui
|
|
13
|
+
# or
|
|
14
|
+
bun add @medialane/ui
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Tailwind preset
|
|
18
|
+
|
|
19
|
+
Add the preset in `tailwind.config.ts` to get all brand tokens and custom utilities:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import uiPreset from "@medialane/ui/preset";
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
presets: [uiPreset],
|
|
26
|
+
content: ["./src/**/*.{ts,tsx}", "./node_modules/@medialane/ui/dist/**/*.js"],
|
|
27
|
+
};
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Global styles
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
// app/layout.tsx or equivalent entry point
|
|
34
|
+
import "@medialane/ui/styles";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Peer Dependencies
|
|
40
|
+
|
|
41
|
+
| Package | Required |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `react` | >=18.0.0 |
|
|
44
|
+
| `react-dom` | >=18.0.0 |
|
|
45
|
+
| `next` | >=14.0.0 |
|
|
46
|
+
| `framer-motion` | >=10.0.0 |
|
|
47
|
+
| `lucide-react` | >=0.400.0 |
|
|
48
|
+
| `sonner` | >=1.0.0 |
|
|
49
|
+
| `tailwind-merge` | >=2.0.0 |
|
|
50
|
+
| `clsx` | >=2.0.0 |
|
|
51
|
+
| `@medialane/sdk` | >=0.6.0 |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Component Reference
|
|
56
|
+
|
|
57
|
+
### Utils
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { cn, formatDisplayPrice, shortenAddress, ipfsToHttp, timeAgo } from "@medialane/ui";
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
| Export | Description |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `cn(...classes)` | clsx + tailwind-merge class combiner |
|
|
66
|
+
| `formatDisplayPrice(price)` | Format price string for display |
|
|
67
|
+
| `shortenAddress(addr)` | Truncate 0x address — `0x1234…abcd` |
|
|
68
|
+
| `ipfsToHttp(uri)` | Convert `ipfs://` URI to Pinata HTTP gateway URL |
|
|
69
|
+
| `timeAgo(timestamp)` | Relative time string — "3 hours ago" |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
### Data (server-safe — no React, safe in Server Components)
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { IP_TYPE_DATA, IP_TYPE_DATA_MAP, BRAND, ACTIVITY_TYPE_CONFIG, TYPE_FILTERS, LAUNCHPAD_SERVICE_DEFINITIONS } from "@medialane/ui";
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
| Export | Description |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `IP_TYPE_DATA` | Array of IP type definitions (label, icon, color) |
|
|
82
|
+
| `IP_TYPE_DATA_MAP` | Map keyed by IP type string |
|
|
83
|
+
| `BRAND` | Brand color and design tokens |
|
|
84
|
+
| `ACTIVITY_TYPE_CONFIG` | Activity type config (mint/sale/offer/transfer/listing/cancelled) |
|
|
85
|
+
| `TYPE_FILTERS` | Activity filter options for UI |
|
|
86
|
+
| `LAUNCHPAD_SERVICE_DEFINITIONS` | All launchpad service card definitions |
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
### v0.1 — Base Components
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { CurrencyIcon, CurrencyAmount, IpTypeBadge, AddressDisplay, MedialaneIcon, MedialaneLogoFull } from "@medialane/ui";
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
| Component | Description |
|
|
97
|
+
|---|---|
|
|
98
|
+
| `<CurrencyIcon currency="ETH" />` | Token currency icon (ETH, STRK, USDC, USDT, WBTC) |
|
|
99
|
+
| `<CurrencyAmount amount="1.5" currency="ETH" />` | Formatted amount with icon |
|
|
100
|
+
| `<IpTypeBadge type="Music" />` | IP type pill badge with color and icon |
|
|
101
|
+
| `<AddressDisplay address="0x..." />` | Formatted address with copy-to-clipboard |
|
|
102
|
+
| `<MedialaneIcon size={24} />` | Medialane "M" brand icon |
|
|
103
|
+
| `<MedialaneLogoFull />` | Full Medialane wordmark |
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### v0.2 — Motion + Cards
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import {
|
|
111
|
+
MotionCard, FadeIn, Stagger, StaggerItem, KineticWords, SPRING, EASE_OUT,
|
|
112
|
+
ScrollSection, ShareButton, CollectionCard, CollectionCardSkeleton,
|
|
113
|
+
TokenCard, TokenCardSkeleton,
|
|
114
|
+
} from "@medialane/ui";
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
| Component | Description |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `<MotionCard>` | Framer Motion card with hover lift |
|
|
120
|
+
| `<FadeIn>` | Fade-in entrance animation wrapper |
|
|
121
|
+
| `<Stagger>` / `<StaggerItem>` | Staggered list entrance animations |
|
|
122
|
+
| `<KineticWords>` | Animated word-by-word text reveal |
|
|
123
|
+
| `SPRING` / `EASE_OUT` | Reusable animation spring/easing constants |
|
|
124
|
+
| `<ScrollSection>` | Scroll-triggered section fade-in |
|
|
125
|
+
| `<ShareButton>` | Native share API with clipboard fallback |
|
|
126
|
+
| `<CollectionCard collection={c} />` | Collection grid card with image, name, stats |
|
|
127
|
+
| `<CollectionCardSkeleton />` | Loading skeleton for CollectionCard |
|
|
128
|
+
| `<TokenCard token={t} />` | Unified NFT/token card — used on marketplace, portfolio, collections |
|
|
129
|
+
| `<TokenCardSkeleton />` | Loading skeleton for TokenCard |
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
### v0.3 — Activity + Launchpad + Marketplace
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
import {
|
|
137
|
+
HeroSlider, HeroSliderSkeleton, ActivityTicker, ListingCard, ListingCardSkeleton,
|
|
138
|
+
ActivityRow, ActivityFeedShell, LaunchpadGrid, CtaCardGrid,
|
|
139
|
+
} from "@medialane/ui";
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
| Component | Description |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `<HeroSlider slides={[...]} />` | Full-width hero carousel with auto-advance |
|
|
145
|
+
| `<HeroSliderSkeleton />` | Loading skeleton for HeroSlider |
|
|
146
|
+
| `<ActivityTicker activities={[...]} />` | Horizontal scrolling live activity feed ticker |
|
|
147
|
+
| `<ListingCard order={o} />` | Marketplace listing card (price, asset image, buy CTA) |
|
|
148
|
+
| `<ListingCardSkeleton />` | Loading skeleton for ListingCard |
|
|
149
|
+
| `<ActivityRow event={a} isLast={false} />` | Timeline activity row with spine connector |
|
|
150
|
+
| `<ActivityFeedShell activities={[...]} />` | Full activity feed with type filters |
|
|
151
|
+
| `<LaunchpadGrid items={[...]} />` | Launchpad feature grid |
|
|
152
|
+
| `<CtaCardGrid items={[...]} />` | CTA card grid section |
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### v0.3.2 — Discover Components
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import {
|
|
160
|
+
DiscoverHero, FeaturedCarousel, FeaturedCarouselSkeleton,
|
|
161
|
+
DiscoverCollectionsStrip, DiscoverCreatorsStrip, DiscoverFeedSection,
|
|
162
|
+
} from "@medialane/ui";
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
| Component | Description |
|
|
166
|
+
|---|---|
|
|
167
|
+
| `<DiscoverHero>` | Discover page hero with headline and search |
|
|
168
|
+
| `<FeaturedCarousel collections={[...]} />` | Featured collections horizontal carousel |
|
|
169
|
+
| `<FeaturedCarouselSkeleton />` | Loading skeleton for FeaturedCarousel |
|
|
170
|
+
| `<DiscoverCollectionsStrip collections={[...]} />` | Horizontal discovery strip for collections |
|
|
171
|
+
| `<DiscoverCreatorsStrip creators={[...]} />` | Horizontal discovery strip for creators |
|
|
172
|
+
| `<DiscoverFeedSection>` | Full discover page feed section |
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### v0.4 — Launchpad Services
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
import { LaunchpadServicesGrid, LAUNCHPAD_SERVICE_DEFINITIONS } from "@medialane/ui";
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
| Export | Description |
|
|
183
|
+
|---|---|
|
|
184
|
+
| `<LaunchpadServicesGrid services={LAUNCHPAD_SERVICE_DEFINITIONS} />` | Launchpad services grid with live/coming-soon badges |
|
|
185
|
+
| `LAUNCHPAD_SERVICE_DEFINITIONS` | Pre-built service definitions for all launchpad products |
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Build & Publish
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
cd medialane-ui
|
|
193
|
+
|
|
194
|
+
# Build (outputs to dist/)
|
|
195
|
+
~/.bun/bin/bun run build
|
|
196
|
+
|
|
197
|
+
# Type-check
|
|
198
|
+
~/.bun/bin/bun run typecheck
|
|
199
|
+
|
|
200
|
+
# Watch mode during development
|
|
201
|
+
~/.bun/bin/bun run dev
|
|
202
|
+
|
|
203
|
+
# Publish to npm
|
|
204
|
+
npm publish
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The package uses [tsup](https://tsup.egoist.dev/) and outputs ESM + CJS + type declarations.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Version History
|
|
212
|
+
|
|
213
|
+
| Version | Added |
|
|
214
|
+
|---|---|
|
|
215
|
+
| **v0.4.0** | `LaunchpadServicesGrid`, `LAUNCHPAD_SERVICE_DEFINITIONS` |
|
|
216
|
+
| **v0.3.2** | `DiscoverHero`, `FeaturedCarousel`, `DiscoverCollectionsStrip`, `DiscoverCreatorsStrip`, `DiscoverFeedSection` |
|
|
217
|
+
| **v0.3.0** | `ActivityRow`, `ActivityFeedShell`, `ActivityTicker`, `HeroSlider`, `ListingCard`, `LaunchpadGrid`, `CtaCardGrid`, `timeAgo`, `ACTIVITY_TYPE_CONFIG` |
|
|
218
|
+
| **v0.2.0** | `MotionCard`, `FadeIn`, `Stagger`, `StaggerItem`, `KineticWords`, `ScrollSection`, `ShareButton`, `CollectionCard`, `TokenCard` |
|
|
219
|
+
| **v0.1.0** | `cn`, `formatDisplayPrice`, `shortenAddress`, `ipfsToHttp`, `CurrencyIcon`, `CurrencyAmount`, `IpTypeBadge`, `AddressDisplay`, `MedialaneIcon`, `MedialaneLogoFull`, `IP_TYPE_DATA`, `BRAND` |
|
|
@@ -71,9 +71,8 @@ function ActivityPill({ listing, getHref }) {
|
|
|
71
71
|
}
|
|
72
72
|
);
|
|
73
73
|
}
|
|
74
|
-
function ActivityTicker({ orders, minItems = 3, className }) {
|
|
74
|
+
function ActivityTicker({ orders, minItems = 3, className, getHref = (o) => `/asset/${o.nftContract}/${o.nftTokenId}` }) {
|
|
75
75
|
if (orders.length < minItems) return null;
|
|
76
|
-
const getHref = (order) => `/asset/${order.nftContract}/${order.nftTokenId}`;
|
|
77
76
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_cn.cn)(className), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative overflow-hidden py-2.5", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
78
77
|
"div",
|
|
79
78
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/activity-ticker.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiOrder } from \"@medialane/sdk\";\n\nexport interface ActivityTickerProps {\n orders: ApiOrder[];\n /** Hide ticker if fewer items than this threshold. Default: 3 */\n minItems?: number;\n className?: string;\n}\n\nfunction ActivityPill({ listing, getHref }: { listing: ApiOrder; getHref: (order: ApiOrder) => string }) {\n const [imgError, setImgError] = useState(false);\n const image = listing.token?.image && !imgError ? ipfsToHttp(listing.token.image) : null;\n\n return (\n <Link\n href={getHref(listing)}\n className=\"flex-shrink-0 flex items-center gap-2 rounded-xl border border-border bg-card px-3 py-2 hover:bg-muted/60 active:scale-[0.98] transition-all duration-150 group\"\n >\n <div className=\"h-8 w-8 rounded-lg overflow-hidden bg-muted shrink-0\">\n {image ? (\n <img\n src={image}\n alt=\"\"\n loading=\"lazy\"\n className=\"w-full h-full object-cover group-hover:scale-105 transition-transform duration-300\"\n onError={() => setImgError(true)}\n />\n ) : (\n <div className=\"w-full h-full bg-gradient-to-br from-brand-purple/20 to-brand-blue/20\" />\n )}\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-xs font-medium whitespace-nowrap max-w-[100px] truncate\">\n {listing.token?.name ?? `#${listing.nftTokenId}`}\n </p>\n {listing.price?.formatted && (\n <p className=\"text-[10px] font-bold text-brand-orange whitespace-nowrap flex items-center gap-0.5\">\n {listing.price.currency && <CurrencyIcon symbol={listing.price.currency} size={10} />}\n {formatDisplayPrice(listing.price.formatted)} {listing.price.currency}\n </p>\n )}\n </div>\n </Link>\n );\n}\n\nexport function ActivityTicker({ orders, minItems = 3, className }: ActivityTickerProps) {\n if (orders.length < minItems) return null;\n\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/activity-ticker.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiOrder } from \"@medialane/sdk\";\n\nexport interface ActivityTickerProps {\n orders: ApiOrder[];\n /** Hide ticker if fewer items than this threshold. Default: 3 */\n minItems?: number;\n className?: string;\n getHref?: (order: ApiOrder) => string;\n}\n\nfunction ActivityPill({ listing, getHref }: { listing: ApiOrder; getHref: (order: ApiOrder) => string }) {\n const [imgError, setImgError] = useState(false);\n const image = listing.token?.image && !imgError ? ipfsToHttp(listing.token.image) : null;\n\n return (\n <Link\n href={getHref(listing)}\n className=\"flex-shrink-0 flex items-center gap-2 rounded-xl border border-border bg-card px-3 py-2 hover:bg-muted/60 active:scale-[0.98] transition-all duration-150 group\"\n >\n <div className=\"h-8 w-8 rounded-lg overflow-hidden bg-muted shrink-0\">\n {image ? (\n <img\n src={image}\n alt=\"\"\n loading=\"lazy\"\n className=\"w-full h-full object-cover group-hover:scale-105 transition-transform duration-300\"\n onError={() => setImgError(true)}\n />\n ) : (\n <div className=\"w-full h-full bg-gradient-to-br from-brand-purple/20 to-brand-blue/20\" />\n )}\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-xs font-medium whitespace-nowrap max-w-[100px] truncate\">\n {listing.token?.name ?? `#${listing.nftTokenId}`}\n </p>\n {listing.price?.formatted && (\n <p className=\"text-[10px] font-bold text-brand-orange whitespace-nowrap flex items-center gap-0.5\">\n {listing.price.currency && <CurrencyIcon symbol={listing.price.currency} size={10} />}\n {formatDisplayPrice(listing.price.formatted)} {listing.price.currency}\n </p>\n )}\n </div>\n </Link>\n );\n}\n\nexport function ActivityTicker({ orders, minItems = 3, className, getHref = (o) => `/asset/${o.nftContract}/${o.nftTokenId}` }: ActivityTickerProps) {\n if (orders.length < minItems) return null;\n\n return (\n <div className={cn(className)}>\n <div className=\"relative overflow-hidden py-2.5\">\n <div\n className=\"flex gap-2 w-max px-2\"\n style={{ animation: \"scroll-strip 50s linear infinite\" }}\n onMouseEnter={(e) => (e.currentTarget.style.animationPlayState = \"paused\")}\n onMouseLeave={(e) => (e.currentTarget.style.animationPlayState = \"running\")}\n >\n {[...orders, ...orders].map((listing, i) => (\n <ActivityPill key={`${listing.orderHash}-${i}`} listing={listing} getHref={getHref} />\n ))}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BU;AA3BV,mBAAyB;AACzB,kBAAiB;AACjB,2BAA6B;AAC7B,oBAAmC;AACnC,kBAA2B;AAC3B,gBAAmB;AAWnB,SAAS,aAAa,EAAE,SAAS,QAAQ,GAAgE;AACvG,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,KAAK;AAC9C,QAAM,QAAQ,QAAQ,OAAO,SAAS,CAAC,eAAW,wBAAW,QAAQ,MAAM,KAAK,IAAI;AAEpF,SACE;AAAA,IAAC,YAAAA;AAAA,IAAA;AAAA,MACC,MAAM,QAAQ,OAAO;AAAA,MACrB,WAAU;AAAA,MAEV;AAAA,oDAAC,SAAI,WAAU,wDACZ,kBACC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAI;AAAA,YACJ,SAAQ;AAAA,YACR,WAAU;AAAA,YACV,SAAS,MAAM,YAAY,IAAI;AAAA;AAAA,QACjC,IAEA,4CAAC,SAAI,WAAU,yEAAwE,GAE3F;AAAA,QACA,6CAAC,SAAI,WAAU,WACb;AAAA,sDAAC,OAAE,WAAU,gEACV,kBAAQ,OAAO,QAAQ,IAAI,QAAQ,UAAU,IAChD;AAAA,UACC,QAAQ,OAAO,aACd,6CAAC,OAAE,WAAU,uFACV;AAAA,oBAAQ,MAAM,YAAY,4CAAC,qCAAa,QAAQ,QAAQ,MAAM,UAAU,MAAM,IAAI;AAAA,gBAClF,kCAAmB,QAAQ,MAAM,SAAS;AAAA,YAAE;AAAA,YAAE,QAAQ,MAAM;AAAA,aAC/D;AAAA,WAEJ;AAAA;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,eAAe,EAAE,QAAQ,WAAW,GAAG,WAAW,UAAU,CAAC,MAAM,UAAU,EAAE,WAAW,IAAI,EAAE,UAAU,GAAG,GAAwB;AACnJ,MAAI,OAAO,SAAS,SAAU,QAAO;AAErC,SACE,4CAAC,SAAI,eAAW,cAAG,SAAS,GAC1B,sDAAC,SAAI,WAAU,mCACb;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO,EAAE,WAAW,mCAAmC;AAAA,MACvD,cAAc,CAAC,MAAO,EAAE,cAAc,MAAM,qBAAqB;AAAA,MACjE,cAAc,CAAC,MAAO,EAAE,cAAc,MAAM,qBAAqB;AAAA,MAEhE,WAAC,GAAG,QAAQ,GAAG,MAAM,EAAE,IAAI,CAAC,SAAS,MACpC,4CAAC,gBAA+C,SAAkB,WAA/C,GAAG,QAAQ,SAAS,IAAI,CAAC,EAAwC,CACrF;AAAA;AAAA,EACH,GACF,GACF;AAEJ;","names":["Link"]}
|
|
@@ -6,7 +6,8 @@ interface ActivityTickerProps {
|
|
|
6
6
|
/** Hide ticker if fewer items than this threshold. Default: 3 */
|
|
7
7
|
minItems?: number;
|
|
8
8
|
className?: string;
|
|
9
|
+
getHref?: (order: ApiOrder) => string;
|
|
9
10
|
}
|
|
10
|
-
declare function ActivityTicker({ orders, minItems, className }: ActivityTickerProps): react_jsx_runtime.JSX.Element | null;
|
|
11
|
+
declare function ActivityTicker({ orders, minItems, className, getHref }: ActivityTickerProps): react_jsx_runtime.JSX.Element | null;
|
|
11
12
|
|
|
12
13
|
export { ActivityTicker, type ActivityTickerProps };
|
|
@@ -6,7 +6,8 @@ interface ActivityTickerProps {
|
|
|
6
6
|
/** Hide ticker if fewer items than this threshold. Default: 3 */
|
|
7
7
|
minItems?: number;
|
|
8
8
|
className?: string;
|
|
9
|
+
getHref?: (order: ApiOrder) => string;
|
|
9
10
|
}
|
|
10
|
-
declare function ActivityTicker({ orders, minItems, className }: ActivityTickerProps): react_jsx_runtime.JSX.Element | null;
|
|
11
|
+
declare function ActivityTicker({ orders, minItems, className, getHref }: ActivityTickerProps): react_jsx_runtime.JSX.Element | null;
|
|
11
12
|
|
|
12
13
|
export { ActivityTicker, type ActivityTickerProps };
|
|
@@ -38,9 +38,8 @@ function ActivityPill({ listing, getHref }) {
|
|
|
38
38
|
}
|
|
39
39
|
);
|
|
40
40
|
}
|
|
41
|
-
function ActivityTicker({ orders, minItems = 3, className }) {
|
|
41
|
+
function ActivityTicker({ orders, minItems = 3, className, getHref = (o) => `/asset/${o.nftContract}/${o.nftTokenId}` }) {
|
|
42
42
|
if (orders.length < minItems) return null;
|
|
43
|
-
const getHref = (order) => `/asset/${order.nftContract}/${order.nftTokenId}`;
|
|
44
43
|
return /* @__PURE__ */ jsx("div", { className: cn(className), children: /* @__PURE__ */ jsx("div", { className: "relative overflow-hidden py-2.5", children: /* @__PURE__ */ jsx(
|
|
45
44
|
"div",
|
|
46
45
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/activity-ticker.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiOrder } from \"@medialane/sdk\";\n\nexport interface ActivityTickerProps {\n orders: ApiOrder[];\n /** Hide ticker if fewer items than this threshold. Default: 3 */\n minItems?: number;\n className?: string;\n}\n\nfunction ActivityPill({ listing, getHref }: { listing: ApiOrder; getHref: (order: ApiOrder) => string }) {\n const [imgError, setImgError] = useState(false);\n const image = listing.token?.image && !imgError ? ipfsToHttp(listing.token.image) : null;\n\n return (\n <Link\n href={getHref(listing)}\n className=\"flex-shrink-0 flex items-center gap-2 rounded-xl border border-border bg-card px-3 py-2 hover:bg-muted/60 active:scale-[0.98] transition-all duration-150 group\"\n >\n <div className=\"h-8 w-8 rounded-lg overflow-hidden bg-muted shrink-0\">\n {image ? (\n <img\n src={image}\n alt=\"\"\n loading=\"lazy\"\n className=\"w-full h-full object-cover group-hover:scale-105 transition-transform duration-300\"\n onError={() => setImgError(true)}\n />\n ) : (\n <div className=\"w-full h-full bg-gradient-to-br from-brand-purple/20 to-brand-blue/20\" />\n )}\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-xs font-medium whitespace-nowrap max-w-[100px] truncate\">\n {listing.token?.name ?? `#${listing.nftTokenId}`}\n </p>\n {listing.price?.formatted && (\n <p className=\"text-[10px] font-bold text-brand-orange whitespace-nowrap flex items-center gap-0.5\">\n {listing.price.currency && <CurrencyIcon symbol={listing.price.currency} size={10} />}\n {formatDisplayPrice(listing.price.formatted)} {listing.price.currency}\n </p>\n )}\n </div>\n </Link>\n );\n}\n\nexport function ActivityTicker({ orders, minItems = 3, className }: ActivityTickerProps) {\n if (orders.length < minItems) return null;\n\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/activity-ticker.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiOrder } from \"@medialane/sdk\";\n\nexport interface ActivityTickerProps {\n orders: ApiOrder[];\n /** Hide ticker if fewer items than this threshold. Default: 3 */\n minItems?: number;\n className?: string;\n getHref?: (order: ApiOrder) => string;\n}\n\nfunction ActivityPill({ listing, getHref }: { listing: ApiOrder; getHref: (order: ApiOrder) => string }) {\n const [imgError, setImgError] = useState(false);\n const image = listing.token?.image && !imgError ? ipfsToHttp(listing.token.image) : null;\n\n return (\n <Link\n href={getHref(listing)}\n className=\"flex-shrink-0 flex items-center gap-2 rounded-xl border border-border bg-card px-3 py-2 hover:bg-muted/60 active:scale-[0.98] transition-all duration-150 group\"\n >\n <div className=\"h-8 w-8 rounded-lg overflow-hidden bg-muted shrink-0\">\n {image ? (\n <img\n src={image}\n alt=\"\"\n loading=\"lazy\"\n className=\"w-full h-full object-cover group-hover:scale-105 transition-transform duration-300\"\n onError={() => setImgError(true)}\n />\n ) : (\n <div className=\"w-full h-full bg-gradient-to-br from-brand-purple/20 to-brand-blue/20\" />\n )}\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-xs font-medium whitespace-nowrap max-w-[100px] truncate\">\n {listing.token?.name ?? `#${listing.nftTokenId}`}\n </p>\n {listing.price?.formatted && (\n <p className=\"text-[10px] font-bold text-brand-orange whitespace-nowrap flex items-center gap-0.5\">\n {listing.price.currency && <CurrencyIcon symbol={listing.price.currency} size={10} />}\n {formatDisplayPrice(listing.price.formatted)} {listing.price.currency}\n </p>\n )}\n </div>\n </Link>\n );\n}\n\nexport function ActivityTicker({ orders, minItems = 3, className, getHref = (o) => `/asset/${o.nftContract}/${o.nftTokenId}` }: ActivityTickerProps) {\n if (orders.length < minItems) return null;\n\n return (\n <div className={cn(className)}>\n <div className=\"relative overflow-hidden py-2.5\">\n <div\n className=\"flex gap-2 w-max px-2\"\n style={{ animation: \"scroll-strip 50s linear infinite\" }}\n onMouseEnter={(e) => (e.currentTarget.style.animationPlayState = \"paused\")}\n onMouseLeave={(e) => (e.currentTarget.style.animationPlayState = \"running\")}\n >\n {[...orders, ...orders].map((listing, i) => (\n <ActivityPill key={`${listing.orderHash}-${i}`} listing={listing} getHref={getHref} />\n ))}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";AA6BU,cAgBA,YAhBA;AA3BV,SAAS,gBAAgB;AACzB,OAAO,UAAU;AACjB,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,kBAAkB;AAC3B,SAAS,UAAU;AAWnB,SAAS,aAAa,EAAE,SAAS,QAAQ,GAAgE;AACvG,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,QAAQ,QAAQ,OAAO,SAAS,CAAC,WAAW,WAAW,QAAQ,MAAM,KAAK,IAAI;AAEpF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,QAAQ,OAAO;AAAA,MACrB,WAAU;AAAA,MAEV;AAAA,4BAAC,SAAI,WAAU,wDACZ,kBACC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAI;AAAA,YACJ,SAAQ;AAAA,YACR,WAAU;AAAA,YACV,SAAS,MAAM,YAAY,IAAI;AAAA;AAAA,QACjC,IAEA,oBAAC,SAAI,WAAU,yEAAwE,GAE3F;AAAA,QACA,qBAAC,SAAI,WAAU,WACb;AAAA,8BAAC,OAAE,WAAU,gEACV,kBAAQ,OAAO,QAAQ,IAAI,QAAQ,UAAU,IAChD;AAAA,UACC,QAAQ,OAAO,aACd,qBAAC,OAAE,WAAU,uFACV;AAAA,oBAAQ,MAAM,YAAY,oBAAC,gBAAa,QAAQ,QAAQ,MAAM,UAAU,MAAM,IAAI;AAAA,YAClF,mBAAmB,QAAQ,MAAM,SAAS;AAAA,YAAE;AAAA,YAAE,QAAQ,MAAM;AAAA,aAC/D;AAAA,WAEJ;AAAA;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,eAAe,EAAE,QAAQ,WAAW,GAAG,WAAW,UAAU,CAAC,MAAM,UAAU,EAAE,WAAW,IAAI,EAAE,UAAU,GAAG,GAAwB;AACnJ,MAAI,OAAO,SAAS,SAAU,QAAO;AAErC,SACE,oBAAC,SAAI,WAAW,GAAG,SAAS,GAC1B,8BAAC,SAAI,WAAU,mCACb;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO,EAAE,WAAW,mCAAmC;AAAA,MACvD,cAAc,CAAC,MAAO,EAAE,cAAc,MAAM,qBAAqB;AAAA,MACjE,cAAc,CAAC,MAAO,EAAE,cAAc,MAAM,qBAAqB;AAAA,MAEhE,WAAC,GAAG,QAAQ,GAAG,MAAM,EAAE,IAAI,CAAC,SAAS,MACpC,oBAAC,gBAA+C,SAAkB,WAA/C,GAAG,QAAQ,SAAS,IAAI,CAAC,EAAwC,CACrF;AAAA;AAAA,EACH,GACF,GACF;AAEJ;","names":[]}
|
|
@@ -78,15 +78,17 @@ function DiscoverCollectionsStrip({
|
|
|
78
78
|
collections,
|
|
79
79
|
isLoading,
|
|
80
80
|
getHref,
|
|
81
|
-
allCollectionsHref = "/collections"
|
|
81
|
+
allCollectionsHref = "/collections",
|
|
82
|
+
sectionLabel = "NFT",
|
|
83
|
+
title = "Collections"
|
|
82
84
|
}) {
|
|
83
85
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_motion_primitives.FadeIn, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-3", children: [
|
|
84
86
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
85
87
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
86
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "section-label", children:
|
|
88
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "section-label", children: sectionLabel }),
|
|
87
89
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2 mt-0.5", children: [
|
|
88
90
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Layers, { className: "h-4 w-4 text-brand-blue" }),
|
|
89
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-lg font-bold", children:
|
|
91
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-lg font-bold", children: title })
|
|
90
92
|
] })
|
|
91
93
|
] }),
|
|
92
94
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/discover-collections-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Layers, ArrowRight } from \"lucide-react\";\nimport { FadeIn } from \"./motion-primitives.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\nexport interface DiscoverCollectionsStripProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n}\n\nfunction CollectionChipSkeleton() {\n return (\n <div className=\"shrink-0 w-80 rounded-xl border border-border overflow-hidden\">\n <div className=\"aspect-square w-full bg-muted animate-pulse\" />\n <div className=\"p-3 space-y-1.5\">\n <div className=\"h-3.5 w-28 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-16 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n );\n}\n\nfunction CollectionChip({\n collection,\n href,\n}: {\n collection: ApiCollection;\n href: string;\n}) {\n const [imgError, setImgError] = useState(false);\n const image = collection.image && !imgError ? ipfsToHttp(collection.image) : null;\n const initial = (collection.name ?? \"?\").charAt(0).toUpperCase();\n\n return (\n <a\n href={href}\n className=\"block shrink-0 w-80 snap-start active:scale-[0.97] transition-transform duration-150\"\n >\n <div className=\"rounded-xl border border-border overflow-hidden group bg-card hover:border-border/80 transition-colors\">\n <div className=\"aspect-square bg-muted relative overflow-hidden\">\n {image ? (\n <img\n src={image}\n alt={collection.name ?? \"\"}\n loading=\"lazy\"\n className=\"w-full h-full object-cover group-hover:scale-105 transition-transform duration-500\"\n onError={() => setImgError(true)}\n />\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/40 flex items-center justify-center\">\n <span className=\"text-5xl font-black text-white/10 select-none\">{initial}</span>\n </div>\n )}\n </div>\n <div className=\"p-3 space-y-0.5\">\n <p className=\"text-sm font-semibold truncate\">{collection.name ?? \"Unnamed\"}</p>\n <div className=\"flex items-center justify-between text-xs text-muted-foreground\">\n <span>{collection.totalSupply ?? 0} items</span>\n {collection.floorPrice && (\n <span className=\"font-semibold text-brand-orange\">\n {formatDisplayPrice(collection.floorPrice)}\n </span>\n )}\n </div>\n </div>\n </div>\n </a>\n );\n}\n\nexport function DiscoverCollectionsStrip({\n collections,\n isLoading,\n getHref,\n allCollectionsHref = \"/collections\",\n}: DiscoverCollectionsStripProps) {\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\">
|
|
1
|
+
{"version":3,"sources":["../../src/components/discover-collections-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Layers, ArrowRight } from \"lucide-react\";\nimport { FadeIn } from \"./motion-primitives.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\nexport interface DiscoverCollectionsStripProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n sectionLabel?: string;\n title?: string;\n}\n\nfunction CollectionChipSkeleton() {\n return (\n <div className=\"shrink-0 w-80 rounded-xl border border-border overflow-hidden\">\n <div className=\"aspect-square w-full bg-muted animate-pulse\" />\n <div className=\"p-3 space-y-1.5\">\n <div className=\"h-3.5 w-28 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-16 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n );\n}\n\nfunction CollectionChip({\n collection,\n href,\n}: {\n collection: ApiCollection;\n href: string;\n}) {\n const [imgError, setImgError] = useState(false);\n const image = collection.image && !imgError ? ipfsToHttp(collection.image) : null;\n const initial = (collection.name ?? \"?\").charAt(0).toUpperCase();\n\n return (\n <a\n href={href}\n className=\"block shrink-0 w-80 snap-start active:scale-[0.97] transition-transform duration-150\"\n >\n <div className=\"rounded-xl border border-border overflow-hidden group bg-card hover:border-border/80 transition-colors\">\n <div className=\"aspect-square bg-muted relative overflow-hidden\">\n {image ? (\n <img\n src={image}\n alt={collection.name ?? \"\"}\n loading=\"lazy\"\n className=\"w-full h-full object-cover group-hover:scale-105 transition-transform duration-500\"\n onError={() => setImgError(true)}\n />\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/40 flex items-center justify-center\">\n <span className=\"text-5xl font-black text-white/10 select-none\">{initial}</span>\n </div>\n )}\n </div>\n <div className=\"p-3 space-y-0.5\">\n <p className=\"text-sm font-semibold truncate\">{collection.name ?? \"Unnamed\"}</p>\n <div className=\"flex items-center justify-between text-xs text-muted-foreground\">\n <span>{collection.totalSupply ?? 0} items</span>\n {collection.floorPrice && (\n <span className=\"font-semibold text-brand-orange\">\n {formatDisplayPrice(collection.floorPrice)}\n </span>\n )}\n </div>\n </div>\n </div>\n </a>\n );\n}\n\nexport function DiscoverCollectionsStrip({\n collections,\n isLoading,\n getHref,\n allCollectionsHref = \"/collections\",\n sectionLabel = \"NFT\",\n title = \"Collections\",\n}: DiscoverCollectionsStripProps) {\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 <Layers className=\"h-4 w-4 text-brand-blue\" />\n <h2 className=\"text-lg font-bold\">{title}</h2>\n </div>\n </div>\n <a\n href={allCollectionsHref}\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-3 w-max pb-1\">\n {isLoading\n ? Array.from({ length: 6 }).map((_, i) => <CollectionChipSkeleton key={i} />)\n : collections.map((col) => (\n <CollectionChip key={col.contractAddress} collection={col} href={getHref(col)} />\n ))}\n </div>\n </div>\n </div>\n </FadeIn>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBM;AAnBN,mBAAyB;AACzB,0BAAmC;AACnC,+BAAuB;AACvB,kBAA2B;AAC3B,oBAAmC;AAYnC,SAAS,yBAAyB;AAChC,SACE,6CAAC,SAAI,WAAU,iEACb;AAAA,gDAAC,SAAI,WAAU,+CAA8C;AAAA,IAC7D,6CAAC,SAAI,WAAU,mBACb;AAAA,kDAAC,SAAI,WAAU,6CAA4C;AAAA,MAC3D,4CAAC,SAAI,WAAU,2CAA0C;AAAA,OAC3D;AAAA,KACF;AAEJ;AAEA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,KAAK;AAC9C,QAAM,QAAQ,WAAW,SAAS,CAAC,eAAW,wBAAW,WAAW,KAAK,IAAI;AAC7E,QAAM,WAAW,WAAW,QAAQ,KAAK,OAAO,CAAC,EAAE,YAAY;AAE/D,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAU;AAAA,MAEV,uDAAC,SAAI,WAAU,0GACb;AAAA,oDAAC,SAAI,WAAU,mDACZ,kBACC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAK,WAAW,QAAQ;AAAA,YACxB,SAAQ;AAAA,YACR,WAAU;AAAA,YACV,SAAS,MAAM,YAAY,IAAI;AAAA;AAAA,QACjC,IAEA,4CAAC,SAAI,WAAU,+HACb,sDAAC,UAAK,WAAU,iDAAiD,mBAAQ,GAC3E,GAEJ;AAAA,QACA,6CAAC,SAAI,WAAU,mBACb;AAAA,sDAAC,OAAE,WAAU,kCAAkC,qBAAW,QAAQ,WAAU;AAAA,UAC5E,6CAAC,SAAI,WAAU,mEACb;AAAA,yDAAC,UAAM;AAAA,yBAAW,eAAe;AAAA,cAAE;AAAA,eAAM;AAAA,YACxC,WAAW,cACV,4CAAC,UAAK,WAAU,mCACb,gDAAmB,WAAW,UAAU,GAC3C;AAAA,aAEJ;AAAA,WACF;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,QAAQ;AACV,GAAkC;AAChC,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,8BAAO,WAAU,2BAA0B;AAAA,UAC5C,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,yBACZ,sBACG,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,4CAAC,4BAA4B,CAAG,CAAE,IAC1E,YAAY,IAAI,CAAC,QACf,4CAAC,kBAAyC,YAAY,KAAK,MAAM,QAAQ,GAAG,KAAvD,IAAI,eAAsD,CAChF,GACP,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}
|
|
@@ -6,7 +6,9 @@ interface DiscoverCollectionsStripProps {
|
|
|
6
6
|
isLoading: boolean;
|
|
7
7
|
getHref: (collection: ApiCollection) => string;
|
|
8
8
|
allCollectionsHref?: string;
|
|
9
|
+
sectionLabel?: string;
|
|
10
|
+
title?: string;
|
|
9
11
|
}
|
|
10
|
-
declare function DiscoverCollectionsStrip({ collections, isLoading, getHref, allCollectionsHref, }: DiscoverCollectionsStripProps): react_jsx_runtime.JSX.Element;
|
|
12
|
+
declare function DiscoverCollectionsStrip({ collections, isLoading, getHref, allCollectionsHref, sectionLabel, title, }: DiscoverCollectionsStripProps): react_jsx_runtime.JSX.Element;
|
|
11
13
|
|
|
12
14
|
export { DiscoverCollectionsStrip, type DiscoverCollectionsStripProps };
|
|
@@ -6,7 +6,9 @@ interface DiscoverCollectionsStripProps {
|
|
|
6
6
|
isLoading: boolean;
|
|
7
7
|
getHref: (collection: ApiCollection) => string;
|
|
8
8
|
allCollectionsHref?: string;
|
|
9
|
+
sectionLabel?: string;
|
|
10
|
+
title?: string;
|
|
9
11
|
}
|
|
10
|
-
declare function DiscoverCollectionsStrip({ collections, isLoading, getHref, allCollectionsHref, }: DiscoverCollectionsStripProps): react_jsx_runtime.JSX.Element;
|
|
12
|
+
declare function DiscoverCollectionsStrip({ collections, isLoading, getHref, allCollectionsHref, sectionLabel, title, }: DiscoverCollectionsStripProps): react_jsx_runtime.JSX.Element;
|
|
11
13
|
|
|
12
14
|
export { DiscoverCollectionsStrip, type DiscoverCollectionsStripProps };
|
|
@@ -55,15 +55,17 @@ function DiscoverCollectionsStrip({
|
|
|
55
55
|
collections,
|
|
56
56
|
isLoading,
|
|
57
57
|
getHref,
|
|
58
|
-
allCollectionsHref = "/collections"
|
|
58
|
+
allCollectionsHref = "/collections",
|
|
59
|
+
sectionLabel = "NFT",
|
|
60
|
+
title = "Collections"
|
|
59
61
|
}) {
|
|
60
62
|
return /* @__PURE__ */ jsx(FadeIn, { children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
61
63
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
62
64
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
63
|
-
/* @__PURE__ */ jsx("p", { className: "section-label", children:
|
|
65
|
+
/* @__PURE__ */ jsx("p", { className: "section-label", children: sectionLabel }),
|
|
64
66
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-0.5", children: [
|
|
65
67
|
/* @__PURE__ */ jsx(Layers, { className: "h-4 w-4 text-brand-blue" }),
|
|
66
|
-
/* @__PURE__ */ jsx("h2", { className: "text-lg font-bold", children:
|
|
68
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-bold", children: title })
|
|
67
69
|
] })
|
|
68
70
|
] }),
|
|
69
71
|
/* @__PURE__ */ jsxs(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/discover-collections-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Layers, ArrowRight } from \"lucide-react\";\nimport { FadeIn } from \"./motion-primitives.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\nexport interface DiscoverCollectionsStripProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n}\n\nfunction CollectionChipSkeleton() {\n return (\n <div className=\"shrink-0 w-80 rounded-xl border border-border overflow-hidden\">\n <div className=\"aspect-square w-full bg-muted animate-pulse\" />\n <div className=\"p-3 space-y-1.5\">\n <div className=\"h-3.5 w-28 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-16 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n );\n}\n\nfunction CollectionChip({\n collection,\n href,\n}: {\n collection: ApiCollection;\n href: string;\n}) {\n const [imgError, setImgError] = useState(false);\n const image = collection.image && !imgError ? ipfsToHttp(collection.image) : null;\n const initial = (collection.name ?? \"?\").charAt(0).toUpperCase();\n\n return (\n <a\n href={href}\n className=\"block shrink-0 w-80 snap-start active:scale-[0.97] transition-transform duration-150\"\n >\n <div className=\"rounded-xl border border-border overflow-hidden group bg-card hover:border-border/80 transition-colors\">\n <div className=\"aspect-square bg-muted relative overflow-hidden\">\n {image ? (\n <img\n src={image}\n alt={collection.name ?? \"\"}\n loading=\"lazy\"\n className=\"w-full h-full object-cover group-hover:scale-105 transition-transform duration-500\"\n onError={() => setImgError(true)}\n />\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/40 flex items-center justify-center\">\n <span className=\"text-5xl font-black text-white/10 select-none\">{initial}</span>\n </div>\n )}\n </div>\n <div className=\"p-3 space-y-0.5\">\n <p className=\"text-sm font-semibold truncate\">{collection.name ?? \"Unnamed\"}</p>\n <div className=\"flex items-center justify-between text-xs text-muted-foreground\">\n <span>{collection.totalSupply ?? 0} items</span>\n {collection.floorPrice && (\n <span className=\"font-semibold text-brand-orange\">\n {formatDisplayPrice(collection.floorPrice)}\n </span>\n )}\n </div>\n </div>\n </div>\n </a>\n );\n}\n\nexport function DiscoverCollectionsStrip({\n collections,\n isLoading,\n getHref,\n allCollectionsHref = \"/collections\",\n}: DiscoverCollectionsStripProps) {\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\">
|
|
1
|
+
{"version":3,"sources":["../../src/components/discover-collections-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Layers, ArrowRight } from \"lucide-react\";\nimport { FadeIn } from \"./motion-primitives.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\nexport interface DiscoverCollectionsStripProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n sectionLabel?: string;\n title?: string;\n}\n\nfunction CollectionChipSkeleton() {\n return (\n <div className=\"shrink-0 w-80 rounded-xl border border-border overflow-hidden\">\n <div className=\"aspect-square w-full bg-muted animate-pulse\" />\n <div className=\"p-3 space-y-1.5\">\n <div className=\"h-3.5 w-28 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-16 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n );\n}\n\nfunction CollectionChip({\n collection,\n href,\n}: {\n collection: ApiCollection;\n href: string;\n}) {\n const [imgError, setImgError] = useState(false);\n const image = collection.image && !imgError ? ipfsToHttp(collection.image) : null;\n const initial = (collection.name ?? \"?\").charAt(0).toUpperCase();\n\n return (\n <a\n href={href}\n className=\"block shrink-0 w-80 snap-start active:scale-[0.97] transition-transform duration-150\"\n >\n <div className=\"rounded-xl border border-border overflow-hidden group bg-card hover:border-border/80 transition-colors\">\n <div className=\"aspect-square bg-muted relative overflow-hidden\">\n {image ? (\n <img\n src={image}\n alt={collection.name ?? \"\"}\n loading=\"lazy\"\n className=\"w-full h-full object-cover group-hover:scale-105 transition-transform duration-500\"\n onError={() => setImgError(true)}\n />\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/40 flex items-center justify-center\">\n <span className=\"text-5xl font-black text-white/10 select-none\">{initial}</span>\n </div>\n )}\n </div>\n <div className=\"p-3 space-y-0.5\">\n <p className=\"text-sm font-semibold truncate\">{collection.name ?? \"Unnamed\"}</p>\n <div className=\"flex items-center justify-between text-xs text-muted-foreground\">\n <span>{collection.totalSupply ?? 0} items</span>\n {collection.floorPrice && (\n <span className=\"font-semibold text-brand-orange\">\n {formatDisplayPrice(collection.floorPrice)}\n </span>\n )}\n </div>\n </div>\n </div>\n </a>\n );\n}\n\nexport function DiscoverCollectionsStrip({\n collections,\n isLoading,\n getHref,\n allCollectionsHref = \"/collections\",\n sectionLabel = \"NFT\",\n title = \"Collections\",\n}: DiscoverCollectionsStripProps) {\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 <Layers className=\"h-4 w-4 text-brand-blue\" />\n <h2 className=\"text-lg font-bold\">{title}</h2>\n </div>\n </div>\n <a\n href={allCollectionsHref}\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-3 w-max pb-1\">\n {isLoading\n ? Array.from({ length: 6 }).map((_, i) => <CollectionChipSkeleton key={i} />)\n : collections.map((col) => (\n <CollectionChip key={col.contractAddress} collection={col} href={getHref(col)} />\n ))}\n </div>\n </div>\n </div>\n </FadeIn>\n );\n}\n"],"mappings":";AAqBM,cACA,YADA;AAnBN,SAAS,gBAAgB;AACzB,SAAS,QAAQ,kBAAkB;AACnC,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAC3B,SAAS,0BAA0B;AAYnC,SAAS,yBAAyB;AAChC,SACE,qBAAC,SAAI,WAAU,iEACb;AAAA,wBAAC,SAAI,WAAU,+CAA8C;AAAA,IAC7D,qBAAC,SAAI,WAAU,mBACb;AAAA,0BAAC,SAAI,WAAU,6CAA4C;AAAA,MAC3D,oBAAC,SAAI,WAAU,2CAA0C;AAAA,OAC3D;AAAA,KACF;AAEJ;AAEA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,QAAQ,WAAW,SAAS,CAAC,WAAW,WAAW,WAAW,KAAK,IAAI;AAC7E,QAAM,WAAW,WAAW,QAAQ,KAAK,OAAO,CAAC,EAAE,YAAY;AAE/D,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAU;AAAA,MAEV,+BAAC,SAAI,WAAU,0GACb;AAAA,4BAAC,SAAI,WAAU,mDACZ,kBACC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAK,WAAW,QAAQ;AAAA,YACxB,SAAQ;AAAA,YACR,WAAU;AAAA,YACV,SAAS,MAAM,YAAY,IAAI;AAAA;AAAA,QACjC,IAEA,oBAAC,SAAI,WAAU,+HACb,8BAAC,UAAK,WAAU,iDAAiD,mBAAQ,GAC3E,GAEJ;AAAA,QACA,qBAAC,SAAI,WAAU,mBACb;AAAA,8BAAC,OAAE,WAAU,kCAAkC,qBAAW,QAAQ,WAAU;AAAA,UAC5E,qBAAC,SAAI,WAAU,mEACb;AAAA,iCAAC,UAAM;AAAA,yBAAW,eAAe;AAAA,cAAE;AAAA,eAAM;AAAA,YACxC,WAAW,cACV,oBAAC,UAAK,WAAU,mCACb,6BAAmB,WAAW,UAAU,GAC3C;AAAA,aAEJ;AAAA,WACF;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,QAAQ;AACV,GAAkC;AAChC,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,UAAO,WAAU,2BAA0B;AAAA,UAC5C,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,yBACZ,sBACG,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,oBAAC,4BAA4B,CAAG,CAAE,IAC1E,YAAY,IAAI,CAAC,QACf,oBAAC,kBAAyC,YAAY,KAAK,MAAM,QAAQ,GAAG,KAAvD,IAAI,eAAsD,CAChF,GACP,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}
|
|
@@ -36,8 +36,8 @@ function CreatorChip({
|
|
|
36
36
|
}) {
|
|
37
37
|
const [avatarError, setAvatarError] = (0, import_react.useState)(false);
|
|
38
38
|
const [bannerError, setBannerError] = (0, import_react.useState)(false);
|
|
39
|
-
const bannerSrc = creator.bannerImage ??
|
|
40
|
-
const avatarSrc = creator.avatarImage ?? creator.
|
|
39
|
+
const bannerSrc = creator.bannerImage ?? null;
|
|
40
|
+
const avatarSrc = creator.avatarImage ?? creator.bannerImage ?? null;
|
|
41
41
|
const bannerUrl = bannerSrc && !bannerError ? (0, import_ipfs.ipfsToHttp)(bannerSrc) : null;
|
|
42
42
|
const avatarUrl = avatarSrc && !avatarError ? (0, import_ipfs.ipfsToHttp)(avatarSrc) : null;
|
|
43
43
|
const displayName = creator.displayName || `@${creator.username}`;
|
|
@@ -86,16 +86,18 @@ function DiscoverCreatorsStrip({
|
|
|
86
86
|
creators,
|
|
87
87
|
isLoading,
|
|
88
88
|
getHref,
|
|
89
|
-
allCreatorsHref = "/creators"
|
|
89
|
+
allCreatorsHref = "/creators",
|
|
90
|
+
sectionLabel = "Creator network",
|
|
91
|
+
title = "Creators"
|
|
90
92
|
}) {
|
|
91
93
|
if (!isLoading && creators.length === 0) return null;
|
|
92
94
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_motion_primitives.FadeIn, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-3", children: [
|
|
93
95
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
94
96
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
95
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "section-label", children:
|
|
97
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "section-label", children: sectionLabel }),
|
|
96
98
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2 mt-0.5", children: [
|
|
97
99
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Users, { className: "h-4 w-4 text-brand-purple" }),
|
|
98
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-lg font-bold", children:
|
|
100
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-lg font-bold", children: title })
|
|
99
101
|
] })
|
|
100
102
|
] }),
|
|
101
103
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/discover-creators-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Users, ArrowRight, AtSign } 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}\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 [avatarError, setAvatarError] = useState(false);\n const [bannerError, setBannerError] = useState(false);\n\n const bannerSrc = creator.bannerImage ??
|
|
1
|
+
{"version":3,"sources":["../../src/components/discover-creators-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Users, ArrowRight, AtSign } 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 [avatarError, setAvatarError] = useState(false);\n const [bannerError, setBannerError] = useState(false);\n\n const bannerSrc = creator.bannerImage ?? null;\n const avatarSrc = creator.avatarImage ?? creator.bannerImage ?? null;\n\n const bannerUrl = bannerSrc && !bannerError ? ipfsToHttp(bannerSrc) : null;\n const avatarUrl = avatarSrc && !avatarError ? ipfsToHttp(avatarSrc) : null;\n\n const displayName = creator.displayName || `@${creator.username}`;\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 inset-0 bg-gradient-to-t from-black/80 via-black/10 to-transparent\" />\n <div className=\"absolute bottom-0 inset-x-0 p-2.5 space-y-1.5\">\n <div className=\"h-8 w-8 rounded-full ring-2 ring-white/20 overflow-hidden bg-muted flex items-center justify-center\">\n {avatarUrl ? (\n <img\n src={avatarUrl}\n alt={displayName ?? \"\"}\n loading=\"lazy\"\n className=\"h-full w-full object-cover\"\n onError={() => setAvatarError(true)}\n />\n ) : (\n <span className=\"text-xs font-black text-white/60\">\n {(displayName ?? \"?\").charAt(0).toUpperCase()}\n </span>\n )}\n </div>\n <div>\n <p className=\"font-bold text-white text-xs truncate\">{displayName}</p>\n <p className=\"text-[10px] text-white/55 flex items-center gap-0.5\">\n <AtSign className=\"h-2 w-2 shrink-0\" />\n <span className=\"truncate\">{creator.username}</span>\n </p>\n </div>\n </div>\n </div>\n </a>\n );\n}\n\nexport function DiscoverCreatorsStrip({\n creators,\n isLoading,\n getHref,\n allCreatorsHref = \"/creators\",\n sectionLabel = \"Creator network\",\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-3 w-max pb-1\">\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,0BAA0C;AAC1C,+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;AACpD,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,KAAK;AAEpD,QAAM,YAAY,QAAQ,eAAe;AACzC,QAAM,YAAY,QAAQ,eAAe,QAAQ,eAAe;AAEhE,QAAM,YAAY,aAAa,CAAC,kBAAc,wBAAW,SAAS,IAAI;AACtE,QAAM,YAAY,aAAa,CAAC,kBAAc,wBAAW,SAAS,IAAI;AAEtE,QAAM,cAAc,QAAQ,eAAe,IAAI,QAAQ,QAAQ;AAE/D,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,+EAA8E;AAAA,QAC7F,6CAAC,SAAI,WAAU,iDACb;AAAA,sDAAC,SAAI,WAAU,uGACZ,sBACC;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,KAAK,eAAe;AAAA,cACpB,SAAQ;AAAA,cACR,WAAU;AAAA,cACV,SAAS,MAAM,eAAe,IAAI;AAAA;AAAA,UACpC,IAEA,4CAAC,UAAK,WAAU,oCACZ,0BAAe,KAAK,OAAO,CAAC,EAAE,YAAY,GAC9C,GAEJ;AAAA,UACA,6CAAC,SACC;AAAA,wDAAC,OAAE,WAAU,yCAAyC,uBAAY;AAAA,YAClE,6CAAC,OAAE,WAAU,uDACX;AAAA,0DAAC,8BAAO,WAAU,oBAAmB;AAAA,cACrC,4CAAC,UAAK,WAAU,YAAY,kBAAQ,UAAS;AAAA,eAC/C;AAAA,aACF;AAAA,WACF;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,yBACZ,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":[]}
|
|
@@ -6,7 +6,9 @@ interface DiscoverCreatorsStripProps {
|
|
|
6
6
|
isLoading: boolean;
|
|
7
7
|
getHref: (creator: ApiCreatorProfile) => string;
|
|
8
8
|
allCreatorsHref?: string;
|
|
9
|
+
sectionLabel?: string;
|
|
10
|
+
title?: string;
|
|
9
11
|
}
|
|
10
|
-
declare function DiscoverCreatorsStrip({ creators, isLoading, getHref, allCreatorsHref, }: DiscoverCreatorsStripProps): react_jsx_runtime.JSX.Element | null;
|
|
12
|
+
declare function DiscoverCreatorsStrip({ creators, isLoading, getHref, allCreatorsHref, sectionLabel, title, }: DiscoverCreatorsStripProps): react_jsx_runtime.JSX.Element | null;
|
|
11
13
|
|
|
12
14
|
export { DiscoverCreatorsStrip, type DiscoverCreatorsStripProps };
|
|
@@ -6,7 +6,9 @@ interface DiscoverCreatorsStripProps {
|
|
|
6
6
|
isLoading: boolean;
|
|
7
7
|
getHref: (creator: ApiCreatorProfile) => string;
|
|
8
8
|
allCreatorsHref?: string;
|
|
9
|
+
sectionLabel?: string;
|
|
10
|
+
title?: string;
|
|
9
11
|
}
|
|
10
|
-
declare function DiscoverCreatorsStrip({ creators, isLoading, getHref, allCreatorsHref, }: DiscoverCreatorsStripProps): react_jsx_runtime.JSX.Element | null;
|
|
12
|
+
declare function DiscoverCreatorsStrip({ creators, isLoading, getHref, allCreatorsHref, sectionLabel, title, }: DiscoverCreatorsStripProps): react_jsx_runtime.JSX.Element | null;
|
|
11
13
|
|
|
12
14
|
export { DiscoverCreatorsStrip, type DiscoverCreatorsStripProps };
|
|
@@ -13,8 +13,8 @@ function CreatorChip({
|
|
|
13
13
|
}) {
|
|
14
14
|
const [avatarError, setAvatarError] = useState(false);
|
|
15
15
|
const [bannerError, setBannerError] = useState(false);
|
|
16
|
-
const bannerSrc = creator.bannerImage ??
|
|
17
|
-
const avatarSrc = creator.avatarImage ?? creator.
|
|
16
|
+
const bannerSrc = creator.bannerImage ?? null;
|
|
17
|
+
const avatarSrc = creator.avatarImage ?? creator.bannerImage ?? null;
|
|
18
18
|
const bannerUrl = bannerSrc && !bannerError ? ipfsToHttp(bannerSrc) : null;
|
|
19
19
|
const avatarUrl = avatarSrc && !avatarError ? ipfsToHttp(avatarSrc) : null;
|
|
20
20
|
const displayName = creator.displayName || `@${creator.username}`;
|
|
@@ -63,16 +63,18 @@ function DiscoverCreatorsStrip({
|
|
|
63
63
|
creators,
|
|
64
64
|
isLoading,
|
|
65
65
|
getHref,
|
|
66
|
-
allCreatorsHref = "/creators"
|
|
66
|
+
allCreatorsHref = "/creators",
|
|
67
|
+
sectionLabel = "Creator network",
|
|
68
|
+
title = "Creators"
|
|
67
69
|
}) {
|
|
68
70
|
if (!isLoading && creators.length === 0) return null;
|
|
69
71
|
return /* @__PURE__ */ jsx(FadeIn, { children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
70
72
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
71
73
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
72
|
-
/* @__PURE__ */ jsx("p", { className: "section-label", children:
|
|
74
|
+
/* @__PURE__ */ jsx("p", { className: "section-label", children: sectionLabel }),
|
|
73
75
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-0.5", children: [
|
|
74
76
|
/* @__PURE__ */ jsx(Users, { className: "h-4 w-4 text-brand-purple" }),
|
|
75
|
-
/* @__PURE__ */ jsx("h2", { className: "text-lg font-bold", children:
|
|
77
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-bold", children: title })
|
|
76
78
|
] })
|
|
77
79
|
] }),
|
|
78
80
|
/* @__PURE__ */ jsxs(
|