@medialane/ui 0.126.0 → 0.126.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -36,6 +36,7 @@ var import_jsx_runtime = require("react/jsx-runtime");
36
36
  var import_react = require("react");
37
37
  var import_image = __toESM(require("next/image"), 1);
38
38
  var import_use_intersection_active = require("../utils/use-intersection-active.js");
39
+ var import_cn = require("../utils/cn.js");
39
40
  function AnimatedTokenMedia({
40
41
  image,
41
42
  alt,
@@ -55,9 +56,11 @@ function AnimatedTokenMedia({
55
56
  setInternalError(true);
56
57
  onImageError?.();
57
58
  };
59
+ const [loaded, setLoaded] = (0, import_react.useState)(false);
60
+ (0, import_react.useEffect)(() => setLoaded(false), [image]);
58
61
  const [ref, isVisible] = (0, import_use_intersection_active.useIntersectionActive)();
59
62
  const showLive = live && !!animationUrl && isVisible;
60
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref, className: mode === "fill" ? "absolute inset-0" : "w-full", children: showLive ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
63
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref, className: mode === "fill" ? "absolute inset-0" : "relative w-full", children: showLive ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
61
64
  "iframe",
62
65
  {
63
66
  src: animationUrl,
@@ -66,32 +69,49 @@ function AnimatedTokenMedia({
66
69
  loading: "lazy",
67
70
  className: mode === "fill" ? "absolute inset-0 w-full h-full border-0" : "w-full aspect-square border-0"
68
71
  }
69
- ) : image && !imgError ? mode === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
70
- import_image.default,
71
- {
72
- src: image,
73
- alt,
74
- fill: true,
75
- unoptimized: true,
76
- sizes,
77
- priority,
78
- className,
79
- onError: handleImageError
80
- }
81
- ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
82
- import_image.default,
83
- {
84
- src: image,
85
- alt,
86
- width: 0,
87
- height: 0,
88
- sizes,
89
- priority,
90
- crossOrigin: "anonymous",
91
- className: className ?? "w-full h-auto",
92
- onError: handleImageError
93
- }
94
- ) : fallback ?? null });
72
+ ) : image && !imgError ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
73
+ !loaded && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
74
+ "div",
75
+ {
76
+ className: (0, import_cn.cn)(
77
+ "animate-[shimmer_1.6s_ease-in-out_infinite] bg-foreground/[0.06] absolute",
78
+ mode === "fill" ? "inset-0" : "inset-x-0 top-0 aspect-square"
79
+ ),
80
+ style: {
81
+ backgroundImage: "linear-gradient(90deg, transparent, color-mix(in srgb, var(--foreground) 8%, transparent), transparent)",
82
+ backgroundSize: "200% 100%"
83
+ }
84
+ }
85
+ ),
86
+ mode === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
87
+ import_image.default,
88
+ {
89
+ src: image,
90
+ alt,
91
+ fill: true,
92
+ unoptimized: true,
93
+ sizes,
94
+ priority,
95
+ className: (0, import_cn.cn)(className, "transition-opacity duration-300", loaded ? "opacity-100" : "opacity-0"),
96
+ onLoad: () => setLoaded(true),
97
+ onError: handleImageError
98
+ }
99
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
100
+ import_image.default,
101
+ {
102
+ src: image,
103
+ alt,
104
+ width: 0,
105
+ height: 0,
106
+ sizes,
107
+ priority,
108
+ crossOrigin: "anonymous",
109
+ className: (0, import_cn.cn)(className ?? "w-full h-auto", "transition-opacity duration-300", loaded ? "opacity-100" : "opacity-0"),
110
+ onLoad: () => setLoaded(true),
111
+ onError: handleImageError
112
+ }
113
+ )
114
+ ] }) : fallback ?? null });
95
115
  }
96
116
  // Annotate the CommonJS export names for ESM import in node:
97
117
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/animated-token-media.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Image from \"next/image\";\nimport { useIntersectionActive } from \"../utils/use-intersection-active.js\";\n\nexport interface AnimatedTokenMediaProps {\n\n image: string | null;\n alt: string;\n\n animationUrl?: string | null;\n\n live?: boolean;\n\n mode?: \"fill\" | \"natural\";\n className?: string;\n sizes?: string;\n priority?: boolean;\n\n imgError?: boolean;\n onImageError?: () => void;\n\n fallback?: React.ReactNode;\n}\n\nexport function AnimatedTokenMedia({\n image,\n alt,\n animationUrl,\n live = false,\n mode = \"fill\",\n className,\n sizes,\n priority,\n imgError: imgErrorProp,\n onImageError,\n fallback,\n}: AnimatedTokenMediaProps) {\n const [internalError, setInternalError] = useState(false);\n const imgError = imgErrorProp ?? internalError;\n const handleImageError = () => {\n setInternalError(true);\n onImageError?.();\n };\n\n const [ref, isVisible] = useIntersectionActive<HTMLDivElement>();\n const showLive = live && !!animationUrl && isVisible;\n\n return (\n <div ref={ref} className={mode === \"fill\" ? \"absolute inset-0\" : \"w-full\"}>\n {showLive ? (\n <iframe\n src={animationUrl!}\n title={alt}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n className={\n mode === \"fill\"\n ? \"absolute inset-0 w-full h-full border-0\"\n : \"w-full aspect-square border-0\"\n }\n />\n ) : image && !imgError ? (\n mode === \"fill\" ? (\n <Image\n src={image}\n alt={alt}\n fill\n unoptimized\n sizes={sizes}\n priority={priority}\n className={className}\n onError={handleImageError}\n />\n ) : (\n <Image\n src={image}\n alt={alt}\n width={0}\n height={0}\n sizes={sizes}\n priority={priority}\n crossOrigin=\"anonymous\"\n className={className ?? \"w-full h-auto\"}\n onError={handleImageError}\n />\n )\n ) : (\n fallback ?? null\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAoDQ;AAlDR,mBAAyB;AACzB,mBAAkB;AAClB,qCAAsC;AAsB/B,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,CAAC,eAAe,gBAAgB,QAAI,uBAAS,KAAK;AACxD,QAAM,WAAW,gBAAgB;AACjC,QAAM,mBAAmB,MAAM;AAC7B,qBAAiB,IAAI;AACrB,mBAAe;AAAA,EACjB;AAEA,QAAM,CAAC,KAAK,SAAS,QAAI,sDAAsC;AAC/D,QAAM,WAAW,QAAQ,CAAC,CAAC,gBAAgB;AAE3C,SACE,4CAAC,SAAI,KAAU,WAAW,SAAS,SAAS,qBAAqB,UAC9D,qBACC;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAQ;AAAA,MACR,SAAQ;AAAA,MACR,WACE,SAAS,SACL,4CACA;AAAA;AAAA,EAER,IACE,SAAS,CAAC,WACZ,SAAS,SACP;AAAA,IAAC,aAAAA;AAAA,IAAA;AAAA,MACC,KAAK;AAAA,MACL;AAAA,MACA,MAAI;AAAA,MACJ,aAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA;AAAA,EACX,IAEA;AAAA,IAAC,aAAAA;AAAA,IAAA;AAAA,MACC,KAAK;AAAA,MACL;AAAA,MACA,OAAO;AAAA,MACP,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,aAAY;AAAA,MACZ,WAAW,aAAa;AAAA,MACxB,SAAS;AAAA;AAAA,EACX,IAGF,YAAY,MAEhB;AAEJ;","names":["Image"]}
1
+ {"version":3,"sources":["../../src/components/animated-token-media.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport Image from \"next/image\";\nimport { useIntersectionActive } from \"../utils/use-intersection-active.js\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface AnimatedTokenMediaProps {\n\n image: string | null;\n alt: string;\n\n animationUrl?: string | null;\n\n live?: boolean;\n\n mode?: \"fill\" | \"natural\";\n className?: string;\n sizes?: string;\n priority?: boolean;\n\n imgError?: boolean;\n onImageError?: () => void;\n\n fallback?: React.ReactNode;\n}\n\nexport function AnimatedTokenMedia({\n image,\n alt,\n animationUrl,\n live = false,\n mode = \"fill\",\n className,\n sizes,\n priority,\n imgError: imgErrorProp,\n onImageError,\n fallback,\n}: AnimatedTokenMediaProps) {\n const [internalError, setInternalError] = useState(false);\n const imgError = imgErrorProp ?? internalError;\n const handleImageError = () => {\n setInternalError(true);\n onImageError?.();\n };\n\n const [loaded, setLoaded] = useState(false);\n useEffect(() => setLoaded(false), [image]);\n\n const [ref, isVisible] = useIntersectionActive<HTMLDivElement>();\n const showLive = live && !!animationUrl && isVisible;\n\n return (\n <div ref={ref} className={mode === \"fill\" ? \"absolute inset-0\" : \"relative w-full\"}>\n {showLive ? (\n <iframe\n src={animationUrl!}\n title={alt}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n className={\n mode === \"fill\"\n ? \"absolute inset-0 w-full h-full border-0\"\n : \"w-full aspect-square border-0\"\n }\n />\n ) : image && !imgError ? (\n <>\n {!loaded && (\n <div\n className={cn(\n \"animate-[shimmer_1.6s_ease-in-out_infinite] bg-foreground/[0.06] absolute\",\n mode === \"fill\" ? \"inset-0\" : \"inset-x-0 top-0 aspect-square\"\n )}\n style={{\n backgroundImage:\n \"linear-gradient(90deg, transparent, color-mix(in srgb, var(--foreground) 8%, transparent), transparent)\",\n backgroundSize: \"200% 100%\",\n }}\n />\n )}\n {mode === \"fill\" ? (\n <Image\n src={image}\n alt={alt}\n fill\n unoptimized\n sizes={sizes}\n priority={priority}\n className={cn(className, \"transition-opacity duration-300\", loaded ? \"opacity-100\" : \"opacity-0\")}\n onLoad={() => setLoaded(true)}\n onError={handleImageError}\n />\n ) : (\n <Image\n src={image}\n alt={alt}\n width={0}\n height={0}\n sizes={sizes}\n priority={priority}\n crossOrigin=\"anonymous\"\n className={cn(className ?? \"w-full h-auto\", \"transition-opacity duration-300\", loaded ? \"opacity-100\" : \"opacity-0\")}\n onLoad={() => setLoaded(true)}\n onError={handleImageError}\n />\n )}\n </>\n ) : (\n fallback ?? null\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAwDQ;AAtDR,mBAAoC;AACpC,mBAAkB;AAClB,qCAAsC;AACtC,gBAAmB;AAsBZ,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,CAAC,eAAe,gBAAgB,QAAI,uBAAS,KAAK;AACxD,QAAM,WAAW,gBAAgB;AACjC,QAAM,mBAAmB,MAAM;AAC7B,qBAAiB,IAAI;AACrB,mBAAe;AAAA,EACjB;AAEA,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,KAAK;AAC1C,8BAAU,MAAM,UAAU,KAAK,GAAG,CAAC,KAAK,CAAC;AAEzC,QAAM,CAAC,KAAK,SAAS,QAAI,sDAAsC;AAC/D,QAAM,WAAW,QAAQ,CAAC,CAAC,gBAAgB;AAE3C,SACE,4CAAC,SAAI,KAAU,WAAW,SAAS,SAAS,qBAAqB,mBAC9D,qBACC;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAQ;AAAA,MACR,SAAQ;AAAA,MACR,WACE,SAAS,SACL,4CACA;AAAA;AAAA,EAER,IACE,SAAS,CAAC,WACZ,4EACG;AAAA,KAAC,UACA;AAAA,MAAC;AAAA;AAAA,QACC,eAAW;AAAA,UACT;AAAA,UACA,SAAS,SAAS,YAAY;AAAA,QAChC;AAAA,QACA,OAAO;AAAA,UACL,iBACE;AAAA,UACF,gBAAgB;AAAA,QAClB;AAAA;AAAA,IACF;AAAA,IAED,SAAS,SACR;AAAA,MAAC,aAAAA;AAAA,MAAA;AAAA,QACC,KAAK;AAAA,QACL;AAAA,QACA,MAAI;AAAA,QACJ,aAAW;AAAA,QACX;AAAA,QACA;AAAA,QACA,eAAW,cAAG,WAAW,mCAAmC,SAAS,gBAAgB,WAAW;AAAA,QAChG,QAAQ,MAAM,UAAU,IAAI;AAAA,QAC5B,SAAS;AAAA;AAAA,IACX,IAEA;AAAA,MAAC,aAAAA;AAAA,MAAA;AAAA,QACC,KAAK;AAAA,QACL;AAAA,QACA,OAAO;AAAA,QACP,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA,aAAY;AAAA,QACZ,eAAW,cAAG,aAAa,iBAAiB,mCAAmC,SAAS,gBAAgB,WAAW;AAAA,QACnH,QAAQ,MAAM,UAAU,IAAI;AAAA,QAC5B,SAAS;AAAA;AAAA,IACX;AAAA,KAEJ,IAEA,YAAY,MAEhB;AAEJ;","names":["Image"]}
@@ -1,8 +1,9 @@
1
1
  "use client";
2
- import { jsx } from "react/jsx-runtime";
3
- import { useState } from "react";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
4
  import Image from "next/image";
5
5
  import { useIntersectionActive } from "../utils/use-intersection-active.js";
6
+ import { cn } from "../utils/cn.js";
6
7
  function AnimatedTokenMedia({
7
8
  image,
8
9
  alt,
@@ -22,9 +23,11 @@ function AnimatedTokenMedia({
22
23
  setInternalError(true);
23
24
  onImageError?.();
24
25
  };
26
+ const [loaded, setLoaded] = useState(false);
27
+ useEffect(() => setLoaded(false), [image]);
25
28
  const [ref, isVisible] = useIntersectionActive();
26
29
  const showLive = live && !!animationUrl && isVisible;
27
- return /* @__PURE__ */ jsx("div", { ref, className: mode === "fill" ? "absolute inset-0" : "w-full", children: showLive ? /* @__PURE__ */ jsx(
30
+ return /* @__PURE__ */ jsx("div", { ref, className: mode === "fill" ? "absolute inset-0" : "relative w-full", children: showLive ? /* @__PURE__ */ jsx(
28
31
  "iframe",
29
32
  {
30
33
  src: animationUrl,
@@ -33,32 +36,49 @@ function AnimatedTokenMedia({
33
36
  loading: "lazy",
34
37
  className: mode === "fill" ? "absolute inset-0 w-full h-full border-0" : "w-full aspect-square border-0"
35
38
  }
36
- ) : image && !imgError ? mode === "fill" ? /* @__PURE__ */ jsx(
37
- Image,
38
- {
39
- src: image,
40
- alt,
41
- fill: true,
42
- unoptimized: true,
43
- sizes,
44
- priority,
45
- className,
46
- onError: handleImageError
47
- }
48
- ) : /* @__PURE__ */ jsx(
49
- Image,
50
- {
51
- src: image,
52
- alt,
53
- width: 0,
54
- height: 0,
55
- sizes,
56
- priority,
57
- crossOrigin: "anonymous",
58
- className: className ?? "w-full h-auto",
59
- onError: handleImageError
60
- }
61
- ) : fallback ?? null });
39
+ ) : image && !imgError ? /* @__PURE__ */ jsxs(Fragment, { children: [
40
+ !loaded && /* @__PURE__ */ jsx(
41
+ "div",
42
+ {
43
+ className: cn(
44
+ "animate-[shimmer_1.6s_ease-in-out_infinite] bg-foreground/[0.06] absolute",
45
+ mode === "fill" ? "inset-0" : "inset-x-0 top-0 aspect-square"
46
+ ),
47
+ style: {
48
+ backgroundImage: "linear-gradient(90deg, transparent, color-mix(in srgb, var(--foreground) 8%, transparent), transparent)",
49
+ backgroundSize: "200% 100%"
50
+ }
51
+ }
52
+ ),
53
+ mode === "fill" ? /* @__PURE__ */ jsx(
54
+ Image,
55
+ {
56
+ src: image,
57
+ alt,
58
+ fill: true,
59
+ unoptimized: true,
60
+ sizes,
61
+ priority,
62
+ className: cn(className, "transition-opacity duration-300", loaded ? "opacity-100" : "opacity-0"),
63
+ onLoad: () => setLoaded(true),
64
+ onError: handleImageError
65
+ }
66
+ ) : /* @__PURE__ */ jsx(
67
+ Image,
68
+ {
69
+ src: image,
70
+ alt,
71
+ width: 0,
72
+ height: 0,
73
+ sizes,
74
+ priority,
75
+ crossOrigin: "anonymous",
76
+ className: cn(className ?? "w-full h-auto", "transition-opacity duration-300", loaded ? "opacity-100" : "opacity-0"),
77
+ onLoad: () => setLoaded(true),
78
+ onError: handleImageError
79
+ }
80
+ )
81
+ ] }) : fallback ?? null });
62
82
  }
63
83
  export {
64
84
  AnimatedTokenMedia
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/animated-token-media.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Image from \"next/image\";\nimport { useIntersectionActive } from \"../utils/use-intersection-active.js\";\n\nexport interface AnimatedTokenMediaProps {\n\n image: string | null;\n alt: string;\n\n animationUrl?: string | null;\n\n live?: boolean;\n\n mode?: \"fill\" | \"natural\";\n className?: string;\n sizes?: string;\n priority?: boolean;\n\n imgError?: boolean;\n onImageError?: () => void;\n\n fallback?: React.ReactNode;\n}\n\nexport function AnimatedTokenMedia({\n image,\n alt,\n animationUrl,\n live = false,\n mode = \"fill\",\n className,\n sizes,\n priority,\n imgError: imgErrorProp,\n onImageError,\n fallback,\n}: AnimatedTokenMediaProps) {\n const [internalError, setInternalError] = useState(false);\n const imgError = imgErrorProp ?? internalError;\n const handleImageError = () => {\n setInternalError(true);\n onImageError?.();\n };\n\n const [ref, isVisible] = useIntersectionActive<HTMLDivElement>();\n const showLive = live && !!animationUrl && isVisible;\n\n return (\n <div ref={ref} className={mode === \"fill\" ? \"absolute inset-0\" : \"w-full\"}>\n {showLive ? (\n <iframe\n src={animationUrl!}\n title={alt}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n className={\n mode === \"fill\"\n ? \"absolute inset-0 w-full h-full border-0\"\n : \"w-full aspect-square border-0\"\n }\n />\n ) : image && !imgError ? (\n mode === \"fill\" ? (\n <Image\n src={image}\n alt={alt}\n fill\n unoptimized\n sizes={sizes}\n priority={priority}\n className={className}\n onError={handleImageError}\n />\n ) : (\n <Image\n src={image}\n alt={alt}\n width={0}\n height={0}\n sizes={sizes}\n priority={priority}\n crossOrigin=\"anonymous\"\n className={className ?? \"w-full h-auto\"}\n onError={handleImageError}\n />\n )\n ) : (\n fallback ?? null\n )}\n </div>\n );\n}\n"],"mappings":";AAoDQ;AAlDR,SAAS,gBAAgB;AACzB,OAAO,WAAW;AAClB,SAAS,6BAA6B;AAsB/B,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,KAAK;AACxD,QAAM,WAAW,gBAAgB;AACjC,QAAM,mBAAmB,MAAM;AAC7B,qBAAiB,IAAI;AACrB,mBAAe;AAAA,EACjB;AAEA,QAAM,CAAC,KAAK,SAAS,IAAI,sBAAsC;AAC/D,QAAM,WAAW,QAAQ,CAAC,CAAC,gBAAgB;AAE3C,SACE,oBAAC,SAAI,KAAU,WAAW,SAAS,SAAS,qBAAqB,UAC9D,qBACC;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAQ;AAAA,MACR,SAAQ;AAAA,MACR,WACE,SAAS,SACL,4CACA;AAAA;AAAA,EAER,IACE,SAAS,CAAC,WACZ,SAAS,SACP;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL;AAAA,MACA,MAAI;AAAA,MACJ,aAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA;AAAA,EACX,IAEA;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL;AAAA,MACA,OAAO;AAAA,MACP,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,aAAY;AAAA,MACZ,WAAW,aAAa;AAAA,MACxB,SAAS;AAAA;AAAA,EACX,IAGF,YAAY,MAEhB;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/animated-token-media.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport Image from \"next/image\";\nimport { useIntersectionActive } from \"../utils/use-intersection-active.js\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface AnimatedTokenMediaProps {\n\n image: string | null;\n alt: string;\n\n animationUrl?: string | null;\n\n live?: boolean;\n\n mode?: \"fill\" | \"natural\";\n className?: string;\n sizes?: string;\n priority?: boolean;\n\n imgError?: boolean;\n onImageError?: () => void;\n\n fallback?: React.ReactNode;\n}\n\nexport function AnimatedTokenMedia({\n image,\n alt,\n animationUrl,\n live = false,\n mode = \"fill\",\n className,\n sizes,\n priority,\n imgError: imgErrorProp,\n onImageError,\n fallback,\n}: AnimatedTokenMediaProps) {\n const [internalError, setInternalError] = useState(false);\n const imgError = imgErrorProp ?? internalError;\n const handleImageError = () => {\n setInternalError(true);\n onImageError?.();\n };\n\n const [loaded, setLoaded] = useState(false);\n useEffect(() => setLoaded(false), [image]);\n\n const [ref, isVisible] = useIntersectionActive<HTMLDivElement>();\n const showLive = live && !!animationUrl && isVisible;\n\n return (\n <div ref={ref} className={mode === \"fill\" ? \"absolute inset-0\" : \"relative w-full\"}>\n {showLive ? (\n <iframe\n src={animationUrl!}\n title={alt}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n className={\n mode === \"fill\"\n ? \"absolute inset-0 w-full h-full border-0\"\n : \"w-full aspect-square border-0\"\n }\n />\n ) : image && !imgError ? (\n <>\n {!loaded && (\n <div\n className={cn(\n \"animate-[shimmer_1.6s_ease-in-out_infinite] bg-foreground/[0.06] absolute\",\n mode === \"fill\" ? \"inset-0\" : \"inset-x-0 top-0 aspect-square\"\n )}\n style={{\n backgroundImage:\n \"linear-gradient(90deg, transparent, color-mix(in srgb, var(--foreground) 8%, transparent), transparent)\",\n backgroundSize: \"200% 100%\",\n }}\n />\n )}\n {mode === \"fill\" ? (\n <Image\n src={image}\n alt={alt}\n fill\n unoptimized\n sizes={sizes}\n priority={priority}\n className={cn(className, \"transition-opacity duration-300\", loaded ? \"opacity-100\" : \"opacity-0\")}\n onLoad={() => setLoaded(true)}\n onError={handleImageError}\n />\n ) : (\n <Image\n src={image}\n alt={alt}\n width={0}\n height={0}\n sizes={sizes}\n priority={priority}\n crossOrigin=\"anonymous\"\n className={cn(className ?? \"w-full h-auto\", \"transition-opacity duration-300\", loaded ? \"opacity-100\" : \"opacity-0\")}\n onLoad={() => setLoaded(true)}\n onError={handleImageError}\n />\n )}\n </>\n ) : (\n fallback ?? null\n )}\n </div>\n );\n}\n"],"mappings":";AAwDQ,SAYA,UAZA,KAYA,YAZA;AAtDR,SAAS,WAAW,gBAAgB;AACpC,OAAO,WAAW;AAClB,SAAS,6BAA6B;AACtC,SAAS,UAAU;AAsBZ,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,KAAK;AACxD,QAAM,WAAW,gBAAgB;AACjC,QAAM,mBAAmB,MAAM;AAC7B,qBAAiB,IAAI;AACrB,mBAAe;AAAA,EACjB;AAEA,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,YAAU,MAAM,UAAU,KAAK,GAAG,CAAC,KAAK,CAAC;AAEzC,QAAM,CAAC,KAAK,SAAS,IAAI,sBAAsC;AAC/D,QAAM,WAAW,QAAQ,CAAC,CAAC,gBAAgB;AAE3C,SACE,oBAAC,SAAI,KAAU,WAAW,SAAS,SAAS,qBAAqB,mBAC9D,qBACC;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAQ;AAAA,MACR,SAAQ;AAAA,MACR,WACE,SAAS,SACL,4CACA;AAAA;AAAA,EAER,IACE,SAAS,CAAC,WACZ,iCACG;AAAA,KAAC,UACA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,SAAS,SAAS,YAAY;AAAA,QAChC;AAAA,QACA,OAAO;AAAA,UACL,iBACE;AAAA,UACF,gBAAgB;AAAA,QAClB;AAAA;AAAA,IACF;AAAA,IAED,SAAS,SACR;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL;AAAA,QACA,MAAI;AAAA,QACJ,aAAW;AAAA,QACX;AAAA,QACA;AAAA,QACA,WAAW,GAAG,WAAW,mCAAmC,SAAS,gBAAgB,WAAW;AAAA,QAChG,QAAQ,MAAM,UAAU,IAAI;AAAA,QAC5B,SAAS;AAAA;AAAA,IACX,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL;AAAA,QACA,OAAO;AAAA,QACP,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA,aAAY;AAAA,QACZ,WAAW,GAAG,aAAa,iBAAiB,mCAAmC,SAAS,gBAAgB,WAAW;AAAA,QACnH,QAAQ,MAAM,UAAU,IAAI;AAAA,QAC5B,SAAS;AAAA;AAAA,IACX;AAAA,KAEJ,IAEA,YAAY,MAEhB;AAEJ;","names":[]}
@@ -37,8 +37,10 @@ __export(asset_top_sections_exports, {
37
37
  module.exports = __toCommonJS(asset_top_sections_exports);
38
38
  var import_jsx_runtime = require("react/jsx-runtime");
39
39
  var import_link = __toESM(require("next/link"), 1);
40
+ var import_react = require("react");
40
41
  var import_framer_motion = require("framer-motion");
41
42
  var import_use_intersection_active = require("../utils/use-intersection-active.js");
43
+ var import_cn = require("../utils/cn.js");
42
44
  var import_address_display = require("./address-display.js");
43
45
  var import_parent_attribution_banner = require("./parent-attribution-banner.js");
44
46
  var import_ip_type_badge = require("./ip-type-badge.js");
@@ -56,7 +58,19 @@ function AssetMediaColumn({
56
58
  stats
57
59
  }) {
58
60
  const [ref, isVisible] = (0, import_use_intersection_active.useIntersectionActive)();
61
+ const [loaded, setLoaded] = (0, import_react.useState)(false);
62
+ (0, import_react.useEffect)(() => setLoaded(false), [image]);
59
63
  const showLive = live && !!animationUrl && isVisible;
64
+ const shimmer = !loaded && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
65
+ "div",
66
+ {
67
+ className: "absolute inset-0 min-h-80 animate-[shimmer_1.6s_ease-in-out_infinite] bg-foreground/[0.06]",
68
+ style: {
69
+ backgroundImage: "linear-gradient(90deg, transparent, color-mix(in srgb, var(--foreground) 8%, transparent), transparent)",
70
+ backgroundSize: "200% 100%"
71
+ }
72
+ }
73
+ );
60
74
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref, className: "w-full lg:sticky lg:top-16", children: [
61
75
  showLive ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-full overflow-hidden rounded-3xl aspect-square", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
62
76
  "iframe",
@@ -67,7 +81,7 @@ function AssetMediaColumn({
67
81
  loading: "lazy",
68
82
  className: "w-full h-full border-0"
69
83
  }
70
- ) }) : !image || imgError ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-full overflow-hidden rounded-3xl", children: fallback }) : onZoom ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
84
+ ) }) : !image || imgError ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-full overflow-hidden rounded-3xl", children: fallback }) : onZoom ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
71
85
  import_framer_motion.motion.button,
72
86
  {
73
87
  type: "button",
@@ -76,35 +90,50 @@ function AssetMediaColumn({
76
90
  initial: shouldReduce ? false : { opacity: 0, scale: 0.98 },
77
91
  animate: { opacity: 1, scale: 1 },
78
92
  transition: { duration: 0.5 },
79
- className: "group block w-full overflow-hidden rounded-3xl cursor-zoom-in focus:outline-none",
80
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
81
- "img",
82
- {
83
- src: image,
84
- alt: imageAlt,
85
- crossOrigin: "anonymous",
86
- onError: onImageError,
87
- className: "w-full h-auto max-h-[80vh] object-contain\n transition duration-300 group-hover:opacity-95 group-active:scale-[0.99]"
88
- }
89
- )
93
+ className: "group relative block w-full overflow-hidden rounded-3xl cursor-zoom-in focus:outline-none",
94
+ children: [
95
+ shimmer,
96
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
97
+ "img",
98
+ {
99
+ src: image,
100
+ alt: imageAlt,
101
+ crossOrigin: "anonymous",
102
+ onLoad: () => setLoaded(true),
103
+ onError: onImageError,
104
+ className: (0, import_cn.cn)(
105
+ "w-full h-auto max-h-[80vh] object-contain",
106
+ "transition-opacity duration-300 group-hover:opacity-95 group-active:scale-[0.99]",
107
+ loaded ? "opacity-100" : "opacity-0"
108
+ )
109
+ }
110
+ )
111
+ ]
90
112
  }
91
- ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
113
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
92
114
  import_framer_motion.motion.div,
93
115
  {
94
116
  initial: shouldReduce ? false : { opacity: 0, scale: 0.98 },
95
117
  animate: { opacity: 1, scale: 1 },
96
118
  transition: { duration: 0.5 },
97
- className: "block w-full overflow-hidden rounded-3xl",
98
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
99
- "img",
100
- {
101
- src: image,
102
- alt: imageAlt,
103
- crossOrigin: "anonymous",
104
- onError: onImageError,
105
- className: "w-full h-auto max-h-[80vh] object-contain"
106
- }
107
- )
119
+ className: "relative block w-full overflow-hidden rounded-3xl",
120
+ children: [
121
+ shimmer,
122
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
123
+ "img",
124
+ {
125
+ src: image,
126
+ alt: imageAlt,
127
+ crossOrigin: "anonymous",
128
+ onLoad: () => setLoaded(true),
129
+ onError: onImageError,
130
+ className: (0, import_cn.cn)(
131
+ "w-full h-auto max-h-[80vh] object-contain transition-opacity duration-300",
132
+ loaded ? "opacity-100" : "opacity-0"
133
+ )
134
+ }
135
+ )
136
+ ]
108
137
  }
109
138
  ),
110
139
  stats && stats.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `grid gap-3 mt-4 ${stats.length === 2 ? "grid-cols-2" : "grid-cols-1"}`, children: stats.map((stat) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rounded-xl border border-border bg-muted/20 p-4 text-center", children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/asset-top-sections.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\nimport { motion } from \"framer-motion\";\nimport { useIntersectionActive } from \"../utils/use-intersection-active.js\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { ParentAttributionBanner } from \"./parent-attribution-banner.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { Layers, Users } from \"lucide-react\";\n\ninterface AssetMediaColumnProps {\n shouldReduce: boolean;\n image: string | null;\n imageAlt: string;\n imgError: boolean;\n onImageError: () => void;\n fallback: React.ReactNode;\n\n onZoom?: () => void;\n\n animationUrl?: string | null;\n\n live?: boolean;\n stats?: Array<{\n value: string;\n label: string;\n icon: React.ReactNode;\n }>;\n}\n\nexport function AssetMediaColumn({\n shouldReduce,\n image,\n imageAlt,\n imgError,\n onImageError,\n fallback,\n onZoom,\n animationUrl,\n live = false,\n stats,\n}: AssetMediaColumnProps) {\n const [ref, isVisible] = useIntersectionActive<HTMLDivElement>();\n const showLive = live && !!animationUrl && isVisible;\n\n return (\n <div ref={ref} className=\"w-full lg:sticky lg:top-16\">\n {showLive ? (\n <div className=\"w-full overflow-hidden rounded-3xl aspect-square\">\n <iframe\n src={animationUrl!}\n title={imageAlt}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n className=\"w-full h-full border-0\"\n />\n </div>\n ) : !image || imgError ? (\n <div className=\"w-full overflow-hidden rounded-3xl\">{fallback}</div>\n ) : onZoom ? (\n <motion.button\n type=\"button\"\n onClick={onZoom}\n aria-label=\"View full image\"\n initial={shouldReduce ? false : { opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ duration: 0.5 }}\n className=\"group block w-full overflow-hidden rounded-3xl cursor-zoom-in focus:outline-none\"\n >\n\n <img\n src={image}\n alt={imageAlt}\n crossOrigin=\"anonymous\"\n onError={onImageError}\n className=\"w-full h-auto max-h-[80vh] object-contain\n transition duration-300 group-hover:opacity-95 group-active:scale-[0.99]\"\n />\n </motion.button>\n ) : (\n <motion.div\n initial={shouldReduce ? false : { opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ duration: 0.5 }}\n className=\"block w-full overflow-hidden rounded-3xl\"\n >\n\n <img\n src={image}\n alt={imageAlt}\n crossOrigin=\"anonymous\"\n onError={onImageError}\n className=\"w-full h-auto max-h-[80vh] object-contain\"\n />\n </motion.div>\n )}\n\n {stats && stats.length > 0 ? (\n <div className={`grid gap-3 mt-4 ${stats.length === 2 ? \"grid-cols-2\" : \"grid-cols-1\"}`}>\n {stats.map((stat) => (\n <div key={stat.label} className=\"rounded-xl border border-border bg-muted/20 p-4 text-center\">\n <p className=\"text-2xl font-black\">{stat.value}</p>\n <div className=\"flex items-center justify-center gap-1 text-xs text-muted-foreground mt-1\">\n {stat.icon}\n {stat.label}\n </div>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n );\n}\n\ninterface AssetHeaderBlockProps {\n name: string;\n description?: string | null;\n ipType?: string | null;\n showMultiEditionBadge?: boolean;\n parentContract?: string | null;\n parentTokenId?: string | null;\n}\n\nexport function AssetHeaderBlock({\n name,\n description,\n ipType,\n showMultiEditionBadge = false,\n parentContract,\n parentTokenId,\n}: AssetHeaderBlockProps) {\n return (\n <div className=\"min-w-0 flex-1\">\n {ipType || showMultiEditionBadge ? (\n <div className=\"flex items-center gap-2 flex-wrap mb-2\">\n {ipType ? <IpTypeBadge ipType={ipType} size=\"md\" /> : null}\n {showMultiEditionBadge ? (\n <span className=\"inline-flex items-center gap-1 text-2xs font-semibold px-2.5 py-1 rounded-full border border-violet-500/30 bg-violet-500/10 text-violet-500\">\n <Layers className=\"h-3 w-3\" />\n Multi-edition\n </span>\n ) : null}\n </div>\n ) : null}\n {parentContract && parentTokenId ? (\n <div className=\"mb-3\">\n <ParentAttributionBanner\n parentContract={parentContract}\n parentTokenId={parentTokenId}\n parentName={`Token #${parentTokenId}`}\n />\n </div>\n ) : null}\n <h1 className=\"text-2xl lg:text-4xl font-bold break-words\">{name}</h1>\n {description ? (\n <p className=\"text-sm text-muted-foreground leading-relaxed mt-1\">{description}</p>\n ) : null}\n </div>\n );\n}\n\nexport interface AssetOwnerRowProps {\n ownerAddress: string;\n ownerHref: string;\n}\n\nexport function AssetOwnerRow({ ownerAddress, ownerHref }: AssetOwnerRowProps) {\n return (\n <div className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <span>Owner</span>\n <Link href={ownerHref} className=\"hover:text-primary transition-colors font-medium\">\n <AddressDisplay address={ownerAddress} />\n </Link>\n </div>\n );\n}\n\nexport function buildEditionStats(totalEditions: number, uniqueOwners: number) {\n return [\n {\n value: totalEditions.toLocaleString(),\n label: \"editions minted\",\n icon: <Layers className=\"h-3 w-3\" />,\n },\n {\n value: uniqueOwners.toLocaleString(),\n label: \"unique owners\",\n icon: <Users className=\"h-3 w-3\" />,\n },\n ];\n}\n"],"mappings":"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","names":["Link"]}
1
+ {"version":3,"sources":["../../src/components/asset-top-sections.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\nimport { useEffect, useState } from \"react\";\nimport { motion } from \"framer-motion\";\nimport { useIntersectionActive } from \"../utils/use-intersection-active.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { ParentAttributionBanner } from \"./parent-attribution-banner.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { Layers, Users } from \"lucide-react\";\n\ninterface AssetMediaColumnProps {\n shouldReduce: boolean;\n image: string | null;\n imageAlt: string;\n imgError: boolean;\n onImageError: () => void;\n fallback: React.ReactNode;\n\n onZoom?: () => void;\n\n animationUrl?: string | null;\n\n live?: boolean;\n stats?: Array<{\n value: string;\n label: string;\n icon: React.ReactNode;\n }>;\n}\n\nexport function AssetMediaColumn({\n shouldReduce,\n image,\n imageAlt,\n imgError,\n onImageError,\n fallback,\n onZoom,\n animationUrl,\n live = false,\n stats,\n}: AssetMediaColumnProps) {\n const [ref, isVisible] = useIntersectionActive<HTMLDivElement>();\n const [loaded, setLoaded] = useState(false);\n useEffect(() => setLoaded(false), [image]);\n const showLive = live && !!animationUrl && isVisible;\n\n const shimmer = !loaded && (\n <div\n className=\"absolute inset-0 min-h-80 animate-[shimmer_1.6s_ease-in-out_infinite] bg-foreground/[0.06]\"\n style={{\n backgroundImage:\n \"linear-gradient(90deg, transparent, color-mix(in srgb, var(--foreground) 8%, transparent), transparent)\",\n backgroundSize: \"200% 100%\",\n }}\n />\n );\n\n return (\n <div ref={ref} className=\"w-full lg:sticky lg:top-16\">\n {showLive ? (\n <div className=\"w-full overflow-hidden rounded-3xl aspect-square\">\n <iframe\n src={animationUrl!}\n title={imageAlt}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n className=\"w-full h-full border-0\"\n />\n </div>\n ) : !image || imgError ? (\n <div className=\"w-full overflow-hidden rounded-3xl\">{fallback}</div>\n ) : onZoom ? (\n <motion.button\n type=\"button\"\n onClick={onZoom}\n aria-label=\"View full image\"\n initial={shouldReduce ? false : { opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ duration: 0.5 }}\n className=\"group relative block w-full overflow-hidden rounded-3xl cursor-zoom-in focus:outline-none\"\n >\n {shimmer}\n <img\n src={image}\n alt={imageAlt}\n crossOrigin=\"anonymous\"\n onLoad={() => setLoaded(true)}\n onError={onImageError}\n className={cn(\n \"w-full h-auto max-h-[80vh] object-contain\",\n \"transition-opacity duration-300 group-hover:opacity-95 group-active:scale-[0.99]\",\n loaded ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n </motion.button>\n ) : (\n <motion.div\n initial={shouldReduce ? false : { opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ duration: 0.5 }}\n className=\"relative block w-full overflow-hidden rounded-3xl\"\n >\n {shimmer}\n <img\n src={image}\n alt={imageAlt}\n crossOrigin=\"anonymous\"\n onLoad={() => setLoaded(true)}\n onError={onImageError}\n className={cn(\n \"w-full h-auto max-h-[80vh] object-contain transition-opacity duration-300\",\n loaded ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n </motion.div>\n )}\n\n {stats && stats.length > 0 ? (\n <div className={`grid gap-3 mt-4 ${stats.length === 2 ? \"grid-cols-2\" : \"grid-cols-1\"}`}>\n {stats.map((stat) => (\n <div key={stat.label} className=\"rounded-xl border border-border bg-muted/20 p-4 text-center\">\n <p className=\"text-2xl font-black\">{stat.value}</p>\n <div className=\"flex items-center justify-center gap-1 text-xs text-muted-foreground mt-1\">\n {stat.icon}\n {stat.label}\n </div>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n );\n}\n\ninterface AssetHeaderBlockProps {\n name: string;\n description?: string | null;\n ipType?: string | null;\n showMultiEditionBadge?: boolean;\n parentContract?: string | null;\n parentTokenId?: string | null;\n}\n\nexport function AssetHeaderBlock({\n name,\n description,\n ipType,\n showMultiEditionBadge = false,\n parentContract,\n parentTokenId,\n}: AssetHeaderBlockProps) {\n return (\n <div className=\"min-w-0 flex-1\">\n {ipType || showMultiEditionBadge ? (\n <div className=\"flex items-center gap-2 flex-wrap mb-2\">\n {ipType ? <IpTypeBadge ipType={ipType} size=\"md\" /> : null}\n {showMultiEditionBadge ? (\n <span className=\"inline-flex items-center gap-1 text-2xs font-semibold px-2.5 py-1 rounded-full border border-violet-500/30 bg-violet-500/10 text-violet-500\">\n <Layers className=\"h-3 w-3\" />\n Multi-edition\n </span>\n ) : null}\n </div>\n ) : null}\n {parentContract && parentTokenId ? (\n <div className=\"mb-3\">\n <ParentAttributionBanner\n parentContract={parentContract}\n parentTokenId={parentTokenId}\n parentName={`Token #${parentTokenId}`}\n />\n </div>\n ) : null}\n <h1 className=\"text-2xl lg:text-4xl font-bold break-words\">{name}</h1>\n {description ? (\n <p className=\"text-sm text-muted-foreground leading-relaxed mt-1\">{description}</p>\n ) : null}\n </div>\n );\n}\n\nexport interface AssetOwnerRowProps {\n ownerAddress: string;\n ownerHref: string;\n}\n\nexport function AssetOwnerRow({ ownerAddress, ownerHref }: AssetOwnerRowProps) {\n return (\n <div className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <span>Owner</span>\n <Link href={ownerHref} className=\"hover:text-primary transition-colors font-medium\">\n <AddressDisplay address={ownerAddress} />\n </Link>\n </div>\n );\n}\n\nexport function buildEditionStats(totalEditions: number, uniqueOwners: number) {\n return [\n {\n value: totalEditions.toLocaleString(),\n label: \"editions minted\",\n icon: <Layers className=\"h-3 w-3\" />,\n },\n {\n value: uniqueOwners.toLocaleString(),\n label: \"unique owners\",\n icon: <Users className=\"h-3 w-3\" />,\n },\n ];\n}\n"],"mappings":"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","names":["Link"]}
@@ -1,8 +1,10 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import Link from "next/link";
4
+ import { useEffect, useState } from "react";
4
5
  import { motion } from "framer-motion";
5
6
  import { useIntersectionActive } from "../utils/use-intersection-active.js";
7
+ import { cn } from "../utils/cn.js";
6
8
  import { AddressDisplay } from "./address-display.js";
7
9
  import { ParentAttributionBanner } from "./parent-attribution-banner.js";
8
10
  import { IpTypeBadge } from "./ip-type-badge.js";
@@ -20,7 +22,19 @@ function AssetMediaColumn({
20
22
  stats
21
23
  }) {
22
24
  const [ref, isVisible] = useIntersectionActive();
25
+ const [loaded, setLoaded] = useState(false);
26
+ useEffect(() => setLoaded(false), [image]);
23
27
  const showLive = live && !!animationUrl && isVisible;
28
+ const shimmer = !loaded && /* @__PURE__ */ jsx(
29
+ "div",
30
+ {
31
+ className: "absolute inset-0 min-h-80 animate-[shimmer_1.6s_ease-in-out_infinite] bg-foreground/[0.06]",
32
+ style: {
33
+ backgroundImage: "linear-gradient(90deg, transparent, color-mix(in srgb, var(--foreground) 8%, transparent), transparent)",
34
+ backgroundSize: "200% 100%"
35
+ }
36
+ }
37
+ );
24
38
  return /* @__PURE__ */ jsxs("div", { ref, className: "w-full lg:sticky lg:top-16", children: [
25
39
  showLive ? /* @__PURE__ */ jsx("div", { className: "w-full overflow-hidden rounded-3xl aspect-square", children: /* @__PURE__ */ jsx(
26
40
  "iframe",
@@ -31,7 +45,7 @@ function AssetMediaColumn({
31
45
  loading: "lazy",
32
46
  className: "w-full h-full border-0"
33
47
  }
34
- ) }) : !image || imgError ? /* @__PURE__ */ jsx("div", { className: "w-full overflow-hidden rounded-3xl", children: fallback }) : onZoom ? /* @__PURE__ */ jsx(
48
+ ) }) : !image || imgError ? /* @__PURE__ */ jsx("div", { className: "w-full overflow-hidden rounded-3xl", children: fallback }) : onZoom ? /* @__PURE__ */ jsxs(
35
49
  motion.button,
36
50
  {
37
51
  type: "button",
@@ -40,35 +54,50 @@ function AssetMediaColumn({
40
54
  initial: shouldReduce ? false : { opacity: 0, scale: 0.98 },
41
55
  animate: { opacity: 1, scale: 1 },
42
56
  transition: { duration: 0.5 },
43
- className: "group block w-full overflow-hidden rounded-3xl cursor-zoom-in focus:outline-none",
44
- children: /* @__PURE__ */ jsx(
45
- "img",
46
- {
47
- src: image,
48
- alt: imageAlt,
49
- crossOrigin: "anonymous",
50
- onError: onImageError,
51
- className: "w-full h-auto max-h-[80vh] object-contain\n transition duration-300 group-hover:opacity-95 group-active:scale-[0.99]"
52
- }
53
- )
57
+ className: "group relative block w-full overflow-hidden rounded-3xl cursor-zoom-in focus:outline-none",
58
+ children: [
59
+ shimmer,
60
+ /* @__PURE__ */ jsx(
61
+ "img",
62
+ {
63
+ src: image,
64
+ alt: imageAlt,
65
+ crossOrigin: "anonymous",
66
+ onLoad: () => setLoaded(true),
67
+ onError: onImageError,
68
+ className: cn(
69
+ "w-full h-auto max-h-[80vh] object-contain",
70
+ "transition-opacity duration-300 group-hover:opacity-95 group-active:scale-[0.99]",
71
+ loaded ? "opacity-100" : "opacity-0"
72
+ )
73
+ }
74
+ )
75
+ ]
54
76
  }
55
- ) : /* @__PURE__ */ jsx(
77
+ ) : /* @__PURE__ */ jsxs(
56
78
  motion.div,
57
79
  {
58
80
  initial: shouldReduce ? false : { opacity: 0, scale: 0.98 },
59
81
  animate: { opacity: 1, scale: 1 },
60
82
  transition: { duration: 0.5 },
61
- className: "block w-full overflow-hidden rounded-3xl",
62
- children: /* @__PURE__ */ jsx(
63
- "img",
64
- {
65
- src: image,
66
- alt: imageAlt,
67
- crossOrigin: "anonymous",
68
- onError: onImageError,
69
- className: "w-full h-auto max-h-[80vh] object-contain"
70
- }
71
- )
83
+ className: "relative block w-full overflow-hidden rounded-3xl",
84
+ children: [
85
+ shimmer,
86
+ /* @__PURE__ */ jsx(
87
+ "img",
88
+ {
89
+ src: image,
90
+ alt: imageAlt,
91
+ crossOrigin: "anonymous",
92
+ onLoad: () => setLoaded(true),
93
+ onError: onImageError,
94
+ className: cn(
95
+ "w-full h-auto max-h-[80vh] object-contain transition-opacity duration-300",
96
+ loaded ? "opacity-100" : "opacity-0"
97
+ )
98
+ }
99
+ )
100
+ ]
72
101
  }
73
102
  ),
74
103
  stats && stats.length > 0 ? /* @__PURE__ */ jsx("div", { className: `grid gap-3 mt-4 ${stats.length === 2 ? "grid-cols-2" : "grid-cols-1"}`, children: stats.map((stat) => /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-border bg-muted/20 p-4 text-center", children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/asset-top-sections.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\nimport { motion } from \"framer-motion\";\nimport { useIntersectionActive } from \"../utils/use-intersection-active.js\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { ParentAttributionBanner } from \"./parent-attribution-banner.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { Layers, Users } from \"lucide-react\";\n\ninterface AssetMediaColumnProps {\n shouldReduce: boolean;\n image: string | null;\n imageAlt: string;\n imgError: boolean;\n onImageError: () => void;\n fallback: React.ReactNode;\n\n onZoom?: () => void;\n\n animationUrl?: string | null;\n\n live?: boolean;\n stats?: Array<{\n value: string;\n label: string;\n icon: React.ReactNode;\n }>;\n}\n\nexport function AssetMediaColumn({\n shouldReduce,\n image,\n imageAlt,\n imgError,\n onImageError,\n fallback,\n onZoom,\n animationUrl,\n live = false,\n stats,\n}: AssetMediaColumnProps) {\n const [ref, isVisible] = useIntersectionActive<HTMLDivElement>();\n const showLive = live && !!animationUrl && isVisible;\n\n return (\n <div ref={ref} className=\"w-full lg:sticky lg:top-16\">\n {showLive ? (\n <div className=\"w-full overflow-hidden rounded-3xl aspect-square\">\n <iframe\n src={animationUrl!}\n title={imageAlt}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n className=\"w-full h-full border-0\"\n />\n </div>\n ) : !image || imgError ? (\n <div className=\"w-full overflow-hidden rounded-3xl\">{fallback}</div>\n ) : onZoom ? (\n <motion.button\n type=\"button\"\n onClick={onZoom}\n aria-label=\"View full image\"\n initial={shouldReduce ? false : { opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ duration: 0.5 }}\n className=\"group block w-full overflow-hidden rounded-3xl cursor-zoom-in focus:outline-none\"\n >\n\n <img\n src={image}\n alt={imageAlt}\n crossOrigin=\"anonymous\"\n onError={onImageError}\n className=\"w-full h-auto max-h-[80vh] object-contain\n transition duration-300 group-hover:opacity-95 group-active:scale-[0.99]\"\n />\n </motion.button>\n ) : (\n <motion.div\n initial={shouldReduce ? false : { opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ duration: 0.5 }}\n className=\"block w-full overflow-hidden rounded-3xl\"\n >\n\n <img\n src={image}\n alt={imageAlt}\n crossOrigin=\"anonymous\"\n onError={onImageError}\n className=\"w-full h-auto max-h-[80vh] object-contain\"\n />\n </motion.div>\n )}\n\n {stats && stats.length > 0 ? (\n <div className={`grid gap-3 mt-4 ${stats.length === 2 ? \"grid-cols-2\" : \"grid-cols-1\"}`}>\n {stats.map((stat) => (\n <div key={stat.label} className=\"rounded-xl border border-border bg-muted/20 p-4 text-center\">\n <p className=\"text-2xl font-black\">{stat.value}</p>\n <div className=\"flex items-center justify-center gap-1 text-xs text-muted-foreground mt-1\">\n {stat.icon}\n {stat.label}\n </div>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n );\n}\n\ninterface AssetHeaderBlockProps {\n name: string;\n description?: string | null;\n ipType?: string | null;\n showMultiEditionBadge?: boolean;\n parentContract?: string | null;\n parentTokenId?: string | null;\n}\n\nexport function AssetHeaderBlock({\n name,\n description,\n ipType,\n showMultiEditionBadge = false,\n parentContract,\n parentTokenId,\n}: AssetHeaderBlockProps) {\n return (\n <div className=\"min-w-0 flex-1\">\n {ipType || showMultiEditionBadge ? (\n <div className=\"flex items-center gap-2 flex-wrap mb-2\">\n {ipType ? <IpTypeBadge ipType={ipType} size=\"md\" /> : null}\n {showMultiEditionBadge ? (\n <span className=\"inline-flex items-center gap-1 text-2xs font-semibold px-2.5 py-1 rounded-full border border-violet-500/30 bg-violet-500/10 text-violet-500\">\n <Layers className=\"h-3 w-3\" />\n Multi-edition\n </span>\n ) : null}\n </div>\n ) : null}\n {parentContract && parentTokenId ? (\n <div className=\"mb-3\">\n <ParentAttributionBanner\n parentContract={parentContract}\n parentTokenId={parentTokenId}\n parentName={`Token #${parentTokenId}`}\n />\n </div>\n ) : null}\n <h1 className=\"text-2xl lg:text-4xl font-bold break-words\">{name}</h1>\n {description ? (\n <p className=\"text-sm text-muted-foreground leading-relaxed mt-1\">{description}</p>\n ) : null}\n </div>\n );\n}\n\nexport interface AssetOwnerRowProps {\n ownerAddress: string;\n ownerHref: string;\n}\n\nexport function AssetOwnerRow({ ownerAddress, ownerHref }: AssetOwnerRowProps) {\n return (\n <div className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <span>Owner</span>\n <Link href={ownerHref} className=\"hover:text-primary transition-colors font-medium\">\n <AddressDisplay address={ownerAddress} />\n </Link>\n </div>\n );\n}\n\nexport function buildEditionStats(totalEditions: number, uniqueOwners: number) {\n return [\n {\n value: totalEditions.toLocaleString(),\n label: \"editions minted\",\n icon: <Layers className=\"h-3 w-3\" />,\n },\n {\n value: uniqueOwners.toLocaleString(),\n label: \"unique owners\",\n icon: <Users className=\"h-3 w-3\" />,\n },\n ];\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/asset-top-sections.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\nimport { useEffect, useState } from \"react\";\nimport { motion } from \"framer-motion\";\nimport { useIntersectionActive } from \"../utils/use-intersection-active.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { ParentAttributionBanner } from \"./parent-attribution-banner.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { Layers, Users } from \"lucide-react\";\n\ninterface AssetMediaColumnProps {\n shouldReduce: boolean;\n image: string | null;\n imageAlt: string;\n imgError: boolean;\n onImageError: () => void;\n fallback: React.ReactNode;\n\n onZoom?: () => void;\n\n animationUrl?: string | null;\n\n live?: boolean;\n stats?: Array<{\n value: string;\n label: string;\n icon: React.ReactNode;\n }>;\n}\n\nexport function AssetMediaColumn({\n shouldReduce,\n image,\n imageAlt,\n imgError,\n onImageError,\n fallback,\n onZoom,\n animationUrl,\n live = false,\n stats,\n}: AssetMediaColumnProps) {\n const [ref, isVisible] = useIntersectionActive<HTMLDivElement>();\n const [loaded, setLoaded] = useState(false);\n useEffect(() => setLoaded(false), [image]);\n const showLive = live && !!animationUrl && isVisible;\n\n const shimmer = !loaded && (\n <div\n className=\"absolute inset-0 min-h-80 animate-[shimmer_1.6s_ease-in-out_infinite] bg-foreground/[0.06]\"\n style={{\n backgroundImage:\n \"linear-gradient(90deg, transparent, color-mix(in srgb, var(--foreground) 8%, transparent), transparent)\",\n backgroundSize: \"200% 100%\",\n }}\n />\n );\n\n return (\n <div ref={ref} className=\"w-full lg:sticky lg:top-16\">\n {showLive ? (\n <div className=\"w-full overflow-hidden rounded-3xl aspect-square\">\n <iframe\n src={animationUrl!}\n title={imageAlt}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n className=\"w-full h-full border-0\"\n />\n </div>\n ) : !image || imgError ? (\n <div className=\"w-full overflow-hidden rounded-3xl\">{fallback}</div>\n ) : onZoom ? (\n <motion.button\n type=\"button\"\n onClick={onZoom}\n aria-label=\"View full image\"\n initial={shouldReduce ? false : { opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ duration: 0.5 }}\n className=\"group relative block w-full overflow-hidden rounded-3xl cursor-zoom-in focus:outline-none\"\n >\n {shimmer}\n <img\n src={image}\n alt={imageAlt}\n crossOrigin=\"anonymous\"\n onLoad={() => setLoaded(true)}\n onError={onImageError}\n className={cn(\n \"w-full h-auto max-h-[80vh] object-contain\",\n \"transition-opacity duration-300 group-hover:opacity-95 group-active:scale-[0.99]\",\n loaded ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n </motion.button>\n ) : (\n <motion.div\n initial={shouldReduce ? false : { opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ duration: 0.5 }}\n className=\"relative block w-full overflow-hidden rounded-3xl\"\n >\n {shimmer}\n <img\n src={image}\n alt={imageAlt}\n crossOrigin=\"anonymous\"\n onLoad={() => setLoaded(true)}\n onError={onImageError}\n className={cn(\n \"w-full h-auto max-h-[80vh] object-contain transition-opacity duration-300\",\n loaded ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n </motion.div>\n )}\n\n {stats && stats.length > 0 ? (\n <div className={`grid gap-3 mt-4 ${stats.length === 2 ? \"grid-cols-2\" : \"grid-cols-1\"}`}>\n {stats.map((stat) => (\n <div key={stat.label} className=\"rounded-xl border border-border bg-muted/20 p-4 text-center\">\n <p className=\"text-2xl font-black\">{stat.value}</p>\n <div className=\"flex items-center justify-center gap-1 text-xs text-muted-foreground mt-1\">\n {stat.icon}\n {stat.label}\n </div>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n );\n}\n\ninterface AssetHeaderBlockProps {\n name: string;\n description?: string | null;\n ipType?: string | null;\n showMultiEditionBadge?: boolean;\n parentContract?: string | null;\n parentTokenId?: string | null;\n}\n\nexport function AssetHeaderBlock({\n name,\n description,\n ipType,\n showMultiEditionBadge = false,\n parentContract,\n parentTokenId,\n}: AssetHeaderBlockProps) {\n return (\n <div className=\"min-w-0 flex-1\">\n {ipType || showMultiEditionBadge ? (\n <div className=\"flex items-center gap-2 flex-wrap mb-2\">\n {ipType ? <IpTypeBadge ipType={ipType} size=\"md\" /> : null}\n {showMultiEditionBadge ? (\n <span className=\"inline-flex items-center gap-1 text-2xs font-semibold px-2.5 py-1 rounded-full border border-violet-500/30 bg-violet-500/10 text-violet-500\">\n <Layers className=\"h-3 w-3\" />\n Multi-edition\n </span>\n ) : null}\n </div>\n ) : null}\n {parentContract && parentTokenId ? (\n <div className=\"mb-3\">\n <ParentAttributionBanner\n parentContract={parentContract}\n parentTokenId={parentTokenId}\n parentName={`Token #${parentTokenId}`}\n />\n </div>\n ) : null}\n <h1 className=\"text-2xl lg:text-4xl font-bold break-words\">{name}</h1>\n {description ? (\n <p className=\"text-sm text-muted-foreground leading-relaxed mt-1\">{description}</p>\n ) : null}\n </div>\n );\n}\n\nexport interface AssetOwnerRowProps {\n ownerAddress: string;\n ownerHref: string;\n}\n\nexport function AssetOwnerRow({ ownerAddress, ownerHref }: AssetOwnerRowProps) {\n return (\n <div className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <span>Owner</span>\n <Link href={ownerHref} className=\"hover:text-primary transition-colors font-medium\">\n <AddressDisplay address={ownerAddress} />\n </Link>\n </div>\n );\n}\n\nexport function buildEditionStats(totalEditions: number, uniqueOwners: number) {\n return [\n {\n value: totalEditions.toLocaleString(),\n label: \"editions minted\",\n icon: <Layers className=\"h-3 w-3\" />,\n },\n {\n value: uniqueOwners.toLocaleString(),\n label: \"unique owners\",\n icon: <Users className=\"h-3 w-3\" />,\n },\n ];\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medialane/ui",
3
- "version": "0.126.0",
3
+ "version": "0.126.2",
4
4
  "description": "Shared UI components for Medialane apps",
5
5
  "type": "module",
6
6
  "sideEffects": false,