@medialane/ui 0.322.0 → 0.323.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.
@@ -58,7 +58,7 @@ function CollectionCard({ collection, href, settingsHref, className }) {
58
58
  const imageUrl = resolveImage(collection.image, { width: 480 });
59
59
  const showImage = imageUrl && !imgError;
60
60
  const floor = parseFloorPrice(collection.floorPrice);
61
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_motion_primitives.MotionCard, { className: (0, import_cn.cn)("card-base group relative", className), children: [
61
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_motion_primitives.MotionCard, { className: (0, import_cn.cn)("group relative overflow-hidden rounded-[calc(var(--radius)*1.25)]", className), children: [
62
62
  settingsHref && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
63
63
  import_link.default,
64
64
  {
@@ -89,7 +89,6 @@ function CollectionCard({ collection, href, settingsHref, className }) {
89
89
  (collection.totalSupply != null || floor) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
90
90
  collection.totalSupply != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "rounded-full px-2.5 py-1 text-2xs font-medium text-white bg-black/30 backdrop-blur-md", children: collection.totalSupply.toLocaleString() }),
91
91
  floor && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-2xs font-bold text-white bg-black/30 backdrop-blur-md", children: [
92
- "Floor",
93
92
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: floor.symbol, size: 10 }),
94
93
  floor.amount
95
94
  ] })
@@ -99,7 +98,7 @@ function CollectionCard({ collection, href, settingsHref, className }) {
99
98
  ] });
100
99
  }
101
100
  function CollectionCardSkeleton() {
102
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "card-base overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative aspect-square w-full overflow-hidden bg-muted", children: [
101
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "overflow-hidden rounded-[calc(var(--radius)*1.25)]", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative aspect-square w-full overflow-hidden bg-muted", children: [
103
102
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 animate-pulse bg-muted" }),
104
103
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "absolute bottom-3 left-3 right-3 space-y-1.5", children: [
105
104
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-4 w-2/3 rounded-md bg-muted-foreground/20 animate-pulse" }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"./link.js\";\nimport Image from \"./image.js\";\nimport { Loader2, Settings2 } from \"lucide-react\";\nimport { cn } from \"../utils/cn.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\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\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\nexport interface CollectionCardProps {\n collection: ApiCollection;\n\n href?: string;\n\n settingsHref?: string;\n className?: string;\n}\n\nexport function CollectionCard({ collection, href, settingsHref, className }: CollectionCardProps) {\n const resolveImage = useImageUrl();\n const [imgError, setImgError] = useState(false);\n const imageUrl = resolveImage(collection.image, { width: 480 });\n const showImage = imageUrl && !imgError;\n const floor = parseFloorPrice(collection.floorPrice);\n\n return (\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 min-h-11 min-w-11 rounded-full flex items-center justify-center\"\n aria-label=\"Collection settings\"\n >\n <span className=\"flex h-7 w-7 items-center justify-center rounded-full bg-black/40 backdrop-blur-sm text-white/70 hover:text-white hover:bg-black/60 transition-colors\">\n <Settings2 className=\"h-3.5 w-3.5\" />\n </span>\n </Link>\n )}\n\n <Link href={href ?? `/collections/${collection.contractAddress}`} className=\"block relative h-full\">\n <div className=\"relative aspect-square w-full overflow-hidden bg-muted\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={collection.name ?? \"Collection\"}\n fill\n className=\"object-cover card-media\"\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\" />\n )}\n\n <div className=\"absolute inset-x-2 bottom-2 flex flex-col items-start gap-1\">\n {!collection.name && collection.metadataStatus === \"PENDING\" ? (\n <span className=\"flex items-center gap-1 rounded-full px-2.5 py-1 text-2xs text-white bg-black/30 backdrop-blur-md\">\n <Loader2 className=\"h-2.5 w-2.5 animate-spin\" />\n Indexing…\n </span>\n ) : (\n <p className=\"max-w-full truncate rounded-full px-3 py-1 text-sm font-bold leading-tight text-white bg-black/30 backdrop-blur-md\">\n {collection.name ?? \"Unnamed Collection\"}\n </p>\n )}\n\n {(collection.totalSupply != null || floor) && (\n <div className=\"flex flex-wrap items-center gap-1\">\n {collection.totalSupply != null && (\n <span className=\"rounded-full px-2.5 py-1 text-2xs font-medium text-white bg-black/30 backdrop-blur-md\">\n {collection.totalSupply.toLocaleString()}\n </span>\n )}\n {floor && (\n <span className=\"inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-2xs font-bold text-white bg-black/30 backdrop-blur-md\">\n Floor\n <CurrencyIcon symbol={floor.symbol} size={10} />\n {floor.amount}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n </Link>\n </MotionCard>\n );\n}\n\nexport function CollectionCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"relative aspect-square 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiDY;AA/CZ,mBAAyB;AACzB,kBAAiB;AACjB,mBAAkB;AAClB,0BAAmC;AACnC,gBAAmB;AACnB,oBAAmC;AACnC,+BAA2B;AAC3B,2BAA6B;AAE7B,2BAA4B;AAE5B,SAAS,gBAAgB,OAA6E;AACpG,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,gBAAY,kCAAmB,KAAK;AAC1C,QAAM,QAAQ,UAAU,KAAK,EAAE,MAAM,KAAK;AAC1C,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,QAAM,SAAS,MAAM,MAAM,SAAS,CAAC;AACrC,QAAM,SAAS,MAAM,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG;AAC1C,SAAO,EAAE,QAAQ,OAAO;AAC1B;AAWO,SAAS,eAAe,EAAE,YAAY,MAAM,cAAc,UAAU,GAAwB;AACjG,QAAM,mBAAe,kCAAY;AACjC,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,KAAK;AAC9C,QAAM,WAAW,aAAa,WAAW,OAAO,EAAE,OAAO,IAAI,CAAC;AAC9D,QAAM,YAAY,YAAY,CAAC;AAC/B,QAAM,QAAQ,gBAAgB,WAAW,UAAU;AAEnD,SACE,6CAAC,uCAAW,eAAW,cAAG,4BAA4B,SAAS,GAC5D;AAAA,oBACC;AAAA,MAAC,YAAAA;AAAA,MAAA;AAAA,QACC,MAAM;AAAA,QACN,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,QAClC,WAAU;AAAA,QACV,cAAW;AAAA,QAEX,sDAAC,UAAK,WAAU,yJACd,sDAAC,iCAAU,WAAU,eAAc,GACrC;AAAA;AAAA,IACF;AAAA,IAGF,4CAAC,YAAAA,SAAA,EAAK,MAAM,QAAQ,gBAAgB,WAAW,eAAe,IAAI,WAAU,yBAC1E,uDAAC,SAAI,WAAU,0DACZ;AAAA,kBACC;AAAA,QAAC,aAAAC;AAAA,QAAA;AAAA,UACC,KAAK;AAAA,UACL,KAAK,WAAW,QAAQ;AAAA,UACxB,MAAI;AAAA,UACJ,WAAU;AAAA,UACV,SAAS,MAAM,YAAY,IAAI;AAAA,UAC/B,aAAW;AAAA;AAAA,MACb,IAEA,4CAAC,SAAI,WAAU,8FAA6F;AAAA,MAG9G,6CAAC,SAAI,WAAU,+DACZ;AAAA,SAAC,WAAW,QAAQ,WAAW,mBAAmB,YACjD,6CAAC,UAAK,WAAU,qGACd;AAAA,sDAAC,+BAAQ,WAAU,4BAA2B;AAAA,UAAE;AAAA,WAElD,IAEA,4CAAC,OAAE,WAAU,sHACV,qBAAW,QAAQ,sBACtB;AAAA,SAGA,WAAW,eAAe,QAAQ,UAClC,6CAAC,SAAI,WAAU,qCACZ;AAAA,qBAAW,eAAe,QACzB,4CAAC,UAAK,WAAU,yFACb,qBAAW,YAAY,eAAe,GACzC;AAAA,UAED,SACC,6CAAC,UAAK,WAAU,sHAAqH;AAAA;AAAA,YAEnI,4CAAC,qCAAa,QAAQ,MAAM,QAAQ,MAAM,IAAI;AAAA,YAC7C,MAAM;AAAA,aACT;AAAA,WAEJ;AAAA,SAEJ;AAAA,OACF,GACF;AAAA,KACF;AAEJ;AAEO,SAAS,yBAAyB;AACvC,SACE,4CAAC,SAAI,WAAU,6BACb,uDAAC,SAAI,WAAU,0DACb;AAAA,gDAAC,SAAI,WAAU,2CAA0C;AAAA,IACzD,6CAAC,SAAI,WAAU,gDACb;AAAA,kDAAC,SAAI,WAAU,6DAA4D;AAAA,MAC3E,4CAAC,SAAI,WAAU,6DAA4D;AAAA,OAC7E;AAAA,KACF,GACF;AAEJ;","names":["Link","Image"]}
1
+ {"version":3,"sources":["../../src/components/collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"./link.js\";\nimport Image from \"./image.js\";\nimport { Loader2, Settings2 } from \"lucide-react\";\nimport { cn } from \"../utils/cn.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\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\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\nexport interface CollectionCardProps {\n collection: ApiCollection;\n\n href?: string;\n\n settingsHref?: string;\n className?: string;\n}\n\nexport function CollectionCard({ collection, href, settingsHref, className }: CollectionCardProps) {\n const resolveImage = useImageUrl();\n const [imgError, setImgError] = useState(false);\n const imageUrl = resolveImage(collection.image, { width: 480 });\n const showImage = imageUrl && !imgError;\n const floor = parseFloorPrice(collection.floorPrice);\n\n return (\n <MotionCard className={cn(\"group relative overflow-hidden rounded-[calc(var(--radius)*1.25)]\", className)}>\n {settingsHref && (\n <Link\n href={settingsHref}\n onClick={(e) => e.stopPropagation()}\n className=\"absolute top-2 right-2 z-10 min-h-11 min-w-11 rounded-full flex items-center justify-center\"\n aria-label=\"Collection settings\"\n >\n <span className=\"flex h-7 w-7 items-center justify-center rounded-full bg-black/40 backdrop-blur-sm text-white/70 hover:text-white hover:bg-black/60 transition-colors\">\n <Settings2 className=\"h-3.5 w-3.5\" />\n </span>\n </Link>\n )}\n\n <Link href={href ?? `/collections/${collection.contractAddress}`} className=\"block relative h-full\">\n <div className=\"relative aspect-square w-full overflow-hidden bg-muted\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={collection.name ?? \"Collection\"}\n fill\n className=\"object-cover card-media\"\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\" />\n )}\n\n <div className=\"absolute inset-x-2 bottom-2 flex flex-col items-start gap-1\">\n {!collection.name && collection.metadataStatus === \"PENDING\" ? (\n <span className=\"flex items-center gap-1 rounded-full px-2.5 py-1 text-2xs text-white bg-black/30 backdrop-blur-md\">\n <Loader2 className=\"h-2.5 w-2.5 animate-spin\" />\n Indexing…\n </span>\n ) : (\n <p className=\"max-w-full truncate rounded-full px-3 py-1 text-sm font-bold leading-tight text-white bg-black/30 backdrop-blur-md\">\n {collection.name ?? \"Unnamed Collection\"}\n </p>\n )}\n\n {(collection.totalSupply != null || floor) && (\n <div className=\"flex flex-wrap items-center gap-1\">\n {collection.totalSupply != null && (\n <span className=\"rounded-full px-2.5 py-1 text-2xs font-medium text-white bg-black/30 backdrop-blur-md\">\n {collection.totalSupply.toLocaleString()}\n </span>\n )}\n {floor && (\n <span className=\"inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-2xs font-bold text-white bg-black/30 backdrop-blur-md\">\n <CurrencyIcon symbol={floor.symbol} size={10} />\n {floor.amount}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n </Link>\n </MotionCard>\n );\n}\n\nexport function CollectionCardSkeleton() {\n return (\n <div className=\"overflow-hidden rounded-[calc(var(--radius)*1.25)]\">\n <div className=\"relative aspect-square 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiDY;AA/CZ,mBAAyB;AACzB,kBAAiB;AACjB,mBAAkB;AAClB,0BAAmC;AACnC,gBAAmB;AACnB,oBAAmC;AACnC,+BAA2B;AAC3B,2BAA6B;AAE7B,2BAA4B;AAE5B,SAAS,gBAAgB,OAA6E;AACpG,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,gBAAY,kCAAmB,KAAK;AAC1C,QAAM,QAAQ,UAAU,KAAK,EAAE,MAAM,KAAK;AAC1C,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,QAAM,SAAS,MAAM,MAAM,SAAS,CAAC;AACrC,QAAM,SAAS,MAAM,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG;AAC1C,SAAO,EAAE,QAAQ,OAAO;AAC1B;AAWO,SAAS,eAAe,EAAE,YAAY,MAAM,cAAc,UAAU,GAAwB;AACjG,QAAM,mBAAe,kCAAY;AACjC,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,KAAK;AAC9C,QAAM,WAAW,aAAa,WAAW,OAAO,EAAE,OAAO,IAAI,CAAC;AAC9D,QAAM,YAAY,YAAY,CAAC;AAC/B,QAAM,QAAQ,gBAAgB,WAAW,UAAU;AAEnD,SACE,6CAAC,uCAAW,eAAW,cAAG,qEAAqE,SAAS,GACrG;AAAA,oBACC;AAAA,MAAC,YAAAA;AAAA,MAAA;AAAA,QACC,MAAM;AAAA,QACN,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,QAClC,WAAU;AAAA,QACV,cAAW;AAAA,QAEX,sDAAC,UAAK,WAAU,yJACd,sDAAC,iCAAU,WAAU,eAAc,GACrC;AAAA;AAAA,IACF;AAAA,IAGF,4CAAC,YAAAA,SAAA,EAAK,MAAM,QAAQ,gBAAgB,WAAW,eAAe,IAAI,WAAU,yBAC1E,uDAAC,SAAI,WAAU,0DACZ;AAAA,kBACC;AAAA,QAAC,aAAAC;AAAA,QAAA;AAAA,UACC,KAAK;AAAA,UACL,KAAK,WAAW,QAAQ;AAAA,UACxB,MAAI;AAAA,UACJ,WAAU;AAAA,UACV,SAAS,MAAM,YAAY,IAAI;AAAA,UAC/B,aAAW;AAAA;AAAA,MACb,IAEA,4CAAC,SAAI,WAAU,8FAA6F;AAAA,MAG9G,6CAAC,SAAI,WAAU,+DACZ;AAAA,SAAC,WAAW,QAAQ,WAAW,mBAAmB,YACjD,6CAAC,UAAK,WAAU,qGACd;AAAA,sDAAC,+BAAQ,WAAU,4BAA2B;AAAA,UAAE;AAAA,WAElD,IAEA,4CAAC,OAAE,WAAU,sHACV,qBAAW,QAAQ,sBACtB;AAAA,SAGA,WAAW,eAAe,QAAQ,UAClC,6CAAC,SAAI,WAAU,qCACZ;AAAA,qBAAW,eAAe,QACzB,4CAAC,UAAK,WAAU,yFACb,qBAAW,YAAY,eAAe,GACzC;AAAA,UAED,SACC,6CAAC,UAAK,WAAU,sHACd;AAAA,wDAAC,qCAAa,QAAQ,MAAM,QAAQ,MAAM,IAAI;AAAA,YAC7C,MAAM;AAAA,aACT;AAAA,WAEJ;AAAA,SAEJ;AAAA,OACF,GACF;AAAA,KACF;AAEJ;AAEO,SAAS,yBAAyB;AACvC,SACE,4CAAC,SAAI,WAAU,sDACb,uDAAC,SAAI,WAAU,0DACb;AAAA,gDAAC,SAAI,WAAU,2CAA0C;AAAA,IACzD,6CAAC,SAAI,WAAU,gDACb;AAAA,kDAAC,SAAI,WAAU,6DAA4D;AAAA,MAC3E,4CAAC,SAAI,WAAU,6DAA4D;AAAA,OAC7E;AAAA,KACF,GACF;AAEJ;","names":["Link","Image"]}
@@ -24,7 +24,7 @@ function CollectionCard({ collection, href, settingsHref, className }) {
24
24
  const imageUrl = resolveImage(collection.image, { width: 480 });
25
25
  const showImage = imageUrl && !imgError;
26
26
  const floor = parseFloorPrice(collection.floorPrice);
27
- return /* @__PURE__ */ jsxs(MotionCard, { className: cn("card-base group relative", className), children: [
27
+ return /* @__PURE__ */ jsxs(MotionCard, { className: cn("group relative overflow-hidden rounded-[calc(var(--radius)*1.25)]", className), children: [
28
28
  settingsHref && /* @__PURE__ */ jsx(
29
29
  Link,
30
30
  {
@@ -55,7 +55,6 @@ function CollectionCard({ collection, href, settingsHref, className }) {
55
55
  (collection.totalSupply != null || floor) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1", children: [
56
56
  collection.totalSupply != null && /* @__PURE__ */ jsx("span", { className: "rounded-full px-2.5 py-1 text-2xs font-medium text-white bg-black/30 backdrop-blur-md", children: collection.totalSupply.toLocaleString() }),
57
57
  floor && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-2xs font-bold text-white bg-black/30 backdrop-blur-md", children: [
58
- "Floor",
59
58
  /* @__PURE__ */ jsx(CurrencyIcon, { symbol: floor.symbol, size: 10 }),
60
59
  floor.amount
61
60
  ] })
@@ -65,7 +64,7 @@ function CollectionCard({ collection, href, settingsHref, className }) {
65
64
  ] });
66
65
  }
67
66
  function CollectionCardSkeleton() {
68
- return /* @__PURE__ */ jsx("div", { className: "card-base overflow-hidden", children: /* @__PURE__ */ jsxs("div", { className: "relative aspect-square w-full overflow-hidden bg-muted", children: [
67
+ return /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-[calc(var(--radius)*1.25)]", children: /* @__PURE__ */ jsxs("div", { className: "relative aspect-square w-full overflow-hidden bg-muted", children: [
69
68
  /* @__PURE__ */ jsx("div", { className: "absolute inset-0 animate-pulse bg-muted" }),
70
69
  /* @__PURE__ */ jsxs("div", { className: "absolute bottom-3 left-3 right-3 space-y-1.5", children: [
71
70
  /* @__PURE__ */ jsx("div", { className: "h-4 w-2/3 rounded-md bg-muted-foreground/20 animate-pulse" }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"./link.js\";\nimport Image from \"./image.js\";\nimport { Loader2, Settings2 } from \"lucide-react\";\nimport { cn } from \"../utils/cn.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\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\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\nexport interface CollectionCardProps {\n collection: ApiCollection;\n\n href?: string;\n\n settingsHref?: string;\n className?: string;\n}\n\nexport function CollectionCard({ collection, href, settingsHref, className }: CollectionCardProps) {\n const resolveImage = useImageUrl();\n const [imgError, setImgError] = useState(false);\n const imageUrl = resolveImage(collection.image, { width: 480 });\n const showImage = imageUrl && !imgError;\n const floor = parseFloorPrice(collection.floorPrice);\n\n return (\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 min-h-11 min-w-11 rounded-full flex items-center justify-center\"\n aria-label=\"Collection settings\"\n >\n <span className=\"flex h-7 w-7 items-center justify-center rounded-full bg-black/40 backdrop-blur-sm text-white/70 hover:text-white hover:bg-black/60 transition-colors\">\n <Settings2 className=\"h-3.5 w-3.5\" />\n </span>\n </Link>\n )}\n\n <Link href={href ?? `/collections/${collection.contractAddress}`} className=\"block relative h-full\">\n <div className=\"relative aspect-square w-full overflow-hidden bg-muted\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={collection.name ?? \"Collection\"}\n fill\n className=\"object-cover card-media\"\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\" />\n )}\n\n <div className=\"absolute inset-x-2 bottom-2 flex flex-col items-start gap-1\">\n {!collection.name && collection.metadataStatus === \"PENDING\" ? (\n <span className=\"flex items-center gap-1 rounded-full px-2.5 py-1 text-2xs text-white bg-black/30 backdrop-blur-md\">\n <Loader2 className=\"h-2.5 w-2.5 animate-spin\" />\n Indexing…\n </span>\n ) : (\n <p className=\"max-w-full truncate rounded-full px-3 py-1 text-sm font-bold leading-tight text-white bg-black/30 backdrop-blur-md\">\n {collection.name ?? \"Unnamed Collection\"}\n </p>\n )}\n\n {(collection.totalSupply != null || floor) && (\n <div className=\"flex flex-wrap items-center gap-1\">\n {collection.totalSupply != null && (\n <span className=\"rounded-full px-2.5 py-1 text-2xs font-medium text-white bg-black/30 backdrop-blur-md\">\n {collection.totalSupply.toLocaleString()}\n </span>\n )}\n {floor && (\n <span className=\"inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-2xs font-bold text-white bg-black/30 backdrop-blur-md\">\n Floor\n <CurrencyIcon symbol={floor.symbol} size={10} />\n {floor.amount}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n </Link>\n </MotionCard>\n );\n}\n\nexport function CollectionCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"relative aspect-square 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":";AAiDY,cAsBE,YAtBF;AA/CZ,SAAS,gBAAgB;AACzB,OAAO,UAAU;AACjB,OAAO,WAAW;AAClB,SAAS,SAAS,iBAAiB;AACnC,SAAS,UAAU;AACnB,SAAS,0BAA0B;AACnC,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAE7B,SAAS,mBAAmB;AAE5B,SAAS,gBAAgB,OAA6E;AACpG,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,YAAY,mBAAmB,KAAK;AAC1C,QAAM,QAAQ,UAAU,KAAK,EAAE,MAAM,KAAK;AAC1C,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,QAAM,SAAS,MAAM,MAAM,SAAS,CAAC;AACrC,QAAM,SAAS,MAAM,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG;AAC1C,SAAO,EAAE,QAAQ,OAAO;AAC1B;AAWO,SAAS,eAAe,EAAE,YAAY,MAAM,cAAc,UAAU,GAAwB;AACjG,QAAM,eAAe,YAAY;AACjC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,WAAW,aAAa,WAAW,OAAO,EAAE,OAAO,IAAI,CAAC;AAC9D,QAAM,YAAY,YAAY,CAAC;AAC/B,QAAM,QAAQ,gBAAgB,WAAW,UAAU;AAEnD,SACE,qBAAC,cAAW,WAAW,GAAG,4BAA4B,SAAS,GAC5D;AAAA,oBACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,QAClC,WAAU;AAAA,QACV,cAAW;AAAA,QAEX,8BAAC,UAAK,WAAU,yJACd,8BAAC,aAAU,WAAU,eAAc,GACrC;AAAA;AAAA,IACF;AAAA,IAGF,oBAAC,QAAK,MAAM,QAAQ,gBAAgB,WAAW,eAAe,IAAI,WAAU,yBAC1E,+BAAC,SAAI,WAAU,0DACZ;AAAA,kBACC;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,KAAK,WAAW,QAAQ;AAAA,UACxB,MAAI;AAAA,UACJ,WAAU;AAAA,UACV,SAAS,MAAM,YAAY,IAAI;AAAA,UAC/B,aAAW;AAAA;AAAA,MACb,IAEA,oBAAC,SAAI,WAAU,8FAA6F;AAAA,MAG9G,qBAAC,SAAI,WAAU,+DACZ;AAAA,SAAC,WAAW,QAAQ,WAAW,mBAAmB,YACjD,qBAAC,UAAK,WAAU,qGACd;AAAA,8BAAC,WAAQ,WAAU,4BAA2B;AAAA,UAAE;AAAA,WAElD,IAEA,oBAAC,OAAE,WAAU,sHACV,qBAAW,QAAQ,sBACtB;AAAA,SAGA,WAAW,eAAe,QAAQ,UAClC,qBAAC,SAAI,WAAU,qCACZ;AAAA,qBAAW,eAAe,QACzB,oBAAC,UAAK,WAAU,yFACb,qBAAW,YAAY,eAAe,GACzC;AAAA,UAED,SACC,qBAAC,UAAK,WAAU,sHAAqH;AAAA;AAAA,YAEnI,oBAAC,gBAAa,QAAQ,MAAM,QAAQ,MAAM,IAAI;AAAA,YAC7C,MAAM;AAAA,aACT;AAAA,WAEJ;AAAA,SAEJ;AAAA,OACF,GACF;AAAA,KACF;AAEJ;AAEO,SAAS,yBAAyB;AACvC,SACE,oBAAC,SAAI,WAAU,6BACb,+BAAC,SAAI,WAAU,0DACb;AAAA,wBAAC,SAAI,WAAU,2CAA0C;AAAA,IACzD,qBAAC,SAAI,WAAU,gDACb;AAAA,0BAAC,SAAI,WAAU,6DAA4D;AAAA,MAC3E,oBAAC,SAAI,WAAU,6DAA4D;AAAA,OAC7E;AAAA,KACF,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"./link.js\";\nimport Image from \"./image.js\";\nimport { Loader2, Settings2 } from \"lucide-react\";\nimport { cn } from \"../utils/cn.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\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\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\nexport interface CollectionCardProps {\n collection: ApiCollection;\n\n href?: string;\n\n settingsHref?: string;\n className?: string;\n}\n\nexport function CollectionCard({ collection, href, settingsHref, className }: CollectionCardProps) {\n const resolveImage = useImageUrl();\n const [imgError, setImgError] = useState(false);\n const imageUrl = resolveImage(collection.image, { width: 480 });\n const showImage = imageUrl && !imgError;\n const floor = parseFloorPrice(collection.floorPrice);\n\n return (\n <MotionCard className={cn(\"group relative overflow-hidden rounded-[calc(var(--radius)*1.25)]\", className)}>\n {settingsHref && (\n <Link\n href={settingsHref}\n onClick={(e) => e.stopPropagation()}\n className=\"absolute top-2 right-2 z-10 min-h-11 min-w-11 rounded-full flex items-center justify-center\"\n aria-label=\"Collection settings\"\n >\n <span className=\"flex h-7 w-7 items-center justify-center rounded-full bg-black/40 backdrop-blur-sm text-white/70 hover:text-white hover:bg-black/60 transition-colors\">\n <Settings2 className=\"h-3.5 w-3.5\" />\n </span>\n </Link>\n )}\n\n <Link href={href ?? `/collections/${collection.contractAddress}`} className=\"block relative h-full\">\n <div className=\"relative aspect-square w-full overflow-hidden bg-muted\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={collection.name ?? \"Collection\"}\n fill\n className=\"object-cover card-media\"\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\" />\n )}\n\n <div className=\"absolute inset-x-2 bottom-2 flex flex-col items-start gap-1\">\n {!collection.name && collection.metadataStatus === \"PENDING\" ? (\n <span className=\"flex items-center gap-1 rounded-full px-2.5 py-1 text-2xs text-white bg-black/30 backdrop-blur-md\">\n <Loader2 className=\"h-2.5 w-2.5 animate-spin\" />\n Indexing…\n </span>\n ) : (\n <p className=\"max-w-full truncate rounded-full px-3 py-1 text-sm font-bold leading-tight text-white bg-black/30 backdrop-blur-md\">\n {collection.name ?? \"Unnamed Collection\"}\n </p>\n )}\n\n {(collection.totalSupply != null || floor) && (\n <div className=\"flex flex-wrap items-center gap-1\">\n {collection.totalSupply != null && (\n <span className=\"rounded-full px-2.5 py-1 text-2xs font-medium text-white bg-black/30 backdrop-blur-md\">\n {collection.totalSupply.toLocaleString()}\n </span>\n )}\n {floor && (\n <span className=\"inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-2xs font-bold text-white bg-black/30 backdrop-blur-md\">\n <CurrencyIcon symbol={floor.symbol} size={10} />\n {floor.amount}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n </Link>\n </MotionCard>\n );\n}\n\nexport function CollectionCardSkeleton() {\n return (\n <div className=\"overflow-hidden rounded-[calc(var(--radius)*1.25)]\">\n <div className=\"relative aspect-square 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":";AAiDY,cAsBE,YAtBF;AA/CZ,SAAS,gBAAgB;AACzB,OAAO,UAAU;AACjB,OAAO,WAAW;AAClB,SAAS,SAAS,iBAAiB;AACnC,SAAS,UAAU;AACnB,SAAS,0BAA0B;AACnC,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAE7B,SAAS,mBAAmB;AAE5B,SAAS,gBAAgB,OAA6E;AACpG,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,YAAY,mBAAmB,KAAK;AAC1C,QAAM,QAAQ,UAAU,KAAK,EAAE,MAAM,KAAK;AAC1C,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,QAAM,SAAS,MAAM,MAAM,SAAS,CAAC;AACrC,QAAM,SAAS,MAAM,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG;AAC1C,SAAO,EAAE,QAAQ,OAAO;AAC1B;AAWO,SAAS,eAAe,EAAE,YAAY,MAAM,cAAc,UAAU,GAAwB;AACjG,QAAM,eAAe,YAAY;AACjC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,WAAW,aAAa,WAAW,OAAO,EAAE,OAAO,IAAI,CAAC;AAC9D,QAAM,YAAY,YAAY,CAAC;AAC/B,QAAM,QAAQ,gBAAgB,WAAW,UAAU;AAEnD,SACE,qBAAC,cAAW,WAAW,GAAG,qEAAqE,SAAS,GACrG;AAAA,oBACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,QAClC,WAAU;AAAA,QACV,cAAW;AAAA,QAEX,8BAAC,UAAK,WAAU,yJACd,8BAAC,aAAU,WAAU,eAAc,GACrC;AAAA;AAAA,IACF;AAAA,IAGF,oBAAC,QAAK,MAAM,QAAQ,gBAAgB,WAAW,eAAe,IAAI,WAAU,yBAC1E,+BAAC,SAAI,WAAU,0DACZ;AAAA,kBACC;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,KAAK,WAAW,QAAQ;AAAA,UACxB,MAAI;AAAA,UACJ,WAAU;AAAA,UACV,SAAS,MAAM,YAAY,IAAI;AAAA,UAC/B,aAAW;AAAA;AAAA,MACb,IAEA,oBAAC,SAAI,WAAU,8FAA6F;AAAA,MAG9G,qBAAC,SAAI,WAAU,+DACZ;AAAA,SAAC,WAAW,QAAQ,WAAW,mBAAmB,YACjD,qBAAC,UAAK,WAAU,qGACd;AAAA,8BAAC,WAAQ,WAAU,4BAA2B;AAAA,UAAE;AAAA,WAElD,IAEA,oBAAC,OAAE,WAAU,sHACV,qBAAW,QAAQ,sBACtB;AAAA,SAGA,WAAW,eAAe,QAAQ,UAClC,qBAAC,SAAI,WAAU,qCACZ;AAAA,qBAAW,eAAe,QACzB,oBAAC,UAAK,WAAU,yFACb,qBAAW,YAAY,eAAe,GACzC;AAAA,UAED,SACC,qBAAC,UAAK,WAAU,sHACd;AAAA,gCAAC,gBAAa,QAAQ,MAAM,QAAQ,MAAM,IAAI;AAAA,YAC7C,MAAM;AAAA,aACT;AAAA,WAEJ;AAAA,SAEJ;AAAA,OACF,GACF;AAAA,KACF;AAEJ;AAEO,SAAS,yBAAyB;AACvC,SACE,oBAAC,SAAI,WAAU,sDACb,+BAAC,SAAI,WAAU,0DACb;AAAA,wBAAC,SAAI,WAAU,2CAA0C;AAAA,IACzD,qBAAC,SAAI,WAAU,gDACb;AAAA,0BAAC,SAAI,WAAU,6DAA4D;AAAA,MAC3E,oBAAC,SAAI,WAAU,6DAA4D;AAAA,OAC7E;AAAA,KACF,GACF;AAEJ;","names":[]}
@@ -38,7 +38,6 @@ var import_swr = __toESM(require("swr"), 1);
38
38
  var import_lucide_react = require("lucide-react");
39
39
  var import_button = require("./button.js");
40
40
  var import_dialog = require("./dialog.js");
41
- var import_select = require("./select.js");
42
41
  var import_help_icon = require("./help-icon.js");
43
42
  var import_input = require("./input.js");
44
43
  var import_result_thumbnail = require("./result-thumbnail.js");
@@ -190,9 +189,10 @@ function CollectionsPage() {
190
189
  }, [collections, isLoading, page]);
191
190
  const hasMore = meta?.total != null ? allCollections.length < meta.total : false;
192
191
  const isInitialLoading = isLoading && allCollections.length === 0;
193
- const activeFilters = [!hideEmpty].filter(Boolean).length;
192
+ const activeFilters = [!hideEmpty, sort !== "recent"].filter(Boolean).length;
194
193
  const resetAll = () => {
195
194
  setHideEmpty(true);
195
+ setSort("recent");
196
196
  };
197
197
  const handleServiceChange = (val) => {
198
198
  setService(val);
@@ -215,30 +215,21 @@ function CollectionsPage() {
215
215
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-3", children: [
216
216
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
217
217
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollectionSearch, {}),
218
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2 sm:ml-auto", children: [
219
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_select.Select, { value: sort, onValueChange: (v) => setSort(v), children: [
220
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_select.SelectTrigger, { className: "h-9 w-auto gap-1.5 text-xs", "aria-label": "Sort collections", children: [
221
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowDownUp, { className: "h-3.5 w-3.5 text-muted-foreground" }),
222
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectValue, {})
223
- ] }),
224
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectContent, { children: SORT_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectItem, { value: opt.value, className: "text-xs", children: opt.label }, opt.value)) })
225
- ] }),
226
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
227
- "button",
228
- {
229
- onClick: () => setFiltersOpen(true),
230
- className: (0, import_cn.cn)(
231
- "relative flex items-center gap-1.5 h-9 px-3 rounded-lg border text-xs font-medium transition-colors",
232
- activeFilters > 0 || service !== void 0 ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:border-primary/50 hover:text-foreground"
233
- ),
234
- children: [
235
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.SlidersHorizontal, { className: "h-3.5 w-3.5" }),
236
- "Filters",
237
- (activeFilters > 0 || service !== void 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex h-4 w-4 items-center justify-center rounded-full bg-primary text-2xs font-bold text-primary-foreground", children: activeFilters + (service !== void 0 ? 1 : 0) })
238
- ]
239
- }
240
- )
241
- ] })
218
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex items-center gap-2 sm:ml-auto", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
219
+ "button",
220
+ {
221
+ onClick: () => setFiltersOpen(true),
222
+ "aria-label": "Filters",
223
+ className: (0, import_cn.cn)(
224
+ "relative flex items-center gap-1.5 h-9 px-3 rounded-lg border text-xs font-medium transition-colors",
225
+ activeFilters > 0 || service !== void 0 ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:border-primary/50 hover:text-foreground"
226
+ ),
227
+ children: [
228
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.SlidersHorizontal, { className: "h-3.5 w-3.5" }),
229
+ (activeFilters > 0 || service !== void 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex h-4 w-4 items-center justify-center rounded-full bg-primary text-2xs font-bold text-primary-foreground", children: activeFilters + (service !== void 0 ? 1 : 0) })
230
+ ]
231
+ }
232
+ ) })
242
233
  ] }),
243
234
  (service !== void 0 || !hideEmpty) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
244
235
  service !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary", children: [
@@ -264,6 +255,21 @@ function CollectionsPage() {
264
255
  }, children: "Clear all" })
265
256
  ] }),
266
257
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 overflow-y-auto px-5 py-4 space-y-5", children: [
258
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
259
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-2xs font-semibold text-muted-foreground", children: "Sort by" }),
260
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-wrap gap-1.5", children: SORT_OPTIONS.map(({ label, value }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
261
+ "button",
262
+ {
263
+ onClick: () => setSort(value),
264
+ className: (0, import_cn.cn)(
265
+ "flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap",
266
+ sort === value ? "border-primary bg-primary/10 text-primary font-medium" : "border-border text-muted-foreground hover:border-primary/50"
267
+ ),
268
+ children: label
269
+ },
270
+ value
271
+ )) })
272
+ ] }),
267
273
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
268
274
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-2xs font-semibold text-muted-foreground", children: "Source" }),
269
275
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-wrap gap-1.5", children: SERVICE_TABS.map(({ label, value }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/collections-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useRef } from \"react\";\nimport useSWR from \"swr\";\nimport { Layers, Eye, SlidersHorizontal, Award, Package, ArrowDownUp, Search, X } from \"lucide-react\";\nimport { Button } from \"./button.js\";\nimport { Dialog, DialogContent, DialogTitle } from \"./dialog.js\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"./select.js\";\nimport { HelpIcon } from \"./help-icon.js\";\nimport { Input } from \"./input.js\";\nimport { ResultThumbnail } from \"./result-thumbnail.js\";\nimport Link from \"./link.js\";\nimport { useRouter } from \"./router.js\";\nimport { PageContainer } from \"./page-container.js\";\nimport { CollectionCard, CollectionCardSkeleton } from \"./collection-card.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { useCollections, type CollectionSort } from \"../utils/use-collections.js\";\nimport { useMedialaneClient } from \"../utils/use-medialane-client.js\";\nimport { SEARCH_MIN_LENGTH, useSearch } from \"../utils/use-search.js\";\nimport { collectionHref, type ApiCollection } from \"@medialane/sdk\";\n\nconst PAGE_SIZE = 25;\n\nconst SORT_OPTIONS: { label: string; value: CollectionSort }[] = [\n { label: \"Recent\", value: \"recent\" },\n { label: \"Most assets\", value: \"supply\" },\n { label: \"Top volume\", value: \"volume\" },\n { label: \"Floor ↑\", value: \"floor\" },\n { label: \"A → Z\", value: \"name\" },\n];\n\nconst SERVICE_TABS = [\n { label: \"All\", value: undefined },\n { label: \"POP Events\", value: \"pop-protocol\" },\n { label: \"Drops\", value: \"drop-collection\" },\n] as const;\n\nfunction useStandardCounts() {\n const client = useMedialaneClient();\n const { data } = useSWR(\n \"collection-standard-counts\",\n async () => {\n const [single, multi] = await Promise.all(\n [\"ERC721\", \"ERC1155\"].map((standard) =>\n client.api.collections.list({ standard, hideEmpty: true, limit: 1 })\n )\n );\n return { single: single.meta?.total, multi: multi.meta?.total };\n },\n { revalidateOnFocus: false, dedupingInterval: 60_000 }\n );\n return data ?? null;\n}\n\nfunction CollectionSearch() {\n const router = useRouter();\n const [value, setValue] = useState(\"\");\n const [query, setQuery] = useState(\"\");\n const [open, setOpen] = useState(false);\n const { results } = useSearch(query, { limit: 6 });\n const matches = results?.collections ?? [];\n\n useEffect(() => {\n const timer = setTimeout(() => setQuery(value), 300);\n return () => clearTimeout(timer);\n }, [value]);\n\n const clear = () => {\n setValue(\"\");\n setQuery(\"\");\n setOpen(false);\n };\n\n return (\n <div className=\"relative w-full sm:max-w-sm sm:flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n className=\"h-9 pl-9 pr-9 text-sm\"\n placeholder=\"Search collections\"\n aria-label=\"Search collections\"\n value={value}\n onChange={(e) => { setValue(e.target.value); setOpen(true); }}\n onFocus={() => setOpen(true)}\n onBlur={() => setTimeout(() => setOpen(false), 200)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && value.trim().length >= SEARCH_MIN_LENGTH) {\n router.push(`/search?q=${encodeURIComponent(value.trim())}`);\n }\n }}\n />\n {value && (\n <button\n aria-label=\"Clear search\"\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground\"\n onClick={clear}\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n )}\n {open && matches.length > 0 && (\n <div className=\"absolute left-0 right-0 top-full z-50 mt-1 overflow-hidden rounded-xl border border-border bg-popover shadow-lg\">\n {matches.map((col) => {\n const label = col.name ?? \"Untitled\";\n return (\n <Link\n key={col.contractAddress}\n href={collectionHref(\"STARKNET\", col.contractAddress)}\n className=\"flex items-center gap-3 px-3 py-2.5 transition-colors hover:bg-muted/50\"\n >\n <ResultThumbnail src={col.image} label={label} />\n <span className=\"truncate text-sm font-medium\">{label}</span>\n </Link>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\nexport function CollectionsPage() {\n const counts = useStandardCounts();\n const [sort, setSort] = useState<CollectionSort>(\"recent\");\n const [hideEmpty, setHideEmpty] = useState(true);\n const [service, setService] = useState<string | undefined>(undefined);\n const [filtersOpen, setFiltersOpen] = useState(false);\n const [page, setPage] = useState(1);\n const [allCollections, setAllCollections] = useState<ApiCollection[]>([]);\n\n const { collections, meta, isLoading } = useCollections(\n page,\n PAGE_SIZE,\n undefined,\n sort,\n service === \"pop-protocol\" || service === \"drop-collection\" ? false : hideEmpty,\n service,\n \"ERC721,ERC1155\"\n );\n\n const { collections: featuredCollections, isLoading: featuredLoading } = useCollections(\n 1,\n 10,\n true,\n \"recent\",\n true,\n undefined,\n \"ERC721,ERC1155\"\n );\n\n const prevFilters = useRef({ sort, hideEmpty, service });\n useEffect(() => {\n const f = prevFilters.current;\n if (f.sort !== sort || f.hideEmpty !== hideEmpty || f.service !== service) {\n prevFilters.current = { sort, hideEmpty, service };\n setPage(1);\n setAllCollections([]);\n }\n }, [sort, hideEmpty, service]);\n\n useEffect(() => {\n if (isLoading || collections.length === 0) return;\n setAllCollections((prev) => {\n const ids = new Set(prev.map((c) => c.contractAddress));\n const next = collections.filter((c) => !ids.has(c.contractAddress));\n return page === 1 ? collections : [...prev, ...next];\n });\n }, [collections, isLoading, page]);\n\n const hasMore = meta?.total != null ? allCollections.length < meta.total : false;\n const isInitialLoading = isLoading && allCollections.length === 0;\n\n const activeFilters = [!hideEmpty].filter(Boolean).length;\n\n const resetAll = () => {\n setHideEmpty(true);\n };\n\n const handleServiceChange = (val: string | undefined) => {\n setService(val);\n };\n\n return (\n <PageContainer className=\"box-border max-w-full pt-14 pb-8 space-y-8\">\n\n <div className=\"space-y-2 pt-8\">\n\n <h1 className=\"text-3xl font-bold\">Onchain Collections</h1>\n <div className=\"flex flex-wrap items-center gap-2 mt-1\">\n {counts?.single != null && counts.multi != null && (\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm\">\n <span className=\"font-bold tabular-nums\">{(counts.single + counts.multi).toLocaleString()}</span>\n <span className=\"text-muted-foreground\">Collections</span>\n </div>\n )}\n {counts?.multi != null && (\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm\">\n <span className=\"font-bold tabular-nums\">{counts.multi.toLocaleString()}</span>\n <span className=\"text-muted-foreground\">Multi editions</span>\n </div>\n )}\n </div>\n </div>\n\n {(featuredLoading || featuredCollections.length > 0) && (\n <div className=\"grid grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-5\">\n {featuredLoading\n ? Array.from({ length: 10 }).map((_, i) => <CollectionCardSkeleton key={i} />)\n : featuredCollections.map((col) => (\n <CollectionCard key={col.contractAddress} collection={col} />\n ))}\n </div>\n )}\n\n <div className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <CollectionSearch />\n <div className=\"flex items-center gap-2 sm:ml-auto\">\n <Select value={sort} onValueChange={(v) => setSort(v as CollectionSort)}>\n <SelectTrigger className=\"h-9 w-auto gap-1.5 text-xs\" aria-label=\"Sort collections\">\n <ArrowDownUp className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SORT_OPTIONS.map((opt) => (\n <SelectItem key={opt.value} value={opt.value} className=\"text-xs\">{opt.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n <button\n onClick={() => setFiltersOpen(true)}\n className={cn(\n \"relative flex items-center gap-1.5 h-9 px-3 rounded-lg border text-xs font-medium transition-colors\",\n activeFilters > 0 || service !== undefined\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50 hover:text-foreground\"\n )}\n >\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n Filters\n {(activeFilters > 0 || service !== undefined) && (\n <span className=\"flex h-4 w-4 items-center justify-center rounded-full bg-primary text-2xs font-bold text-primary-foreground\">\n {activeFilters + (service !== undefined ? 1 : 0)}\n </span>\n )}\n </button>\n </div>\n </div>\n {(service !== undefined || !hideEmpty) && (\n <div className=\"flex flex-wrap items-center gap-2\">\n {service !== undefined && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n {service === \"drop-collection\" ? <Package className=\"h-3 w-3\" /> : <Award className=\"h-3 w-3\" />}\n {SERVICE_TABS.find((t) => t.value === service)?.label}\n <button onClick={() => setService(undefined)} className=\"ml-0.5 hover:text-primary/60\" aria-label=\"Remove source filter\">×</button>\n </span>\n )}\n {!hideEmpty && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n Show empty\n <button onClick={() => setHideEmpty(true)} className=\"ml-0.5 hover:text-primary/60\" aria-label=\"Remove show empty filter\">×</button>\n </span>\n )}\n </div>\n )}\n </div>\n\n <Dialog open={filtersOpen} onOpenChange={setFiltersOpen}>\n <DialogContent className=\"w-full max-w-sm sm:max-w-md p-0 overflow-hidden gap-0 flex flex-col max-h-[85svh]\">\n\n <div className=\"flex items-center justify-between px-5 py-4 border-b border-border/60 pr-12\">\n <DialogTitle className=\"text-base font-bold flex items-center gap-2\">\n <SlidersHorizontal className=\"h-4 w-4 text-primary\" />\n Filters\n </DialogTitle>\n {(activeFilters > 0 || service !== undefined) && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 text-xs text-muted-foreground\" onClick={() => { resetAll(); setService(undefined); }}>\n Clear all\n </Button>\n )}\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-5 py-4 space-y-5\">\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Source</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {SERVICE_TABS.map(({ label, value }) => (\n <button\n key={label}\n onClick={() => handleServiceChange(value)}\n className={cn(\n \"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap\",\n service === value\n ? \"border-primary bg-primary/10 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n {value === \"pop-protocol\" && <Award className=\"h-3 w-3\" />}\n {value === \"drop-collection\" && <Package className=\"h-3 w-3\" />}\n {label}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Show</p>\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setHideEmpty((v) => !v)}\n className={cn(\n \"flex flex-1 items-center gap-2 text-sm px-3 py-2 rounded-lg border transition-colors text-left\",\n !hideEmpty\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n <Eye className=\"h-4 w-4 shrink-0\" />\n Show empty collections\n </button>\n <HelpIcon content=\"Include collections with no minted assets yet — hidden by default to keep the feed clean\" side=\"left\" />\n </div>\n </div>\n </div>\n\n </div>\n\n <div className=\"px-5 py-3 border-t border-border/60\">\n <Button className=\"w-full\" onClick={() => setFiltersOpen(false)}>\n Show results\n </Button>\n </div>\n\n </DialogContent>\n </Dialog>\n\n {isInitialLoading ? (\n <div className=\"grid grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-5\">\n {Array.from({ length: 10 }).map((_, i) => <CollectionCardSkeleton key={i} />)}\n </div>\n ) : allCollections.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-24 gap-4 text-center\">\n <Layers className=\"h-12 w-12 text-muted-foreground/30\" />\n <p className=\"text-2xl font-bold\">No collections found</p>\n <p className=\"text-muted-foreground max-w-sm\">\n {hideEmpty\n ? \"No collections with assets yet.\"\n : \"Deploy the first collection on Medialane.\"}\n </p>\n {activeFilters > 0 && (\n <Button variant=\"outline\" size=\"sm\" onClick={resetAll}>\n Clear filters\n </Button>\n )}\n </div>\n ) : (\n <div className=\"space-y-6\">\n <div className=\"grid grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-5\">\n {allCollections.map((col) => (\n <CollectionCard key={col.contractAddress} collection={col} />\n ))}\n </div>\n\n <LoadMoreSentinel\n hasMore={hasMore}\n isLoading={isLoading}\n onLoadMore={() => setPage((p) => p + 1)}\n />\n </div>\n )}\n </PageContainer>\n );\n}\n"],"mappings":"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","names":["useSWR","Link"]}
1
+ {"version":3,"sources":["../../src/components/collections-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useRef } from \"react\";\nimport useSWR from \"swr\";\nimport { Layers, Eye, SlidersHorizontal, Award, Package, Search, X } from \"lucide-react\";\nimport { Button } from \"./button.js\";\nimport { Dialog, DialogContent, DialogTitle } from \"./dialog.js\";\nimport { HelpIcon } from \"./help-icon.js\";\nimport { Input } from \"./input.js\";\nimport { ResultThumbnail } from \"./result-thumbnail.js\";\nimport Link from \"./link.js\";\nimport { useRouter } from \"./router.js\";\nimport { PageContainer } from \"./page-container.js\";\nimport { CollectionCard, CollectionCardSkeleton } from \"./collection-card.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { useCollections, type CollectionSort } from \"../utils/use-collections.js\";\nimport { useMedialaneClient } from \"../utils/use-medialane-client.js\";\nimport { SEARCH_MIN_LENGTH, useSearch } from \"../utils/use-search.js\";\nimport { collectionHref, type ApiCollection } from \"@medialane/sdk\";\n\nconst PAGE_SIZE = 25;\n\nconst SORT_OPTIONS: { label: string; value: CollectionSort }[] = [\n { label: \"Recent\", value: \"recent\" },\n { label: \"Most assets\", value: \"supply\" },\n { label: \"Top volume\", value: \"volume\" },\n { label: \"Floor ↑\", value: \"floor\" },\n { label: \"A → Z\", value: \"name\" },\n];\n\nconst SERVICE_TABS = [\n { label: \"All\", value: undefined },\n { label: \"POP Events\", value: \"pop-protocol\" },\n { label: \"Drops\", value: \"drop-collection\" },\n] as const;\n\nfunction useStandardCounts() {\n const client = useMedialaneClient();\n const { data } = useSWR(\n \"collection-standard-counts\",\n async () => {\n const [single, multi] = await Promise.all(\n [\"ERC721\", \"ERC1155\"].map((standard) =>\n client.api.collections.list({ standard, hideEmpty: true, limit: 1 })\n )\n );\n return { single: single.meta?.total, multi: multi.meta?.total };\n },\n { revalidateOnFocus: false, dedupingInterval: 60_000 }\n );\n return data ?? null;\n}\n\nfunction CollectionSearch() {\n const router = useRouter();\n const [value, setValue] = useState(\"\");\n const [query, setQuery] = useState(\"\");\n const [open, setOpen] = useState(false);\n const { results } = useSearch(query, { limit: 6 });\n const matches = results?.collections ?? [];\n\n useEffect(() => {\n const timer = setTimeout(() => setQuery(value), 300);\n return () => clearTimeout(timer);\n }, [value]);\n\n const clear = () => {\n setValue(\"\");\n setQuery(\"\");\n setOpen(false);\n };\n\n return (\n <div className=\"relative w-full sm:max-w-sm sm:flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n className=\"h-9 pl-9 pr-9 text-sm\"\n placeholder=\"Search collections\"\n aria-label=\"Search collections\"\n value={value}\n onChange={(e) => { setValue(e.target.value); setOpen(true); }}\n onFocus={() => setOpen(true)}\n onBlur={() => setTimeout(() => setOpen(false), 200)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && value.trim().length >= SEARCH_MIN_LENGTH) {\n router.push(`/search?q=${encodeURIComponent(value.trim())}`);\n }\n }}\n />\n {value && (\n <button\n aria-label=\"Clear search\"\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground\"\n onClick={clear}\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n )}\n {open && matches.length > 0 && (\n <div className=\"absolute left-0 right-0 top-full z-50 mt-1 overflow-hidden rounded-xl border border-border bg-popover shadow-lg\">\n {matches.map((col) => {\n const label = col.name ?? \"Untitled\";\n return (\n <Link\n key={col.contractAddress}\n href={collectionHref(\"STARKNET\", col.contractAddress)}\n className=\"flex items-center gap-3 px-3 py-2.5 transition-colors hover:bg-muted/50\"\n >\n <ResultThumbnail src={col.image} label={label} />\n <span className=\"truncate text-sm font-medium\">{label}</span>\n </Link>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\nexport function CollectionsPage() {\n const counts = useStandardCounts();\n const [sort, setSort] = useState<CollectionSort>(\"recent\");\n const [hideEmpty, setHideEmpty] = useState(true);\n const [service, setService] = useState<string | undefined>(undefined);\n const [filtersOpen, setFiltersOpen] = useState(false);\n const [page, setPage] = useState(1);\n const [allCollections, setAllCollections] = useState<ApiCollection[]>([]);\n\n const { collections, meta, isLoading } = useCollections(\n page,\n PAGE_SIZE,\n undefined,\n sort,\n service === \"pop-protocol\" || service === \"drop-collection\" ? false : hideEmpty,\n service,\n \"ERC721,ERC1155\"\n );\n\n const { collections: featuredCollections, isLoading: featuredLoading } = useCollections(\n 1,\n 10,\n true,\n \"recent\",\n true,\n undefined,\n \"ERC721,ERC1155\"\n );\n\n const prevFilters = useRef({ sort, hideEmpty, service });\n useEffect(() => {\n const f = prevFilters.current;\n if (f.sort !== sort || f.hideEmpty !== hideEmpty || f.service !== service) {\n prevFilters.current = { sort, hideEmpty, service };\n setPage(1);\n setAllCollections([]);\n }\n }, [sort, hideEmpty, service]);\n\n useEffect(() => {\n if (isLoading || collections.length === 0) return;\n setAllCollections((prev) => {\n const ids = new Set(prev.map((c) => c.contractAddress));\n const next = collections.filter((c) => !ids.has(c.contractAddress));\n return page === 1 ? collections : [...prev, ...next];\n });\n }, [collections, isLoading, page]);\n\n const hasMore = meta?.total != null ? allCollections.length < meta.total : false;\n const isInitialLoading = isLoading && allCollections.length === 0;\n\n const activeFilters = [!hideEmpty, sort !== \"recent\"].filter(Boolean).length;\n\n const resetAll = () => {\n setHideEmpty(true);\n setSort(\"recent\");\n };\n\n const handleServiceChange = (val: string | undefined) => {\n setService(val);\n };\n\n return (\n <PageContainer className=\"box-border max-w-full pt-14 pb-8 space-y-8\">\n\n <div className=\"space-y-2 pt-8\">\n\n <h1 className=\"text-3xl font-bold\">Onchain Collections</h1>\n <div className=\"flex flex-wrap items-center gap-2 mt-1\">\n {counts?.single != null && counts.multi != null && (\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm\">\n <span className=\"font-bold tabular-nums\">{(counts.single + counts.multi).toLocaleString()}</span>\n <span className=\"text-muted-foreground\">Collections</span>\n </div>\n )}\n {counts?.multi != null && (\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm\">\n <span className=\"font-bold tabular-nums\">{counts.multi.toLocaleString()}</span>\n <span className=\"text-muted-foreground\">Multi editions</span>\n </div>\n )}\n </div>\n </div>\n\n {(featuredLoading || featuredCollections.length > 0) && (\n <div className=\"grid grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-5\">\n {featuredLoading\n ? Array.from({ length: 10 }).map((_, i) => <CollectionCardSkeleton key={i} />)\n : featuredCollections.map((col) => (\n <CollectionCard key={col.contractAddress} collection={col} />\n ))}\n </div>\n )}\n\n <div className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <CollectionSearch />\n <div className=\"flex items-center gap-2 sm:ml-auto\">\n <button\n onClick={() => setFiltersOpen(true)}\n aria-label=\"Filters\"\n className={cn(\n \"relative flex items-center gap-1.5 h-9 px-3 rounded-lg border text-xs font-medium transition-colors\",\n activeFilters > 0 || service !== undefined\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50 hover:text-foreground\"\n )}\n >\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n {(activeFilters > 0 || service !== undefined) && (\n <span className=\"flex h-4 w-4 items-center justify-center rounded-full bg-primary text-2xs font-bold text-primary-foreground\">\n {activeFilters + (service !== undefined ? 1 : 0)}\n </span>\n )}\n </button>\n </div>\n </div>\n {(service !== undefined || !hideEmpty) && (\n <div className=\"flex flex-wrap items-center gap-2\">\n {service !== undefined && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n {service === \"drop-collection\" ? <Package className=\"h-3 w-3\" /> : <Award className=\"h-3 w-3\" />}\n {SERVICE_TABS.find((t) => t.value === service)?.label}\n <button onClick={() => setService(undefined)} className=\"ml-0.5 hover:text-primary/60\" aria-label=\"Remove source filter\">×</button>\n </span>\n )}\n {!hideEmpty && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n Show empty\n <button onClick={() => setHideEmpty(true)} className=\"ml-0.5 hover:text-primary/60\" aria-label=\"Remove show empty filter\">×</button>\n </span>\n )}\n </div>\n )}\n </div>\n\n <Dialog open={filtersOpen} onOpenChange={setFiltersOpen}>\n <DialogContent className=\"w-full max-w-sm sm:max-w-md p-0 overflow-hidden gap-0 flex flex-col max-h-[85svh]\">\n\n <div className=\"flex items-center justify-between px-5 py-4 border-b border-border/60 pr-12\">\n <DialogTitle className=\"text-base font-bold flex items-center gap-2\">\n <SlidersHorizontal className=\"h-4 w-4 text-primary\" />\n Filters\n </DialogTitle>\n {(activeFilters > 0 || service !== undefined) && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 text-xs text-muted-foreground\" onClick={() => { resetAll(); setService(undefined); }}>\n Clear all\n </Button>\n )}\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-5 py-4 space-y-5\">\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Sort by</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {SORT_OPTIONS.map(({ label, value }) => (\n <button\n key={value}\n onClick={() => setSort(value)}\n className={cn(\n \"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap\",\n sort === value\n ? \"border-primary bg-primary/10 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n {label}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Source</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {SERVICE_TABS.map(({ label, value }) => (\n <button\n key={label}\n onClick={() => handleServiceChange(value)}\n className={cn(\n \"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap\",\n service === value\n ? \"border-primary bg-primary/10 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n {value === \"pop-protocol\" && <Award className=\"h-3 w-3\" />}\n {value === \"drop-collection\" && <Package className=\"h-3 w-3\" />}\n {label}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Show</p>\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setHideEmpty((v) => !v)}\n className={cn(\n \"flex flex-1 items-center gap-2 text-sm px-3 py-2 rounded-lg border transition-colors text-left\",\n !hideEmpty\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n <Eye className=\"h-4 w-4 shrink-0\" />\n Show empty collections\n </button>\n <HelpIcon content=\"Include collections with no minted assets yet — hidden by default to keep the feed clean\" side=\"left\" />\n </div>\n </div>\n </div>\n\n </div>\n\n <div className=\"px-5 py-3 border-t border-border/60\">\n <Button className=\"w-full\" onClick={() => setFiltersOpen(false)}>\n Show results\n </Button>\n </div>\n\n </DialogContent>\n </Dialog>\n\n {isInitialLoading ? (\n <div className=\"grid grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-5\">\n {Array.from({ length: 10 }).map((_, i) => <CollectionCardSkeleton key={i} />)}\n </div>\n ) : allCollections.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-24 gap-4 text-center\">\n <Layers className=\"h-12 w-12 text-muted-foreground/30\" />\n <p className=\"text-2xl font-bold\">No collections found</p>\n <p className=\"text-muted-foreground max-w-sm\">\n {hideEmpty\n ? \"No collections with assets yet.\"\n : \"Deploy the first collection on Medialane.\"}\n </p>\n {activeFilters > 0 && (\n <Button variant=\"outline\" size=\"sm\" onClick={resetAll}>\n Clear filters\n </Button>\n )}\n </div>\n ) : (\n <div className=\"space-y-6\">\n <div className=\"grid grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-5\">\n {allCollections.map((col) => (\n <CollectionCard key={col.contractAddress} collection={col} />\n ))}\n </div>\n\n <LoadMoreSentinel\n hasMore={hasMore}\n isLoading={isLoading}\n onLoadMore={() => setPage((p) => p + 1)}\n />\n </div>\n )}\n </PageContainer>\n );\n}\n"],"mappings":"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","names":["useSWR","Link"]}
@@ -2,10 +2,9 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useRef } from "react";
4
4
  import useSWR from "swr";
5
- import { Layers, Eye, SlidersHorizontal, Award, Package, ArrowDownUp, Search, X } from "lucide-react";
5
+ import { Layers, Eye, SlidersHorizontal, Award, Package, Search, X } from "lucide-react";
6
6
  import { Button } from "./button.js";
7
7
  import { Dialog, DialogContent, DialogTitle } from "./dialog.js";
8
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./select.js";
9
8
  import { HelpIcon } from "./help-icon.js";
10
9
  import { Input } from "./input.js";
11
10
  import { ResultThumbnail } from "./result-thumbnail.js";
@@ -157,9 +156,10 @@ function CollectionsPage() {
157
156
  }, [collections, isLoading, page]);
158
157
  const hasMore = meta?.total != null ? allCollections.length < meta.total : false;
159
158
  const isInitialLoading = isLoading && allCollections.length === 0;
160
- const activeFilters = [!hideEmpty].filter(Boolean).length;
159
+ const activeFilters = [!hideEmpty, sort !== "recent"].filter(Boolean).length;
161
160
  const resetAll = () => {
162
161
  setHideEmpty(true);
162
+ setSort("recent");
163
163
  };
164
164
  const handleServiceChange = (val) => {
165
165
  setService(val);
@@ -182,30 +182,21 @@ function CollectionsPage() {
182
182
  /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
183
183
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
184
184
  /* @__PURE__ */ jsx(CollectionSearch, {}),
185
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 sm:ml-auto", children: [
186
- /* @__PURE__ */ jsxs(Select, { value: sort, onValueChange: (v) => setSort(v), children: [
187
- /* @__PURE__ */ jsxs(SelectTrigger, { className: "h-9 w-auto gap-1.5 text-xs", "aria-label": "Sort collections", children: [
188
- /* @__PURE__ */ jsx(ArrowDownUp, { className: "h-3.5 w-3.5 text-muted-foreground" }),
189
- /* @__PURE__ */ jsx(SelectValue, {})
190
- ] }),
191
- /* @__PURE__ */ jsx(SelectContent, { children: SORT_OPTIONS.map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt.value, className: "text-xs", children: opt.label }, opt.value)) })
192
- ] }),
193
- /* @__PURE__ */ jsxs(
194
- "button",
195
- {
196
- onClick: () => setFiltersOpen(true),
197
- className: cn(
198
- "relative flex items-center gap-1.5 h-9 px-3 rounded-lg border text-xs font-medium transition-colors",
199
- activeFilters > 0 || service !== void 0 ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:border-primary/50 hover:text-foreground"
200
- ),
201
- children: [
202
- /* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-3.5 w-3.5" }),
203
- "Filters",
204
- (activeFilters > 0 || service !== void 0) && /* @__PURE__ */ jsx("span", { className: "flex h-4 w-4 items-center justify-center rounded-full bg-primary text-2xs font-bold text-primary-foreground", children: activeFilters + (service !== void 0 ? 1 : 0) })
205
- ]
206
- }
207
- )
208
- ] })
185
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 sm:ml-auto", children: /* @__PURE__ */ jsxs(
186
+ "button",
187
+ {
188
+ onClick: () => setFiltersOpen(true),
189
+ "aria-label": "Filters",
190
+ className: cn(
191
+ "relative flex items-center gap-1.5 h-9 px-3 rounded-lg border text-xs font-medium transition-colors",
192
+ activeFilters > 0 || service !== void 0 ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:border-primary/50 hover:text-foreground"
193
+ ),
194
+ children: [
195
+ /* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-3.5 w-3.5" }),
196
+ (activeFilters > 0 || service !== void 0) && /* @__PURE__ */ jsx("span", { className: "flex h-4 w-4 items-center justify-center rounded-full bg-primary text-2xs font-bold text-primary-foreground", children: activeFilters + (service !== void 0 ? 1 : 0) })
197
+ ]
198
+ }
199
+ ) })
209
200
  ] }),
210
201
  (service !== void 0 || !hideEmpty) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
211
202
  service !== void 0 && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary", children: [
@@ -231,6 +222,21 @@ function CollectionsPage() {
231
222
  }, children: "Clear all" })
232
223
  ] }),
233
224
  /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-5 py-4 space-y-5", children: [
225
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
226
+ /* @__PURE__ */ jsx("p", { className: "text-2xs font-semibold text-muted-foreground", children: "Sort by" }),
227
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: SORT_OPTIONS.map(({ label, value }) => /* @__PURE__ */ jsx(
228
+ "button",
229
+ {
230
+ onClick: () => setSort(value),
231
+ className: cn(
232
+ "flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap",
233
+ sort === value ? "border-primary bg-primary/10 text-primary font-medium" : "border-border text-muted-foreground hover:border-primary/50"
234
+ ),
235
+ children: label
236
+ },
237
+ value
238
+ )) })
239
+ ] }),
234
240
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
235
241
  /* @__PURE__ */ jsx("p", { className: "text-2xs font-semibold text-muted-foreground", children: "Source" }),
236
242
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: SERVICE_TABS.map(({ label, value }) => /* @__PURE__ */ jsxs(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/collections-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useRef } from \"react\";\nimport useSWR from \"swr\";\nimport { Layers, Eye, SlidersHorizontal, Award, Package, ArrowDownUp, Search, X } from \"lucide-react\";\nimport { Button } from \"./button.js\";\nimport { Dialog, DialogContent, DialogTitle } from \"./dialog.js\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"./select.js\";\nimport { HelpIcon } from \"./help-icon.js\";\nimport { Input } from \"./input.js\";\nimport { ResultThumbnail } from \"./result-thumbnail.js\";\nimport Link from \"./link.js\";\nimport { useRouter } from \"./router.js\";\nimport { PageContainer } from \"./page-container.js\";\nimport { CollectionCard, CollectionCardSkeleton } from \"./collection-card.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { useCollections, type CollectionSort } from \"../utils/use-collections.js\";\nimport { useMedialaneClient } from \"../utils/use-medialane-client.js\";\nimport { SEARCH_MIN_LENGTH, useSearch } from \"../utils/use-search.js\";\nimport { collectionHref, type ApiCollection } from \"@medialane/sdk\";\n\nconst PAGE_SIZE = 25;\n\nconst SORT_OPTIONS: { label: string; value: CollectionSort }[] = [\n { label: \"Recent\", value: \"recent\" },\n { label: \"Most assets\", value: \"supply\" },\n { label: \"Top volume\", value: \"volume\" },\n { label: \"Floor ↑\", value: \"floor\" },\n { label: \"A → Z\", value: \"name\" },\n];\n\nconst SERVICE_TABS = [\n { label: \"All\", value: undefined },\n { label: \"POP Events\", value: \"pop-protocol\" },\n { label: \"Drops\", value: \"drop-collection\" },\n] as const;\n\nfunction useStandardCounts() {\n const client = useMedialaneClient();\n const { data } = useSWR(\n \"collection-standard-counts\",\n async () => {\n const [single, multi] = await Promise.all(\n [\"ERC721\", \"ERC1155\"].map((standard) =>\n client.api.collections.list({ standard, hideEmpty: true, limit: 1 })\n )\n );\n return { single: single.meta?.total, multi: multi.meta?.total };\n },\n { revalidateOnFocus: false, dedupingInterval: 60_000 }\n );\n return data ?? null;\n}\n\nfunction CollectionSearch() {\n const router = useRouter();\n const [value, setValue] = useState(\"\");\n const [query, setQuery] = useState(\"\");\n const [open, setOpen] = useState(false);\n const { results } = useSearch(query, { limit: 6 });\n const matches = results?.collections ?? [];\n\n useEffect(() => {\n const timer = setTimeout(() => setQuery(value), 300);\n return () => clearTimeout(timer);\n }, [value]);\n\n const clear = () => {\n setValue(\"\");\n setQuery(\"\");\n setOpen(false);\n };\n\n return (\n <div className=\"relative w-full sm:max-w-sm sm:flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n className=\"h-9 pl-9 pr-9 text-sm\"\n placeholder=\"Search collections\"\n aria-label=\"Search collections\"\n value={value}\n onChange={(e) => { setValue(e.target.value); setOpen(true); }}\n onFocus={() => setOpen(true)}\n onBlur={() => setTimeout(() => setOpen(false), 200)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && value.trim().length >= SEARCH_MIN_LENGTH) {\n router.push(`/search?q=${encodeURIComponent(value.trim())}`);\n }\n }}\n />\n {value && (\n <button\n aria-label=\"Clear search\"\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground\"\n onClick={clear}\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n )}\n {open && matches.length > 0 && (\n <div className=\"absolute left-0 right-0 top-full z-50 mt-1 overflow-hidden rounded-xl border border-border bg-popover shadow-lg\">\n {matches.map((col) => {\n const label = col.name ?? \"Untitled\";\n return (\n <Link\n key={col.contractAddress}\n href={collectionHref(\"STARKNET\", col.contractAddress)}\n className=\"flex items-center gap-3 px-3 py-2.5 transition-colors hover:bg-muted/50\"\n >\n <ResultThumbnail src={col.image} label={label} />\n <span className=\"truncate text-sm font-medium\">{label}</span>\n </Link>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\nexport function CollectionsPage() {\n const counts = useStandardCounts();\n const [sort, setSort] = useState<CollectionSort>(\"recent\");\n const [hideEmpty, setHideEmpty] = useState(true);\n const [service, setService] = useState<string | undefined>(undefined);\n const [filtersOpen, setFiltersOpen] = useState(false);\n const [page, setPage] = useState(1);\n const [allCollections, setAllCollections] = useState<ApiCollection[]>([]);\n\n const { collections, meta, isLoading } = useCollections(\n page,\n PAGE_SIZE,\n undefined,\n sort,\n service === \"pop-protocol\" || service === \"drop-collection\" ? false : hideEmpty,\n service,\n \"ERC721,ERC1155\"\n );\n\n const { collections: featuredCollections, isLoading: featuredLoading } = useCollections(\n 1,\n 10,\n true,\n \"recent\",\n true,\n undefined,\n \"ERC721,ERC1155\"\n );\n\n const prevFilters = useRef({ sort, hideEmpty, service });\n useEffect(() => {\n const f = prevFilters.current;\n if (f.sort !== sort || f.hideEmpty !== hideEmpty || f.service !== service) {\n prevFilters.current = { sort, hideEmpty, service };\n setPage(1);\n setAllCollections([]);\n }\n }, [sort, hideEmpty, service]);\n\n useEffect(() => {\n if (isLoading || collections.length === 0) return;\n setAllCollections((prev) => {\n const ids = new Set(prev.map((c) => c.contractAddress));\n const next = collections.filter((c) => !ids.has(c.contractAddress));\n return page === 1 ? collections : [...prev, ...next];\n });\n }, [collections, isLoading, page]);\n\n const hasMore = meta?.total != null ? allCollections.length < meta.total : false;\n const isInitialLoading = isLoading && allCollections.length === 0;\n\n const activeFilters = [!hideEmpty].filter(Boolean).length;\n\n const resetAll = () => {\n setHideEmpty(true);\n };\n\n const handleServiceChange = (val: string | undefined) => {\n setService(val);\n };\n\n return (\n <PageContainer className=\"box-border max-w-full pt-14 pb-8 space-y-8\">\n\n <div className=\"space-y-2 pt-8\">\n\n <h1 className=\"text-3xl font-bold\">Onchain Collections</h1>\n <div className=\"flex flex-wrap items-center gap-2 mt-1\">\n {counts?.single != null && counts.multi != null && (\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm\">\n <span className=\"font-bold tabular-nums\">{(counts.single + counts.multi).toLocaleString()}</span>\n <span className=\"text-muted-foreground\">Collections</span>\n </div>\n )}\n {counts?.multi != null && (\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm\">\n <span className=\"font-bold tabular-nums\">{counts.multi.toLocaleString()}</span>\n <span className=\"text-muted-foreground\">Multi editions</span>\n </div>\n )}\n </div>\n </div>\n\n {(featuredLoading || featuredCollections.length > 0) && (\n <div className=\"grid grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-5\">\n {featuredLoading\n ? Array.from({ length: 10 }).map((_, i) => <CollectionCardSkeleton key={i} />)\n : featuredCollections.map((col) => (\n <CollectionCard key={col.contractAddress} collection={col} />\n ))}\n </div>\n )}\n\n <div className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <CollectionSearch />\n <div className=\"flex items-center gap-2 sm:ml-auto\">\n <Select value={sort} onValueChange={(v) => setSort(v as CollectionSort)}>\n <SelectTrigger className=\"h-9 w-auto gap-1.5 text-xs\" aria-label=\"Sort collections\">\n <ArrowDownUp className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SORT_OPTIONS.map((opt) => (\n <SelectItem key={opt.value} value={opt.value} className=\"text-xs\">{opt.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n <button\n onClick={() => setFiltersOpen(true)}\n className={cn(\n \"relative flex items-center gap-1.5 h-9 px-3 rounded-lg border text-xs font-medium transition-colors\",\n activeFilters > 0 || service !== undefined\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50 hover:text-foreground\"\n )}\n >\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n Filters\n {(activeFilters > 0 || service !== undefined) && (\n <span className=\"flex h-4 w-4 items-center justify-center rounded-full bg-primary text-2xs font-bold text-primary-foreground\">\n {activeFilters + (service !== undefined ? 1 : 0)}\n </span>\n )}\n </button>\n </div>\n </div>\n {(service !== undefined || !hideEmpty) && (\n <div className=\"flex flex-wrap items-center gap-2\">\n {service !== undefined && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n {service === \"drop-collection\" ? <Package className=\"h-3 w-3\" /> : <Award className=\"h-3 w-3\" />}\n {SERVICE_TABS.find((t) => t.value === service)?.label}\n <button onClick={() => setService(undefined)} className=\"ml-0.5 hover:text-primary/60\" aria-label=\"Remove source filter\">×</button>\n </span>\n )}\n {!hideEmpty && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n Show empty\n <button onClick={() => setHideEmpty(true)} className=\"ml-0.5 hover:text-primary/60\" aria-label=\"Remove show empty filter\">×</button>\n </span>\n )}\n </div>\n )}\n </div>\n\n <Dialog open={filtersOpen} onOpenChange={setFiltersOpen}>\n <DialogContent className=\"w-full max-w-sm sm:max-w-md p-0 overflow-hidden gap-0 flex flex-col max-h-[85svh]\">\n\n <div className=\"flex items-center justify-between px-5 py-4 border-b border-border/60 pr-12\">\n <DialogTitle className=\"text-base font-bold flex items-center gap-2\">\n <SlidersHorizontal className=\"h-4 w-4 text-primary\" />\n Filters\n </DialogTitle>\n {(activeFilters > 0 || service !== undefined) && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 text-xs text-muted-foreground\" onClick={() => { resetAll(); setService(undefined); }}>\n Clear all\n </Button>\n )}\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-5 py-4 space-y-5\">\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Source</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {SERVICE_TABS.map(({ label, value }) => (\n <button\n key={label}\n onClick={() => handleServiceChange(value)}\n className={cn(\n \"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap\",\n service === value\n ? \"border-primary bg-primary/10 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n {value === \"pop-protocol\" && <Award className=\"h-3 w-3\" />}\n {value === \"drop-collection\" && <Package className=\"h-3 w-3\" />}\n {label}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Show</p>\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setHideEmpty((v) => !v)}\n className={cn(\n \"flex flex-1 items-center gap-2 text-sm px-3 py-2 rounded-lg border transition-colors text-left\",\n !hideEmpty\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n <Eye className=\"h-4 w-4 shrink-0\" />\n Show empty collections\n </button>\n <HelpIcon content=\"Include collections with no minted assets yet — hidden by default to keep the feed clean\" side=\"left\" />\n </div>\n </div>\n </div>\n\n </div>\n\n <div className=\"px-5 py-3 border-t border-border/60\">\n <Button className=\"w-full\" onClick={() => setFiltersOpen(false)}>\n Show results\n </Button>\n </div>\n\n </DialogContent>\n </Dialog>\n\n {isInitialLoading ? (\n <div className=\"grid grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-5\">\n {Array.from({ length: 10 }).map((_, i) => <CollectionCardSkeleton key={i} />)}\n </div>\n ) : allCollections.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-24 gap-4 text-center\">\n <Layers className=\"h-12 w-12 text-muted-foreground/30\" />\n <p className=\"text-2xl font-bold\">No collections found</p>\n <p className=\"text-muted-foreground max-w-sm\">\n {hideEmpty\n ? \"No collections with assets yet.\"\n : \"Deploy the first collection on Medialane.\"}\n </p>\n {activeFilters > 0 && (\n <Button variant=\"outline\" size=\"sm\" onClick={resetAll}>\n Clear filters\n </Button>\n )}\n </div>\n ) : (\n <div className=\"space-y-6\">\n <div className=\"grid grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-5\">\n {allCollections.map((col) => (\n <CollectionCard key={col.contractAddress} collection={col} />\n ))}\n </div>\n\n <LoadMoreSentinel\n hasMore={hasMore}\n isLoading={isLoading}\n onLoadMore={() => setPage((p) => p + 1)}\n />\n </div>\n )}\n </PageContainer>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/collections-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useRef } from \"react\";\nimport useSWR from \"swr\";\nimport { Layers, Eye, SlidersHorizontal, Award, Package, Search, X } from \"lucide-react\";\nimport { Button } from \"./button.js\";\nimport { Dialog, DialogContent, DialogTitle } from \"./dialog.js\";\nimport { HelpIcon } from \"./help-icon.js\";\nimport { Input } from \"./input.js\";\nimport { ResultThumbnail } from \"./result-thumbnail.js\";\nimport Link from \"./link.js\";\nimport { useRouter } from \"./router.js\";\nimport { PageContainer } from \"./page-container.js\";\nimport { CollectionCard, CollectionCardSkeleton } from \"./collection-card.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { useCollections, type CollectionSort } from \"../utils/use-collections.js\";\nimport { useMedialaneClient } from \"../utils/use-medialane-client.js\";\nimport { SEARCH_MIN_LENGTH, useSearch } from \"../utils/use-search.js\";\nimport { collectionHref, type ApiCollection } from \"@medialane/sdk\";\n\nconst PAGE_SIZE = 25;\n\nconst SORT_OPTIONS: { label: string; value: CollectionSort }[] = [\n { label: \"Recent\", value: \"recent\" },\n { label: \"Most assets\", value: \"supply\" },\n { label: \"Top volume\", value: \"volume\" },\n { label: \"Floor ↑\", value: \"floor\" },\n { label: \"A → Z\", value: \"name\" },\n];\n\nconst SERVICE_TABS = [\n { label: \"All\", value: undefined },\n { label: \"POP Events\", value: \"pop-protocol\" },\n { label: \"Drops\", value: \"drop-collection\" },\n] as const;\n\nfunction useStandardCounts() {\n const client = useMedialaneClient();\n const { data } = useSWR(\n \"collection-standard-counts\",\n async () => {\n const [single, multi] = await Promise.all(\n [\"ERC721\", \"ERC1155\"].map((standard) =>\n client.api.collections.list({ standard, hideEmpty: true, limit: 1 })\n )\n );\n return { single: single.meta?.total, multi: multi.meta?.total };\n },\n { revalidateOnFocus: false, dedupingInterval: 60_000 }\n );\n return data ?? null;\n}\n\nfunction CollectionSearch() {\n const router = useRouter();\n const [value, setValue] = useState(\"\");\n const [query, setQuery] = useState(\"\");\n const [open, setOpen] = useState(false);\n const { results } = useSearch(query, { limit: 6 });\n const matches = results?.collections ?? [];\n\n useEffect(() => {\n const timer = setTimeout(() => setQuery(value), 300);\n return () => clearTimeout(timer);\n }, [value]);\n\n const clear = () => {\n setValue(\"\");\n setQuery(\"\");\n setOpen(false);\n };\n\n return (\n <div className=\"relative w-full sm:max-w-sm sm:flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n className=\"h-9 pl-9 pr-9 text-sm\"\n placeholder=\"Search collections\"\n aria-label=\"Search collections\"\n value={value}\n onChange={(e) => { setValue(e.target.value); setOpen(true); }}\n onFocus={() => setOpen(true)}\n onBlur={() => setTimeout(() => setOpen(false), 200)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && value.trim().length >= SEARCH_MIN_LENGTH) {\n router.push(`/search?q=${encodeURIComponent(value.trim())}`);\n }\n }}\n />\n {value && (\n <button\n aria-label=\"Clear search\"\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground\"\n onClick={clear}\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n )}\n {open && matches.length > 0 && (\n <div className=\"absolute left-0 right-0 top-full z-50 mt-1 overflow-hidden rounded-xl border border-border bg-popover shadow-lg\">\n {matches.map((col) => {\n const label = col.name ?? \"Untitled\";\n return (\n <Link\n key={col.contractAddress}\n href={collectionHref(\"STARKNET\", col.contractAddress)}\n className=\"flex items-center gap-3 px-3 py-2.5 transition-colors hover:bg-muted/50\"\n >\n <ResultThumbnail src={col.image} label={label} />\n <span className=\"truncate text-sm font-medium\">{label}</span>\n </Link>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\nexport function CollectionsPage() {\n const counts = useStandardCounts();\n const [sort, setSort] = useState<CollectionSort>(\"recent\");\n const [hideEmpty, setHideEmpty] = useState(true);\n const [service, setService] = useState<string | undefined>(undefined);\n const [filtersOpen, setFiltersOpen] = useState(false);\n const [page, setPage] = useState(1);\n const [allCollections, setAllCollections] = useState<ApiCollection[]>([]);\n\n const { collections, meta, isLoading } = useCollections(\n page,\n PAGE_SIZE,\n undefined,\n sort,\n service === \"pop-protocol\" || service === \"drop-collection\" ? false : hideEmpty,\n service,\n \"ERC721,ERC1155\"\n );\n\n const { collections: featuredCollections, isLoading: featuredLoading } = useCollections(\n 1,\n 10,\n true,\n \"recent\",\n true,\n undefined,\n \"ERC721,ERC1155\"\n );\n\n const prevFilters = useRef({ sort, hideEmpty, service });\n useEffect(() => {\n const f = prevFilters.current;\n if (f.sort !== sort || f.hideEmpty !== hideEmpty || f.service !== service) {\n prevFilters.current = { sort, hideEmpty, service };\n setPage(1);\n setAllCollections([]);\n }\n }, [sort, hideEmpty, service]);\n\n useEffect(() => {\n if (isLoading || collections.length === 0) return;\n setAllCollections((prev) => {\n const ids = new Set(prev.map((c) => c.contractAddress));\n const next = collections.filter((c) => !ids.has(c.contractAddress));\n return page === 1 ? collections : [...prev, ...next];\n });\n }, [collections, isLoading, page]);\n\n const hasMore = meta?.total != null ? allCollections.length < meta.total : false;\n const isInitialLoading = isLoading && allCollections.length === 0;\n\n const activeFilters = [!hideEmpty, sort !== \"recent\"].filter(Boolean).length;\n\n const resetAll = () => {\n setHideEmpty(true);\n setSort(\"recent\");\n };\n\n const handleServiceChange = (val: string | undefined) => {\n setService(val);\n };\n\n return (\n <PageContainer className=\"box-border max-w-full pt-14 pb-8 space-y-8\">\n\n <div className=\"space-y-2 pt-8\">\n\n <h1 className=\"text-3xl font-bold\">Onchain Collections</h1>\n <div className=\"flex flex-wrap items-center gap-2 mt-1\">\n {counts?.single != null && counts.multi != null && (\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm\">\n <span className=\"font-bold tabular-nums\">{(counts.single + counts.multi).toLocaleString()}</span>\n <span className=\"text-muted-foreground\">Collections</span>\n </div>\n )}\n {counts?.multi != null && (\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm\">\n <span className=\"font-bold tabular-nums\">{counts.multi.toLocaleString()}</span>\n <span className=\"text-muted-foreground\">Multi editions</span>\n </div>\n )}\n </div>\n </div>\n\n {(featuredLoading || featuredCollections.length > 0) && (\n <div className=\"grid grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-5\">\n {featuredLoading\n ? Array.from({ length: 10 }).map((_, i) => <CollectionCardSkeleton key={i} />)\n : featuredCollections.map((col) => (\n <CollectionCard key={col.contractAddress} collection={col} />\n ))}\n </div>\n )}\n\n <div className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <CollectionSearch />\n <div className=\"flex items-center gap-2 sm:ml-auto\">\n <button\n onClick={() => setFiltersOpen(true)}\n aria-label=\"Filters\"\n className={cn(\n \"relative flex items-center gap-1.5 h-9 px-3 rounded-lg border text-xs font-medium transition-colors\",\n activeFilters > 0 || service !== undefined\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50 hover:text-foreground\"\n )}\n >\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n {(activeFilters > 0 || service !== undefined) && (\n <span className=\"flex h-4 w-4 items-center justify-center rounded-full bg-primary text-2xs font-bold text-primary-foreground\">\n {activeFilters + (service !== undefined ? 1 : 0)}\n </span>\n )}\n </button>\n </div>\n </div>\n {(service !== undefined || !hideEmpty) && (\n <div className=\"flex flex-wrap items-center gap-2\">\n {service !== undefined && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n {service === \"drop-collection\" ? <Package className=\"h-3 w-3\" /> : <Award className=\"h-3 w-3\" />}\n {SERVICE_TABS.find((t) => t.value === service)?.label}\n <button onClick={() => setService(undefined)} className=\"ml-0.5 hover:text-primary/60\" aria-label=\"Remove source filter\">×</button>\n </span>\n )}\n {!hideEmpty && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n Show empty\n <button onClick={() => setHideEmpty(true)} className=\"ml-0.5 hover:text-primary/60\" aria-label=\"Remove show empty filter\">×</button>\n </span>\n )}\n </div>\n )}\n </div>\n\n <Dialog open={filtersOpen} onOpenChange={setFiltersOpen}>\n <DialogContent className=\"w-full max-w-sm sm:max-w-md p-0 overflow-hidden gap-0 flex flex-col max-h-[85svh]\">\n\n <div className=\"flex items-center justify-between px-5 py-4 border-b border-border/60 pr-12\">\n <DialogTitle className=\"text-base font-bold flex items-center gap-2\">\n <SlidersHorizontal className=\"h-4 w-4 text-primary\" />\n Filters\n </DialogTitle>\n {(activeFilters > 0 || service !== undefined) && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 text-xs text-muted-foreground\" onClick={() => { resetAll(); setService(undefined); }}>\n Clear all\n </Button>\n )}\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-5 py-4 space-y-5\">\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Sort by</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {SORT_OPTIONS.map(({ label, value }) => (\n <button\n key={value}\n onClick={() => setSort(value)}\n className={cn(\n \"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap\",\n sort === value\n ? \"border-primary bg-primary/10 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n {label}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Source</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {SERVICE_TABS.map(({ label, value }) => (\n <button\n key={label}\n onClick={() => handleServiceChange(value)}\n className={cn(\n \"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap\",\n service === value\n ? \"border-primary bg-primary/10 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n {value === \"pop-protocol\" && <Award className=\"h-3 w-3\" />}\n {value === \"drop-collection\" && <Package className=\"h-3 w-3\" />}\n {label}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Show</p>\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setHideEmpty((v) => !v)}\n className={cn(\n \"flex flex-1 items-center gap-2 text-sm px-3 py-2 rounded-lg border transition-colors text-left\",\n !hideEmpty\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n <Eye className=\"h-4 w-4 shrink-0\" />\n Show empty collections\n </button>\n <HelpIcon content=\"Include collections with no minted assets yet — hidden by default to keep the feed clean\" side=\"left\" />\n </div>\n </div>\n </div>\n\n </div>\n\n <div className=\"px-5 py-3 border-t border-border/60\">\n <Button className=\"w-full\" onClick={() => setFiltersOpen(false)}>\n Show results\n </Button>\n </div>\n\n </DialogContent>\n </Dialog>\n\n {isInitialLoading ? (\n <div className=\"grid grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-5\">\n {Array.from({ length: 10 }).map((_, i) => <CollectionCardSkeleton key={i} />)}\n </div>\n ) : allCollections.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-24 gap-4 text-center\">\n <Layers className=\"h-12 w-12 text-muted-foreground/30\" />\n <p className=\"text-2xl font-bold\">No collections found</p>\n <p className=\"text-muted-foreground max-w-sm\">\n {hideEmpty\n ? \"No collections with assets yet.\"\n : \"Deploy the first collection on Medialane.\"}\n </p>\n {activeFilters > 0 && (\n <Button variant=\"outline\" size=\"sm\" onClick={resetAll}>\n Clear filters\n </Button>\n )}\n </div>\n ) : (\n <div className=\"space-y-6\">\n <div className=\"grid grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-5\">\n {allCollections.map((col) => (\n <CollectionCard key={col.contractAddress} collection={col} />\n ))}\n </div>\n\n <LoadMoreSentinel\n hasMore={hasMore}\n isLoading={isLoading}\n onLoadMore={() => setPage((p) => p + 1)}\n />\n </div>\n )}\n </PageContainer>\n );\n}\n"],"mappings":"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","names":[]}
@@ -30,12 +30,13 @@ function DiscoverCollectionsStrip({
30
30
  collections,
31
31
  isLoading,
32
32
  allCollectionsHref = "/collections",
33
- title = "Collections"
33
+ title = "Collections",
34
+ icon = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Layers, {})
34
35
  }) {
35
36
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
36
37
  import_scroll_section.ScrollSection,
37
38
  {
38
- icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Layers, { className: "h-4 w-4" }),
39
+ icon,
39
40
  title,
40
41
  href: allCollectionsHref,
41
42
  linkLabel: "View all",
@@ -1 +1 @@
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\n getHref?: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n\n sectionLabel?: string;\n title?: string;\n}\n\nexport function DiscoverCollectionsStrip({\n collections,\n isLoading,\n allCollectionsHref = \"/collections\",\n title = \"Collections\",\n}: DiscoverCollectionsStripProps) {\n return (\n <ScrollSection\n icon={<Layers className=\"h-4 w-4\" />}\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;AA0BY;AAxBZ,0BAAuB;AACvB,4BAA8B;AAC9B,6BAAuD;AAchD,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,WAAU;AAAA,MAClC;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":[]}
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\n getHref?: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n\n sectionLabel?: string;\n title?: string;\n icon?: React.ReactNode;\n}\n\nexport function DiscoverCollectionsStrip({\n collections,\n isLoading,\n allCollectionsHref = \"/collections\",\n title = \"Collections\",\n icon = <Layers />,\n}: DiscoverCollectionsStripProps) {\n return (\n <ScrollSection\n icon={icon}\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;AAwBS;AAtBT,0BAAuB;AACvB,4BAA8B;AAC9B,6BAAuD;AAehD,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EACrB,QAAQ;AAAA,EACR,OAAO,4CAAC,8BAAO;AACjB,GAAkC;AAChC,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;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":[]}
@@ -8,7 +8,8 @@ interface DiscoverCollectionsStripProps {
8
8
  allCollectionsHref?: string;
9
9
  sectionLabel?: string;
10
10
  title?: string;
11
+ icon?: React.ReactNode;
11
12
  }
12
- declare function DiscoverCollectionsStrip({ collections, isLoading, allCollectionsHref, title, }: DiscoverCollectionsStripProps): react_jsx_runtime.JSX.Element;
13
+ declare function DiscoverCollectionsStrip({ collections, isLoading, allCollectionsHref, title, icon, }: DiscoverCollectionsStripProps): react_jsx_runtime.JSX.Element;
13
14
 
14
15
  export { DiscoverCollectionsStrip, type DiscoverCollectionsStripProps };
@@ -8,7 +8,8 @@ interface DiscoverCollectionsStripProps {
8
8
  allCollectionsHref?: string;
9
9
  sectionLabel?: string;
10
10
  title?: string;
11
+ icon?: React.ReactNode;
11
12
  }
12
- declare function DiscoverCollectionsStrip({ collections, isLoading, allCollectionsHref, title, }: DiscoverCollectionsStripProps): react_jsx_runtime.JSX.Element;
13
+ declare function DiscoverCollectionsStrip({ collections, isLoading, allCollectionsHref, title, icon, }: DiscoverCollectionsStripProps): react_jsx_runtime.JSX.Element;
13
14
 
14
15
  export { DiscoverCollectionsStrip, type DiscoverCollectionsStripProps };
@@ -7,12 +7,13 @@ function DiscoverCollectionsStrip({
7
7
  collections,
8
8
  isLoading,
9
9
  allCollectionsHref = "/collections",
10
- title = "Collections"
10
+ title = "Collections",
11
+ icon = /* @__PURE__ */ jsx(Layers, {})
11
12
  }) {
12
13
  return /* @__PURE__ */ jsx(
13
14
  ScrollSection,
14
15
  {
15
- icon: /* @__PURE__ */ jsx(Layers, { className: "h-4 w-4" }),
16
+ icon,
16
17
  title,
17
18
  href: allCollectionsHref,
18
19
  linkLabel: "View all",
@@ -1 +1 @@
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\n getHref?: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n\n sectionLabel?: string;\n title?: string;\n}\n\nexport function DiscoverCollectionsStrip({\n collections,\n isLoading,\n allCollectionsHref = \"/collections\",\n title = \"Collections\",\n}: DiscoverCollectionsStripProps) {\n return (\n <ScrollSection\n icon={<Layers className=\"h-4 w-4\" />}\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":";AA0BY;AAxBZ,SAAS,cAAc;AACvB,SAAS,qBAAqB;AAC9B,SAAS,gBAAgB,8BAA8B;AAchD,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,WAAU;AAAA,MAClC;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":[]}
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\n getHref?: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n\n sectionLabel?: string;\n title?: string;\n icon?: React.ReactNode;\n}\n\nexport function DiscoverCollectionsStrip({\n collections,\n isLoading,\n allCollectionsHref = \"/collections\",\n title = \"Collections\",\n icon = <Layers />,\n}: DiscoverCollectionsStripProps) {\n return (\n <ScrollSection\n icon={icon}\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":";AAwBS;AAtBT,SAAS,cAAc;AACvB,SAAS,qBAAqB;AAC9B,SAAS,gBAAgB,8BAA8B;AAehD,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EACrB,QAAQ;AAAA,EACR,OAAO,oBAAC,UAAO;AACjB,GAAkC;AAChC,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;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":[]}
@@ -24,6 +24,7 @@ __export(discover_page_exports, {
24
24
  module.exports = __toCommonJS(discover_page_exports);
25
25
  var import_jsx_runtime = require("react/jsx-runtime");
26
26
  var import_sdk = require("@medialane/sdk");
27
+ var import_lucide_react = require("lucide-react");
27
28
  var import_page_container = require("./page-container.js");
28
29
  var import_discover_hero = require("./discover-hero.js");
29
30
  var import_discover_collections_strip = require("./discover-collections-strip.js");
@@ -63,7 +64,8 @@ function DiscoverPage({ useMarketActions, heroBadge, heroHeadline }) {
63
64
  isLoading: featuredLoading,
64
65
  getHref: (c) => (0, import_sdk.collectionHref)("STARKNET", c.contractAddress),
65
66
  allCollectionsHref: "/collections",
66
- title: "Featured"
67
+ title: "Featured",
68
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Sparkles, {})
67
69
  }
68
70
  ),
69
71
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/discover-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { assetHref, collectionHref } from \"@medialane/sdk\";\nimport { PageContainer } from \"./page-container.js\";\nimport { DiscoverHero } from \"./discover-hero.js\";\nimport { DiscoverCollectionsStrip } from \"./discover-collections-strip.js\";\nimport { DiscoverActivityStrip } from \"./discover-feed-section.js\";\nimport { DiscoverCommunitySection } from \"./discover-community-section.js\";\nimport { IpTypeNav } from \"./ip-type-nav.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport type { CollectionMarketActions } from \"./collection-page.js\";\nimport { useOrders } from \"../utils/use-orders.js\";\nimport { useCollections } from \"../utils/use-collections.js\";\nimport { usePlatformStats } from \"../utils/use-platform-stats.js\";\nimport { isSameAddress } from \"../utils/same-address.js\";\n\nexport interface DiscoverPageProps {\n useMarketActions: () => CollectionMarketActions;\n heroBadge?: string;\n heroHeadline?: string;\n}\n\nexport function DiscoverPage({ useMarketActions, heroBadge, heroHeadline }: DiscoverPageProps) {\n const { walletAddress } = useMedialaneApp();\n const market = useMarketActions();\n const { stats } = usePlatformStats();\n const { orders: tickerOrders } = useOrders({ status: \"ACTIVE\", sort: \"recent\", limit: 14 });\n const { orders: feedOrders, isLoading: feedLoading } = useOrders({ status: \"ACTIVE\", sort: \"recent\", limit: 10 });\n const { collections: featured, isLoading: featuredLoading } = useCollections(1, 8, true);\n const { collections, isLoading: collectionsLoading } = useCollections(1, 8);\n\n return (\n <PageContainer className=\"box-border max-w-full space-y-14 px-4 pt-20 sm:space-y-20 sm:px-5 lg:px-6\">\n <div className=\"space-y-8 sm:space-y-10\">\n <DiscoverHero\n stats={stats ?? null}\n orders={tickerOrders}\n badgeText={heroBadge}\n headlineText={heroHeadline}\n getTickerHref={(o) => assetHref(\"STARKNET\", o.nftContract, o.nftTokenId)}\n />\n <div className=\"space-y-14 sm:space-y-20\">\n {(featuredLoading || featured.length > 0) && (\n <DiscoverCollectionsStrip\n collections={featured}\n isLoading={featuredLoading}\n getHref={(c) => collectionHref(\"STARKNET\", c.contractAddress)}\n allCollectionsHref=\"/collections\"\n title=\"Featured\"\n />\n )}\n <DiscoverCollectionsStrip\n collections={collections}\n isLoading={collectionsLoading}\n getHref={(c) => collectionHref(\"STARKNET\", c.contractAddress)}\n allCollectionsHref=\"/collections\"\n />\n </div>\n </div>\n <DiscoverActivityStrip\n orders={feedOrders}\n isLoading={feedLoading}\n marketplaceHref=\"/marketplace\"\n onBuyOrder={market.buy}\n isOwnOrder={(o) => !!walletAddress && !!o.offerer && isSameAddress(o.offerer, walletAddress)}\n />\n <IpTypeNav />\n <DiscoverCommunitySection />\n {market.dialogs}\n </PageContainer>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkCQ;AAhCR,iBAA0C;AAC1C,4BAA8B;AAC9B,2BAA6B;AAC7B,wCAAyC;AACzC,mCAAsC;AACtC,wCAAyC;AACzC,yBAA0B;AAC1B,2BAAgC;AAEhC,wBAA0B;AAC1B,6BAA+B;AAC/B,gCAAiC;AACjC,0BAA8B;AAQvB,SAAS,aAAa,EAAE,kBAAkB,WAAW,aAAa,GAAsB;AAC7F,QAAM,EAAE,cAAc,QAAI,sCAAgB;AAC1C,QAAM,SAAS,iBAAiB;AAChC,QAAM,EAAE,MAAM,QAAI,4CAAiB;AACnC,QAAM,EAAE,QAAQ,aAAa,QAAI,6BAAU,EAAE,QAAQ,UAAU,MAAM,UAAU,OAAO,GAAG,CAAC;AAC1F,QAAM,EAAE,QAAQ,YAAY,WAAW,YAAY,QAAI,6BAAU,EAAE,QAAQ,UAAU,MAAM,UAAU,OAAO,GAAG,CAAC;AAChH,QAAM,EAAE,aAAa,UAAU,WAAW,gBAAgB,QAAI,uCAAe,GAAG,GAAG,IAAI;AACvF,QAAM,EAAE,aAAa,WAAW,mBAAmB,QAAI,uCAAe,GAAG,CAAC;AAE1E,SACE,6CAAC,uCAAc,WAAU,6EACvB;AAAA,iDAAC,SAAI,WAAU,2BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,SAAS;AAAA,UAChB,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,cAAc;AAAA,UACd,eAAe,CAAC,UAAM,sBAAU,YAAY,EAAE,aAAa,EAAE,UAAU;AAAA;AAAA,MACzE;AAAA,MACA,6CAAC,SAAI,WAAU,4BACX;AAAA,4BAAmB,SAAS,SAAS,MACrC;AAAA,UAAC;AAAA;AAAA,YACC,aAAa;AAAA,YACb,WAAW;AAAA,YACX,SAAS,CAAC,UAAM,2BAAe,YAAY,EAAE,eAAe;AAAA,YAC5D,oBAAmB;AAAA,YACnB,OAAM;AAAA;AAAA,QACR;AAAA,QAEF;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,WAAW;AAAA,YACX,SAAS,CAAC,UAAM,2BAAe,YAAY,EAAE,eAAe;AAAA,YAC5D,oBAAmB;AAAA;AAAA,QACrB;AAAA,SACF;AAAA,OACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,iBAAgB;AAAA,QAChB,YAAY,OAAO;AAAA,QACnB,YAAY,CAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC,EAAE,eAAW,mCAAc,EAAE,SAAS,aAAa;AAAA;AAAA,IAC7F;AAAA,IACA,4CAAC,gCAAU;AAAA,IACX,4CAAC,8DAAyB;AAAA,IACzB,OAAO;AAAA,KACV;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/discover-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { assetHref, collectionHref } from \"@medialane/sdk\";\nimport { Sparkles } from \"lucide-react\";\nimport { PageContainer } from \"./page-container.js\";\nimport { DiscoverHero } from \"./discover-hero.js\";\nimport { DiscoverCollectionsStrip } from \"./discover-collections-strip.js\";\nimport { DiscoverActivityStrip } from \"./discover-feed-section.js\";\nimport { DiscoverCommunitySection } from \"./discover-community-section.js\";\nimport { IpTypeNav } from \"./ip-type-nav.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport type { CollectionMarketActions } from \"./collection-page.js\";\nimport { useOrders } from \"../utils/use-orders.js\";\nimport { useCollections } from \"../utils/use-collections.js\";\nimport { usePlatformStats } from \"../utils/use-platform-stats.js\";\nimport { isSameAddress } from \"../utils/same-address.js\";\n\nexport interface DiscoverPageProps {\n useMarketActions: () => CollectionMarketActions;\n heroBadge?: string;\n heroHeadline?: string;\n}\n\nexport function DiscoverPage({ useMarketActions, heroBadge, heroHeadline }: DiscoverPageProps) {\n const { walletAddress } = useMedialaneApp();\n const market = useMarketActions();\n const { stats } = usePlatformStats();\n const { orders: tickerOrders } = useOrders({ status: \"ACTIVE\", sort: \"recent\", limit: 14 });\n const { orders: feedOrders, isLoading: feedLoading } = useOrders({ status: \"ACTIVE\", sort: \"recent\", limit: 10 });\n const { collections: featured, isLoading: featuredLoading } = useCollections(1, 8, true);\n const { collections, isLoading: collectionsLoading } = useCollections(1, 8);\n\n return (\n <PageContainer className=\"box-border max-w-full space-y-14 px-4 pt-20 sm:space-y-20 sm:px-5 lg:px-6\">\n <div className=\"space-y-8 sm:space-y-10\">\n <DiscoverHero\n stats={stats ?? null}\n orders={tickerOrders}\n badgeText={heroBadge}\n headlineText={heroHeadline}\n getTickerHref={(o) => assetHref(\"STARKNET\", o.nftContract, o.nftTokenId)}\n />\n <div className=\"space-y-14 sm:space-y-20\">\n {(featuredLoading || featured.length > 0) && (\n <DiscoverCollectionsStrip\n collections={featured}\n isLoading={featuredLoading}\n getHref={(c) => collectionHref(\"STARKNET\", c.contractAddress)}\n allCollectionsHref=\"/collections\"\n title=\"Featured\"\n icon={<Sparkles />}\n />\n )}\n <DiscoverCollectionsStrip\n collections={collections}\n isLoading={collectionsLoading}\n getHref={(c) => collectionHref(\"STARKNET\", c.contractAddress)}\n allCollectionsHref=\"/collections\"\n />\n </div>\n </div>\n <DiscoverActivityStrip\n orders={feedOrders}\n isLoading={feedLoading}\n marketplaceHref=\"/marketplace\"\n onBuyOrder={market.buy}\n isOwnOrder={(o) => !!walletAddress && !!o.offerer && isSameAddress(o.offerer, walletAddress)}\n />\n <IpTypeNav />\n <DiscoverCommunitySection />\n {market.dialogs}\n </PageContainer>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCQ;AAjCR,iBAA0C;AAC1C,0BAAyB;AACzB,4BAA8B;AAC9B,2BAA6B;AAC7B,wCAAyC;AACzC,mCAAsC;AACtC,wCAAyC;AACzC,yBAA0B;AAC1B,2BAAgC;AAEhC,wBAA0B;AAC1B,6BAA+B;AAC/B,gCAAiC;AACjC,0BAA8B;AAQvB,SAAS,aAAa,EAAE,kBAAkB,WAAW,aAAa,GAAsB;AAC7F,QAAM,EAAE,cAAc,QAAI,sCAAgB;AAC1C,QAAM,SAAS,iBAAiB;AAChC,QAAM,EAAE,MAAM,QAAI,4CAAiB;AACnC,QAAM,EAAE,QAAQ,aAAa,QAAI,6BAAU,EAAE,QAAQ,UAAU,MAAM,UAAU,OAAO,GAAG,CAAC;AAC1F,QAAM,EAAE,QAAQ,YAAY,WAAW,YAAY,QAAI,6BAAU,EAAE,QAAQ,UAAU,MAAM,UAAU,OAAO,GAAG,CAAC;AAChH,QAAM,EAAE,aAAa,UAAU,WAAW,gBAAgB,QAAI,uCAAe,GAAG,GAAG,IAAI;AACvF,QAAM,EAAE,aAAa,WAAW,mBAAmB,QAAI,uCAAe,GAAG,CAAC;AAE1E,SACE,6CAAC,uCAAc,WAAU,6EACvB;AAAA,iDAAC,SAAI,WAAU,2BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,SAAS;AAAA,UAChB,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,cAAc;AAAA,UACd,eAAe,CAAC,UAAM,sBAAU,YAAY,EAAE,aAAa,EAAE,UAAU;AAAA;AAAA,MACzE;AAAA,MACA,6CAAC,SAAI,WAAU,4BACX;AAAA,4BAAmB,SAAS,SAAS,MACrC;AAAA,UAAC;AAAA;AAAA,YACC,aAAa;AAAA,YACb,WAAW;AAAA,YACX,SAAS,CAAC,UAAM,2BAAe,YAAY,EAAE,eAAe;AAAA,YAC5D,oBAAmB;AAAA,YACnB,OAAM;AAAA,YACN,MAAM,4CAAC,gCAAS;AAAA;AAAA,QAClB;AAAA,QAEF;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,WAAW;AAAA,YACX,SAAS,CAAC,UAAM,2BAAe,YAAY,EAAE,eAAe;AAAA,YAC5D,oBAAmB;AAAA;AAAA,QACrB;AAAA,SACF;AAAA,OACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,iBAAgB;AAAA,QAChB,YAAY,OAAO;AAAA,QACnB,YAAY,CAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC,EAAE,eAAW,mCAAc,EAAE,SAAS,aAAa;AAAA;AAAA,IAC7F;AAAA,IACA,4CAAC,gCAAU;AAAA,IACX,4CAAC,8DAAyB;AAAA,IACzB,OAAO;AAAA,KACV;AAEJ;","names":[]}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { assetHref, collectionHref } from "@medialane/sdk";
4
+ import { Sparkles } from "lucide-react";
4
5
  import { PageContainer } from "./page-container.js";
5
6
  import { DiscoverHero } from "./discover-hero.js";
6
7
  import { DiscoverCollectionsStrip } from "./discover-collections-strip.js";
@@ -40,7 +41,8 @@ function DiscoverPage({ useMarketActions, heroBadge, heroHeadline }) {
40
41
  isLoading: featuredLoading,
41
42
  getHref: (c) => collectionHref("STARKNET", c.contractAddress),
42
43
  allCollectionsHref: "/collections",
43
- title: "Featured"
44
+ title: "Featured",
45
+ icon: /* @__PURE__ */ jsx(Sparkles, {})
44
46
  }
45
47
  ),
46
48
  /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/discover-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { assetHref, collectionHref } from \"@medialane/sdk\";\nimport { PageContainer } from \"./page-container.js\";\nimport { DiscoverHero } from \"./discover-hero.js\";\nimport { DiscoverCollectionsStrip } from \"./discover-collections-strip.js\";\nimport { DiscoverActivityStrip } from \"./discover-feed-section.js\";\nimport { DiscoverCommunitySection } from \"./discover-community-section.js\";\nimport { IpTypeNav } from \"./ip-type-nav.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport type { CollectionMarketActions } from \"./collection-page.js\";\nimport { useOrders } from \"../utils/use-orders.js\";\nimport { useCollections } from \"../utils/use-collections.js\";\nimport { usePlatformStats } from \"../utils/use-platform-stats.js\";\nimport { isSameAddress } from \"../utils/same-address.js\";\n\nexport interface DiscoverPageProps {\n useMarketActions: () => CollectionMarketActions;\n heroBadge?: string;\n heroHeadline?: string;\n}\n\nexport function DiscoverPage({ useMarketActions, heroBadge, heroHeadline }: DiscoverPageProps) {\n const { walletAddress } = useMedialaneApp();\n const market = useMarketActions();\n const { stats } = usePlatformStats();\n const { orders: tickerOrders } = useOrders({ status: \"ACTIVE\", sort: \"recent\", limit: 14 });\n const { orders: feedOrders, isLoading: feedLoading } = useOrders({ status: \"ACTIVE\", sort: \"recent\", limit: 10 });\n const { collections: featured, isLoading: featuredLoading } = useCollections(1, 8, true);\n const { collections, isLoading: collectionsLoading } = useCollections(1, 8);\n\n return (\n <PageContainer className=\"box-border max-w-full space-y-14 px-4 pt-20 sm:space-y-20 sm:px-5 lg:px-6\">\n <div className=\"space-y-8 sm:space-y-10\">\n <DiscoverHero\n stats={stats ?? null}\n orders={tickerOrders}\n badgeText={heroBadge}\n headlineText={heroHeadline}\n getTickerHref={(o) => assetHref(\"STARKNET\", o.nftContract, o.nftTokenId)}\n />\n <div className=\"space-y-14 sm:space-y-20\">\n {(featuredLoading || featured.length > 0) && (\n <DiscoverCollectionsStrip\n collections={featured}\n isLoading={featuredLoading}\n getHref={(c) => collectionHref(\"STARKNET\", c.contractAddress)}\n allCollectionsHref=\"/collections\"\n title=\"Featured\"\n />\n )}\n <DiscoverCollectionsStrip\n collections={collections}\n isLoading={collectionsLoading}\n getHref={(c) => collectionHref(\"STARKNET\", c.contractAddress)}\n allCollectionsHref=\"/collections\"\n />\n </div>\n </div>\n <DiscoverActivityStrip\n orders={feedOrders}\n isLoading={feedLoading}\n marketplaceHref=\"/marketplace\"\n onBuyOrder={market.buy}\n isOwnOrder={(o) => !!walletAddress && !!o.offerer && isSameAddress(o.offerer, walletAddress)}\n />\n <IpTypeNav />\n <DiscoverCommunitySection />\n {market.dialogs}\n </PageContainer>\n );\n}\n"],"mappings":";AAkCQ,cAOA,YAPA;AAhCR,SAAS,WAAW,sBAAsB;AAC1C,SAAS,qBAAqB;AAC9B,SAAS,oBAAoB;AAC7B,SAAS,gCAAgC;AACzC,SAAS,6BAA6B;AACtC,SAAS,gCAAgC;AACzC,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAEhC,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC,SAAS,qBAAqB;AAQvB,SAAS,aAAa,EAAE,kBAAkB,WAAW,aAAa,GAAsB;AAC7F,QAAM,EAAE,cAAc,IAAI,gBAAgB;AAC1C,QAAM,SAAS,iBAAiB;AAChC,QAAM,EAAE,MAAM,IAAI,iBAAiB;AACnC,QAAM,EAAE,QAAQ,aAAa,IAAI,UAAU,EAAE,QAAQ,UAAU,MAAM,UAAU,OAAO,GAAG,CAAC;AAC1F,QAAM,EAAE,QAAQ,YAAY,WAAW,YAAY,IAAI,UAAU,EAAE,QAAQ,UAAU,MAAM,UAAU,OAAO,GAAG,CAAC;AAChH,QAAM,EAAE,aAAa,UAAU,WAAW,gBAAgB,IAAI,eAAe,GAAG,GAAG,IAAI;AACvF,QAAM,EAAE,aAAa,WAAW,mBAAmB,IAAI,eAAe,GAAG,CAAC;AAE1E,SACE,qBAAC,iBAAc,WAAU,6EACvB;AAAA,yBAAC,SAAI,WAAU,2BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,SAAS;AAAA,UAChB,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,cAAc;AAAA,UACd,eAAe,CAAC,MAAM,UAAU,YAAY,EAAE,aAAa,EAAE,UAAU;AAAA;AAAA,MACzE;AAAA,MACA,qBAAC,SAAI,WAAU,4BACX;AAAA,4BAAmB,SAAS,SAAS,MACrC;AAAA,UAAC;AAAA;AAAA,YACC,aAAa;AAAA,YACb,WAAW;AAAA,YACX,SAAS,CAAC,MAAM,eAAe,YAAY,EAAE,eAAe;AAAA,YAC5D,oBAAmB;AAAA,YACnB,OAAM;AAAA;AAAA,QACR;AAAA,QAEF;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,WAAW;AAAA,YACX,SAAS,CAAC,MAAM,eAAe,YAAY,EAAE,eAAe;AAAA,YAC5D,oBAAmB;AAAA;AAAA,QACrB;AAAA,SACF;AAAA,OACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,iBAAgB;AAAA,QAChB,YAAY,OAAO;AAAA,QACnB,YAAY,CAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC,EAAE,WAAW,cAAc,EAAE,SAAS,aAAa;AAAA;AAAA,IAC7F;AAAA,IACA,oBAAC,aAAU;AAAA,IACX,oBAAC,4BAAyB;AAAA,IACzB,OAAO;AAAA,KACV;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/discover-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { assetHref, collectionHref } from \"@medialane/sdk\";\nimport { Sparkles } from \"lucide-react\";\nimport { PageContainer } from \"./page-container.js\";\nimport { DiscoverHero } from \"./discover-hero.js\";\nimport { DiscoverCollectionsStrip } from \"./discover-collections-strip.js\";\nimport { DiscoverActivityStrip } from \"./discover-feed-section.js\";\nimport { DiscoverCommunitySection } from \"./discover-community-section.js\";\nimport { IpTypeNav } from \"./ip-type-nav.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport type { CollectionMarketActions } from \"./collection-page.js\";\nimport { useOrders } from \"../utils/use-orders.js\";\nimport { useCollections } from \"../utils/use-collections.js\";\nimport { usePlatformStats } from \"../utils/use-platform-stats.js\";\nimport { isSameAddress } from \"../utils/same-address.js\";\n\nexport interface DiscoverPageProps {\n useMarketActions: () => CollectionMarketActions;\n heroBadge?: string;\n heroHeadline?: string;\n}\n\nexport function DiscoverPage({ useMarketActions, heroBadge, heroHeadline }: DiscoverPageProps) {\n const { walletAddress } = useMedialaneApp();\n const market = useMarketActions();\n const { stats } = usePlatformStats();\n const { orders: tickerOrders } = useOrders({ status: \"ACTIVE\", sort: \"recent\", limit: 14 });\n const { orders: feedOrders, isLoading: feedLoading } = useOrders({ status: \"ACTIVE\", sort: \"recent\", limit: 10 });\n const { collections: featured, isLoading: featuredLoading } = useCollections(1, 8, true);\n const { collections, isLoading: collectionsLoading } = useCollections(1, 8);\n\n return (\n <PageContainer className=\"box-border max-w-full space-y-14 px-4 pt-20 sm:space-y-20 sm:px-5 lg:px-6\">\n <div className=\"space-y-8 sm:space-y-10\">\n <DiscoverHero\n stats={stats ?? null}\n orders={tickerOrders}\n badgeText={heroBadge}\n headlineText={heroHeadline}\n getTickerHref={(o) => assetHref(\"STARKNET\", o.nftContract, o.nftTokenId)}\n />\n <div className=\"space-y-14 sm:space-y-20\">\n {(featuredLoading || featured.length > 0) && (\n <DiscoverCollectionsStrip\n collections={featured}\n isLoading={featuredLoading}\n getHref={(c) => collectionHref(\"STARKNET\", c.contractAddress)}\n allCollectionsHref=\"/collections\"\n title=\"Featured\"\n icon={<Sparkles />}\n />\n )}\n <DiscoverCollectionsStrip\n collections={collections}\n isLoading={collectionsLoading}\n getHref={(c) => collectionHref(\"STARKNET\", c.contractAddress)}\n allCollectionsHref=\"/collections\"\n />\n </div>\n </div>\n <DiscoverActivityStrip\n orders={feedOrders}\n isLoading={feedLoading}\n marketplaceHref=\"/marketplace\"\n onBuyOrder={market.buy}\n isOwnOrder={(o) => !!walletAddress && !!o.offerer && isSameAddress(o.offerer, walletAddress)}\n />\n <IpTypeNav />\n <DiscoverCommunitySection />\n {market.dialogs}\n </PageContainer>\n );\n}\n"],"mappings":";AAmCQ,cAOA,YAPA;AAjCR,SAAS,WAAW,sBAAsB;AAC1C,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAC9B,SAAS,oBAAoB;AAC7B,SAAS,gCAAgC;AACzC,SAAS,6BAA6B;AACtC,SAAS,gCAAgC;AACzC,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAEhC,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC,SAAS,qBAAqB;AAQvB,SAAS,aAAa,EAAE,kBAAkB,WAAW,aAAa,GAAsB;AAC7F,QAAM,EAAE,cAAc,IAAI,gBAAgB;AAC1C,QAAM,SAAS,iBAAiB;AAChC,QAAM,EAAE,MAAM,IAAI,iBAAiB;AACnC,QAAM,EAAE,QAAQ,aAAa,IAAI,UAAU,EAAE,QAAQ,UAAU,MAAM,UAAU,OAAO,GAAG,CAAC;AAC1F,QAAM,EAAE,QAAQ,YAAY,WAAW,YAAY,IAAI,UAAU,EAAE,QAAQ,UAAU,MAAM,UAAU,OAAO,GAAG,CAAC;AAChH,QAAM,EAAE,aAAa,UAAU,WAAW,gBAAgB,IAAI,eAAe,GAAG,GAAG,IAAI;AACvF,QAAM,EAAE,aAAa,WAAW,mBAAmB,IAAI,eAAe,GAAG,CAAC;AAE1E,SACE,qBAAC,iBAAc,WAAU,6EACvB;AAAA,yBAAC,SAAI,WAAU,2BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,SAAS;AAAA,UAChB,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,cAAc;AAAA,UACd,eAAe,CAAC,MAAM,UAAU,YAAY,EAAE,aAAa,EAAE,UAAU;AAAA;AAAA,MACzE;AAAA,MACA,qBAAC,SAAI,WAAU,4BACX;AAAA,4BAAmB,SAAS,SAAS,MACrC;AAAA,UAAC;AAAA;AAAA,YACC,aAAa;AAAA,YACb,WAAW;AAAA,YACX,SAAS,CAAC,MAAM,eAAe,YAAY,EAAE,eAAe;AAAA,YAC5D,oBAAmB;AAAA,YACnB,OAAM;AAAA,YACN,MAAM,oBAAC,YAAS;AAAA;AAAA,QAClB;AAAA,QAEF;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,WAAW;AAAA,YACX,SAAS,CAAC,MAAM,eAAe,YAAY,EAAE,eAAe;AAAA,YAC5D,oBAAmB;AAAA;AAAA,QACrB;AAAA,SACF;AAAA,OACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,iBAAgB;AAAA,QAChB,YAAY,OAAO;AAAA,QACnB,YAAY,CAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC,EAAE,WAAW,cAAc,EAAE,SAAS,aAAa;AAAA;AAAA,IAC7F;AAAA,IACA,oBAAC,aAAU;AAAA,IACX,oBAAC,4BAAyB;AAAA,IACzB,OAAO;AAAA,KACV;AAEJ;","names":[]}
@@ -28,6 +28,7 @@ var import_react = require("react");
28
28
  var import_framer_motion = require("framer-motion");
29
29
  var import_lucide_react = require("lucide-react");
30
30
  var import_motion_primitives = require("./motion-primitives.js");
31
+ var import_section_heading = require("./section-heading.js");
31
32
  var import_format = require("../utils/format.js");
32
33
  var import_use_image_url = require("../utils/use-image-url.js");
33
34
  function Slide({ collection, href }) {
@@ -75,10 +76,7 @@ function Slide({ collection, href }) {
75
76
  }
76
77
  function FeaturedCarouselSkeleton() {
77
78
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_motion_primitives.FadeIn, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "space-y-4", children: [
78
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2 mt-0.5", children: [
79
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Sparkles, { className: "h-4 w-4 text-brand-purple" }),
80
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-xl font-bold", children: "Featured Collections" })
81
- ] }),
79
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_section_heading.SectionHeading, { icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Sparkles, {}), title: "Featured Collections", href: "/collections", linkLabel: "View all" }),
82
80
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "-mx-4 sm:-mx-6 lg:-mx-8 aspect-[16/7] sm:aspect-[21/9] bg-muted animate-pulse" })
83
81
  ] }) });
84
82
  }
@@ -104,23 +102,7 @@ function FeaturedCarousel({
104
102
  if (isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FeaturedCarouselSkeleton, {});
105
103
  if (total === 0) return null;
106
104
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_motion_primitives.FadeIn, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "space-y-4", children: [
107
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
108
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2 mt-0.5", children: [
109
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Sparkles, { className: "h-4 w-4 text-brand-purple" }),
110
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-xl font-bold", children: "Featured Collections" })
111
- ] }),
112
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
113
- "a",
114
- {
115
- href: allCollectionsHref,
116
- 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",
117
- children: [
118
- "View all ",
119
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRight, { className: "h-3.5 w-3.5" })
120
- ]
121
- }
122
- )
123
- ] }),
105
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_section_heading.SectionHeading, { icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Sparkles, {}), title: "Featured Collections", href: allCollectionsHref, linkLabel: "View all" }),
124
106
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
125
107
  "div",
126
108
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/featured-carousel.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { ChevronLeft, ChevronRight, ArrowRight, Sparkles } from \"lucide-react\";\nimport { FadeIn, EASE_OUT } from \"./motion-primitives.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\nexport interface FeaturedCarouselProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n}\n\nfunction Slide({ collection, href }: { collection: ApiCollection; href: string }) {\n const resolveImage = useImageUrl();\n const name = collection.name ?? \"Featured Collection\";\n const image = resolveImage(collection.image);\n\n return (\n <div className=\"relative w-full h-full\">\n {image ? (\n <img\n src={image}\n alt={name}\n loading=\"lazy\"\n className=\"absolute inset-0 w-full h-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/40\" />\n )}\n <div className=\"absolute inset-0 bg-gradient-to-t from-black/85 via-black/30 to-black/10\" />\n <div className=\"absolute inset-0 bg-gradient-to-r from-black/50 via-transparent to-transparent\" />\n <div className=\"absolute bottom-0 left-0 right-0 p-5 sm:p-8 lg:p-10\">\n <h2 className=\"text-2xl sm:text-3xl lg:text-4xl font-black text-white leading-tight mb-3 max-w-lg\">\n {name}\n </h2>\n <div className=\"flex items-center gap-4 mb-5\">\n {collection.totalSupply != null && (\n <span className=\"text-sm text-white/70\">\n <span className=\"font-bold text-white\">{collection.totalSupply}</span> items\n </span>\n )}\n {collection.floorPrice && (\n <span className=\"text-sm text-white/70\">\n Floor{\" \"}\n <span className=\"font-bold text-brand-orange\">\n {formatDisplayPrice(collection.floorPrice)}\n </span>\n </span>\n )}\n </div>\n <a\n href={href}\n className=\"inline-flex items-center gap-2 text-sm font-semibold px-4 py-2 rounded-lg bg-white/15 hover:bg-white/25 text-white border border-white/20 backdrop-blur-sm transition-colors\"\n >\n View Collection <ArrowRight className=\"h-3.5 w-3.5\" />\n </a>\n </div>\n </div>\n );\n}\n\nexport function FeaturedCarouselSkeleton() {\n return (\n <FadeIn>\n <section className=\"space-y-4\">\n <div className=\"flex items-center gap-2 mt-0.5\">\n <Sparkles className=\"h-4 w-4 text-brand-purple\" />\n <h2 className=\"text-xl font-bold\">Featured Collections</h2>\n </div>\n <div className=\"-mx-4 sm:-mx-6 lg:-mx-8 aspect-[16/7] sm:aspect-[21/9] bg-muted animate-pulse\" />\n </section>\n </FadeIn>\n );\n}\n\nexport function FeaturedCarousel({\n collections,\n isLoading,\n getHref,\n allCollectionsHref = \"/collections\",\n}: FeaturedCarouselProps) {\n const [active, setActive] = useState(0);\n const [paused, setPaused] = useState(false);\n const total = collections.length;\n\n const next = useCallback(() => setActive((p) => (p + 1) % total), [total]);\n const prev = useCallback(() => setActive((p) => (p - 1 + total) % total), [total]);\n\n useEffect(() => { setActive(0); }, [total]);\n\n useEffect(() => {\n if (paused || total <= 1) return;\n const id = setInterval(next, 6000);\n return () => clearInterval(id);\n }, [next, paused, total]);\n\n if (isLoading) return <FeaturedCarouselSkeleton />;\n if (total === 0) return null;\n\n return (\n <FadeIn>\n <section className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2 mt-0.5\">\n <Sparkles className=\"h-4 w-4 text-brand-purple\" />\n <h2 className=\"text-xl font-bold\">Featured Collections</h2>\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\n <div\n className=\"-mx-4 sm:-mx-6 lg:-mx-8 relative overflow-hidden aspect-[16/7] sm:aspect-[21/9] bg-muted\"\n onMouseEnter={() => setPaused(true)}\n onMouseLeave={() => setPaused(false)}\n >\n <AnimatePresence mode=\"wait\">\n <motion.div\n key={active}\n className=\"absolute inset-0\"\n initial={{ opacity: 0, x: 40 }}\n animate={{ opacity: 1, x: 0 }}\n exit={{ opacity: 0, x: -40 }}\n transition={{ duration: 0.45, ease: EASE_OUT }}\n >\n <Slide collection={collections[active]} href={getHref(collections[active])} />\n </motion.div>\n </AnimatePresence>\n\n {total > 1 && (\n <>\n <button\n onClick={prev}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 min-h-11 min-w-11 rounded-full flex items-center justify-center z-10\"\n aria-label=\"Previous\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-black/40 border border-white/10 backdrop-blur-sm text-white hover:bg-black/60 transition-colors\">\n <ChevronLeft className=\"h-4 w-4\" />\n </span>\n </button>\n <button\n onClick={next}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 min-h-11 min-w-11 rounded-full flex items-center justify-center z-10\"\n aria-label=\"Next\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-black/40 border border-white/10 backdrop-blur-sm text-white hover:bg-black/60 transition-colors\">\n <ChevronRight className=\"h-4 w-4\" />\n </span>\n </button>\n </>\n )}\n\n {total > 1 && (\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 flex items-center gap-1.5 z-10\">\n {collections.map((_, i) => (\n <button\n key={i}\n onClick={() => setActive(i)}\n className={`h-1.5 rounded-full transition-all duration-300 ${\n i === active ? \"w-6 bg-white\" : \"w-1.5 bg-white/40 hover:bg-white/70\"\n }`}\n aria-label={`Go to slide ${i + 1}`}\n />\n ))}\n </div>\n )}\n </div>\n </section>\n </FadeIn>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/featured-carousel.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { ChevronLeft, ChevronRight, ArrowRight, Sparkles } from \"lucide-react\";\nimport { FadeIn, EASE_OUT } from \"./motion-primitives.js\";\nimport { SectionHeading } from \"./section-heading.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\nexport interface FeaturedCarouselProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n}\n\nfunction Slide({ collection, href }: { collection: ApiCollection; href: string }) {\n const resolveImage = useImageUrl();\n const name = collection.name ?? \"Featured Collection\";\n const image = resolveImage(collection.image);\n\n return (\n <div className=\"relative w-full h-full\">\n {image ? (\n <img\n src={image}\n alt={name}\n loading=\"lazy\"\n className=\"absolute inset-0 w-full h-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/40\" />\n )}\n <div className=\"absolute inset-0 bg-gradient-to-t from-black/85 via-black/30 to-black/10\" />\n <div className=\"absolute inset-0 bg-gradient-to-r from-black/50 via-transparent to-transparent\" />\n <div className=\"absolute bottom-0 left-0 right-0 p-5 sm:p-8 lg:p-10\">\n <h2 className=\"text-2xl sm:text-3xl lg:text-4xl font-black text-white leading-tight mb-3 max-w-lg\">\n {name}\n </h2>\n <div className=\"flex items-center gap-4 mb-5\">\n {collection.totalSupply != null && (\n <span className=\"text-sm text-white/70\">\n <span className=\"font-bold text-white\">{collection.totalSupply}</span> items\n </span>\n )}\n {collection.floorPrice && (\n <span className=\"text-sm text-white/70\">\n Floor{\" \"}\n <span className=\"font-bold text-brand-orange\">\n {formatDisplayPrice(collection.floorPrice)}\n </span>\n </span>\n )}\n </div>\n <a\n href={href}\n className=\"inline-flex items-center gap-2 text-sm font-semibold px-4 py-2 rounded-lg bg-white/15 hover:bg-white/25 text-white border border-white/20 backdrop-blur-sm transition-colors\"\n >\n View Collection <ArrowRight className=\"h-3.5 w-3.5\" />\n </a>\n </div>\n </div>\n );\n}\n\nexport function FeaturedCarouselSkeleton() {\n return (\n <FadeIn>\n <section className=\"space-y-4\">\n <SectionHeading icon={<Sparkles />} title=\"Featured Collections\" href=\"/collections\" linkLabel=\"View all\" />\n <div className=\"-mx-4 sm:-mx-6 lg:-mx-8 aspect-[16/7] sm:aspect-[21/9] bg-muted animate-pulse\" />\n </section>\n </FadeIn>\n );\n}\n\nexport function FeaturedCarousel({\n collections,\n isLoading,\n getHref,\n allCollectionsHref = \"/collections\",\n}: FeaturedCarouselProps) {\n const [active, setActive] = useState(0);\n const [paused, setPaused] = useState(false);\n const total = collections.length;\n\n const next = useCallback(() => setActive((p) => (p + 1) % total), [total]);\n const prev = useCallback(() => setActive((p) => (p - 1 + total) % total), [total]);\n\n useEffect(() => { setActive(0); }, [total]);\n\n useEffect(() => {\n if (paused || total <= 1) return;\n const id = setInterval(next, 6000);\n return () => clearInterval(id);\n }, [next, paused, total]);\n\n if (isLoading) return <FeaturedCarouselSkeleton />;\n if (total === 0) return null;\n\n return (\n <FadeIn>\n <section className=\"space-y-4\">\n <SectionHeading icon={<Sparkles />} title=\"Featured Collections\" href={allCollectionsHref} linkLabel=\"View all\" />\n\n <div\n className=\"-mx-4 sm:-mx-6 lg:-mx-8 relative overflow-hidden aspect-[16/7] sm:aspect-[21/9] bg-muted\"\n onMouseEnter={() => setPaused(true)}\n onMouseLeave={() => setPaused(false)}\n >\n <AnimatePresence mode=\"wait\">\n <motion.div\n key={active}\n className=\"absolute inset-0\"\n initial={{ opacity: 0, x: 40 }}\n animate={{ opacity: 1, x: 0 }}\n exit={{ opacity: 0, x: -40 }}\n transition={{ duration: 0.45, ease: EASE_OUT }}\n >\n <Slide collection={collections[active]} href={getHref(collections[active])} />\n </motion.div>\n </AnimatePresence>\n\n {total > 1 && (\n <>\n <button\n onClick={prev}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 min-h-11 min-w-11 rounded-full flex items-center justify-center z-10\"\n aria-label=\"Previous\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-black/40 border border-white/10 backdrop-blur-sm text-white hover:bg-black/60 transition-colors\">\n <ChevronLeft className=\"h-4 w-4\" />\n </span>\n </button>\n <button\n onClick={next}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 min-h-11 min-w-11 rounded-full flex items-center justify-center z-10\"\n aria-label=\"Next\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-black/40 border border-white/10 backdrop-blur-sm text-white hover:bg-black/60 transition-colors\">\n <ChevronRight className=\"h-4 w-4\" />\n </span>\n </button>\n </>\n )}\n\n {total > 1 && (\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 flex items-center gap-1.5 z-10\">\n {collections.map((_, i) => (\n <button\n key={i}\n onClick={() => setActive(i)}\n className={`h-1.5 rounded-full transition-all duration-300 ${\n i === active ? \"w-6 bg-white\" : \"w-1.5 bg-white/40 hover:bg-white/70\"\n }`}\n aria-label={`Go to slide ${i + 1}`}\n />\n ))}\n </div>\n )}\n </div>\n </section>\n </FadeIn>\n );\n}\n"],"mappings":"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","names":[]}
@@ -4,6 +4,7 @@ import { useState, useEffect, useCallback } from "react";
4
4
  import { motion, AnimatePresence } from "framer-motion";
5
5
  import { ChevronLeft, ChevronRight, ArrowRight, Sparkles } from "lucide-react";
6
6
  import { FadeIn, EASE_OUT } from "./motion-primitives.js";
7
+ import { SectionHeading } from "./section-heading.js";
7
8
  import { formatDisplayPrice } from "../utils/format.js";
8
9
  import { useImageUrl } from "../utils/use-image-url.js";
9
10
  function Slide({ collection, href }) {
@@ -51,10 +52,7 @@ function Slide({ collection, href }) {
51
52
  }
52
53
  function FeaturedCarouselSkeleton() {
53
54
  return /* @__PURE__ */ jsx(FadeIn, { children: /* @__PURE__ */ jsxs("section", { className: "space-y-4", children: [
54
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-0.5", children: [
55
- /* @__PURE__ */ jsx(Sparkles, { className: "h-4 w-4 text-brand-purple" }),
56
- /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold", children: "Featured Collections" })
57
- ] }),
55
+ /* @__PURE__ */ jsx(SectionHeading, { icon: /* @__PURE__ */ jsx(Sparkles, {}), title: "Featured Collections", href: "/collections", linkLabel: "View all" }),
58
56
  /* @__PURE__ */ jsx("div", { className: "-mx-4 sm:-mx-6 lg:-mx-8 aspect-[16/7] sm:aspect-[21/9] bg-muted animate-pulse" })
59
57
  ] }) });
60
58
  }
@@ -80,23 +78,7 @@ function FeaturedCarousel({
80
78
  if (isLoading) return /* @__PURE__ */ jsx(FeaturedCarouselSkeleton, {});
81
79
  if (total === 0) return null;
82
80
  return /* @__PURE__ */ jsx(FadeIn, { children: /* @__PURE__ */ jsxs("section", { className: "space-y-4", children: [
83
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
84
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-0.5", children: [
85
- /* @__PURE__ */ jsx(Sparkles, { className: "h-4 w-4 text-brand-purple" }),
86
- /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold", children: "Featured Collections" })
87
- ] }),
88
- /* @__PURE__ */ jsxs(
89
- "a",
90
- {
91
- href: allCollectionsHref,
92
- 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",
93
- children: [
94
- "View all ",
95
- /* @__PURE__ */ jsx(ArrowRight, { className: "h-3.5 w-3.5" })
96
- ]
97
- }
98
- )
99
- ] }),
81
+ /* @__PURE__ */ jsx(SectionHeading, { icon: /* @__PURE__ */ jsx(Sparkles, {}), title: "Featured Collections", href: allCollectionsHref, linkLabel: "View all" }),
100
82
  /* @__PURE__ */ jsxs(
101
83
  "div",
102
84
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/featured-carousel.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { ChevronLeft, ChevronRight, ArrowRight, Sparkles } from \"lucide-react\";\nimport { FadeIn, EASE_OUT } from \"./motion-primitives.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\nexport interface FeaturedCarouselProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n}\n\nfunction Slide({ collection, href }: { collection: ApiCollection; href: string }) {\n const resolveImage = useImageUrl();\n const name = collection.name ?? \"Featured Collection\";\n const image = resolveImage(collection.image);\n\n return (\n <div className=\"relative w-full h-full\">\n {image ? (\n <img\n src={image}\n alt={name}\n loading=\"lazy\"\n className=\"absolute inset-0 w-full h-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/40\" />\n )}\n <div className=\"absolute inset-0 bg-gradient-to-t from-black/85 via-black/30 to-black/10\" />\n <div className=\"absolute inset-0 bg-gradient-to-r from-black/50 via-transparent to-transparent\" />\n <div className=\"absolute bottom-0 left-0 right-0 p-5 sm:p-8 lg:p-10\">\n <h2 className=\"text-2xl sm:text-3xl lg:text-4xl font-black text-white leading-tight mb-3 max-w-lg\">\n {name}\n </h2>\n <div className=\"flex items-center gap-4 mb-5\">\n {collection.totalSupply != null && (\n <span className=\"text-sm text-white/70\">\n <span className=\"font-bold text-white\">{collection.totalSupply}</span> items\n </span>\n )}\n {collection.floorPrice && (\n <span className=\"text-sm text-white/70\">\n Floor{\" \"}\n <span className=\"font-bold text-brand-orange\">\n {formatDisplayPrice(collection.floorPrice)}\n </span>\n </span>\n )}\n </div>\n <a\n href={href}\n className=\"inline-flex items-center gap-2 text-sm font-semibold px-4 py-2 rounded-lg bg-white/15 hover:bg-white/25 text-white border border-white/20 backdrop-blur-sm transition-colors\"\n >\n View Collection <ArrowRight className=\"h-3.5 w-3.5\" />\n </a>\n </div>\n </div>\n );\n}\n\nexport function FeaturedCarouselSkeleton() {\n return (\n <FadeIn>\n <section className=\"space-y-4\">\n <div className=\"flex items-center gap-2 mt-0.5\">\n <Sparkles className=\"h-4 w-4 text-brand-purple\" />\n <h2 className=\"text-xl font-bold\">Featured Collections</h2>\n </div>\n <div className=\"-mx-4 sm:-mx-6 lg:-mx-8 aspect-[16/7] sm:aspect-[21/9] bg-muted animate-pulse\" />\n </section>\n </FadeIn>\n );\n}\n\nexport function FeaturedCarousel({\n collections,\n isLoading,\n getHref,\n allCollectionsHref = \"/collections\",\n}: FeaturedCarouselProps) {\n const [active, setActive] = useState(0);\n const [paused, setPaused] = useState(false);\n const total = collections.length;\n\n const next = useCallback(() => setActive((p) => (p + 1) % total), [total]);\n const prev = useCallback(() => setActive((p) => (p - 1 + total) % total), [total]);\n\n useEffect(() => { setActive(0); }, [total]);\n\n useEffect(() => {\n if (paused || total <= 1) return;\n const id = setInterval(next, 6000);\n return () => clearInterval(id);\n }, [next, paused, total]);\n\n if (isLoading) return <FeaturedCarouselSkeleton />;\n if (total === 0) return null;\n\n return (\n <FadeIn>\n <section className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2 mt-0.5\">\n <Sparkles className=\"h-4 w-4 text-brand-purple\" />\n <h2 className=\"text-xl font-bold\">Featured Collections</h2>\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\n <div\n className=\"-mx-4 sm:-mx-6 lg:-mx-8 relative overflow-hidden aspect-[16/7] sm:aspect-[21/9] bg-muted\"\n onMouseEnter={() => setPaused(true)}\n onMouseLeave={() => setPaused(false)}\n >\n <AnimatePresence mode=\"wait\">\n <motion.div\n key={active}\n className=\"absolute inset-0\"\n initial={{ opacity: 0, x: 40 }}\n animate={{ opacity: 1, x: 0 }}\n exit={{ opacity: 0, x: -40 }}\n transition={{ duration: 0.45, ease: EASE_OUT }}\n >\n <Slide collection={collections[active]} href={getHref(collections[active])} />\n </motion.div>\n </AnimatePresence>\n\n {total > 1 && (\n <>\n <button\n onClick={prev}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 min-h-11 min-w-11 rounded-full flex items-center justify-center z-10\"\n aria-label=\"Previous\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-black/40 border border-white/10 backdrop-blur-sm text-white hover:bg-black/60 transition-colors\">\n <ChevronLeft className=\"h-4 w-4\" />\n </span>\n </button>\n <button\n onClick={next}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 min-h-11 min-w-11 rounded-full flex items-center justify-center z-10\"\n aria-label=\"Next\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-black/40 border border-white/10 backdrop-blur-sm text-white hover:bg-black/60 transition-colors\">\n <ChevronRight className=\"h-4 w-4\" />\n </span>\n </button>\n </>\n )}\n\n {total > 1 && (\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 flex items-center gap-1.5 z-10\">\n {collections.map((_, i) => (\n <button\n key={i}\n onClick={() => setActive(i)}\n className={`h-1.5 rounded-full transition-all duration-300 ${\n i === active ? \"w-6 bg-white\" : \"w-1.5 bg-white/40 hover:bg-white/70\"\n }`}\n aria-label={`Go to slide ${i + 1}`}\n />\n ))}\n </div>\n )}\n </div>\n </section>\n </FadeIn>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/featured-carousel.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { ChevronLeft, ChevronRight, ArrowRight, Sparkles } from \"lucide-react\";\nimport { FadeIn, EASE_OUT } from \"./motion-primitives.js\";\nimport { SectionHeading } from \"./section-heading.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\nexport interface FeaturedCarouselProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n allCollectionsHref?: string;\n}\n\nfunction Slide({ collection, href }: { collection: ApiCollection; href: string }) {\n const resolveImage = useImageUrl();\n const name = collection.name ?? \"Featured Collection\";\n const image = resolveImage(collection.image);\n\n return (\n <div className=\"relative w-full h-full\">\n {image ? (\n <img\n src={image}\n alt={name}\n loading=\"lazy\"\n className=\"absolute inset-0 w-full h-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/40\" />\n )}\n <div className=\"absolute inset-0 bg-gradient-to-t from-black/85 via-black/30 to-black/10\" />\n <div className=\"absolute inset-0 bg-gradient-to-r from-black/50 via-transparent to-transparent\" />\n <div className=\"absolute bottom-0 left-0 right-0 p-5 sm:p-8 lg:p-10\">\n <h2 className=\"text-2xl sm:text-3xl lg:text-4xl font-black text-white leading-tight mb-3 max-w-lg\">\n {name}\n </h2>\n <div className=\"flex items-center gap-4 mb-5\">\n {collection.totalSupply != null && (\n <span className=\"text-sm text-white/70\">\n <span className=\"font-bold text-white\">{collection.totalSupply}</span> items\n </span>\n )}\n {collection.floorPrice && (\n <span className=\"text-sm text-white/70\">\n Floor{\" \"}\n <span className=\"font-bold text-brand-orange\">\n {formatDisplayPrice(collection.floorPrice)}\n </span>\n </span>\n )}\n </div>\n <a\n href={href}\n className=\"inline-flex items-center gap-2 text-sm font-semibold px-4 py-2 rounded-lg bg-white/15 hover:bg-white/25 text-white border border-white/20 backdrop-blur-sm transition-colors\"\n >\n View Collection <ArrowRight className=\"h-3.5 w-3.5\" />\n </a>\n </div>\n </div>\n );\n}\n\nexport function FeaturedCarouselSkeleton() {\n return (\n <FadeIn>\n <section className=\"space-y-4\">\n <SectionHeading icon={<Sparkles />} title=\"Featured Collections\" href=\"/collections\" linkLabel=\"View all\" />\n <div className=\"-mx-4 sm:-mx-6 lg:-mx-8 aspect-[16/7] sm:aspect-[21/9] bg-muted animate-pulse\" />\n </section>\n </FadeIn>\n );\n}\n\nexport function FeaturedCarousel({\n collections,\n isLoading,\n getHref,\n allCollectionsHref = \"/collections\",\n}: FeaturedCarouselProps) {\n const [active, setActive] = useState(0);\n const [paused, setPaused] = useState(false);\n const total = collections.length;\n\n const next = useCallback(() => setActive((p) => (p + 1) % total), [total]);\n const prev = useCallback(() => setActive((p) => (p - 1 + total) % total), [total]);\n\n useEffect(() => { setActive(0); }, [total]);\n\n useEffect(() => {\n if (paused || total <= 1) return;\n const id = setInterval(next, 6000);\n return () => clearInterval(id);\n }, [next, paused, total]);\n\n if (isLoading) return <FeaturedCarouselSkeleton />;\n if (total === 0) return null;\n\n return (\n <FadeIn>\n <section className=\"space-y-4\">\n <SectionHeading icon={<Sparkles />} title=\"Featured Collections\" href={allCollectionsHref} linkLabel=\"View all\" />\n\n <div\n className=\"-mx-4 sm:-mx-6 lg:-mx-8 relative overflow-hidden aspect-[16/7] sm:aspect-[21/9] bg-muted\"\n onMouseEnter={() => setPaused(true)}\n onMouseLeave={() => setPaused(false)}\n >\n <AnimatePresence mode=\"wait\">\n <motion.div\n key={active}\n className=\"absolute inset-0\"\n initial={{ opacity: 0, x: 40 }}\n animate={{ opacity: 1, x: 0 }}\n exit={{ opacity: 0, x: -40 }}\n transition={{ duration: 0.45, ease: EASE_OUT }}\n >\n <Slide collection={collections[active]} href={getHref(collections[active])} />\n </motion.div>\n </AnimatePresence>\n\n {total > 1 && (\n <>\n <button\n onClick={prev}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 min-h-11 min-w-11 rounded-full flex items-center justify-center z-10\"\n aria-label=\"Previous\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-black/40 border border-white/10 backdrop-blur-sm text-white hover:bg-black/60 transition-colors\">\n <ChevronLeft className=\"h-4 w-4\" />\n </span>\n </button>\n <button\n onClick={next}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 min-h-11 min-w-11 rounded-full flex items-center justify-center z-10\"\n aria-label=\"Next\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-black/40 border border-white/10 backdrop-blur-sm text-white hover:bg-black/60 transition-colors\">\n <ChevronRight className=\"h-4 w-4\" />\n </span>\n </button>\n </>\n )}\n\n {total > 1 && (\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 flex items-center gap-1.5 z-10\">\n {collections.map((_, i) => (\n <button\n key={i}\n onClick={() => setActive(i)}\n className={`h-1.5 rounded-full transition-all duration-300 ${\n i === active ? \"w-6 bg-white\" : \"w-1.5 bg-white/40 hover:bg-white/70\"\n }`}\n aria-label={`Go to slide ${i + 1}`}\n />\n ))}\n </div>\n )}\n </div>\n </section>\n </FadeIn>\n );\n}\n"],"mappings":";AA0BQ,SAoGI,UApGJ,KAiBI,YAjBJ;AAxBR,SAAS,UAAU,WAAW,mBAAmB;AACjD,SAAS,QAAQ,uBAAuB;AACxC,SAAS,aAAa,cAAc,YAAY,gBAAgB;AAChE,SAAS,QAAQ,gBAAgB;AACjC,SAAS,sBAAsB;AAC/B,SAAS,0BAA0B;AAEnC,SAAS,mBAAmB;AAS5B,SAAS,MAAM,EAAE,YAAY,KAAK,GAAgD;AAChF,QAAM,eAAe,YAAY;AACjC,QAAM,OAAO,WAAW,QAAQ;AAChC,QAAM,QAAQ,aAAa,WAAW,KAAK;AAE3C,SACE,qBAAC,SAAI,WAAU,0BACZ;AAAA,YACC;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,KAAK;AAAA,QACL,SAAQ;AAAA,QACR,WAAU;AAAA;AAAA,IACZ,IAEA,oBAAC,SAAI,WAAU,8FAA6F;AAAA,IAE9G,oBAAC,SAAI,WAAU,4EAA2E;AAAA,IAC1F,oBAAC,SAAI,WAAU,kFAAiF;AAAA,IAChG,qBAAC,SAAI,WAAU,uDACb;AAAA,0BAAC,QAAG,WAAU,sFACX,gBACH;AAAA,MACA,qBAAC,SAAI,WAAU,gCACZ;AAAA,mBAAW,eAAe,QACzB,qBAAC,UAAK,WAAU,yBACd;AAAA,8BAAC,UAAK,WAAU,wBAAwB,qBAAW,aAAY;AAAA,UAAO;AAAA,WACxE;AAAA,QAED,WAAW,cACV,qBAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,UAChC;AAAA,UACN,oBAAC,UAAK,WAAU,+BACb,6BAAmB,WAAW,UAAU,GAC3C;AAAA,WACF;AAAA,SAEJ;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,WAAU;AAAA,UACX;AAAA;AAAA,YACiB,oBAAC,cAAW,WAAU,eAAc;AAAA;AAAA;AAAA,MACtD;AAAA,OACF;AAAA,KACF;AAEJ;AAEO,SAAS,2BAA2B;AACzC,SACE,oBAAC,UACC,+BAAC,aAAQ,WAAU,aACjB;AAAA,wBAAC,kBAAe,MAAM,oBAAC,YAAS,GAAI,OAAM,wBAAuB,MAAK,gBAAe,WAAU,YAAW;AAAA,IAC1G,oBAAC,SAAI,WAAU,iFAAgF;AAAA,KACjG,GACF;AAEJ;AAEO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB;AACvB,GAA0B;AACxB,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,CAAC;AACtC,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,QAAQ,YAAY;AAE1B,QAAM,OAAO,YAAY,MAAM,UAAU,CAAC,OAAO,IAAI,KAAK,KAAK,GAAG,CAAC,KAAK,CAAC;AACzE,QAAM,OAAO,YAAY,MAAM,UAAU,CAAC,OAAO,IAAI,IAAI,SAAS,KAAK,GAAG,CAAC,KAAK,CAAC;AAEjF,YAAU,MAAM;AAAE,cAAU,CAAC;AAAA,EAAG,GAAG,CAAC,KAAK,CAAC;AAE1C,YAAU,MAAM;AACd,QAAI,UAAU,SAAS,EAAG;AAC1B,UAAM,KAAK,YAAY,MAAM,GAAI;AACjC,WAAO,MAAM,cAAc,EAAE;AAAA,EAC/B,GAAG,CAAC,MAAM,QAAQ,KAAK,CAAC;AAExB,MAAI,UAAW,QAAO,oBAAC,4BAAyB;AAChD,MAAI,UAAU,EAAG,QAAO;AAExB,SACE,oBAAC,UACC,+BAAC,aAAQ,WAAU,aACjB;AAAA,wBAAC,kBAAe,MAAM,oBAAC,YAAS,GAAI,OAAM,wBAAuB,MAAM,oBAAoB,WAAU,YAAW;AAAA,IAEhH;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,cAAc,MAAM,UAAU,IAAI;AAAA,QAClC,cAAc,MAAM,UAAU,KAAK;AAAA,QAEnC;AAAA,8BAAC,mBAAgB,MAAK,QACpB;AAAA,YAAC,OAAO;AAAA,YAAP;AAAA,cAEC,WAAU;AAAA,cACV,SAAS,EAAE,SAAS,GAAG,GAAG,GAAG;AAAA,cAC7B,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;AAAA,cAC5B,MAAM,EAAE,SAAS,GAAG,GAAG,IAAI;AAAA,cAC3B,YAAY,EAAE,UAAU,MAAM,MAAM,SAAS;AAAA,cAE7C,8BAAC,SAAM,YAAY,YAAY,MAAM,GAAG,MAAM,QAAQ,YAAY,MAAM,CAAC,GAAG;AAAA;AAAA,YAPvE;AAAA,UAQP,GACF;AAAA,UAEC,QAAQ,KACP,iCACE;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,SAAS;AAAA,gBACT,WAAU;AAAA,gBACV,cAAW;AAAA,gBAEX,8BAAC,UAAK,WAAU,4JACd,8BAAC,eAAY,WAAU,WAAU,GACnC;AAAA;AAAA,YACF;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,SAAS;AAAA,gBACT,WAAU;AAAA,gBACV,cAAW;AAAA,gBAEX,8BAAC,UAAK,WAAU,4JACd,8BAAC,gBAAa,WAAU,WAAU,GACpC;AAAA;AAAA,YACF;AAAA,aACF;AAAA,UAGD,QAAQ,KACP,oBAAC,SAAI,WAAU,8EACZ,sBAAY,IAAI,CAAC,GAAG,MACnB;AAAA,YAAC;AAAA;AAAA,cAEC,SAAS,MAAM,UAAU,CAAC;AAAA,cAC1B,WAAW,kDACT,MAAM,SAAS,iBAAiB,qCAClC;AAAA,cACA,cAAY,eAAe,IAAI,CAAC;AAAA;AAAA,YAL3B;AAAA,UAMP,CACD,GACH;AAAA;AAAA;AAAA,IAEJ;AAAA,KACF,GACF;AAEJ;","names":[]}
@@ -35,24 +35,12 @@ module.exports = __toCommonJS(ip_type_nav_exports);
35
35
  var import_jsx_runtime = require("react/jsx-runtime");
36
36
  var import_link = __toESM(require("./link.js"), 1);
37
37
  var import_lucide_react = require("lucide-react");
38
+ var import_section_heading = require("./section-heading.js");
38
39
  var import_ip_type_badge = require("./ip-type-badge.js");
39
40
  var import_cn = require("../utils/cn.js");
40
41
  function IpTypeNav() {
41
42
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "space-y-4", children: [
42
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
43
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-xl sm:text-2xl font-black", children: "Browse by Type" }),
44
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
45
- import_link.default,
46
- {
47
- href: "/nft",
48
- className: "flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors",
49
- children: [
50
- "View all ",
51
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRight, { className: "h-3.5 w-3.5" })
52
- ]
53
- }
54
- )
55
- ] }),
43
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_section_heading.SectionHeading, { icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.LayoutGrid, {}), title: "Browse by Type", href: "/nft", linkLabel: "View all" }),
56
44
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 gap-3", children: import_ip_type_badge.IP_TYPE_CONFIG.map(({ slug, label, icon: Icon, colorClass, bgClass }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
57
45
  import_link.default,
58
46
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/ip-type-nav.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport { ArrowRight } from \"lucide-react\";\nimport { IP_TYPE_CONFIG } from \"./ip-type-badge.js\";\nimport { cn } from \"../utils/cn.js\";\n\nexport function IpTypeNav() {\n return (\n <section className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-xl sm:text-2xl font-black\">Browse by Type</h2>\n <Link\n href=\"/nft\"\n className=\"flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors\"\n >\n View all <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n <div className=\"grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 gap-3\">\n {IP_TYPE_CONFIG.map(({ slug, label, icon: Icon, colorClass, bgClass }) => (\n <Link\n key={slug}\n href={`/${slug}`}\n className=\"group flex flex-col items-center gap-2.5 p-4 rounded-xl border border-border bg-card hover:border-primary/40 hover:bg-card/80 transition-all hover:shadow-md hover:shadow-black/10\"\n >\n <div className={cn(\"h-10 w-10 rounded-xl flex items-center justify-center\", bgClass)}>\n <Icon className={cn(\"h-5 w-5\", colorClass)} />\n </div>\n <span className=\"text-xs font-semibold text-center leading-tight\">{label}</span>\n </Link>\n ))}\n </div>\n </section>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAWQ;AATR,kBAAiB;AACjB,0BAA2B;AAC3B,2BAA+B;AAC/B,gBAAmB;AAEZ,SAAS,YAAY;AAC1B,SACE,6CAAC,aAAQ,WAAU,aACjB;AAAA,iDAAC,SAAI,WAAU,qCACb;AAAA,kDAAC,QAAG,WAAU,kCAAiC,4BAAc;AAAA,MAC7D;AAAA,QAAC,YAAAA;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACX;AAAA;AAAA,YACU,4CAAC,kCAAW,WAAU,eAAc;AAAA;AAAA;AAAA,MAC/C;AAAA,OACF;AAAA,IAEA,4CAAC,SAAI,WAAU,wDACZ,8CAAe,IAAI,CAAC,EAAE,MAAM,OAAO,MAAM,MAAM,YAAY,QAAQ,MAClE;AAAA,MAAC,YAAAA;AAAA,MAAA;AAAA,QAEC,MAAM,IAAI,IAAI;AAAA,QACd,WAAU;AAAA,QAEV;AAAA,sDAAC,SAAI,eAAW,cAAG,yDAAyD,OAAO,GACjF,sDAAC,QAAK,eAAW,cAAG,WAAW,UAAU,GAAG,GAC9C;AAAA,UACA,4CAAC,UAAK,WAAU,mDAAmD,iBAAM;AAAA;AAAA;AAAA,MAPpE;AAAA,IAQP,CACD,GACH;AAAA,KACF;AAEJ;","names":["Link"]}
1
+ {"version":3,"sources":["../../src/components/ip-type-nav.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport { LayoutGrid } from \"lucide-react\";\nimport { SectionHeading } from \"./section-heading.js\";\nimport { IP_TYPE_CONFIG } from \"./ip-type-badge.js\";\nimport { cn } from \"../utils/cn.js\";\n\nexport function IpTypeNav() {\n return (\n <section className=\"space-y-4\">\n <SectionHeading icon={<LayoutGrid />} title=\"Browse by Type\" href=\"/nft\" linkLabel=\"View all\" />\n\n <div className=\"grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 gap-3\">\n {IP_TYPE_CONFIG.map(({ slug, label, icon: Icon, colorClass, bgClass }) => (\n <Link\n key={slug}\n href={`/${slug}`}\n className=\"group flex flex-col items-center gap-2.5 p-4 rounded-xl border border-border bg-card hover:border-primary/40 hover:bg-card/80 transition-all hover:shadow-md hover:shadow-black/10\"\n >\n <div className={cn(\"h-10 w-10 rounded-xl flex items-center justify-center\", bgClass)}>\n <Icon className={cn(\"h-5 w-5\", colorClass)} />\n </div>\n <span className=\"text-xs font-semibold text-center leading-tight\">{label}</span>\n </Link>\n ))}\n </div>\n </section>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAW4B;AAT5B,kBAAiB;AACjB,0BAA2B;AAC3B,6BAA+B;AAC/B,2BAA+B;AAC/B,gBAAmB;AAEZ,SAAS,YAAY;AAC1B,SACE,6CAAC,aAAQ,WAAU,aACjB;AAAA,gDAAC,yCAAe,MAAM,4CAAC,kCAAW,GAAI,OAAM,kBAAiB,MAAK,QAAO,WAAU,YAAW;AAAA,IAE9F,4CAAC,SAAI,WAAU,wDACZ,8CAAe,IAAI,CAAC,EAAE,MAAM,OAAO,MAAM,MAAM,YAAY,QAAQ,MAClE;AAAA,MAAC,YAAAA;AAAA,MAAA;AAAA,QAEC,MAAM,IAAI,IAAI;AAAA,QACd,WAAU;AAAA,QAEV;AAAA,sDAAC,SAAI,eAAW,cAAG,yDAAyD,OAAO,GACjF,sDAAC,QAAK,eAAW,cAAG,WAAW,UAAU,GAAG,GAC9C;AAAA,UACA,4CAAC,UAAK,WAAU,mDAAmD,iBAAM;AAAA;AAAA;AAAA,MAPpE;AAAA,IAQP,CACD,GACH;AAAA,KACF;AAEJ;","names":["Link"]}
@@ -1,25 +1,13 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import Link from "./link.js";
4
- import { ArrowRight } from "lucide-react";
4
+ import { LayoutGrid } from "lucide-react";
5
+ import { SectionHeading } from "./section-heading.js";
5
6
  import { IP_TYPE_CONFIG } from "./ip-type-badge.js";
6
7
  import { cn } from "../utils/cn.js";
7
8
  function IpTypeNav() {
8
9
  return /* @__PURE__ */ jsxs("section", { className: "space-y-4", children: [
9
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
10
- /* @__PURE__ */ jsx("h2", { className: "text-xl sm:text-2xl font-black", children: "Browse by Type" }),
11
- /* @__PURE__ */ jsxs(
12
- Link,
13
- {
14
- href: "/nft",
15
- className: "flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors",
16
- children: [
17
- "View all ",
18
- /* @__PURE__ */ jsx(ArrowRight, { className: "h-3.5 w-3.5" })
19
- ]
20
- }
21
- )
22
- ] }),
10
+ /* @__PURE__ */ jsx(SectionHeading, { icon: /* @__PURE__ */ jsx(LayoutGrid, {}), title: "Browse by Type", href: "/nft", linkLabel: "View all" }),
23
11
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 gap-3", children: IP_TYPE_CONFIG.map(({ slug, label, icon: Icon, colorClass, bgClass }) => /* @__PURE__ */ jsxs(
24
12
  Link,
25
13
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/ip-type-nav.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport { ArrowRight } from \"lucide-react\";\nimport { IP_TYPE_CONFIG } from \"./ip-type-badge.js\";\nimport { cn } from \"../utils/cn.js\";\n\nexport function IpTypeNav() {\n return (\n <section className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-xl sm:text-2xl font-black\">Browse by Type</h2>\n <Link\n href=\"/nft\"\n className=\"flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors\"\n >\n View all <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n <div className=\"grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 gap-3\">\n {IP_TYPE_CONFIG.map(({ slug, label, icon: Icon, colorClass, bgClass }) => (\n <Link\n key={slug}\n href={`/${slug}`}\n className=\"group flex flex-col items-center gap-2.5 p-4 rounded-xl border border-border bg-card hover:border-primary/40 hover:bg-card/80 transition-all hover:shadow-md hover:shadow-black/10\"\n >\n <div className={cn(\"h-10 w-10 rounded-xl flex items-center justify-center\", bgClass)}>\n <Icon className={cn(\"h-5 w-5\", colorClass)} />\n </div>\n <span className=\"text-xs font-semibold text-center leading-tight\">{label}</span>\n </Link>\n ))}\n </div>\n </section>\n );\n}\n"],"mappings":";AAWQ,cACA,YADA;AATR,OAAO,UAAU;AACjB,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB;AAC/B,SAAS,UAAU;AAEZ,SAAS,YAAY;AAC1B,SACE,qBAAC,aAAQ,WAAU,aACjB;AAAA,yBAAC,SAAI,WAAU,qCACb;AAAA,0BAAC,QAAG,WAAU,kCAAiC,4BAAc;AAAA,MAC7D;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACX;AAAA;AAAA,YACU,oBAAC,cAAW,WAAU,eAAc;AAAA;AAAA;AAAA,MAC/C;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAU,wDACZ,yBAAe,IAAI,CAAC,EAAE,MAAM,OAAO,MAAM,MAAM,YAAY,QAAQ,MAClE;AAAA,MAAC;AAAA;AAAA,QAEC,MAAM,IAAI,IAAI;AAAA,QACd,WAAU;AAAA,QAEV;AAAA,8BAAC,SAAI,WAAW,GAAG,yDAAyD,OAAO,GACjF,8BAAC,QAAK,WAAW,GAAG,WAAW,UAAU,GAAG,GAC9C;AAAA,UACA,oBAAC,UAAK,WAAU,mDAAmD,iBAAM;AAAA;AAAA;AAAA,MAPpE;AAAA,IAQP,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/ip-type-nav.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport { LayoutGrid } from \"lucide-react\";\nimport { SectionHeading } from \"./section-heading.js\";\nimport { IP_TYPE_CONFIG } from \"./ip-type-badge.js\";\nimport { cn } from \"../utils/cn.js\";\n\nexport function IpTypeNav() {\n return (\n <section className=\"space-y-4\">\n <SectionHeading icon={<LayoutGrid />} title=\"Browse by Type\" href=\"/nft\" linkLabel=\"View all\" />\n\n <div className=\"grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 gap-3\">\n {IP_TYPE_CONFIG.map(({ slug, label, icon: Icon, colorClass, bgClass }) => (\n <Link\n key={slug}\n href={`/${slug}`}\n className=\"group flex flex-col items-center gap-2.5 p-4 rounded-xl border border-border bg-card hover:border-primary/40 hover:bg-card/80 transition-all hover:shadow-md hover:shadow-black/10\"\n >\n <div className={cn(\"h-10 w-10 rounded-xl flex items-center justify-center\", bgClass)}>\n <Icon className={cn(\"h-5 w-5\", colorClass)} />\n </div>\n <span className=\"text-xs font-semibold text-center leading-tight\">{label}</span>\n </Link>\n ))}\n </div>\n </section>\n );\n}\n"],"mappings":";AAW4B,cAIlB,YAJkB;AAT5B,OAAO,UAAU;AACjB,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,UAAU;AAEZ,SAAS,YAAY;AAC1B,SACE,qBAAC,aAAQ,WAAU,aACjB;AAAA,wBAAC,kBAAe,MAAM,oBAAC,cAAW,GAAI,OAAM,kBAAiB,MAAK,QAAO,WAAU,YAAW;AAAA,IAE9F,oBAAC,SAAI,WAAU,wDACZ,yBAAe,IAAI,CAAC,EAAE,MAAM,OAAO,MAAM,MAAM,YAAY,QAAQ,MAClE;AAAA,MAAC;AAAA;AAAA,QAEC,MAAM,IAAI,IAAI;AAAA,QACd,WAAU;AAAA,QAEV;AAAA,8BAAC,SAAI,WAAW,GAAG,yDAAyD,OAAO,GACjF,8BAAC,QAAK,WAAW,GAAG,WAAW,UAAU,GAAG,GAC9C;AAAA,UACA,oBAAC,UAAK,WAAU,mDAAmD,iBAAM;AAAA;AAAA;AAAA,MAPpE;AAAA,IAQP,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medialane/ui",
3
- "version": "0.322.0",
3
+ "version": "0.323.0",
4
4
  "description": "Shared UI components for Medialane apps",
5
5
  "type": "module",
6
6
  "sideEffects": false,