@medialane/ui 0.11.2 → 0.12.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/dist/components/collection-card.cjs +20 -14
- package/dist/components/collection-card.cjs.map +1 -1
- package/dist/components/collection-card.js +21 -15
- package/dist/components/collection-card.js.map +1 -1
- package/dist/components/discover-collections-strip.cjs +13 -75
- package/dist/components/discover-collections-strip.cjs.map +1 -1
- package/dist/components/discover-collections-strip.d.cts +6 -2
- package/dist/components/discover-collections-strip.d.ts +6 -2
- package/dist/components/discover-collections-strip.js +15 -77
- package/dist/components/discover-collections-strip.js.map +1 -1
- package/dist/components/discover-creators-strip.cjs +5 -28
- package/dist/components/discover-creators-strip.cjs.map +1 -1
- package/dist/components/discover-creators-strip.js +6 -29
- package/dist/components/discover-creators-strip.js.map +1 -1
- package/dist/components/scroll-section.cjs +6 -2
- package/dist/components/scroll-section.cjs.map +1 -1
- package/dist/components/scroll-section.d.cts +3 -1
- package/dist/components/scroll-section.d.ts +3 -1
- package/dist/components/scroll-section.js +6 -2
- package/dist/components/scroll-section.js.map +1 -1
- package/dist/medialane.css +6 -0
- package/package.json +1 -1
|
@@ -42,20 +42,24 @@ var import_cn = require("../utils/cn.js");
|
|
|
42
42
|
var import_ipfs = require("../utils/ipfs.js");
|
|
43
43
|
var import_format = require("../utils/format.js");
|
|
44
44
|
var import_motion_primitives = require("./motion-primitives.js");
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
var import_currency_icon = require("./currency-icon.js");
|
|
46
|
+
function parseFloorPrice(floor) {
|
|
47
|
+
if (!floor) return null;
|
|
48
|
+
const formatted = (0, import_format.formatDisplayPrice)(floor);
|
|
49
|
+
const parts = formatted.trim().split(/\s+/);
|
|
50
|
+
if (parts.length < 2) return null;
|
|
51
|
+
const symbol = parts[parts.length - 1];
|
|
52
|
+
const amount = parts.slice(0, -1).join(" ");
|
|
53
|
+
return { amount, symbol };
|
|
51
54
|
}
|
|
52
55
|
function CollectionCard({ collection, settingsHref, className }) {
|
|
53
56
|
const [imgError, setImgError] = (0, import_react.useState)(false);
|
|
54
57
|
const imageUrl = collection.image ? (0, import_ipfs.ipfsToHttp)(collection.image) : null;
|
|
55
58
|
const showImage = imageUrl && !imgError;
|
|
56
59
|
const initial = (collection.name ?? collection.contractAddress).charAt(0).toUpperCase();
|
|
57
|
-
const
|
|
58
|
-
|
|
60
|
+
const floor = parseFloorPrice(collection.floorPrice);
|
|
61
|
+
const hasExclusiveContent = !!collection.profile?.hasGatedContent;
|
|
62
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_cn.cn)(hasExclusiveContent && "card-exclusive-wrapper btn-border-animated"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_motion_primitives.MotionCard, { className: (0, import_cn.cn)("card-base group relative", className), children: [
|
|
59
63
|
settingsHref && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
60
64
|
import_link.default,
|
|
61
65
|
{
|
|
@@ -78,7 +82,7 @@ function CollectionCard({ collection, settingsHref, className }) {
|
|
|
78
82
|
unoptimized: true
|
|
79
83
|
}
|
|
80
84
|
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("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", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-8xl font-black text-white/10 select-none tracking-tighter", children: initial }) }),
|
|
81
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "absolute bottom-0 left-0 right-0 px-
|
|
85
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "absolute bottom-0 left-0 right-0 px-3 pb-3 flex flex-col gap-1.5 items-start", children: [
|
|
82
86
|
!collection.name && collection.metadataStatus === "PENDING" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "flex items-center gap-1 text-[10px] text-white/60 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5", children: [
|
|
83
87
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Loader2, { className: "h-2.5 w-2.5 animate-spin" }),
|
|
84
88
|
"Indexing\u2026"
|
|
@@ -95,14 +99,16 @@ function CollectionCard({ collection, settingsHref, className }) {
|
|
|
95
99
|
collection.totalSupply.toLocaleString(),
|
|
96
100
|
" items"
|
|
97
101
|
] }),
|
|
98
|
-
|
|
99
|
-
"Floor
|
|
100
|
-
(0,
|
|
101
|
-
|
|
102
|
+
floor && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "inline-flex items-center gap-1 text-[10px] font-bold text-white/90 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5", children: [
|
|
103
|
+
"Floor",
|
|
104
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: floor.symbol, size: 10 }),
|
|
105
|
+
floor.amount
|
|
106
|
+
] }),
|
|
107
|
+
hasExclusiveContent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "inline-flex items-center gap-1 text-[10px] font-bold text-white backdrop-blur-md bg-black/50 rounded-full px-2 py-0.5", children: "\u2726 Exclusive" })
|
|
102
108
|
] })
|
|
103
109
|
] })
|
|
104
110
|
] }) })
|
|
105
|
-
] });
|
|
111
|
+
] }) });
|
|
106
112
|
}
|
|
107
113
|
function CollectionCardSkeleton() {
|
|
108
114
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "card-base overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative aspect-[3/4] w-full overflow-hidden bg-muted", children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { Loader2, Settings2
|
|
1
|
+
{"version":3,"sources":["../../src/components/collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { Loader2, Settings2 } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { MotionCard } from \"./motion-primitives.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\n/** \"0.990000 USDC\" → { amount: \"0.99\", symbol: \"USDC\" } */\nfunction parseFloorPrice(floor: string | null | undefined): { amount: string; symbol: string } | null {\n if (!floor) return null;\n const formatted = formatDisplayPrice(floor);\n const parts = formatted.trim().split(/\\s+/);\n if (parts.length < 2) return null;\n const symbol = parts[parts.length - 1];\n const amount = parts.slice(0, -1).join(\" \");\n return { amount, symbol };\n}\n\n/** ui's pinned SDK lags the apps — extend structurally for newer fields. */\ntype CollectionWithProfile = ApiCollection & {\n profile?: { hasGatedContent?: boolean } | null;\n};\n\nexport interface CollectionCardProps {\n collection: ApiCollection;\n /** Shows settings gear icon linking to this path — used in portfolio pages */\n settingsHref?: string;\n className?: string;\n}\n\nexport function CollectionCard({ collection, settingsHref, className }: CollectionCardProps) {\n const [imgError, setImgError] = useState(false);\n const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;\n const showImage = imageUrl && !imgError;\n const initial = (collection.name ?? collection.contractAddress).charAt(0).toUpperCase();\n const floor = parseFloorPrice(collection.floorPrice);\n const hasExclusiveContent = !!(collection as CollectionWithProfile).profile?.hasGatedContent;\n\n return (\n <div className={cn(hasExclusiveContent && \"card-exclusive-wrapper btn-border-animated\")}>\n <MotionCard className={cn(\"card-base group relative\", className)}>\n {settingsHref && (\n <Link\n href={settingsHref}\n onClick={(e) => e.stopPropagation()}\n className=\"absolute top-2 right-2 z-10 h-7 w-7 rounded-full bg-black/40 backdrop-blur-sm flex items-center justify-center text-white/70 hover:text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Collection settings\"\n >\n <Settings2 className=\"h-3.5 w-3.5\" />\n </Link>\n )}\n\n <Link href={`/collections/${collection.contractAddress}`} className=\"block relative h-full\">\n <div className=\"relative aspect-[3/4] w-full overflow-hidden bg-muted\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={collection.name ?? \"Collection\"}\n fill\n className=\"object-cover transition-transform duration-500 group-hover:scale-105\"\n onError={() => setImgError(true)}\n unoptimized\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-8xl font-black text-white/10 select-none tracking-tighter\">\n {initial}\n </span>\n </div>\n )}\n\n <div className=\"absolute bottom-0 left-0 right-0 px-3 pb-3 flex flex-col gap-1.5 items-start\">\n {!collection.name && collection.metadataStatus === \"PENDING\" ? (\n <span className=\"flex items-center gap-1 text-[10px] text-white/60 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n <Loader2 className=\"h-2.5 w-2.5 animate-spin\" />\n Indexing…\n </span>\n ) : (\n <p\n className=\"font-bold text-sm text-white leading-tight backdrop-blur-md bg-black/30 rounded-lg px-2.5 py-1 max-w-full truncate\"\n style={{ textShadow: \"0 1px 6px rgba(0,0,0,0.5)\" }}\n >\n {collection.name ?? \"Unnamed Collection\"}\n </p>\n )}\n\n <div className=\"flex items-center gap-1.5 flex-wrap\">\n {collection.totalSupply != null && (\n <span className=\"text-[10px] font-medium text-white/80 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n {collection.totalSupply.toLocaleString()} items\n </span>\n )}\n {floor && (\n <span className=\"inline-flex items-center gap-1 text-[10px] font-bold text-white/90 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n Floor\n <CurrencyIcon symbol={floor.symbol} size={10} />\n {floor.amount}\n </span>\n )}\n {hasExclusiveContent && (\n <span className=\"inline-flex items-center gap-1 text-[10px] font-bold text-white backdrop-blur-md bg-black/50 rounded-full px-2 py-0.5\">\n ✦ Exclusive\n </span>\n )}\n </div>\n </div>\n </div>\n </Link>\n </MotionCard>\n </div>\n );\n}\n\nexport function CollectionCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"relative aspect-[3/4] w-full overflow-hidden bg-muted\">\n <div className=\"absolute inset-0 animate-pulse bg-muted\" />\n <div className=\"absolute bottom-3 left-3 right-3 space-y-1.5\">\n <div className=\"h-4 w-2/3 rounded-md bg-muted-foreground/20 animate-pulse\" />\n <div className=\"h-3 w-1/3 rounded-md bg-muted-foreground/20 animate-pulse\" />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["Link","Image"]}
|
|
@@ -3,25 +3,29 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import Link from "next/link";
|
|
5
5
|
import Image from "next/image";
|
|
6
|
-
import { Loader2, Settings2
|
|
6
|
+
import { Loader2, Settings2 } from "lucide-react";
|
|
7
7
|
import { cn } from "../utils/cn.js";
|
|
8
8
|
import { ipfsToHttp } from "../utils/ipfs.js";
|
|
9
9
|
import { formatDisplayPrice } from "../utils/format.js";
|
|
10
10
|
import { MotionCard } from "./motion-primitives.js";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
import { CurrencyIcon } from "./currency-icon.js";
|
|
12
|
+
function parseFloorPrice(floor) {
|
|
13
|
+
if (!floor) return null;
|
|
14
|
+
const formatted = formatDisplayPrice(floor);
|
|
15
|
+
const parts = formatted.trim().split(/\s+/);
|
|
16
|
+
if (parts.length < 2) return null;
|
|
17
|
+
const symbol = parts[parts.length - 1];
|
|
18
|
+
const amount = parts.slice(0, -1).join(" ");
|
|
19
|
+
return { amount, symbol };
|
|
17
20
|
}
|
|
18
21
|
function CollectionCard({ collection, settingsHref, className }) {
|
|
19
22
|
const [imgError, setImgError] = useState(false);
|
|
20
23
|
const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;
|
|
21
24
|
const showImage = imageUrl && !imgError;
|
|
22
25
|
const initial = (collection.name ?? collection.contractAddress).charAt(0).toUpperCase();
|
|
23
|
-
const
|
|
24
|
-
|
|
26
|
+
const floor = parseFloorPrice(collection.floorPrice);
|
|
27
|
+
const hasExclusiveContent = !!collection.profile?.hasGatedContent;
|
|
28
|
+
return /* @__PURE__ */ jsx("div", { className: cn(hasExclusiveContent && "card-exclusive-wrapper btn-border-animated"), children: /* @__PURE__ */ jsxs(MotionCard, { className: cn("card-base group relative", className), children: [
|
|
25
29
|
settingsHref && /* @__PURE__ */ jsx(
|
|
26
30
|
Link,
|
|
27
31
|
{
|
|
@@ -44,7 +48,7 @@ function CollectionCard({ collection, settingsHref, className }) {
|
|
|
44
48
|
unoptimized: true
|
|
45
49
|
}
|
|
46
50
|
) : /* @__PURE__ */ jsx("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", children: /* @__PURE__ */ jsx("span", { className: "text-8xl font-black text-white/10 select-none tracking-tighter", children: initial }) }),
|
|
47
|
-
/* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 left-0 right-0 px-
|
|
51
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 left-0 right-0 px-3 pb-3 flex flex-col gap-1.5 items-start", children: [
|
|
48
52
|
!collection.name && collection.metadataStatus === "PENDING" ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-[10px] text-white/60 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5", children: [
|
|
49
53
|
/* @__PURE__ */ jsx(Loader2, { className: "h-2.5 w-2.5 animate-spin" }),
|
|
50
54
|
"Indexing\u2026"
|
|
@@ -61,14 +65,16 @@ function CollectionCard({ collection, settingsHref, className }) {
|
|
|
61
65
|
collection.totalSupply.toLocaleString(),
|
|
62
66
|
" items"
|
|
63
67
|
] }),
|
|
64
|
-
|
|
65
|
-
"Floor
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
floor && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-[10px] font-bold text-white/90 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5", children: [
|
|
69
|
+
"Floor",
|
|
70
|
+
/* @__PURE__ */ jsx(CurrencyIcon, { symbol: floor.symbol, size: 10 }),
|
|
71
|
+
floor.amount
|
|
72
|
+
] }),
|
|
73
|
+
hasExclusiveContent && /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-1 text-[10px] font-bold text-white backdrop-blur-md bg-black/50 rounded-full px-2 py-0.5", children: "\u2726 Exclusive" })
|
|
68
74
|
] })
|
|
69
75
|
] })
|
|
70
76
|
] }) })
|
|
71
|
-
] });
|
|
77
|
+
] }) });
|
|
72
78
|
}
|
|
73
79
|
function CollectionCardSkeleton() {
|
|
74
80
|
return /* @__PURE__ */ jsx("div", { className: "card-base overflow-hidden", children: /* @__PURE__ */ jsxs("div", { className: "relative aspect-[3/4] w-full overflow-hidden bg-muted", children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { Loader2, Settings2
|
|
1
|
+
{"version":3,"sources":["../../src/components/collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { Loader2, Settings2 } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { MotionCard } from \"./motion-primitives.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\n/** \"0.990000 USDC\" → { amount: \"0.99\", symbol: \"USDC\" } */\nfunction parseFloorPrice(floor: string | null | undefined): { amount: string; symbol: string } | null {\n if (!floor) return null;\n const formatted = formatDisplayPrice(floor);\n const parts = formatted.trim().split(/\\s+/);\n if (parts.length < 2) return null;\n const symbol = parts[parts.length - 1];\n const amount = parts.slice(0, -1).join(\" \");\n return { amount, symbol };\n}\n\n/** ui's pinned SDK lags the apps — extend structurally for newer fields. */\ntype CollectionWithProfile = ApiCollection & {\n profile?: { hasGatedContent?: boolean } | null;\n};\n\nexport interface CollectionCardProps {\n collection: ApiCollection;\n /** Shows settings gear icon linking to this path — used in portfolio pages */\n settingsHref?: string;\n className?: string;\n}\n\nexport function CollectionCard({ collection, settingsHref, className }: CollectionCardProps) {\n const [imgError, setImgError] = useState(false);\n const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;\n const showImage = imageUrl && !imgError;\n const initial = (collection.name ?? collection.contractAddress).charAt(0).toUpperCase();\n const floor = parseFloorPrice(collection.floorPrice);\n const hasExclusiveContent = !!(collection as CollectionWithProfile).profile?.hasGatedContent;\n\n return (\n <div className={cn(hasExclusiveContent && \"card-exclusive-wrapper btn-border-animated\")}>\n <MotionCard className={cn(\"card-base group relative\", className)}>\n {settingsHref && (\n <Link\n href={settingsHref}\n onClick={(e) => e.stopPropagation()}\n className=\"absolute top-2 right-2 z-10 h-7 w-7 rounded-full bg-black/40 backdrop-blur-sm flex items-center justify-center text-white/70 hover:text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Collection settings\"\n >\n <Settings2 className=\"h-3.5 w-3.5\" />\n </Link>\n )}\n\n <Link href={`/collections/${collection.contractAddress}`} className=\"block relative h-full\">\n <div className=\"relative aspect-[3/4] w-full overflow-hidden bg-muted\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={collection.name ?? \"Collection\"}\n fill\n className=\"object-cover transition-transform duration-500 group-hover:scale-105\"\n onError={() => setImgError(true)}\n unoptimized\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-8xl font-black text-white/10 select-none tracking-tighter\">\n {initial}\n </span>\n </div>\n )}\n\n <div className=\"absolute bottom-0 left-0 right-0 px-3 pb-3 flex flex-col gap-1.5 items-start\">\n {!collection.name && collection.metadataStatus === \"PENDING\" ? (\n <span className=\"flex items-center gap-1 text-[10px] text-white/60 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n <Loader2 className=\"h-2.5 w-2.5 animate-spin\" />\n Indexing…\n </span>\n ) : (\n <p\n className=\"font-bold text-sm text-white leading-tight backdrop-blur-md bg-black/30 rounded-lg px-2.5 py-1 max-w-full truncate\"\n style={{ textShadow: \"0 1px 6px rgba(0,0,0,0.5)\" }}\n >\n {collection.name ?? \"Unnamed Collection\"}\n </p>\n )}\n\n <div className=\"flex items-center gap-1.5 flex-wrap\">\n {collection.totalSupply != null && (\n <span className=\"text-[10px] font-medium text-white/80 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n {collection.totalSupply.toLocaleString()} items\n </span>\n )}\n {floor && (\n <span className=\"inline-flex items-center gap-1 text-[10px] font-bold text-white/90 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n Floor\n <CurrencyIcon symbol={floor.symbol} size={10} />\n {floor.amount}\n </span>\n )}\n {hasExclusiveContent && (\n <span className=\"inline-flex items-center gap-1 text-[10px] font-bold text-white backdrop-blur-md bg-black/50 rounded-full px-2 py-0.5\">\n ✦ Exclusive\n </span>\n )}\n </div>\n </div>\n </div>\n </Link>\n </MotionCard>\n </div>\n );\n}\n\nexport function CollectionCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"relative aspect-[3/4] w-full overflow-hidden bg-muted\">\n <div className=\"absolute inset-0 animate-pulse bg-muted\" />\n <div className=\"absolute bottom-3 left-3 right-3 space-y-1.5\">\n <div className=\"h-4 w-2/3 rounded-md bg-muted-foreground/20 animate-pulse\" />\n <div className=\"h-3 w-1/3 rounded-md bg-muted-foreground/20 animate-pulse\" />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -23,88 +23,26 @@ __export(discover_collections_strip_exports, {
|
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(discover_collections_strip_exports);
|
|
25
25
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
26
|
-
var import_react = require("react");
|
|
27
26
|
var import_lucide_react = require("lucide-react");
|
|
28
|
-
var
|
|
29
|
-
var
|
|
30
|
-
var import_format = require("../utils/format.js");
|
|
31
|
-
function CollectionChipSkeleton() {
|
|
32
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "shrink-0 w-80 rounded-xl border border-border overflow-hidden", children: [
|
|
33
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "aspect-square w-full bg-muted animate-pulse" }),
|
|
34
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "p-3 space-y-1.5", children: [
|
|
35
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-3.5 w-28 bg-muted animate-pulse rounded" }),
|
|
36
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-3 w-16 bg-muted animate-pulse rounded" })
|
|
37
|
-
] })
|
|
38
|
-
] });
|
|
39
|
-
}
|
|
40
|
-
function CollectionChip({
|
|
41
|
-
collection,
|
|
42
|
-
href
|
|
43
|
-
}) {
|
|
44
|
-
const [imgError, setImgError] = (0, import_react.useState)(false);
|
|
45
|
-
const image = collection.image && !imgError ? (0, import_ipfs.ipfsToHttp)(collection.image) : null;
|
|
46
|
-
const initial = (collection.name ?? "?").charAt(0).toUpperCase();
|
|
47
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
48
|
-
"a",
|
|
49
|
-
{
|
|
50
|
-
href,
|
|
51
|
-
className: "block shrink-0 w-80 snap-start active:scale-[0.97] transition-transform duration-150",
|
|
52
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rounded-xl border border-border overflow-hidden group bg-card hover:border-border/80 transition-colors", children: [
|
|
53
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "aspect-square bg-muted relative overflow-hidden", children: image ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
54
|
-
"img",
|
|
55
|
-
{
|
|
56
|
-
src: image,
|
|
57
|
-
alt: collection.name ?? "",
|
|
58
|
-
loading: "lazy",
|
|
59
|
-
className: "w-full h-full object-cover group-hover:scale-105 transition-transform duration-500",
|
|
60
|
-
onError: () => setImgError(true)
|
|
61
|
-
}
|
|
62
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("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", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-5xl font-black text-white/10 select-none", children: initial }) }) }),
|
|
63
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "p-3 space-y-0.5", children: [
|
|
64
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-semibold truncate", children: collection.name ?? "Unnamed" }),
|
|
65
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [
|
|
66
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
67
|
-
collection.totalSupply ?? 0,
|
|
68
|
-
" items"
|
|
69
|
-
] }),
|
|
70
|
-
collection.floorPrice && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-semibold text-brand-orange", children: (0, import_format.formatDisplayPrice)(collection.floorPrice) })
|
|
71
|
-
] })
|
|
72
|
-
] })
|
|
73
|
-
] })
|
|
74
|
-
}
|
|
75
|
-
);
|
|
76
|
-
}
|
|
27
|
+
var import_scroll_section = require("./scroll-section.js");
|
|
28
|
+
var import_collection_card = require("./collection-card.js");
|
|
77
29
|
function DiscoverCollectionsStrip({
|
|
78
30
|
collections,
|
|
79
31
|
isLoading,
|
|
80
|
-
getHref,
|
|
81
32
|
allCollectionsHref = "/collections",
|
|
82
|
-
sectionLabel = "NFT",
|
|
83
33
|
title = "Collections"
|
|
84
34
|
}) {
|
|
85
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
{
|
|
97
|
-
href: allCollectionsHref,
|
|
98
|
-
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",
|
|
99
|
-
children: [
|
|
100
|
-
"View all ",
|
|
101
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRight, { className: "h-3.5 w-3.5" })
|
|
102
|
-
]
|
|
103
|
-
}
|
|
104
|
-
)
|
|
105
|
-
] }),
|
|
106
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "overflow-x-auto scrollbar-hide snap-x snap-mandatory -mx-4 px-4 md:mx-0 md:px-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex gap-3 w-max pb-1", children: isLoading ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollectionChipSkeleton, {}, i)) : collections.map((col) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollectionChip, { collection: col, href: getHref(col) }, col.contractAddress)) }) })
|
|
107
|
-
] }) });
|
|
35
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
36
|
+
import_scroll_section.ScrollSection,
|
|
37
|
+
{
|
|
38
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Layers, { className: "h-3.5 w-3.5 text-white" }),
|
|
39
|
+
iconBg: "bg-gradient-to-br from-brand-blue to-indigo-600 shadow-md shadow-brand-blue/20",
|
|
40
|
+
title,
|
|
41
|
+
href: allCollectionsHref,
|
|
42
|
+
linkLabel: "View all",
|
|
43
|
+
children: isLoading ? Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-56 sm:w-64 snap-start shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_collection_card.CollectionCardSkeleton, {}) }, i)) : collections.map((col) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-56 sm:w-64 snap-start shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_collection_card.CollectionCard, { collection: col }) }, col.contractAddress))
|
|
44
|
+
}
|
|
45
|
+
);
|
|
108
46
|
}
|
|
109
47
|
// Annotate the CommonJS export names for ESM import in node:
|
|
110
48
|
0 && (module.exports = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/discover-collections-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/components/discover-collections-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { Layers } from \"lucide-react\";\nimport { ScrollSection } from \"./scroll-section.js\";\nimport { CollectionCard, CollectionCardSkeleton } from \"./collection-card.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\nexport interface DiscoverCollectionsStripProps {\n collections: ApiCollection[];\n isLoading: boolean;\n /** Kept for API compat — CollectionCard links to /collections/:contract internally */\n getHref?: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n /** Kept for API compat — the io-style header has no eyebrow label */\n sectionLabel?: string;\n title?: string;\n}\n\n/** Discover Collections carousel — CollectionCard tiles under the shared\n * icon-badge ScrollSection header (io-approved design). */\nexport function DiscoverCollectionsStrip({\n collections,\n isLoading,\n allCollectionsHref = \"/collections\",\n title = \"Collections\",\n}: DiscoverCollectionsStripProps) {\n return (\n <ScrollSection\n icon={<Layers className=\"h-3.5 w-3.5 text-white\" />}\n iconBg=\"bg-gradient-to-br from-brand-blue to-indigo-600 shadow-md shadow-brand-blue/20\"\n title={title}\n href={allCollectionsHref}\n linkLabel=\"View all\"\n >\n {isLoading\n ? Array.from({ length: 5 }).map((_, i) => (\n <div key={i} className=\"w-56 sm:w-64 snap-start shrink-0\">\n <CollectionCardSkeleton />\n </div>\n ))\n : collections.map((col) => (\n <div key={col.contractAddress} className=\"w-56 sm:w-64 snap-start shrink-0\">\n <CollectionCard collection={col} />\n </div>\n ))}\n </ScrollSection>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BY;AA1BZ,0BAAuB;AACvB,4BAA8B;AAC9B,6BAAuD;AAgBhD,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EACrB,QAAQ;AACV,GAAkC;AAChC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,4CAAC,8BAAO,WAAU,0BAAyB;AAAA,MACjD,QAAO;AAAA,MACP;AAAA,MACA,MAAM;AAAA,MACN,WAAU;AAAA,MAET,sBACG,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAChC,4CAAC,SAAY,WAAU,oCACrB,sDAAC,iDAAuB,KADhB,CAEV,CACD,IACD,YAAY,IAAI,CAAC,QACf,4CAAC,SAA8B,WAAU,oCACvC,sDAAC,yCAAe,YAAY,KAAK,KADzB,IAAI,eAEd,CACD;AAAA;AAAA,EACP;AAEJ;","names":[]}
|
|
@@ -4,11 +4,15 @@ import { ApiCollection } from '@medialane/sdk';
|
|
|
4
4
|
interface DiscoverCollectionsStripProps {
|
|
5
5
|
collections: ApiCollection[];
|
|
6
6
|
isLoading: boolean;
|
|
7
|
-
|
|
7
|
+
/** Kept for API compat — CollectionCard links to /collections/:contract internally */
|
|
8
|
+
getHref?: (collection: ApiCollection) => string;
|
|
8
9
|
allCollectionsHref?: string;
|
|
10
|
+
/** Kept for API compat — the io-style header has no eyebrow label */
|
|
9
11
|
sectionLabel?: string;
|
|
10
12
|
title?: string;
|
|
11
13
|
}
|
|
12
|
-
|
|
14
|
+
/** Discover Collections carousel — CollectionCard tiles under the shared
|
|
15
|
+
* icon-badge ScrollSection header (io-approved design). */
|
|
16
|
+
declare function DiscoverCollectionsStrip({ collections, isLoading, allCollectionsHref, title, }: DiscoverCollectionsStripProps): react_jsx_runtime.JSX.Element;
|
|
13
17
|
|
|
14
18
|
export { DiscoverCollectionsStrip, type DiscoverCollectionsStripProps };
|
|
@@ -4,11 +4,15 @@ import { ApiCollection } from '@medialane/sdk';
|
|
|
4
4
|
interface DiscoverCollectionsStripProps {
|
|
5
5
|
collections: ApiCollection[];
|
|
6
6
|
isLoading: boolean;
|
|
7
|
-
|
|
7
|
+
/** Kept for API compat — CollectionCard links to /collections/:contract internally */
|
|
8
|
+
getHref?: (collection: ApiCollection) => string;
|
|
8
9
|
allCollectionsHref?: string;
|
|
10
|
+
/** Kept for API compat — the io-style header has no eyebrow label */
|
|
9
11
|
sectionLabel?: string;
|
|
10
12
|
title?: string;
|
|
11
13
|
}
|
|
12
|
-
|
|
14
|
+
/** Discover Collections carousel — CollectionCard tiles under the shared
|
|
15
|
+
* icon-badge ScrollSection header (io-approved design). */
|
|
16
|
+
declare function DiscoverCollectionsStrip({ collections, isLoading, allCollectionsHref, title, }: DiscoverCollectionsStripProps): react_jsx_runtime.JSX.Element;
|
|
13
17
|
|
|
14
18
|
export { DiscoverCollectionsStrip, type DiscoverCollectionsStripProps };
|
|
@@ -1,87 +1,25 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { ipfsToHttp } from "../utils/ipfs.js";
|
|
7
|
-
import { formatDisplayPrice } from "../utils/format.js";
|
|
8
|
-
function CollectionChipSkeleton() {
|
|
9
|
-
return /* @__PURE__ */ jsxs("div", { className: "shrink-0 w-80 rounded-xl border border-border overflow-hidden", children: [
|
|
10
|
-
/* @__PURE__ */ jsx("div", { className: "aspect-square w-full bg-muted animate-pulse" }),
|
|
11
|
-
/* @__PURE__ */ jsxs("div", { className: "p-3 space-y-1.5", children: [
|
|
12
|
-
/* @__PURE__ */ jsx("div", { className: "h-3.5 w-28 bg-muted animate-pulse rounded" }),
|
|
13
|
-
/* @__PURE__ */ jsx("div", { className: "h-3 w-16 bg-muted animate-pulse rounded" })
|
|
14
|
-
] })
|
|
15
|
-
] });
|
|
16
|
-
}
|
|
17
|
-
function CollectionChip({
|
|
18
|
-
collection,
|
|
19
|
-
href
|
|
20
|
-
}) {
|
|
21
|
-
const [imgError, setImgError] = useState(false);
|
|
22
|
-
const image = collection.image && !imgError ? ipfsToHttp(collection.image) : null;
|
|
23
|
-
const initial = (collection.name ?? "?").charAt(0).toUpperCase();
|
|
24
|
-
return /* @__PURE__ */ jsx(
|
|
25
|
-
"a",
|
|
26
|
-
{
|
|
27
|
-
href,
|
|
28
|
-
className: "block shrink-0 w-80 snap-start active:scale-[0.97] transition-transform duration-150",
|
|
29
|
-
children: /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-border overflow-hidden group bg-card hover:border-border/80 transition-colors", children: [
|
|
30
|
-
/* @__PURE__ */ jsx("div", { className: "aspect-square bg-muted relative overflow-hidden", children: image ? /* @__PURE__ */ jsx(
|
|
31
|
-
"img",
|
|
32
|
-
{
|
|
33
|
-
src: image,
|
|
34
|
-
alt: collection.name ?? "",
|
|
35
|
-
loading: "lazy",
|
|
36
|
-
className: "w-full h-full object-cover group-hover:scale-105 transition-transform duration-500",
|
|
37
|
-
onError: () => setImgError(true)
|
|
38
|
-
}
|
|
39
|
-
) : /* @__PURE__ */ jsx("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", children: /* @__PURE__ */ jsx("span", { className: "text-5xl font-black text-white/10 select-none", children: initial }) }) }),
|
|
40
|
-
/* @__PURE__ */ jsxs("div", { className: "p-3 space-y-0.5", children: [
|
|
41
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold truncate", children: collection.name ?? "Unnamed" }),
|
|
42
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [
|
|
43
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
44
|
-
collection.totalSupply ?? 0,
|
|
45
|
-
" items"
|
|
46
|
-
] }),
|
|
47
|
-
collection.floorPrice && /* @__PURE__ */ jsx("span", { className: "font-semibold text-brand-orange", children: formatDisplayPrice(collection.floorPrice) })
|
|
48
|
-
] })
|
|
49
|
-
] })
|
|
50
|
-
] })
|
|
51
|
-
}
|
|
52
|
-
);
|
|
53
|
-
}
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Layers } from "lucide-react";
|
|
4
|
+
import { ScrollSection } from "./scroll-section.js";
|
|
5
|
+
import { CollectionCard, CollectionCardSkeleton } from "./collection-card.js";
|
|
54
6
|
function DiscoverCollectionsStrip({
|
|
55
7
|
collections,
|
|
56
8
|
isLoading,
|
|
57
|
-
getHref,
|
|
58
9
|
allCollectionsHref = "/collections",
|
|
59
|
-
sectionLabel = "NFT",
|
|
60
10
|
title = "Collections"
|
|
61
11
|
}) {
|
|
62
|
-
return /* @__PURE__ */ jsx(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
{
|
|
74
|
-
href: allCollectionsHref,
|
|
75
|
-
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",
|
|
76
|
-
children: [
|
|
77
|
-
"View all ",
|
|
78
|
-
/* @__PURE__ */ jsx(ArrowRight, { className: "h-3.5 w-3.5" })
|
|
79
|
-
]
|
|
80
|
-
}
|
|
81
|
-
)
|
|
82
|
-
] }),
|
|
83
|
-
/* @__PURE__ */ jsx("div", { className: "overflow-x-auto scrollbar-hide snap-x snap-mandatory -mx-4 px-4 md:mx-0 md:px-0", children: /* @__PURE__ */ jsx("div", { className: "flex gap-3 w-max pb-1", children: isLoading ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsx(CollectionChipSkeleton, {}, i)) : collections.map((col) => /* @__PURE__ */ jsx(CollectionChip, { collection: col, href: getHref(col) }, col.contractAddress)) }) })
|
|
84
|
-
] }) });
|
|
12
|
+
return /* @__PURE__ */ jsx(
|
|
13
|
+
ScrollSection,
|
|
14
|
+
{
|
|
15
|
+
icon: /* @__PURE__ */ jsx(Layers, { className: "h-3.5 w-3.5 text-white" }),
|
|
16
|
+
iconBg: "bg-gradient-to-br from-brand-blue to-indigo-600 shadow-md shadow-brand-blue/20",
|
|
17
|
+
title,
|
|
18
|
+
href: allCollectionsHref,
|
|
19
|
+
linkLabel: "View all",
|
|
20
|
+
children: isLoading ? Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsx("div", { className: "w-56 sm:w-64 snap-start shrink-0", children: /* @__PURE__ */ jsx(CollectionCardSkeleton, {}) }, i)) : collections.map((col) => /* @__PURE__ */ jsx("div", { className: "w-56 sm:w-64 snap-start shrink-0", children: /* @__PURE__ */ jsx(CollectionCard, { collection: col }) }, col.contractAddress))
|
|
21
|
+
}
|
|
22
|
+
);
|
|
85
23
|
}
|
|
86
24
|
export {
|
|
87
25
|
DiscoverCollectionsStrip
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/discover-collections-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/components/discover-collections-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { Layers } from \"lucide-react\";\nimport { ScrollSection } from \"./scroll-section.js\";\nimport { CollectionCard, CollectionCardSkeleton } from \"./collection-card.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\nexport interface DiscoverCollectionsStripProps {\n collections: ApiCollection[];\n isLoading: boolean;\n /** Kept for API compat — CollectionCard links to /collections/:contract internally */\n getHref?: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n /** Kept for API compat — the io-style header has no eyebrow label */\n sectionLabel?: string;\n title?: string;\n}\n\n/** Discover Collections carousel — CollectionCard tiles under the shared\n * icon-badge ScrollSection header (io-approved design). */\nexport function DiscoverCollectionsStrip({\n collections,\n isLoading,\n allCollectionsHref = \"/collections\",\n title = \"Collections\",\n}: DiscoverCollectionsStripProps) {\n return (\n <ScrollSection\n icon={<Layers className=\"h-3.5 w-3.5 text-white\" />}\n iconBg=\"bg-gradient-to-br from-brand-blue to-indigo-600 shadow-md shadow-brand-blue/20\"\n title={title}\n href={allCollectionsHref}\n linkLabel=\"View all\"\n >\n {isLoading\n ? Array.from({ length: 5 }).map((_, i) => (\n <div key={i} className=\"w-56 sm:w-64 snap-start shrink-0\">\n <CollectionCardSkeleton />\n </div>\n ))\n : collections.map((col) => (\n <div key={col.contractAddress} className=\"w-56 sm:w-64 snap-start shrink-0\">\n <CollectionCard collection={col} />\n </div>\n ))}\n </ScrollSection>\n );\n}\n"],"mappings":";AA4BY;AA1BZ,SAAS,cAAc;AACvB,SAAS,qBAAqB;AAC9B,SAAS,gBAAgB,8BAA8B;AAgBhD,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EACrB,QAAQ;AACV,GAAkC;AAChC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,oBAAC,UAAO,WAAU,0BAAyB;AAAA,MACjD,QAAO;AAAA,MACP;AAAA,MACA,MAAM;AAAA,MACN,WAAU;AAAA,MAET,sBACG,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAChC,oBAAC,SAAY,WAAU,oCACrB,8BAAC,0BAAuB,KADhB,CAEV,CACD,IACD,YAAY,IAAI,CAAC,QACf,oBAAC,SAA8B,WAAU,oCACvC,8BAAC,kBAAe,YAAY,KAAK,KADzB,IAAI,eAEd,CACD;AAAA;AAAA,EACP;AAEJ;","names":[]}
|
|
@@ -34,13 +34,9 @@ function CreatorChip({
|
|
|
34
34
|
creator,
|
|
35
35
|
href
|
|
36
36
|
}) {
|
|
37
|
-
const [avatarError, setAvatarError] = (0, import_react.useState)(false);
|
|
38
37
|
const [bannerError, setBannerError] = (0, import_react.useState)(false);
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
const bannerUrl = bannerSrc && !bannerError ? (0, import_ipfs.ipfsToHttp)(bannerSrc) : null;
|
|
42
|
-
const avatarUrl = avatarSrc && !avatarError ? (0, import_ipfs.ipfsToHttp)(avatarSrc) : null;
|
|
43
|
-
const displayName = creator.displayName || `@${creator.username}`;
|
|
38
|
+
const rawSrc = creator.bannerImage || creator.collectionImage || null;
|
|
39
|
+
const bannerUrl = rawSrc && !bannerError ? (0, import_ipfs.ipfsToHttp)(rawSrc) : null;
|
|
44
40
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
45
41
|
"a",
|
|
46
42
|
{
|
|
@@ -58,26 +54,7 @@ function CreatorChip({
|
|
|
58
54
|
onError: () => setBannerError(true)
|
|
59
55
|
}
|
|
60
56
|
),
|
|
61
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0
|
|
62
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "absolute bottom-0 inset-x-0 p-2.5 space-y-1.5", children: [
|
|
63
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-8 w-8 rounded-full ring-2 ring-white/20 overflow-hidden bg-muted flex items-center justify-center", children: avatarUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
64
|
-
"img",
|
|
65
|
-
{
|
|
66
|
-
src: avatarUrl,
|
|
67
|
-
alt: displayName ?? "",
|
|
68
|
-
loading: "lazy",
|
|
69
|
-
className: "h-full w-full object-cover",
|
|
70
|
-
onError: () => setAvatarError(true)
|
|
71
|
-
}
|
|
72
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs font-black text-white/60", children: (displayName ?? "?").charAt(0).toUpperCase() }) }),
|
|
73
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
74
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "font-bold text-white text-xs truncate", children: displayName }),
|
|
75
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-[10px] text-white/55 flex items-center gap-0.5", children: [
|
|
76
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.AtSign, { className: "h-2 w-2 shrink-0" }),
|
|
77
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate", children: creator.username })
|
|
78
|
-
] })
|
|
79
|
-
] })
|
|
80
|
-
] })
|
|
57
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute bottom-0 inset-x-0 px-3 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "font-bold text-2xl text-white truncate", children: creator.username }) })
|
|
81
58
|
] })
|
|
82
59
|
}
|
|
83
60
|
);
|
|
@@ -87,7 +64,7 @@ function DiscoverCreatorsStrip({
|
|
|
87
64
|
isLoading,
|
|
88
65
|
getHref,
|
|
89
66
|
allCreatorsHref = "/creators",
|
|
90
|
-
sectionLabel = "
|
|
67
|
+
sectionLabel = "Explore",
|
|
91
68
|
title = "Creators"
|
|
92
69
|
}) {
|
|
93
70
|
if (!isLoading && creators.length === 0) return null;
|
|
@@ -112,7 +89,7 @@ function DiscoverCreatorsStrip({
|
|
|
112
89
|
}
|
|
113
90
|
)
|
|
114
91
|
] }),
|
|
115
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "overflow-x-auto scrollbar-hide snap-x snap-mandatory -mx-4 px-4 md:mx-0 md:px-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex gap-
|
|
92
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "overflow-x-auto scrollbar-hide snap-x snap-mandatory -mx-4 px-4 md:mx-0 md:px-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex gap-5 sm:gap-6 w-max pb-2", children: isLoading ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CreatorChipSkeleton, {}, i)) : creators.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CreatorChip, { creator: c, href: getHref(c) }, c.walletAddress)) }) })
|
|
116
93
|
] }) });
|
|
117
94
|
}
|
|
118
95
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/discover-creators-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Users, ArrowRight
|
|
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,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState } from "react";
|
|
4
|
-
import { Users, ArrowRight
|
|
4
|
+
import { Users, ArrowRight } from "lucide-react";
|
|
5
5
|
import { FadeIn } from "./motion-primitives.js";
|
|
6
6
|
import { ipfsToHttp } from "../utils/ipfs.js";
|
|
7
7
|
function CreatorChipSkeleton() {
|
|
@@ -11,13 +11,9 @@ function CreatorChip({
|
|
|
11
11
|
creator,
|
|
12
12
|
href
|
|
13
13
|
}) {
|
|
14
|
-
const [avatarError, setAvatarError] = useState(false);
|
|
15
14
|
const [bannerError, setBannerError] = useState(false);
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const bannerUrl = bannerSrc && !bannerError ? ipfsToHttp(bannerSrc) : null;
|
|
19
|
-
const avatarUrl = avatarSrc && !avatarError ? ipfsToHttp(avatarSrc) : null;
|
|
20
|
-
const displayName = creator.displayName || `@${creator.username}`;
|
|
15
|
+
const rawSrc = creator.bannerImage || creator.collectionImage || null;
|
|
16
|
+
const bannerUrl = rawSrc && !bannerError ? ipfsToHttp(rawSrc) : null;
|
|
21
17
|
return /* @__PURE__ */ jsx(
|
|
22
18
|
"a",
|
|
23
19
|
{
|
|
@@ -35,26 +31,7 @@ function CreatorChip({
|
|
|
35
31
|
onError: () => setBannerError(true)
|
|
36
32
|
}
|
|
37
33
|
),
|
|
38
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0
|
|
39
|
-
/* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 inset-x-0 p-2.5 space-y-1.5", children: [
|
|
40
|
-
/* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-full ring-2 ring-white/20 overflow-hidden bg-muted flex items-center justify-center", children: avatarUrl ? /* @__PURE__ */ jsx(
|
|
41
|
-
"img",
|
|
42
|
-
{
|
|
43
|
-
src: avatarUrl,
|
|
44
|
-
alt: displayName ?? "",
|
|
45
|
-
loading: "lazy",
|
|
46
|
-
className: "h-full w-full object-cover",
|
|
47
|
-
onError: () => setAvatarError(true)
|
|
48
|
-
}
|
|
49
|
-
) : /* @__PURE__ */ jsx("span", { className: "text-xs font-black text-white/60", children: (displayName ?? "?").charAt(0).toUpperCase() }) }),
|
|
50
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
51
|
-
/* @__PURE__ */ jsx("p", { className: "font-bold text-white text-xs truncate", children: displayName }),
|
|
52
|
-
/* @__PURE__ */ jsxs("p", { className: "text-[10px] text-white/55 flex items-center gap-0.5", children: [
|
|
53
|
-
/* @__PURE__ */ jsx(AtSign, { className: "h-2 w-2 shrink-0" }),
|
|
54
|
-
/* @__PURE__ */ jsx("span", { className: "truncate", children: creator.username })
|
|
55
|
-
] })
|
|
56
|
-
] })
|
|
57
|
-
] })
|
|
34
|
+
/* @__PURE__ */ jsx("div", { className: "absolute bottom-0 inset-x-0 px-3 py-3", children: /* @__PURE__ */ jsx("p", { className: "font-bold text-2xl text-white truncate", children: creator.username }) })
|
|
58
35
|
] })
|
|
59
36
|
}
|
|
60
37
|
);
|
|
@@ -64,7 +41,7 @@ function DiscoverCreatorsStrip({
|
|
|
64
41
|
isLoading,
|
|
65
42
|
getHref,
|
|
66
43
|
allCreatorsHref = "/creators",
|
|
67
|
-
sectionLabel = "
|
|
44
|
+
sectionLabel = "Explore",
|
|
68
45
|
title = "Creators"
|
|
69
46
|
}) {
|
|
70
47
|
if (!isLoading && creators.length === 0) return null;
|
|
@@ -89,7 +66,7 @@ function DiscoverCreatorsStrip({
|
|
|
89
66
|
}
|
|
90
67
|
)
|
|
91
68
|
] }),
|
|
92
|
-
/* @__PURE__ */ jsx("div", { className: "overflow-x-auto scrollbar-hide snap-x snap-mandatory -mx-4 px-4 md:mx-0 md:px-0", children: /* @__PURE__ */ jsx("div", { className: "flex gap-
|
|
69
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-x-auto scrollbar-hide snap-x snap-mandatory -mx-4 px-4 md:mx-0 md:px-0", children: /* @__PURE__ */ jsx("div", { className: "flex gap-5 sm:gap-6 w-max pb-2", children: isLoading ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsx(CreatorChipSkeleton, {}, i)) : creators.map((c) => /* @__PURE__ */ jsx(CreatorChip, { creator: c, href: getHref(c) }, c.walletAddress)) }) })
|
|
93
70
|
] }) });
|
|
94
71
|
}
|
|
95
72
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/discover-creators-strip.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Users, ArrowRight
|
|
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":[]}
|
|
@@ -39,6 +39,7 @@ function ScrollSection({
|
|
|
39
39
|
icon,
|
|
40
40
|
iconBg,
|
|
41
41
|
title,
|
|
42
|
+
subtitle,
|
|
42
43
|
href,
|
|
43
44
|
linkLabel = "See all",
|
|
44
45
|
children
|
|
@@ -47,7 +48,10 @@ function ScrollSection({
|
|
|
47
48
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
48
49
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2.5", children: [
|
|
49
50
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `h-7 w-7 rounded-lg flex items-center justify-center ${iconBg}`, children: icon }),
|
|
50
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
51
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
52
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-lg sm:text-xl font-semibold leading-none", children: title }),
|
|
53
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-[10px] text-muted-foreground mt-1", children: subtitle })
|
|
54
|
+
] })
|
|
51
55
|
] }),
|
|
52
56
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
53
57
|
import_link.default,
|
|
@@ -62,7 +66,7 @@ function ScrollSection({
|
|
|
62
66
|
}
|
|
63
67
|
)
|
|
64
68
|
] }),
|
|
65
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-full overflow-x-auto scrollbar-hide", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex gap-
|
|
69
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-full overflow-x-auto scrollbar-hide", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex gap-5 sm:gap-6 snap-x snap-mandatory pb-2", style: { width: "max-content" }, children }) })
|
|
66
70
|
] });
|
|
67
71
|
}
|
|
68
72
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/scroll-section.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\nimport { ArrowRight } from \"lucide-react\";\n\nexport interface ScrollSectionProps {\n /** Icon element rendered inside the colored badge */\n icon: React.ReactNode;\n /** Tailwind classes for the icon badge (background + shadow) */\n iconBg: string;\n title: string;\n /** \"See all\" link destination */\n href: string;\n /** Button label — defaults to \"See all\" */\n linkLabel?: string;\n /** Scroll items: wrap each in a sized snap-start div */\n children: React.ReactNode;\n}\n\nexport function ScrollSection({\n icon,\n iconBg,\n title,\n href,\n linkLabel = \"See all\",\n children,\n}: ScrollSectionProps) {\n return (\n <section className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2.5\">\n <div className={`h-7 w-7 rounded-lg flex items-center justify-center ${iconBg}`}>\n {icon}\n </div>\n <h2 className=\"text-lg sm:text-xl font-semibold\">{title}</h2>\n </div>\n <Link\n href={href}\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 {linkLabel} <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n <div className=\"w-full overflow-x-auto scrollbar-hide\">\n <div className=\"flex gap-
|
|
1
|
+
{"version":3,"sources":["../../src/components/scroll-section.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\nimport { ArrowRight } from \"lucide-react\";\n\nexport interface ScrollSectionProps {\n /** Icon element rendered inside the colored badge */\n icon: React.ReactNode;\n /** Tailwind classes for the icon badge (background + shadow) */\n iconBg: string;\n title: string;\n /** Optional small line under the title (e.g. \"Updated 1m ago\") */\n subtitle?: React.ReactNode;\n /** \"See all\" link destination */\n href: string;\n /** Button label — defaults to \"See all\" */\n linkLabel?: string;\n /** Scroll items: wrap each in a sized snap-start div */\n children: React.ReactNode;\n}\n\nexport function ScrollSection({\n icon,\n iconBg,\n title,\n subtitle,\n href,\n linkLabel = \"See all\",\n children,\n}: ScrollSectionProps) {\n return (\n <section className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2.5\">\n <div className={`h-7 w-7 rounded-lg flex items-center justify-center ${iconBg}`}>\n {icon}\n </div>\n <div>\n <h2 className=\"text-lg sm:text-xl font-semibold leading-none\">{title}</h2>\n {subtitle && <p className=\"text-[10px] text-muted-foreground mt-1\">{subtitle}</p>}\n </div>\n </div>\n <Link\n href={href}\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 {linkLabel} <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n <div className=\"w-full overflow-x-auto scrollbar-hide\">\n <div className=\"flex gap-5 sm:gap-6 snap-x snap-mandatory pb-2\" style={{ width: \"max-content\" }}>\n {children}\n </div>\n </div>\n </section>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkCU;AAhCV,kBAAiB;AACjB,0BAA2B;AAkBpB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AACF,GAAuB;AACrB,SACE,6CAAC,aAAQ,WAAU,aACjB;AAAA,iDAAC,SAAI,WAAU,qCACb;AAAA,mDAAC,SAAI,WAAU,6BACb;AAAA,oDAAC,SAAI,WAAW,uDAAuD,MAAM,IAC1E,gBACH;AAAA,QACA,6CAAC,SACC;AAAA,sDAAC,QAAG,WAAU,iDAAiD,iBAAM;AAAA,UACpE,YAAY,4CAAC,OAAE,WAAU,0CAA0C,oBAAS;AAAA,WAC/E;AAAA,SACF;AAAA,MACA;AAAA,QAAC,YAAAA;AAAA,QAAA;AAAA,UACC;AAAA,UACA,WAAU;AAAA,UAET;AAAA;AAAA,YAAU;AAAA,YAAC,4CAAC,kCAAW,WAAU,eAAc;AAAA;AAAA;AAAA,MAClD;AAAA,OACF;AAAA,IAEA,4CAAC,SAAI,WAAU,yCACb,sDAAC,SAAI,WAAU,kDAAiD,OAAO,EAAE,OAAO,cAAc,GAC3F,UACH,GACF;AAAA,KACF;AAEJ;","names":["Link"]}
|
|
@@ -6,6 +6,8 @@ interface ScrollSectionProps {
|
|
|
6
6
|
/** Tailwind classes for the icon badge (background + shadow) */
|
|
7
7
|
iconBg: string;
|
|
8
8
|
title: string;
|
|
9
|
+
/** Optional small line under the title (e.g. "Updated 1m ago") */
|
|
10
|
+
subtitle?: React.ReactNode;
|
|
9
11
|
/** "See all" link destination */
|
|
10
12
|
href: string;
|
|
11
13
|
/** Button label — defaults to "See all" */
|
|
@@ -13,6 +15,6 @@ interface ScrollSectionProps {
|
|
|
13
15
|
/** Scroll items: wrap each in a sized snap-start div */
|
|
14
16
|
children: React.ReactNode;
|
|
15
17
|
}
|
|
16
|
-
declare function ScrollSection({ icon, iconBg, title, href, linkLabel, children, }: ScrollSectionProps): react_jsx_runtime.JSX.Element;
|
|
18
|
+
declare function ScrollSection({ icon, iconBg, title, subtitle, href, linkLabel, children, }: ScrollSectionProps): react_jsx_runtime.JSX.Element;
|
|
17
19
|
|
|
18
20
|
export { ScrollSection, type ScrollSectionProps };
|
|
@@ -6,6 +6,8 @@ interface ScrollSectionProps {
|
|
|
6
6
|
/** Tailwind classes for the icon badge (background + shadow) */
|
|
7
7
|
iconBg: string;
|
|
8
8
|
title: string;
|
|
9
|
+
/** Optional small line under the title (e.g. "Updated 1m ago") */
|
|
10
|
+
subtitle?: React.ReactNode;
|
|
9
11
|
/** "See all" link destination */
|
|
10
12
|
href: string;
|
|
11
13
|
/** Button label — defaults to "See all" */
|
|
@@ -13,6 +15,6 @@ interface ScrollSectionProps {
|
|
|
13
15
|
/** Scroll items: wrap each in a sized snap-start div */
|
|
14
16
|
children: React.ReactNode;
|
|
15
17
|
}
|
|
16
|
-
declare function ScrollSection({ icon, iconBg, title, href, linkLabel, children, }: ScrollSectionProps): react_jsx_runtime.JSX.Element;
|
|
18
|
+
declare function ScrollSection({ icon, iconBg, title, subtitle, href, linkLabel, children, }: ScrollSectionProps): react_jsx_runtime.JSX.Element;
|
|
17
19
|
|
|
18
20
|
export { ScrollSection, type ScrollSectionProps };
|
|
@@ -6,6 +6,7 @@ function ScrollSection({
|
|
|
6
6
|
icon,
|
|
7
7
|
iconBg,
|
|
8
8
|
title,
|
|
9
|
+
subtitle,
|
|
9
10
|
href,
|
|
10
11
|
linkLabel = "See all",
|
|
11
12
|
children
|
|
@@ -14,7 +15,10 @@ function ScrollSection({
|
|
|
14
15
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
15
16
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
16
17
|
/* @__PURE__ */ jsx("div", { className: `h-7 w-7 rounded-lg flex items-center justify-center ${iconBg}`, children: icon }),
|
|
17
|
-
/* @__PURE__ */
|
|
18
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
19
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg sm:text-xl font-semibold leading-none", children: title }),
|
|
20
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground mt-1", children: subtitle })
|
|
21
|
+
] })
|
|
18
22
|
] }),
|
|
19
23
|
/* @__PURE__ */ jsxs(
|
|
20
24
|
Link,
|
|
@@ -29,7 +33,7 @@ function ScrollSection({
|
|
|
29
33
|
}
|
|
30
34
|
)
|
|
31
35
|
] }),
|
|
32
|
-
/* @__PURE__ */ jsx("div", { className: "w-full overflow-x-auto scrollbar-hide", children: /* @__PURE__ */ jsx("div", { className: "flex gap-
|
|
36
|
+
/* @__PURE__ */ jsx("div", { className: "w-full overflow-x-auto scrollbar-hide", children: /* @__PURE__ */ jsx("div", { className: "flex gap-5 sm:gap-6 snap-x snap-mandatory pb-2", style: { width: "max-content" }, children }) })
|
|
33
37
|
] });
|
|
34
38
|
}
|
|
35
39
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/scroll-section.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\nimport { ArrowRight } from \"lucide-react\";\n\nexport interface ScrollSectionProps {\n /** Icon element rendered inside the colored badge */\n icon: React.ReactNode;\n /** Tailwind classes for the icon badge (background + shadow) */\n iconBg: string;\n title: string;\n /** \"See all\" link destination */\n href: string;\n /** Button label — defaults to \"See all\" */\n linkLabel?: string;\n /** Scroll items: wrap each in a sized snap-start div */\n children: React.ReactNode;\n}\n\nexport function ScrollSection({\n icon,\n iconBg,\n title,\n href,\n linkLabel = \"See all\",\n children,\n}: ScrollSectionProps) {\n return (\n <section className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2.5\">\n <div className={`h-7 w-7 rounded-lg flex items-center justify-center ${iconBg}`}>\n {icon}\n </div>\n <h2 className=\"text-lg sm:text-xl font-semibold\">{title}</h2>\n </div>\n <Link\n href={href}\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 {linkLabel} <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n <div className=\"w-full overflow-x-auto scrollbar-hide\">\n <div className=\"flex gap-
|
|
1
|
+
{"version":3,"sources":["../../src/components/scroll-section.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\nimport { ArrowRight } from \"lucide-react\";\n\nexport interface ScrollSectionProps {\n /** Icon element rendered inside the colored badge */\n icon: React.ReactNode;\n /** Tailwind classes for the icon badge (background + shadow) */\n iconBg: string;\n title: string;\n /** Optional small line under the title (e.g. \"Updated 1m ago\") */\n subtitle?: React.ReactNode;\n /** \"See all\" link destination */\n href: string;\n /** Button label — defaults to \"See all\" */\n linkLabel?: string;\n /** Scroll items: wrap each in a sized snap-start div */\n children: React.ReactNode;\n}\n\nexport function ScrollSection({\n icon,\n iconBg,\n title,\n subtitle,\n href,\n linkLabel = \"See all\",\n children,\n}: ScrollSectionProps) {\n return (\n <section className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2.5\">\n <div className={`h-7 w-7 rounded-lg flex items-center justify-center ${iconBg}`}>\n {icon}\n </div>\n <div>\n <h2 className=\"text-lg sm:text-xl font-semibold leading-none\">{title}</h2>\n {subtitle && <p className=\"text-[10px] text-muted-foreground mt-1\">{subtitle}</p>}\n </div>\n </div>\n <Link\n href={href}\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 {linkLabel} <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n <div className=\"w-full overflow-x-auto scrollbar-hide\">\n <div className=\"flex gap-5 sm:gap-6 snap-x snap-mandatory pb-2\" style={{ width: \"max-content\" }}>\n {children}\n </div>\n </div>\n </section>\n );\n}\n"],"mappings":";AAkCU,cAGA,YAHA;AAhCV,OAAO,UAAU;AACjB,SAAS,kBAAkB;AAkBpB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AACF,GAAuB;AACrB,SACE,qBAAC,aAAQ,WAAU,aACjB;AAAA,yBAAC,SAAI,WAAU,qCACb;AAAA,2BAAC,SAAI,WAAU,6BACb;AAAA,4BAAC,SAAI,WAAW,uDAAuD,MAAM,IAC1E,gBACH;AAAA,QACA,qBAAC,SACC;AAAA,8BAAC,QAAG,WAAU,iDAAiD,iBAAM;AAAA,UACpE,YAAY,oBAAC,OAAE,WAAU,0CAA0C,oBAAS;AAAA,WAC/E;AAAA,SACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,WAAU;AAAA,UAET;AAAA;AAAA,YAAU;AAAA,YAAC,oBAAC,cAAW,WAAU,eAAc;AAAA;AAAA;AAAA,MAClD;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAU,yCACb,8BAAC,SAAI,WAAU,kDAAiD,OAAO,EAAE,OAAO,cAAc,GAC3F,UACH,GACF;AAAA,KACF;AAEJ;","names":[]}
|
package/dist/medialane.css
CHANGED
|
@@ -192,6 +192,12 @@ input[type="number"]::-webkit-outer-spin-button,
|
|
|
192
192
|
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
|
|
193
193
|
input[type="number"] { -moz-appearance: textfield; }
|
|
194
194
|
|
|
195
|
+
/* ── Wrapper that adds a 2px animated gradient border around a .card-base card ── */
|
|
196
|
+
.card-exclusive-wrapper {
|
|
197
|
+
padding: 2px;
|
|
198
|
+
border-radius: calc(var(--radius) * 1.25 + 2px);
|
|
199
|
+
}
|
|
200
|
+
|
|
195
201
|
/* ── Animated gradient border (marketplace buy button) ────────────────── */
|
|
196
202
|
.btn-border-animated {
|
|
197
203
|
background: linear-gradient(270deg, #2563eb, #9333ea, #f43f5e, #ea580c, #2563eb);
|