@medialane/ui 0.43.0 → 0.45.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.
@@ -37,6 +37,12 @@ var import_image = __toESM(require("next/image"), 1);
37
37
  var import_link = __toESM(require("next/link"), 1);
38
38
  var import_lucide_react = require("lucide-react");
39
39
  var import_cn = require("../utils/cn.js");
40
+ const GRID_COLS = {
41
+ 1: "grid-cols-1",
42
+ 2: "grid-cols-2",
43
+ 3: "grid-cols-3",
44
+ 4: "grid-cols-4"
45
+ };
40
46
  function AssetCollectionBar({
41
47
  collectionName,
42
48
  collectionImage,
@@ -45,53 +51,76 @@ function AssetCollectionBar({
45
51
  siblingTokens,
46
52
  onNavigate
47
53
  }) {
48
- const currentIndex = siblingTokens.findIndex((t) => String(t.tokenId) === String(currentTokenId));
49
- const prevToken = currentIndex > 0 ? siblingTokens[currentIndex - 1] : null;
50
- const nextToken = currentIndex >= 0 && currentIndex < siblingTokens.length - 1 ? siblingTokens[currentIndex + 1] : null;
51
- const showFilmstrip = siblingTokens.length > 1;
52
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rounded-2xl bg-card/40 px-4 py-3 space-y-3", children: [
53
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_link.default, { href: collectionHref, className: "flex items-center justify-center gap-3 min-w-0 group", children: [
54
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative h-10 w-10 rounded-xl overflow-hidden shrink-0 bg-gradient-to-br from-primary/20 to-purple-500/20 ring-1 ring-border/60 group-hover:ring-primary/40 transition", children: collectionImage ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_image.default, { src: collectionImage, alt: "", fill: true, className: "object-cover", unoptimized: true }) : null }),
55
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-semibold truncate group-hover:text-primary transition-colors", children: collectionName })
54
+ const total = siblingTokens.length;
55
+ const currentIndex = siblingTokens.findIndex(
56
+ (t) => String(t.tokenId) === String(currentTokenId)
57
+ );
58
+ const PREVIEW_SIZE = 4;
59
+ const windowStart = Math.max(
60
+ 0,
61
+ Math.min(currentIndex - 1, total - PREVIEW_SIZE)
62
+ );
63
+ const preview = siblingTokens.slice(windowStart, windowStart + PREVIEW_SIZE);
64
+ const colCount = Math.min(preview.length, 4);
65
+ const gridCols = GRID_COLS[colCount] ?? "grid-cols-4";
66
+ const showGrid = total > 1;
67
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rounded-2xl border border-border/50 bg-card overflow-hidden", children: [
68
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "px-4 pt-4 pb-3.5", children: [
69
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/60 mb-2.5 select-none", children: "Collection" }),
70
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_link.default, { href: collectionHref, className: "flex items-center gap-3 group min-w-0", children: [
71
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative h-11 w-11 rounded-xl overflow-hidden shrink-0 bg-gradient-to-br from-brand-blue/20 to-brand-purple/20 ring-1 ring-border/40 group-hover:ring-border/70 transition-all", children: collectionImage ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_image.default, { src: collectionImage, alt: "", fill: true, className: "object-cover", unoptimized: true }) : null }),
72
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-bold leading-tight truncate min-w-0 flex-1 group-hover:text-primary transition-colors", children: collectionName }),
73
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "shrink-0 h-8 w-8 rounded-xl bg-muted/60 flex items-center justify-center text-muted-foreground group-hover:bg-muted group-hover:text-foreground transition-all", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRight, { className: "h-3.5 w-3.5" }) })
74
+ ] })
56
75
  ] }),
57
- showFilmstrip ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1.5", children: [
58
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
59
- "button",
60
- {
61
- type: "button",
62
- disabled: !prevToken,
63
- onClick: () => prevToken && onNavigate(prevToken.tokenId),
64
- className: "shrink-0 inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:text-foreground active:scale-95 disabled:opacity-30 disabled:pointer-events-none",
65
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronLeft, { className: "h-4 w-4" })
66
- }
67
- ),
68
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex items-center gap-2 overflow-x-auto scroll-smooth [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: siblingTokens.map((sibling) => {
69
- const isCurrent = String(sibling.tokenId) === String(currentTokenId);
70
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
71
- "button",
72
- {
73
- type: "button",
74
- onClick: () => onNavigate(sibling.tokenId),
75
- className: (0, import_cn.cn)(
76
- "relative h-20 w-20 shrink-0 rounded-xl overflow-hidden ring-2 transition",
77
- isCurrent ? "ring-primary" : "ring-transparent hover:ring-border"
78
- ),
79
- children: sibling.image ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_image.default, { src: sibling.image, alt: "", fill: true, className: "object-cover", unoptimized: true }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-full w-full bg-muted" })
80
- },
81
- sibling.tokenId
82
- );
83
- }) }),
84
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
85
- "button",
86
- {
87
- type: "button",
88
- disabled: !nextToken,
89
- onClick: () => nextToken && onNavigate(nextToken.tokenId),
90
- className: "shrink-0 inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:text-foreground active:scale-95 disabled:opacity-30 disabled:pointer-events-none",
91
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronRight, { className: "h-4 w-4" })
92
- }
93
- )
94
- ] }) : null
76
+ showGrid && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
77
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-px bg-border/40 mx-4" }),
78
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "px-4 py-3.5", children: [
79
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between mb-3", children: [
80
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/60 select-none", children: [
81
+ "In this collection \xB7 ",
82
+ total
83
+ ] }),
84
+ total > PREVIEW_SIZE && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
85
+ import_link.default,
86
+ {
87
+ href: collectionHref,
88
+ className: "text-[10px] font-semibold text-muted-foreground hover:text-foreground transition-colors",
89
+ children: "See all \u2192"
90
+ }
91
+ )
92
+ ] }),
93
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_cn.cn)("grid gap-1.5", gridCols), children: preview.map((sibling) => {
94
+ const isCurrent = String(sibling.tokenId) === String(currentTokenId);
95
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
96
+ "button",
97
+ {
98
+ type: "button",
99
+ onClick: () => !isCurrent && onNavigate(sibling.tokenId),
100
+ disabled: isCurrent,
101
+ className: (0, import_cn.cn)(
102
+ "group relative aspect-square rounded-xl overflow-hidden transition-all duration-200",
103
+ isCurrent ? "opacity-100 cursor-default" : "opacity-50 hover:opacity-100 active:scale-95"
104
+ ),
105
+ children: sibling.image ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
106
+ import_image.default,
107
+ {
108
+ src: sibling.image,
109
+ alt: "",
110
+ fill: true,
111
+ className: (0, import_cn.cn)(
112
+ "object-cover transition-transform duration-300",
113
+ !isCurrent && "group-hover:scale-105"
114
+ ),
115
+ unoptimized: true
116
+ }
117
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-full w-full bg-muted" })
118
+ },
119
+ sibling.tokenId
120
+ );
121
+ }) })
122
+ ] })
123
+ ] })
95
124
  ] });
96
125
  }
97
126
  // Annotate the CommonJS export names for ESM import in node:
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/asset-collection-bar.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"next/image\";\nimport Link from \"next/link\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface AssetCollectionBarSibling {\n tokenId: string;\n /** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). `null` renders a placeholder. */\n image: string | null;\n}\n\nexport interface AssetCollectionBarProps {\n collectionName: string;\n /** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). */\n collectionImage?: string | null;\n collectionHref: string;\n currentTokenId: string;\n siblingTokens: AssetCollectionBarSibling[];\n onNavigate: (tokenId: string) => void;\n}\n\n/**\n * Collection identity bar: centered avatar+name, with a filmstrip of\n * collection siblings on a second row for browsing (replaces plain-text\n * Prev/Next). Soft `bg-card/40` surface, no hard border — matches the\n * aurora-glow design language instead of an OpenSea-style boxed panel.\n * Collection-only: putting Owner inside this card reads as if ownership were\n * a collection attribute (2026-07-05 feedback) — it lives in `AssetOwnerRow`\n * as a sibling instead. Other asset-level concerns (IP-type, explorer/share/\n * report) still live elsewhere (`AssetHeaderBlock`, `AssetUtilityIcons`).\n */\nexport function AssetCollectionBar({\n collectionName,\n collectionImage,\n collectionHref,\n currentTokenId,\n siblingTokens,\n onNavigate,\n}: AssetCollectionBarProps) {\n const currentIndex = siblingTokens.findIndex((t) => String(t.tokenId) === String(currentTokenId));\n const prevToken = currentIndex > 0 ? siblingTokens[currentIndex - 1] : null;\n const nextToken =\n currentIndex >= 0 && currentIndex < siblingTokens.length - 1 ? siblingTokens[currentIndex + 1] : null;\n const showFilmstrip = siblingTokens.length > 1;\n\n return (\n <div className=\"rounded-2xl bg-card/40 px-4 py-3 space-y-3\">\n <Link href={collectionHref} className=\"flex items-center justify-center gap-3 min-w-0 group\">\n <div className=\"relative h-10 w-10 rounded-xl overflow-hidden shrink-0 bg-gradient-to-br from-primary/20 to-purple-500/20 ring-1 ring-border/60 group-hover:ring-primary/40 transition\">\n {collectionImage ? (\n <Image src={collectionImage} alt=\"\" fill className=\"object-cover\" unoptimized />\n ) : null}\n </div>\n <p className=\"text-sm font-semibold truncate group-hover:text-primary transition-colors\">\n {collectionName}\n </p>\n </Link>\n\n {showFilmstrip ? (\n <div className=\"flex items-center gap-1.5\">\n <button\n type=\"button\"\n disabled={!prevToken}\n onClick={() => prevToken && onNavigate(prevToken.tokenId)}\n className=\"shrink-0 inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:text-foreground active:scale-95 disabled:opacity-30 disabled:pointer-events-none\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </button>\n <div className=\"flex items-center gap-2 overflow-x-auto scroll-smooth [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\">\n {siblingTokens.map((sibling) => {\n const isCurrent = String(sibling.tokenId) === String(currentTokenId);\n return (\n <button\n key={sibling.tokenId}\n type=\"button\"\n onClick={() => onNavigate(sibling.tokenId)}\n className={cn(\n \"relative h-20 w-20 shrink-0 rounded-xl overflow-hidden ring-2 transition\",\n isCurrent ? \"ring-primary\" : \"ring-transparent hover:ring-border\"\n )}\n >\n {sibling.image ? (\n <Image src={sibling.image} alt=\"\" fill className=\"object-cover\" unoptimized />\n ) : (\n <div className=\"h-full w-full bg-muted\" />\n )}\n </button>\n );\n })}\n </div>\n <button\n type=\"button\"\n disabled={!nextToken}\n onClick={() => nextToken && onNavigate(nextToken.tokenId)}\n className=\"shrink-0 inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:text-foreground active:scale-95 disabled:opacity-30 disabled:pointer-events-none\"\n >\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiDM;AA/CN,mBAAkB;AAClB,kBAAiB;AACjB,0BAA0C;AAC1C,gBAAmB;AA4BZ,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,eAAe,cAAc,UAAU,CAAC,MAAM,OAAO,EAAE,OAAO,MAAM,OAAO,cAAc,CAAC;AAChG,QAAM,YAAY,eAAe,IAAI,cAAc,eAAe,CAAC,IAAI;AACvE,QAAM,YACJ,gBAAgB,KAAK,eAAe,cAAc,SAAS,IAAI,cAAc,eAAe,CAAC,IAAI;AACnG,QAAM,gBAAgB,cAAc,SAAS;AAE7C,SACE,6CAAC,SAAI,WAAU,8CACb;AAAA,iDAAC,YAAAA,SAAA,EAAK,MAAM,gBAAgB,WAAU,wDACpC;AAAA,kDAAC,SAAI,WAAU,0KACZ,4BACC,4CAAC,aAAAC,SAAA,EAAM,KAAK,iBAAiB,KAAI,IAAG,MAAI,MAAC,WAAU,gBAAe,aAAW,MAAC,IAC5E,MACN;AAAA,MACA,4CAAC,OAAE,WAAU,6EACV,0BACH;AAAA,OACF;AAAA,IAEC,gBACC,6CAAC,SAAI,WAAU,6BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,CAAC;AAAA,UACX,SAAS,MAAM,aAAa,WAAW,UAAU,OAAO;AAAA,UACxD,WAAU;AAAA,UAEV,sDAAC,mCAAY,WAAU,WAAU;AAAA;AAAA,MACnC;AAAA,MACA,4CAAC,SAAI,WAAU,8GACZ,wBAAc,IAAI,CAAC,YAAY;AAC9B,cAAM,YAAY,OAAO,QAAQ,OAAO,MAAM,OAAO,cAAc;AACnE,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,SAAS,MAAM,WAAW,QAAQ,OAAO;AAAA,YACzC,eAAW;AAAA,cACT;AAAA,cACA,YAAY,iBAAiB;AAAA,YAC/B;AAAA,YAEC,kBAAQ,QACP,4CAAC,aAAAA,SAAA,EAAM,KAAK,QAAQ,OAAO,KAAI,IAAG,MAAI,MAAC,WAAU,gBAAe,aAAW,MAAC,IAE5E,4CAAC,SAAI,WAAU,0BAAyB;AAAA;AAAA,UAXrC,QAAQ;AAAA,QAaf;AAAA,MAEJ,CAAC,GACH;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,CAAC;AAAA,UACX,SAAS,MAAM,aAAa,WAAW,UAAU,OAAO;AAAA,UACxD,WAAU;AAAA,UAEV,sDAAC,oCAAa,WAAU,WAAU;AAAA;AAAA,MACpC;AAAA,OACF,IACE;AAAA,KACN;AAEJ;","names":["Link","Image"]}
1
+ {"version":3,"sources":["../../src/components/asset-collection-bar.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"next/image\";\nimport Link from \"next/link\";\nimport { ArrowRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface AssetCollectionBarSibling {\n tokenId: string;\n /** Already-resolved, ready-to-render src. `null` renders a placeholder. */\n image: string | null;\n}\n\nexport interface AssetCollectionBarProps {\n collectionName: string;\n collectionImage?: string | null;\n collectionHref: string;\n currentTokenId: string;\n siblingTokens: AssetCollectionBarSibling[];\n onNavigate: (tokenId: string) => void;\n}\n\nconst GRID_COLS: Record<number, string> = {\n 1: \"grid-cols-1\",\n 2: \"grid-cols-2\",\n 3: \"grid-cols-3\",\n 4: \"grid-cols-4\",\n};\n\nexport function AssetCollectionBar({\n collectionName,\n collectionImage,\n collectionHref,\n currentTokenId,\n siblingTokens,\n onNavigate,\n}: AssetCollectionBarProps) {\n const total = siblingTokens.length;\n const currentIndex = siblingTokens.findIndex(\n (t) => String(t.tokenId) === String(currentTokenId)\n );\n\n // Window of up to 4 items centered around the current token\n const PREVIEW_SIZE = 4;\n const windowStart = Math.max(\n 0,\n Math.min(currentIndex - 1, total - PREVIEW_SIZE)\n );\n const preview = siblingTokens.slice(windowStart, windowStart + PREVIEW_SIZE);\n const colCount = Math.min(preview.length, 4) as 1 | 2 | 3 | 4;\n const gridCols = GRID_COLS[colCount] ?? \"grid-cols-4\";\n\n const showGrid = total > 1;\n\n return (\n <div className=\"rounded-2xl border border-border/50 bg-card overflow-hidden\">\n\n {/* ── Collection identity ── */}\n <div className=\"px-4 pt-4 pb-3.5\">\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/60 mb-2.5 select-none\">\n Collection\n </p>\n <Link href={collectionHref} className=\"flex items-center gap-3 group min-w-0\">\n {/* Avatar */}\n <div className=\"relative h-11 w-11 rounded-xl overflow-hidden shrink-0 bg-gradient-to-br from-brand-blue/20 to-brand-purple/20 ring-1 ring-border/40 group-hover:ring-border/70 transition-all\">\n {collectionImage ? (\n <Image src={collectionImage} alt=\"\" fill className=\"object-cover\" unoptimized />\n ) : null}\n </div>\n\n {/* Name */}\n <p className=\"text-sm font-bold leading-tight truncate min-w-0 flex-1 group-hover:text-primary transition-colors\">\n {collectionName}\n </p>\n\n {/* Arrow chip */}\n <div className=\"shrink-0 h-8 w-8 rounded-xl bg-muted/60 flex items-center justify-center text-muted-foreground group-hover:bg-muted group-hover:text-foreground transition-all\">\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </div>\n </Link>\n </div>\n\n {/* ── Grid explorer ── */}\n {showGrid && (\n <>\n <div className=\"h-px bg-border/40 mx-4\" />\n <div className=\"px-4 py-3.5\">\n <div className=\"flex items-center justify-between mb-3\">\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/60 select-none\">\n In this collection · {total}\n </p>\n {total > PREVIEW_SIZE && (\n <Link\n href={collectionHref}\n className=\"text-[10px] font-semibold text-muted-foreground hover:text-foreground transition-colors\"\n >\n See all →\n </Link>\n )}\n </div>\n\n <div className={cn(\"grid gap-1.5\", gridCols)}>\n {preview.map((sibling) => {\n const isCurrent =\n String(sibling.tokenId) === String(currentTokenId);\n return (\n <button\n key={sibling.tokenId}\n type=\"button\"\n onClick={() => !isCurrent && onNavigate(sibling.tokenId)}\n disabled={isCurrent}\n className={cn(\n \"group relative aspect-square rounded-xl overflow-hidden transition-all duration-200\",\n isCurrent\n ? \"opacity-100 cursor-default\"\n : \"opacity-50 hover:opacity-100 active:scale-95\"\n )}\n >\n {sibling.image ? (\n <Image\n src={sibling.image}\n alt=\"\"\n fill\n className={cn(\n \"object-cover transition-transform duration-300\",\n !isCurrent && \"group-hover:scale-105\"\n )}\n unoptimized\n />\n ) : (\n <div className=\"h-full w-full bg-muted\" />\n )}\n </button>\n );\n })}\n </div>\n </div>\n </>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA2DQ;AAzDR,mBAAkB;AAClB,kBAAiB;AACjB,0BAA2B;AAC3B,gBAAmB;AAiBnB,MAAM,YAAoC;AAAA,EACxC,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAEO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,QAAQ,cAAc;AAC5B,QAAM,eAAe,cAAc;AAAA,IACjC,CAAC,MAAM,OAAO,EAAE,OAAO,MAAM,OAAO,cAAc;AAAA,EACpD;AAGA,QAAM,eAAe;AACrB,QAAM,cAAc,KAAK;AAAA,IACvB;AAAA,IACA,KAAK,IAAI,eAAe,GAAG,QAAQ,YAAY;AAAA,EACjD;AACA,QAAM,UAAU,cAAc,MAAM,aAAa,cAAc,YAAY;AAC3E,QAAM,WAAW,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAC3C,QAAM,WAAW,UAAU,QAAQ,KAAK;AAExC,QAAM,WAAW,QAAQ;AAEzB,SACE,6CAAC,SAAI,WAAU,+DAGb;AAAA,iDAAC,SAAI,WAAU,oBACb;AAAA,kDAAC,OAAE,WAAU,mGAAkG,wBAE/G;AAAA,MACA,6CAAC,YAAAA,SAAA,EAAK,MAAM,gBAAgB,WAAU,yCAEpC;AAAA,oDAAC,SAAI,WAAU,kLACZ,4BACC,4CAAC,aAAAC,SAAA,EAAM,KAAK,iBAAiB,KAAI,IAAG,MAAI,MAAC,WAAU,gBAAe,aAAW,MAAC,IAC5E,MACN;AAAA,QAGA,4CAAC,OAAE,WAAU,sGACV,0BACH;AAAA,QAGA,4CAAC,SAAI,WAAU,kKACb,sDAAC,kCAAW,WAAU,eAAc,GACtC;AAAA,SACF;AAAA,OACF;AAAA,IAGC,YACC,4EACE;AAAA,kDAAC,SAAI,WAAU,0BAAyB;AAAA,MACxC,6CAAC,SAAI,WAAU,eACb;AAAA,qDAAC,SAAI,WAAU,0CACb;AAAA,uDAAC,OAAE,WAAU,4FAA2F;AAAA;AAAA,YAChF;AAAA,aACxB;AAAA,UACC,QAAQ,gBACP;AAAA,YAAC,YAAAD;AAAA,YAAA;AAAA,cACC,MAAM;AAAA,cACN,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,WAEJ;AAAA,QAEA,4CAAC,SAAI,eAAW,cAAG,gBAAgB,QAAQ,GACxC,kBAAQ,IAAI,CAAC,YAAY;AACxB,gBAAM,YACJ,OAAO,QAAQ,OAAO,MAAM,OAAO,cAAc;AACnD,iBACE;AAAA,YAAC;AAAA;AAAA,cAEC,MAAK;AAAA,cACL,SAAS,MAAM,CAAC,aAAa,WAAW,QAAQ,OAAO;AAAA,cACvD,UAAU;AAAA,cACV,eAAW;AAAA,gBACT;AAAA,gBACA,YACI,+BACA;AAAA,cACN;AAAA,cAEC,kBAAQ,QACP;AAAA,gBAAC,aAAAC;AAAA,gBAAA;AAAA,kBACC,KAAK,QAAQ;AAAA,kBACb,KAAI;AAAA,kBACJ,MAAI;AAAA,kBACJ,eAAW;AAAA,oBACT;AAAA,oBACA,CAAC,aAAa;AAAA,kBAChB;AAAA,kBACA,aAAW;AAAA;AAAA,cACb,IAEA,4CAAC,SAAI,WAAU,0BAAyB;AAAA;AAAA,YAvBrC,QAAQ;AAAA,UAyBf;AAAA,QAEJ,CAAC,GACH;AAAA,SACF;AAAA,OACF;AAAA,KAEJ;AAEJ;","names":["Link","Image"]}
@@ -2,28 +2,17 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
3
  interface AssetCollectionBarSibling {
4
4
  tokenId: string;
5
- /** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). `null` renders a placeholder. */
5
+ /** Already-resolved, ready-to-render src. `null` renders a placeholder. */
6
6
  image: string | null;
7
7
  }
8
8
  interface AssetCollectionBarProps {
9
9
  collectionName: string;
10
- /** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). */
11
10
  collectionImage?: string | null;
12
11
  collectionHref: string;
13
12
  currentTokenId: string;
14
13
  siblingTokens: AssetCollectionBarSibling[];
15
14
  onNavigate: (tokenId: string) => void;
16
15
  }
17
- /**
18
- * Collection identity bar: centered avatar+name, with a filmstrip of
19
- * collection siblings on a second row for browsing (replaces plain-text
20
- * Prev/Next). Soft `bg-card/40` surface, no hard border — matches the
21
- * aurora-glow design language instead of an OpenSea-style boxed panel.
22
- * Collection-only: putting Owner inside this card reads as if ownership were
23
- * a collection attribute (2026-07-05 feedback) — it lives in `AssetOwnerRow`
24
- * as a sibling instead. Other asset-level concerns (IP-type, explorer/share/
25
- * report) still live elsewhere (`AssetHeaderBlock`, `AssetUtilityIcons`).
26
- */
27
16
  declare function AssetCollectionBar({ collectionName, collectionImage, collectionHref, currentTokenId, siblingTokens, onNavigate, }: AssetCollectionBarProps): react_jsx_runtime.JSX.Element;
28
17
 
29
18
  export { AssetCollectionBar, type AssetCollectionBarProps, type AssetCollectionBarSibling };
@@ -2,28 +2,17 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
3
  interface AssetCollectionBarSibling {
4
4
  tokenId: string;
5
- /** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). `null` renders a placeholder. */
5
+ /** Already-resolved, ready-to-render src. `null` renders a placeholder. */
6
6
  image: string | null;
7
7
  }
8
8
  interface AssetCollectionBarProps {
9
9
  collectionName: string;
10
- /** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). */
11
10
  collectionImage?: string | null;
12
11
  collectionHref: string;
13
12
  currentTokenId: string;
14
13
  siblingTokens: AssetCollectionBarSibling[];
15
14
  onNavigate: (tokenId: string) => void;
16
15
  }
17
- /**
18
- * Collection identity bar: centered avatar+name, with a filmstrip of
19
- * collection siblings on a second row for browsing (replaces plain-text
20
- * Prev/Next). Soft `bg-card/40` surface, no hard border — matches the
21
- * aurora-glow design language instead of an OpenSea-style boxed panel.
22
- * Collection-only: putting Owner inside this card reads as if ownership were
23
- * a collection attribute (2026-07-05 feedback) — it lives in `AssetOwnerRow`
24
- * as a sibling instead. Other asset-level concerns (IP-type, explorer/share/
25
- * report) still live elsewhere (`AssetHeaderBlock`, `AssetUtilityIcons`).
26
- */
27
16
  declare function AssetCollectionBar({ collectionName, collectionImage, collectionHref, currentTokenId, siblingTokens, onNavigate, }: AssetCollectionBarProps): react_jsx_runtime.JSX.Element;
28
17
 
29
18
  export { AssetCollectionBar, type AssetCollectionBarProps, type AssetCollectionBarSibling };
@@ -1,9 +1,15 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import Image from "next/image";
4
4
  import Link from "next/link";
5
- import { ChevronLeft, ChevronRight } from "lucide-react";
5
+ import { ArrowRight } from "lucide-react";
6
6
  import { cn } from "../utils/cn.js";
7
+ const GRID_COLS = {
8
+ 1: "grid-cols-1",
9
+ 2: "grid-cols-2",
10
+ 3: "grid-cols-3",
11
+ 4: "grid-cols-4"
12
+ };
7
13
  function AssetCollectionBar({
8
14
  collectionName,
9
15
  collectionImage,
@@ -12,53 +18,76 @@ function AssetCollectionBar({
12
18
  siblingTokens,
13
19
  onNavigate
14
20
  }) {
15
- const currentIndex = siblingTokens.findIndex((t) => String(t.tokenId) === String(currentTokenId));
16
- const prevToken = currentIndex > 0 ? siblingTokens[currentIndex - 1] : null;
17
- const nextToken = currentIndex >= 0 && currentIndex < siblingTokens.length - 1 ? siblingTokens[currentIndex + 1] : null;
18
- const showFilmstrip = siblingTokens.length > 1;
19
- return /* @__PURE__ */ jsxs("div", { className: "rounded-2xl bg-card/40 px-4 py-3 space-y-3", children: [
20
- /* @__PURE__ */ jsxs(Link, { href: collectionHref, className: "flex items-center justify-center gap-3 min-w-0 group", children: [
21
- /* @__PURE__ */ jsx("div", { className: "relative h-10 w-10 rounded-xl overflow-hidden shrink-0 bg-gradient-to-br from-primary/20 to-purple-500/20 ring-1 ring-border/60 group-hover:ring-primary/40 transition", children: collectionImage ? /* @__PURE__ */ jsx(Image, { src: collectionImage, alt: "", fill: true, className: "object-cover", unoptimized: true }) : null }),
22
- /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold truncate group-hover:text-primary transition-colors", children: collectionName })
21
+ const total = siblingTokens.length;
22
+ const currentIndex = siblingTokens.findIndex(
23
+ (t) => String(t.tokenId) === String(currentTokenId)
24
+ );
25
+ const PREVIEW_SIZE = 4;
26
+ const windowStart = Math.max(
27
+ 0,
28
+ Math.min(currentIndex - 1, total - PREVIEW_SIZE)
29
+ );
30
+ const preview = siblingTokens.slice(windowStart, windowStart + PREVIEW_SIZE);
31
+ const colCount = Math.min(preview.length, 4);
32
+ const gridCols = GRID_COLS[colCount] ?? "grid-cols-4";
33
+ const showGrid = total > 1;
34
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border border-border/50 bg-card overflow-hidden", children: [
35
+ /* @__PURE__ */ jsxs("div", { className: "px-4 pt-4 pb-3.5", children: [
36
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/60 mb-2.5 select-none", children: "Collection" }),
37
+ /* @__PURE__ */ jsxs(Link, { href: collectionHref, className: "flex items-center gap-3 group min-w-0", children: [
38
+ /* @__PURE__ */ jsx("div", { className: "relative h-11 w-11 rounded-xl overflow-hidden shrink-0 bg-gradient-to-br from-brand-blue/20 to-brand-purple/20 ring-1 ring-border/40 group-hover:ring-border/70 transition-all", children: collectionImage ? /* @__PURE__ */ jsx(Image, { src: collectionImage, alt: "", fill: true, className: "object-cover", unoptimized: true }) : null }),
39
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-bold leading-tight truncate min-w-0 flex-1 group-hover:text-primary transition-colors", children: collectionName }),
40
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 h-8 w-8 rounded-xl bg-muted/60 flex items-center justify-center text-muted-foreground group-hover:bg-muted group-hover:text-foreground transition-all", children: /* @__PURE__ */ jsx(ArrowRight, { className: "h-3.5 w-3.5" }) })
41
+ ] })
23
42
  ] }),
24
- showFilmstrip ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
25
- /* @__PURE__ */ jsx(
26
- "button",
27
- {
28
- type: "button",
29
- disabled: !prevToken,
30
- onClick: () => prevToken && onNavigate(prevToken.tokenId),
31
- className: "shrink-0 inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:text-foreground active:scale-95 disabled:opacity-30 disabled:pointer-events-none",
32
- children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
33
- }
34
- ),
35
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 overflow-x-auto scroll-smooth [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: siblingTokens.map((sibling) => {
36
- const isCurrent = String(sibling.tokenId) === String(currentTokenId);
37
- return /* @__PURE__ */ jsx(
38
- "button",
39
- {
40
- type: "button",
41
- onClick: () => onNavigate(sibling.tokenId),
42
- className: cn(
43
- "relative h-20 w-20 shrink-0 rounded-xl overflow-hidden ring-2 transition",
44
- isCurrent ? "ring-primary" : "ring-transparent hover:ring-border"
45
- ),
46
- children: sibling.image ? /* @__PURE__ */ jsx(Image, { src: sibling.image, alt: "", fill: true, className: "object-cover", unoptimized: true }) : /* @__PURE__ */ jsx("div", { className: "h-full w-full bg-muted" })
47
- },
48
- sibling.tokenId
49
- );
50
- }) }),
51
- /* @__PURE__ */ jsx(
52
- "button",
53
- {
54
- type: "button",
55
- disabled: !nextToken,
56
- onClick: () => nextToken && onNavigate(nextToken.tokenId),
57
- className: "shrink-0 inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:text-foreground active:scale-95 disabled:opacity-30 disabled:pointer-events-none",
58
- children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
59
- }
60
- )
61
- ] }) : null
43
+ showGrid && /* @__PURE__ */ jsxs(Fragment, { children: [
44
+ /* @__PURE__ */ jsx("div", { className: "h-px bg-border/40 mx-4" }),
45
+ /* @__PURE__ */ jsxs("div", { className: "px-4 py-3.5", children: [
46
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
47
+ /* @__PURE__ */ jsxs("p", { className: "text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/60 select-none", children: [
48
+ "In this collection \xB7 ",
49
+ total
50
+ ] }),
51
+ total > PREVIEW_SIZE && /* @__PURE__ */ jsx(
52
+ Link,
53
+ {
54
+ href: collectionHref,
55
+ className: "text-[10px] font-semibold text-muted-foreground hover:text-foreground transition-colors",
56
+ children: "See all \u2192"
57
+ }
58
+ )
59
+ ] }),
60
+ /* @__PURE__ */ jsx("div", { className: cn("grid gap-1.5", gridCols), children: preview.map((sibling) => {
61
+ const isCurrent = String(sibling.tokenId) === String(currentTokenId);
62
+ return /* @__PURE__ */ jsx(
63
+ "button",
64
+ {
65
+ type: "button",
66
+ onClick: () => !isCurrent && onNavigate(sibling.tokenId),
67
+ disabled: isCurrent,
68
+ className: cn(
69
+ "group relative aspect-square rounded-xl overflow-hidden transition-all duration-200",
70
+ isCurrent ? "opacity-100 cursor-default" : "opacity-50 hover:opacity-100 active:scale-95"
71
+ ),
72
+ children: sibling.image ? /* @__PURE__ */ jsx(
73
+ Image,
74
+ {
75
+ src: sibling.image,
76
+ alt: "",
77
+ fill: true,
78
+ className: cn(
79
+ "object-cover transition-transform duration-300",
80
+ !isCurrent && "group-hover:scale-105"
81
+ ),
82
+ unoptimized: true
83
+ }
84
+ ) : /* @__PURE__ */ jsx("div", { className: "h-full w-full bg-muted" })
85
+ },
86
+ sibling.tokenId
87
+ );
88
+ }) })
89
+ ] })
90
+ ] })
62
91
  ] });
63
92
  }
64
93
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/asset-collection-bar.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"next/image\";\nimport Link from \"next/link\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface AssetCollectionBarSibling {\n tokenId: string;\n /** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). `null` renders a placeholder. */\n image: string | null;\n}\n\nexport interface AssetCollectionBarProps {\n collectionName: string;\n /** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). */\n collectionImage?: string | null;\n collectionHref: string;\n currentTokenId: string;\n siblingTokens: AssetCollectionBarSibling[];\n onNavigate: (tokenId: string) => void;\n}\n\n/**\n * Collection identity bar: centered avatar+name, with a filmstrip of\n * collection siblings on a second row for browsing (replaces plain-text\n * Prev/Next). Soft `bg-card/40` surface, no hard border — matches the\n * aurora-glow design language instead of an OpenSea-style boxed panel.\n * Collection-only: putting Owner inside this card reads as if ownership were\n * a collection attribute (2026-07-05 feedback) — it lives in `AssetOwnerRow`\n * as a sibling instead. Other asset-level concerns (IP-type, explorer/share/\n * report) still live elsewhere (`AssetHeaderBlock`, `AssetUtilityIcons`).\n */\nexport function AssetCollectionBar({\n collectionName,\n collectionImage,\n collectionHref,\n currentTokenId,\n siblingTokens,\n onNavigate,\n}: AssetCollectionBarProps) {\n const currentIndex = siblingTokens.findIndex((t) => String(t.tokenId) === String(currentTokenId));\n const prevToken = currentIndex > 0 ? siblingTokens[currentIndex - 1] : null;\n const nextToken =\n currentIndex >= 0 && currentIndex < siblingTokens.length - 1 ? siblingTokens[currentIndex + 1] : null;\n const showFilmstrip = siblingTokens.length > 1;\n\n return (\n <div className=\"rounded-2xl bg-card/40 px-4 py-3 space-y-3\">\n <Link href={collectionHref} className=\"flex items-center justify-center gap-3 min-w-0 group\">\n <div className=\"relative h-10 w-10 rounded-xl overflow-hidden shrink-0 bg-gradient-to-br from-primary/20 to-purple-500/20 ring-1 ring-border/60 group-hover:ring-primary/40 transition\">\n {collectionImage ? (\n <Image src={collectionImage} alt=\"\" fill className=\"object-cover\" unoptimized />\n ) : null}\n </div>\n <p className=\"text-sm font-semibold truncate group-hover:text-primary transition-colors\">\n {collectionName}\n </p>\n </Link>\n\n {showFilmstrip ? (\n <div className=\"flex items-center gap-1.5\">\n <button\n type=\"button\"\n disabled={!prevToken}\n onClick={() => prevToken && onNavigate(prevToken.tokenId)}\n className=\"shrink-0 inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:text-foreground active:scale-95 disabled:opacity-30 disabled:pointer-events-none\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </button>\n <div className=\"flex items-center gap-2 overflow-x-auto scroll-smooth [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\">\n {siblingTokens.map((sibling) => {\n const isCurrent = String(sibling.tokenId) === String(currentTokenId);\n return (\n <button\n key={sibling.tokenId}\n type=\"button\"\n onClick={() => onNavigate(sibling.tokenId)}\n className={cn(\n \"relative h-20 w-20 shrink-0 rounded-xl overflow-hidden ring-2 transition\",\n isCurrent ? \"ring-primary\" : \"ring-transparent hover:ring-border\"\n )}\n >\n {sibling.image ? (\n <Image src={sibling.image} alt=\"\" fill className=\"object-cover\" unoptimized />\n ) : (\n <div className=\"h-full w-full bg-muted\" />\n )}\n </button>\n );\n })}\n </div>\n <button\n type=\"button\"\n disabled={!nextToken}\n onClick={() => nextToken && onNavigate(nextToken.tokenId)}\n className=\"shrink-0 inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:text-foreground active:scale-95 disabled:opacity-30 disabled:pointer-events-none\"\n >\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":";AAiDM,SAGM,KAHN;AA/CN,OAAO,WAAW;AAClB,OAAO,UAAU;AACjB,SAAS,aAAa,oBAAoB;AAC1C,SAAS,UAAU;AA4BZ,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,eAAe,cAAc,UAAU,CAAC,MAAM,OAAO,EAAE,OAAO,MAAM,OAAO,cAAc,CAAC;AAChG,QAAM,YAAY,eAAe,IAAI,cAAc,eAAe,CAAC,IAAI;AACvE,QAAM,YACJ,gBAAgB,KAAK,eAAe,cAAc,SAAS,IAAI,cAAc,eAAe,CAAC,IAAI;AACnG,QAAM,gBAAgB,cAAc,SAAS;AAE7C,SACE,qBAAC,SAAI,WAAU,8CACb;AAAA,yBAAC,QAAK,MAAM,gBAAgB,WAAU,wDACpC;AAAA,0BAAC,SAAI,WAAU,0KACZ,4BACC,oBAAC,SAAM,KAAK,iBAAiB,KAAI,IAAG,MAAI,MAAC,WAAU,gBAAe,aAAW,MAAC,IAC5E,MACN;AAAA,MACA,oBAAC,OAAE,WAAU,6EACV,0BACH;AAAA,OACF;AAAA,IAEC,gBACC,qBAAC,SAAI,WAAU,6BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,CAAC;AAAA,UACX,SAAS,MAAM,aAAa,WAAW,UAAU,OAAO;AAAA,UACxD,WAAU;AAAA,UAEV,8BAAC,eAAY,WAAU,WAAU;AAAA;AAAA,MACnC;AAAA,MACA,oBAAC,SAAI,WAAU,8GACZ,wBAAc,IAAI,CAAC,YAAY;AAC9B,cAAM,YAAY,OAAO,QAAQ,OAAO,MAAM,OAAO,cAAc;AACnE,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,SAAS,MAAM,WAAW,QAAQ,OAAO;AAAA,YACzC,WAAW;AAAA,cACT;AAAA,cACA,YAAY,iBAAiB;AAAA,YAC/B;AAAA,YAEC,kBAAQ,QACP,oBAAC,SAAM,KAAK,QAAQ,OAAO,KAAI,IAAG,MAAI,MAAC,WAAU,gBAAe,aAAW,MAAC,IAE5E,oBAAC,SAAI,WAAU,0BAAyB;AAAA;AAAA,UAXrC,QAAQ;AAAA,QAaf;AAAA,MAEJ,CAAC,GACH;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,CAAC;AAAA,UACX,SAAS,MAAM,aAAa,WAAW,UAAU,OAAO;AAAA,UACxD,WAAU;AAAA,UAEV,8BAAC,gBAAa,WAAU,WAAU;AAAA;AAAA,MACpC;AAAA,OACF,IACE;AAAA,KACN;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/asset-collection-bar.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"next/image\";\nimport Link from \"next/link\";\nimport { ArrowRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface AssetCollectionBarSibling {\n tokenId: string;\n /** Already-resolved, ready-to-render src. `null` renders a placeholder. */\n image: string | null;\n}\n\nexport interface AssetCollectionBarProps {\n collectionName: string;\n collectionImage?: string | null;\n collectionHref: string;\n currentTokenId: string;\n siblingTokens: AssetCollectionBarSibling[];\n onNavigate: (tokenId: string) => void;\n}\n\nconst GRID_COLS: Record<number, string> = {\n 1: \"grid-cols-1\",\n 2: \"grid-cols-2\",\n 3: \"grid-cols-3\",\n 4: \"grid-cols-4\",\n};\n\nexport function AssetCollectionBar({\n collectionName,\n collectionImage,\n collectionHref,\n currentTokenId,\n siblingTokens,\n onNavigate,\n}: AssetCollectionBarProps) {\n const total = siblingTokens.length;\n const currentIndex = siblingTokens.findIndex(\n (t) => String(t.tokenId) === String(currentTokenId)\n );\n\n // Window of up to 4 items centered around the current token\n const PREVIEW_SIZE = 4;\n const windowStart = Math.max(\n 0,\n Math.min(currentIndex - 1, total - PREVIEW_SIZE)\n );\n const preview = siblingTokens.slice(windowStart, windowStart + PREVIEW_SIZE);\n const colCount = Math.min(preview.length, 4) as 1 | 2 | 3 | 4;\n const gridCols = GRID_COLS[colCount] ?? \"grid-cols-4\";\n\n const showGrid = total > 1;\n\n return (\n <div className=\"rounded-2xl border border-border/50 bg-card overflow-hidden\">\n\n {/* ── Collection identity ── */}\n <div className=\"px-4 pt-4 pb-3.5\">\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/60 mb-2.5 select-none\">\n Collection\n </p>\n <Link href={collectionHref} className=\"flex items-center gap-3 group min-w-0\">\n {/* Avatar */}\n <div className=\"relative h-11 w-11 rounded-xl overflow-hidden shrink-0 bg-gradient-to-br from-brand-blue/20 to-brand-purple/20 ring-1 ring-border/40 group-hover:ring-border/70 transition-all\">\n {collectionImage ? (\n <Image src={collectionImage} alt=\"\" fill className=\"object-cover\" unoptimized />\n ) : null}\n </div>\n\n {/* Name */}\n <p className=\"text-sm font-bold leading-tight truncate min-w-0 flex-1 group-hover:text-primary transition-colors\">\n {collectionName}\n </p>\n\n {/* Arrow chip */}\n <div className=\"shrink-0 h-8 w-8 rounded-xl bg-muted/60 flex items-center justify-center text-muted-foreground group-hover:bg-muted group-hover:text-foreground transition-all\">\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </div>\n </Link>\n </div>\n\n {/* ── Grid explorer ── */}\n {showGrid && (\n <>\n <div className=\"h-px bg-border/40 mx-4\" />\n <div className=\"px-4 py-3.5\">\n <div className=\"flex items-center justify-between mb-3\">\n <p className=\"text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/60 select-none\">\n In this collection · {total}\n </p>\n {total > PREVIEW_SIZE && (\n <Link\n href={collectionHref}\n className=\"text-[10px] font-semibold text-muted-foreground hover:text-foreground transition-colors\"\n >\n See all →\n </Link>\n )}\n </div>\n\n <div className={cn(\"grid gap-1.5\", gridCols)}>\n {preview.map((sibling) => {\n const isCurrent =\n String(sibling.tokenId) === String(currentTokenId);\n return (\n <button\n key={sibling.tokenId}\n type=\"button\"\n onClick={() => !isCurrent && onNavigate(sibling.tokenId)}\n disabled={isCurrent}\n className={cn(\n \"group relative aspect-square rounded-xl overflow-hidden transition-all duration-200\",\n isCurrent\n ? \"opacity-100 cursor-default\"\n : \"opacity-50 hover:opacity-100 active:scale-95\"\n )}\n >\n {sibling.image ? (\n <Image\n src={sibling.image}\n alt=\"\"\n fill\n className={cn(\n \"object-cover transition-transform duration-300\",\n !isCurrent && \"group-hover:scale-105\"\n )}\n unoptimized\n />\n ) : (\n <div className=\"h-full w-full bg-muted\" />\n )}\n </button>\n );\n })}\n </div>\n </div>\n </>\n )}\n </div>\n );\n}\n"],"mappings":";AA2DQ,SAyBA,UAzBA,KAGA,YAHA;AAzDR,OAAO,WAAW;AAClB,OAAO,UAAU;AACjB,SAAS,kBAAkB;AAC3B,SAAS,UAAU;AAiBnB,MAAM,YAAoC;AAAA,EACxC,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAEO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,QAAQ,cAAc;AAC5B,QAAM,eAAe,cAAc;AAAA,IACjC,CAAC,MAAM,OAAO,EAAE,OAAO,MAAM,OAAO,cAAc;AAAA,EACpD;AAGA,QAAM,eAAe;AACrB,QAAM,cAAc,KAAK;AAAA,IACvB;AAAA,IACA,KAAK,IAAI,eAAe,GAAG,QAAQ,YAAY;AAAA,EACjD;AACA,QAAM,UAAU,cAAc,MAAM,aAAa,cAAc,YAAY;AAC3E,QAAM,WAAW,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAC3C,QAAM,WAAW,UAAU,QAAQ,KAAK;AAExC,QAAM,WAAW,QAAQ;AAEzB,SACE,qBAAC,SAAI,WAAU,+DAGb;AAAA,yBAAC,SAAI,WAAU,oBACb;AAAA,0BAAC,OAAE,WAAU,mGAAkG,wBAE/G;AAAA,MACA,qBAAC,QAAK,MAAM,gBAAgB,WAAU,yCAEpC;AAAA,4BAAC,SAAI,WAAU,kLACZ,4BACC,oBAAC,SAAM,KAAK,iBAAiB,KAAI,IAAG,MAAI,MAAC,WAAU,gBAAe,aAAW,MAAC,IAC5E,MACN;AAAA,QAGA,oBAAC,OAAE,WAAU,sGACV,0BACH;AAAA,QAGA,oBAAC,SAAI,WAAU,kKACb,8BAAC,cAAW,WAAU,eAAc,GACtC;AAAA,SACF;AAAA,OACF;AAAA,IAGC,YACC,iCACE;AAAA,0BAAC,SAAI,WAAU,0BAAyB;AAAA,MACxC,qBAAC,SAAI,WAAU,eACb;AAAA,6BAAC,SAAI,WAAU,0CACb;AAAA,+BAAC,OAAE,WAAU,4FAA2F;AAAA;AAAA,YAChF;AAAA,aACxB;AAAA,UACC,QAAQ,gBACP;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,WAEJ;AAAA,QAEA,oBAAC,SAAI,WAAW,GAAG,gBAAgB,QAAQ,GACxC,kBAAQ,IAAI,CAAC,YAAY;AACxB,gBAAM,YACJ,OAAO,QAAQ,OAAO,MAAM,OAAO,cAAc;AACnD,iBACE;AAAA,YAAC;AAAA;AAAA,cAEC,MAAK;AAAA,cACL,SAAS,MAAM,CAAC,aAAa,WAAW,QAAQ,OAAO;AAAA,cACvD,UAAU;AAAA,cACV,WAAW;AAAA,gBACT;AAAA,gBACA,YACI,+BACA;AAAA,cACN;AAAA,cAEC,kBAAQ,QACP;AAAA,gBAAC;AAAA;AAAA,kBACC,KAAK,QAAQ;AAAA,kBACb,KAAI;AAAA,kBACJ,MAAI;AAAA,kBACJ,WAAW;AAAA,oBACT;AAAA,oBACA,CAAC,aAAa;AAAA,kBAChB;AAAA,kBACA,aAAW;AAAA;AAAA,cACb,IAEA,oBAAC,SAAI,WAAU,0BAAyB;AAAA;AAAA,YAvBrC,QAAQ;AAAA,UAyBf;AAAA,QAEJ,CAAC,GACH;AAAA,SACF;AAAA,OACF;AAAA,KAEJ;AAEJ;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medialane/ui",
3
- "version": "0.43.0",
3
+ "version": "0.45.0",
4
4
  "description": "Shared UI components for Medialane apps",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",