@medialane/ui 0.54.0 → 0.55.1

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.
@@ -22,13 +22,13 @@ __export(medialane_collection_card_exports, {
22
22
  MedialaneCollectionCard: () => MedialaneCollectionCard
23
23
  });
24
24
  module.exports = __toCommonJS(medialane_collection_card_exports);
25
- var import_jsx_runtime = (
26
- // eslint-disable-next-line @next/next/no-img-element
27
- require("react/jsx-runtime")
28
- );
25
+ var import_jsx_runtime = require("react/jsx-runtime");
29
26
  var import_react = require("react");
30
27
  var import_cn = require("../utils/cn.js");
31
28
  const FRAME_GRADIENT = "linear-gradient(135deg, #3b7bff, #8a5cf6 38%, #f6608f 70%, #fb8b46)";
29
+ const MATERIAL = `radial-gradient(120% 90% at 0% 0%, rgba(59,123,255,0.14), transparent 55%),
30
+ radial-gradient(120% 90% at 100% 100%, rgba(251,139,70,0.10), transparent 55%),
31
+ #0a0e1f`;
32
32
  function MedialaneCollectionCard({
33
33
  image,
34
34
  name,
@@ -45,87 +45,100 @@ function MedialaneCollectionCard({
45
45
  const rect = el.getBoundingClientRect();
46
46
  const x = (e.clientX - rect.left) / rect.width;
47
47
  const y = (e.clientY - rect.top) / rect.height;
48
- el.style.setProperty("--rx", `${(0.5 - y) * 8}deg`);
49
- el.style.setProperty("--ry", `${(x - 0.5) * 8}deg`);
48
+ el.style.setProperty("--rx", `${(0.5 - y) * 9}deg`);
49
+ el.style.setProperty("--ry", `${(x - 0.5) * 9}deg`);
50
50
  el.style.setProperty("--mx", `${x * 100}%`);
51
51
  el.style.setProperty("--my", `${y * 100}%`);
52
+ el.style.setProperty("--pop", "1.015");
52
53
  };
53
54
  const handleLeave = () => {
54
55
  const el = frameRef.current;
55
56
  if (!el) return;
56
57
  el.style.setProperty("--rx", "0deg");
57
58
  el.style.setProperty("--ry", "0deg");
59
+ el.style.setProperty("--pop", "1");
58
60
  };
59
61
  const displayName = name?.trim() || "Untitled";
60
- const monogram = displayName[0]?.toUpperCase() ?? "M";
61
62
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_cn.cn)("group", className), style: { perspective: "1000px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
62
63
  "div",
63
64
  {
64
65
  ref: frameRef,
65
66
  onPointerMove: handleMove,
66
67
  onPointerLeave: handleLeave,
67
- className: "rounded-[24px] p-[1.5px] transition-transform duration-200 ease-out will-change-transform",
68
+ className: "rounded-[24px] p-[1.5px] transition-transform duration-200 ease-out will-change-transform shadow-[0_16px_40px_-16px_rgba(91,76,230,0.45)]",
68
69
  style: {
69
70
  background: FRAME_GRADIENT,
70
- transform: "rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg))",
71
+ transform: "rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) scale(var(--pop, 1))",
71
72
  transformStyle: "preserve-3d"
72
73
  },
73
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative rounded-[22.5px] overflow-hidden bg-[#0a0e1f] text-white", children: [
74
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative aspect-[4/5] w-full overflow-hidden", children: image ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: image, alt: displayName, className: "h-full w-full object-cover" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
75
- "div",
76
- {
77
- className: "h-full w-full flex items-center justify-center",
78
- style: { background: FRAME_GRADIENT, opacity: 0.9 },
79
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
80
- "span",
81
- {
82
- className: "text-7xl font-black text-white/90",
83
- style: { fontFamily: "var(--font-display, inherit)" },
84
- children: monogram
85
- }
86
- )
87
- }
88
- ) }),
89
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
90
- "div",
91
- {
92
- "aria-hidden": true,
93
- className: "pointer-events-none absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-300",
94
- style: {
95
- background: `radial-gradient(420px circle at var(--mx, 50%) var(--my, 35%), rgba(255,255,255,0.22), transparent 45%),
96
- linear-gradient(115deg, rgba(59,123,255,0.16), rgba(138,92,246,0.16) 35%, rgba(246,96,143,0.16) 65%, rgba(251,139,70,0.16))`,
97
- mixBlendMode: "screen"
98
- }
99
- }
100
- ),
101
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative p-4 pt-3.5", children: [
102
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
103
- "p",
104
- {
105
- className: "text-[17px] font-bold leading-snug truncate",
106
- style: { fontFamily: "var(--font-display, inherit)" },
107
- children: displayName
108
- }
109
- ),
110
- (collection || serial) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-0.5 flex items-baseline gap-2", children: [
111
- collection && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-[12.5px] text-white/60 truncate", children: collection }),
112
- serial && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "ml-auto shrink-0 text-[12.5px] text-white/80 tabular-nums", children: serial })
113
- ] }),
114
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "my-3 h-px bg-white/10" }),
115
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
74
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
75
+ "div",
76
+ {
77
+ className: "relative rounded-[22.5px] overflow-hidden text-white ring-1 ring-inset ring-white/[0.06]",
78
+ style: { background: MATERIAL },
79
+ children: [
80
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "p-2.5 pb-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative aspect-[4/5] w-full overflow-hidden rounded-[16px] ring-1 ring-white/10", children: [
81
+ image ? (
82
+ // eslint-disable-next-line @next/next/no-img-element
83
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: image, alt: displayName, className: "h-full w-full object-cover" })
84
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
85
+ "div",
86
+ {
87
+ className: "h-full w-full",
88
+ style: { background: FRAME_GRADIENT, opacity: 0.9 }
89
+ }
90
+ ),
91
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
92
+ "div",
93
+ {
94
+ "aria-hidden": true,
95
+ className: "pointer-events-none absolute inset-x-0 bottom-0 h-16",
96
+ style: { background: "linear-gradient(to top, rgba(10,14,31,0.45), transparent)" }
97
+ }
98
+ )
99
+ ] }) }),
116
100
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
117
- "span",
101
+ "div",
118
102
  {
119
103
  "aria-hidden": true,
120
- className: "h-3.5 w-3.5 rounded-full shrink-0",
121
- style: { background: FRAME_GRADIENT }
104
+ className: "pointer-events-none absolute inset-0 opacity-40 group-hover:opacity-100 transition-opacity duration-300",
105
+ style: {
106
+ background: `radial-gradient(420px circle at var(--mx, 70%) var(--my, 20%), rgba(255,255,255,0.20), transparent 45%),
107
+ linear-gradient(115deg, rgba(59,123,255,0.14), rgba(138,92,246,0.14) 35%, rgba(246,96,143,0.14) 65%, rgba(251,139,70,0.14))`,
108
+ mixBlendMode: "screen"
109
+ }
122
110
  }
123
111
  ),
124
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[9px] font-bold tracking-[0.18em] text-white/50", children: "MEDIALANE" }),
125
- creator && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-auto min-w-0 truncate text-[11px] text-white/60", children: creator })
126
- ] })
127
- ] })
128
- ] })
112
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative px-4 pt-3 pb-4", children: [
113
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-start gap-2", children: [
114
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
115
+ "p",
116
+ {
117
+ className: "min-w-0 flex-1 text-[18px] font-bold leading-snug truncate",
118
+ style: { fontFamily: "var(--font-display, inherit)" },
119
+ children: displayName
120
+ }
121
+ ),
122
+ serial && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "mt-0.5 shrink-0 rounded-full bg-white/10 px-2 py-0.5 text-[11px] font-semibold text-white/80 tabular-nums", children: serial })
123
+ ] }),
124
+ collection && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mt-0.5 text-[12.5px] text-white/55 truncate", children: collection }),
125
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "my-3 h-px bg-white/10" }),
126
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
127
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
128
+ "span",
129
+ {
130
+ "aria-hidden": true,
131
+ className: "h-3.5 w-3.5 rounded-full shrink-0",
132
+ style: { background: FRAME_GRADIENT }
133
+ }
134
+ ),
135
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[9px] font-bold tracking-[0.18em] text-white/50", children: "MEDIALANE" }),
136
+ creator && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-auto min-w-0 truncate text-[11px] text-white/55 tabular-nums", children: creator })
137
+ ] })
138
+ ] })
139
+ ]
140
+ }
141
+ )
129
142
  }
130
143
  ) });
131
144
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/medialane-collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useRef } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface MedialaneCollectionCardProps {\n /** Resolved, browser-loadable image URL. Empty → branded monogram placeholder. */\n image?: string | null;\n /** Asset or collection name. */\n name?: string;\n /** Secondary line under the name (collection name, symbol, ticker…). */\n collection?: string;\n /** Edition or serial shown right-aligned, e.g. \"#42\" or \"1 / 300\". */\n serial?: string;\n /** Creator display name or shortened address. */\n creator?: string;\n className?: string;\n}\n\nconst FRAME_GRADIENT =\n \"linear-gradient(135deg, #3b7bff, #8a5cf6 38%, #f6608f 70%, #fb8b46)\";\n\n/** The Medialane Collection Card — a branded collectors-card preview of an\n * asset or collection. A self-contained dark collectible object (identical in\n * both themes): brand-spectrum frame, pointer-tracked 3D tilt + holographic\n * sheen, display-face name, tabular serial, Medialane maker's mark. Fluid\n * width — size it with the parent container. Pure presentation. */\nexport function MedialaneCollectionCard({\n image,\n name,\n collection,\n serial,\n creator,\n className,\n}: MedialaneCollectionCardProps) {\n const frameRef = useRef<HTMLDivElement>(null);\n\n const handleMove = (e: React.PointerEvent<HTMLDivElement>) => {\n const el = frameRef.current;\n if (!el || e.pointerType !== \"mouse\") return;\n if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n const rect = el.getBoundingClientRect();\n const x = (e.clientX - rect.left) / rect.width;\n const y = (e.clientY - rect.top) / rect.height;\n el.style.setProperty(\"--rx\", `${(0.5 - y) * 8}deg`);\n el.style.setProperty(\"--ry\", `${(x - 0.5) * 8}deg`);\n el.style.setProperty(\"--mx\", `${x * 100}%`);\n el.style.setProperty(\"--my\", `${y * 100}%`);\n };\n\n const handleLeave = () => {\n const el = frameRef.current;\n if (!el) return;\n el.style.setProperty(\"--rx\", \"0deg\");\n el.style.setProperty(\"--ry\", \"0deg\");\n };\n\n const displayName = name?.trim() || \"Untitled\";\n const monogram = displayName[0]?.toUpperCase() ?? \"M\";\n\n return (\n <div className={cn(\"group\", className)} style={{ perspective: \"1000px\" }}>\n <div\n ref={frameRef}\n onPointerMove={handleMove}\n onPointerLeave={handleLeave}\n className=\"rounded-[24px] p-[1.5px] transition-transform duration-200 ease-out will-change-transform\"\n style={{\n background: FRAME_GRADIENT,\n transform:\n \"rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg))\",\n transformStyle: \"preserve-3d\",\n }}\n >\n <div className=\"relative rounded-[22.5px] overflow-hidden bg-[#0a0e1f] text-white\">\n {/* Artwork */}\n <div className=\"relative aspect-[4/5] w-full overflow-hidden\">\n {image ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img src={image} alt={displayName} className=\"h-full w-full object-cover\" />\n ) : (\n <div\n className=\"h-full w-full flex items-center justify-center\"\n style={{ background: FRAME_GRADIENT, opacity: 0.9 }}\n >\n <span\n className=\"text-7xl font-black text-white/90\"\n style={{ fontFamily: \"var(--font-display, inherit)\" }}\n >\n {monogram}\n </span>\n </div>\n )}\n </div>\n\n {/* Holographic sheen — follows the pointer, brand spectrum tint */}\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-300\"\n style={{\n background: `radial-gradient(420px circle at var(--mx, 50%) var(--my, 35%), rgba(255,255,255,0.22), transparent 45%),\n linear-gradient(115deg, rgba(59,123,255,0.16), rgba(138,92,246,0.16) 35%, rgba(246,96,143,0.16) 65%, rgba(251,139,70,0.16))`,\n mixBlendMode: \"screen\",\n }}\n />\n\n {/* Meta */}\n <div className=\"relative p-4 pt-3.5\">\n <p\n className=\"text-[17px] font-bold leading-snug truncate\"\n style={{ fontFamily: \"var(--font-display, inherit)\" }}\n >\n {displayName}\n </p>\n {(collection || serial) && (\n <div className=\"mt-0.5 flex items-baseline gap-2\">\n {collection && (\n <p className=\"text-[12.5px] text-white/60 truncate\">{collection}</p>\n )}\n {serial && (\n <p className=\"ml-auto shrink-0 text-[12.5px] text-white/80 tabular-nums\">\n {serial}\n </p>\n )}\n </div>\n )}\n <div className=\"my-3 h-px bg-white/10\" />\n <div className=\"flex items-center gap-2\">\n <span\n aria-hidden\n className=\"h-3.5 w-3.5 rounded-full shrink-0\"\n style={{ background: FRAME_GRADIENT }}\n />\n <span className=\"text-[9px] font-bold tracking-[0.18em] text-white/50\">\n MEDIALANE\n </span>\n {creator && (\n <span className=\"ml-auto min-w-0 truncate text-[11px] text-white/60\">\n {creator}\n </span>\n )}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/medialane-collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useRef } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface MedialaneCollectionCardProps {\n /** Resolved, browser-loadable image URL. Empty → brand-gradient placeholder. */\n image?: string | null;\n /** Asset or collection name. */\n name?: string;\n /** Secondary line under the name (collection name, symbol, ticker…). */\n collection?: string;\n /** Edition or serial shown as a pill, e.g. \"#42\" or \"1 / 300\". */\n serial?: string;\n /** Creator display name or shortened address. */\n creator?: string;\n className?: string;\n}\n\nconst FRAME_GRADIENT =\n \"linear-gradient(135deg, #3b7bff, #8a5cf6 38%, #f6608f 70%, #fb8b46)\";\n\n/** Foil tints on the card material — faint brand radials, like printed foil. */\nconst MATERIAL =\n `radial-gradient(120% 90% at 0% 0%, rgba(59,123,255,0.14), transparent 55%),\n radial-gradient(120% 90% at 100% 100%, rgba(251,139,70,0.10), transparent 55%),\n #0a0e1f`;\n\n/** The Medialane Collection Card — a branded collectors-card preview of an\n * asset or collection. A self-contained dark collectible object (identical in\n * both themes): brand-spectrum frame, inset artwork on foil-tinted material,\n * pointer-tracked 3D tilt + holographic sheen, display-face name, serial\n * pill, Medialane maker's mark. Fluid width — size it with the parent\n * container. Pure presentation. */\nexport function MedialaneCollectionCard({\n image,\n name,\n collection,\n serial,\n creator,\n className,\n}: MedialaneCollectionCardProps) {\n const frameRef = useRef<HTMLDivElement>(null);\n\n const handleMove = (e: React.PointerEvent<HTMLDivElement>) => {\n const el = frameRef.current;\n if (!el || e.pointerType !== \"mouse\") return;\n if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n const rect = el.getBoundingClientRect();\n const x = (e.clientX - rect.left) / rect.width;\n const y = (e.clientY - rect.top) / rect.height;\n el.style.setProperty(\"--rx\", `${(0.5 - y) * 9}deg`);\n el.style.setProperty(\"--ry\", `${(x - 0.5) * 9}deg`);\n el.style.setProperty(\"--mx\", `${x * 100}%`);\n el.style.setProperty(\"--my\", `${y * 100}%`);\n el.style.setProperty(\"--pop\", \"1.015\");\n };\n\n const handleLeave = () => {\n const el = frameRef.current;\n if (!el) return;\n el.style.setProperty(\"--rx\", \"0deg\");\n el.style.setProperty(\"--ry\", \"0deg\");\n el.style.setProperty(\"--pop\", \"1\");\n };\n\n const displayName = name?.trim() || \"Untitled\";\n\n return (\n <div className={cn(\"group\", className)} style={{ perspective: \"1000px\" }}>\n <div\n ref={frameRef}\n onPointerMove={handleMove}\n onPointerLeave={handleLeave}\n className=\"rounded-[24px] p-[1.5px] transition-transform duration-200 ease-out will-change-transform shadow-[0_16px_40px_-16px_rgba(91,76,230,0.45)]\"\n style={{\n background: FRAME_GRADIENT,\n transform:\n \"rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) scale(var(--pop, 1))\",\n transformStyle: \"preserve-3d\",\n }}\n >\n <div\n className=\"relative rounded-[22.5px] overflow-hidden text-white ring-1 ring-inset ring-white/[0.06]\"\n style={{ background: MATERIAL }}\n >\n {/* Artwork — inset like a printed trading card */}\n <div className=\"p-2.5 pb-0\">\n <div className=\"relative aspect-[4/5] w-full overflow-hidden rounded-[16px] ring-1 ring-white/10\">\n {image ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img src={image} alt={displayName} className=\"h-full w-full object-cover\" />\n ) : (\n <div\n className=\"h-full w-full\"\n style={{ background: FRAME_GRADIENT, opacity: 0.9 }}\n />\n )}\n {/* Bottom scrim for depth against the meta block */}\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-x-0 bottom-0 h-16\"\n style={{ background: \"linear-gradient(to top, rgba(10,14,31,0.45), transparent)\" }}\n />\n </div>\n </div>\n\n {/* Holographic sheen — visible at rest, blooms and tracks on hover */}\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0 opacity-40 group-hover:opacity-100 transition-opacity duration-300\"\n style={{\n background: `radial-gradient(420px circle at var(--mx, 70%) var(--my, 20%), rgba(255,255,255,0.20), transparent 45%),\n linear-gradient(115deg, rgba(59,123,255,0.14), rgba(138,92,246,0.14) 35%, rgba(246,96,143,0.14) 65%, rgba(251,139,70,0.14))`,\n mixBlendMode: \"screen\",\n }}\n />\n\n {/* Meta */}\n <div className=\"relative px-4 pt-3 pb-4\">\n <div className=\"flex items-start gap-2\">\n <p\n className=\"min-w-0 flex-1 text-[18px] font-bold leading-snug truncate\"\n style={{ fontFamily: \"var(--font-display, inherit)\" }}\n >\n {displayName}\n </p>\n {serial && (\n <span className=\"mt-0.5 shrink-0 rounded-full bg-white/10 px-2 py-0.5 text-[11px] font-semibold text-white/80 tabular-nums\">\n {serial}\n </span>\n )}\n </div>\n {collection && (\n <p className=\"mt-0.5 text-[12.5px] text-white/55 truncate\">{collection}</p>\n )}\n <div className=\"my-3 h-px bg-white/10\" />\n <div className=\"flex items-center gap-2\">\n <span\n aria-hidden\n className=\"h-3.5 w-3.5 rounded-full shrink-0\"\n style={{ background: FRAME_GRADIENT }}\n />\n <span className=\"text-[9px] font-bold tracking-[0.18em] text-white/50\">\n MEDIALANE\n </span>\n {creator && (\n <span className=\"ml-auto min-w-0 truncate text-[11px] text-white/55 tabular-nums\">\n {creator}\n </span>\n )}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,13 +1,13 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
3
  interface MedialaneCollectionCardProps {
4
- /** Resolved, browser-loadable image URL. Empty → branded monogram placeholder. */
4
+ /** Resolved, browser-loadable image URL. Empty → brand-gradient placeholder. */
5
5
  image?: string | null;
6
6
  /** Asset or collection name. */
7
7
  name?: string;
8
8
  /** Secondary line under the name (collection name, symbol, ticker…). */
9
9
  collection?: string;
10
- /** Edition or serial shown right-aligned, e.g. "#42" or "1 / 300". */
10
+ /** Edition or serial shown as a pill, e.g. "#42" or "1 / 300". */
11
11
  serial?: string;
12
12
  /** Creator display name or shortened address. */
13
13
  creator?: string;
@@ -15,9 +15,10 @@ interface MedialaneCollectionCardProps {
15
15
  }
16
16
  /** The Medialane Collection Card — a branded collectors-card preview of an
17
17
  * asset or collection. A self-contained dark collectible object (identical in
18
- * both themes): brand-spectrum frame, pointer-tracked 3D tilt + holographic
19
- * sheen, display-face name, tabular serial, Medialane maker's mark. Fluid
20
- * width — size it with the parent container. Pure presentation. */
18
+ * both themes): brand-spectrum frame, inset artwork on foil-tinted material,
19
+ * pointer-tracked 3D tilt + holographic sheen, display-face name, serial
20
+ * pill, Medialane maker's mark. Fluid width — size it with the parent
21
+ * container. Pure presentation. */
21
22
  declare function MedialaneCollectionCard({ image, name, collection, serial, creator, className, }: MedialaneCollectionCardProps): react_jsx_runtime.JSX.Element;
22
23
 
23
24
  export { MedialaneCollectionCard, type MedialaneCollectionCardProps };
@@ -1,13 +1,13 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
3
  interface MedialaneCollectionCardProps {
4
- /** Resolved, browser-loadable image URL. Empty → branded monogram placeholder. */
4
+ /** Resolved, browser-loadable image URL. Empty → brand-gradient placeholder. */
5
5
  image?: string | null;
6
6
  /** Asset or collection name. */
7
7
  name?: string;
8
8
  /** Secondary line under the name (collection name, symbol, ticker…). */
9
9
  collection?: string;
10
- /** Edition or serial shown right-aligned, e.g. "#42" or "1 / 300". */
10
+ /** Edition or serial shown as a pill, e.g. "#42" or "1 / 300". */
11
11
  serial?: string;
12
12
  /** Creator display name or shortened address. */
13
13
  creator?: string;
@@ -15,9 +15,10 @@ interface MedialaneCollectionCardProps {
15
15
  }
16
16
  /** The Medialane Collection Card — a branded collectors-card preview of an
17
17
  * asset or collection. A self-contained dark collectible object (identical in
18
- * both themes): brand-spectrum frame, pointer-tracked 3D tilt + holographic
19
- * sheen, display-face name, tabular serial, Medialane maker's mark. Fluid
20
- * width — size it with the parent container. Pure presentation. */
18
+ * both themes): brand-spectrum frame, inset artwork on foil-tinted material,
19
+ * pointer-tracked 3D tilt + holographic sheen, display-face name, serial
20
+ * pill, Medialane maker's mark. Fluid width — size it with the parent
21
+ * container. Pure presentation. */
21
22
  declare function MedialaneCollectionCard({ image, name, collection, serial, creator, className, }: MedialaneCollectionCardProps): react_jsx_runtime.JSX.Element;
22
23
 
23
24
  export { MedialaneCollectionCard, type MedialaneCollectionCardProps };
@@ -3,6 +3,9 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useRef } from "react";
4
4
  import { cn } from "../utils/cn.js";
5
5
  const FRAME_GRADIENT = "linear-gradient(135deg, #3b7bff, #8a5cf6 38%, #f6608f 70%, #fb8b46)";
6
+ const MATERIAL = `radial-gradient(120% 90% at 0% 0%, rgba(59,123,255,0.14), transparent 55%),
7
+ radial-gradient(120% 90% at 100% 100%, rgba(251,139,70,0.10), transparent 55%),
8
+ #0a0e1f`;
6
9
  function MedialaneCollectionCard({
7
10
  image,
8
11
  name,
@@ -19,90 +22,100 @@ function MedialaneCollectionCard({
19
22
  const rect = el.getBoundingClientRect();
20
23
  const x = (e.clientX - rect.left) / rect.width;
21
24
  const y = (e.clientY - rect.top) / rect.height;
22
- el.style.setProperty("--rx", `${(0.5 - y) * 8}deg`);
23
- el.style.setProperty("--ry", `${(x - 0.5) * 8}deg`);
25
+ el.style.setProperty("--rx", `${(0.5 - y) * 9}deg`);
26
+ el.style.setProperty("--ry", `${(x - 0.5) * 9}deg`);
24
27
  el.style.setProperty("--mx", `${x * 100}%`);
25
28
  el.style.setProperty("--my", `${y * 100}%`);
29
+ el.style.setProperty("--pop", "1.015");
26
30
  };
27
31
  const handleLeave = () => {
28
32
  const el = frameRef.current;
29
33
  if (!el) return;
30
34
  el.style.setProperty("--rx", "0deg");
31
35
  el.style.setProperty("--ry", "0deg");
36
+ el.style.setProperty("--pop", "1");
32
37
  };
33
38
  const displayName = name?.trim() || "Untitled";
34
- const monogram = displayName[0]?.toUpperCase() ?? "M";
35
39
  return /* @__PURE__ */ jsx("div", { className: cn("group", className), style: { perspective: "1000px" }, children: /* @__PURE__ */ jsx(
36
40
  "div",
37
41
  {
38
42
  ref: frameRef,
39
43
  onPointerMove: handleMove,
40
44
  onPointerLeave: handleLeave,
41
- className: "rounded-[24px] p-[1.5px] transition-transform duration-200 ease-out will-change-transform",
45
+ className: "rounded-[24px] p-[1.5px] transition-transform duration-200 ease-out will-change-transform shadow-[0_16px_40px_-16px_rgba(91,76,230,0.45)]",
42
46
  style: {
43
47
  background: FRAME_GRADIENT,
44
- transform: "rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg))",
48
+ transform: "rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) scale(var(--pop, 1))",
45
49
  transformStyle: "preserve-3d"
46
50
  },
47
- children: /* @__PURE__ */ jsxs("div", { className: "relative rounded-[22.5px] overflow-hidden bg-[#0a0e1f] text-white", children: [
48
- /* @__PURE__ */ jsx("div", { className: "relative aspect-[4/5] w-full overflow-hidden", children: image ? (
49
- // eslint-disable-next-line @next/next/no-img-element
50
- /* @__PURE__ */ jsx("img", { src: image, alt: displayName, className: "h-full w-full object-cover" })
51
- ) : /* @__PURE__ */ jsx(
52
- "div",
53
- {
54
- className: "h-full w-full flex items-center justify-center",
55
- style: { background: FRAME_GRADIENT, opacity: 0.9 },
56
- children: /* @__PURE__ */ jsx(
57
- "span",
58
- {
59
- className: "text-7xl font-black text-white/90",
60
- style: { fontFamily: "var(--font-display, inherit)" },
61
- children: monogram
62
- }
63
- )
64
- }
65
- ) }),
66
- /* @__PURE__ */ jsx(
67
- "div",
68
- {
69
- "aria-hidden": true,
70
- className: "pointer-events-none absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-300",
71
- style: {
72
- background: `radial-gradient(420px circle at var(--mx, 50%) var(--my, 35%), rgba(255,255,255,0.22), transparent 45%),
73
- linear-gradient(115deg, rgba(59,123,255,0.16), rgba(138,92,246,0.16) 35%, rgba(246,96,143,0.16) 65%, rgba(251,139,70,0.16))`,
74
- mixBlendMode: "screen"
75
- }
76
- }
77
- ),
78
- /* @__PURE__ */ jsxs("div", { className: "relative p-4 pt-3.5", children: [
79
- /* @__PURE__ */ jsx(
80
- "p",
81
- {
82
- className: "text-[17px] font-bold leading-snug truncate",
83
- style: { fontFamily: "var(--font-display, inherit)" },
84
- children: displayName
85
- }
86
- ),
87
- (collection || serial) && /* @__PURE__ */ jsxs("div", { className: "mt-0.5 flex items-baseline gap-2", children: [
88
- collection && /* @__PURE__ */ jsx("p", { className: "text-[12.5px] text-white/60 truncate", children: collection }),
89
- serial && /* @__PURE__ */ jsx("p", { className: "ml-auto shrink-0 text-[12.5px] text-white/80 tabular-nums", children: serial })
90
- ] }),
91
- /* @__PURE__ */ jsx("div", { className: "my-3 h-px bg-white/10" }),
92
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
51
+ children: /* @__PURE__ */ jsxs(
52
+ "div",
53
+ {
54
+ className: "relative rounded-[22.5px] overflow-hidden text-white ring-1 ring-inset ring-white/[0.06]",
55
+ style: { background: MATERIAL },
56
+ children: [
57
+ /* @__PURE__ */ jsx("div", { className: "p-2.5 pb-0", children: /* @__PURE__ */ jsxs("div", { className: "relative aspect-[4/5] w-full overflow-hidden rounded-[16px] ring-1 ring-white/10", children: [
58
+ image ? (
59
+ // eslint-disable-next-line @next/next/no-img-element
60
+ /* @__PURE__ */ jsx("img", { src: image, alt: displayName, className: "h-full w-full object-cover" })
61
+ ) : /* @__PURE__ */ jsx(
62
+ "div",
63
+ {
64
+ className: "h-full w-full",
65
+ style: { background: FRAME_GRADIENT, opacity: 0.9 }
66
+ }
67
+ ),
68
+ /* @__PURE__ */ jsx(
69
+ "div",
70
+ {
71
+ "aria-hidden": true,
72
+ className: "pointer-events-none absolute inset-x-0 bottom-0 h-16",
73
+ style: { background: "linear-gradient(to top, rgba(10,14,31,0.45), transparent)" }
74
+ }
75
+ )
76
+ ] }) }),
93
77
  /* @__PURE__ */ jsx(
94
- "span",
78
+ "div",
95
79
  {
96
80
  "aria-hidden": true,
97
- className: "h-3.5 w-3.5 rounded-full shrink-0",
98
- style: { background: FRAME_GRADIENT }
81
+ className: "pointer-events-none absolute inset-0 opacity-40 group-hover:opacity-100 transition-opacity duration-300",
82
+ style: {
83
+ background: `radial-gradient(420px circle at var(--mx, 70%) var(--my, 20%), rgba(255,255,255,0.20), transparent 45%),
84
+ linear-gradient(115deg, rgba(59,123,255,0.14), rgba(138,92,246,0.14) 35%, rgba(246,96,143,0.14) 65%, rgba(251,139,70,0.14))`,
85
+ mixBlendMode: "screen"
86
+ }
99
87
  }
100
88
  ),
101
- /* @__PURE__ */ jsx("span", { className: "text-[9px] font-bold tracking-[0.18em] text-white/50", children: "MEDIALANE" }),
102
- creator && /* @__PURE__ */ jsx("span", { className: "ml-auto min-w-0 truncate text-[11px] text-white/60", children: creator })
103
- ] })
104
- ] })
105
- ] })
89
+ /* @__PURE__ */ jsxs("div", { className: "relative px-4 pt-3 pb-4", children: [
90
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
91
+ /* @__PURE__ */ jsx(
92
+ "p",
93
+ {
94
+ className: "min-w-0 flex-1 text-[18px] font-bold leading-snug truncate",
95
+ style: { fontFamily: "var(--font-display, inherit)" },
96
+ children: displayName
97
+ }
98
+ ),
99
+ serial && /* @__PURE__ */ jsx("span", { className: "mt-0.5 shrink-0 rounded-full bg-white/10 px-2 py-0.5 text-[11px] font-semibold text-white/80 tabular-nums", children: serial })
100
+ ] }),
101
+ collection && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-[12.5px] text-white/55 truncate", children: collection }),
102
+ /* @__PURE__ */ jsx("div", { className: "my-3 h-px bg-white/10" }),
103
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
104
+ /* @__PURE__ */ jsx(
105
+ "span",
106
+ {
107
+ "aria-hidden": true,
108
+ className: "h-3.5 w-3.5 rounded-full shrink-0",
109
+ style: { background: FRAME_GRADIENT }
110
+ }
111
+ ),
112
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] font-bold tracking-[0.18em] text-white/50", children: "MEDIALANE" }),
113
+ creator && /* @__PURE__ */ jsx("span", { className: "ml-auto min-w-0 truncate text-[11px] text-white/55 tabular-nums", children: creator })
114
+ ] })
115
+ ] })
116
+ ]
117
+ }
118
+ )
106
119
  }
107
120
  ) });
108
121
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/medialane-collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useRef } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface MedialaneCollectionCardProps {\n /** Resolved, browser-loadable image URL. Empty → branded monogram placeholder. */\n image?: string | null;\n /** Asset or collection name. */\n name?: string;\n /** Secondary line under the name (collection name, symbol, ticker…). */\n collection?: string;\n /** Edition or serial shown right-aligned, e.g. \"#42\" or \"1 / 300\". */\n serial?: string;\n /** Creator display name or shortened address. */\n creator?: string;\n className?: string;\n}\n\nconst FRAME_GRADIENT =\n \"linear-gradient(135deg, #3b7bff, #8a5cf6 38%, #f6608f 70%, #fb8b46)\";\n\n/** The Medialane Collection Card — a branded collectors-card preview of an\n * asset or collection. A self-contained dark collectible object (identical in\n * both themes): brand-spectrum frame, pointer-tracked 3D tilt + holographic\n * sheen, display-face name, tabular serial, Medialane maker's mark. Fluid\n * width — size it with the parent container. Pure presentation. */\nexport function MedialaneCollectionCard({\n image,\n name,\n collection,\n serial,\n creator,\n className,\n}: MedialaneCollectionCardProps) {\n const frameRef = useRef<HTMLDivElement>(null);\n\n const handleMove = (e: React.PointerEvent<HTMLDivElement>) => {\n const el = frameRef.current;\n if (!el || e.pointerType !== \"mouse\") return;\n if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n const rect = el.getBoundingClientRect();\n const x = (e.clientX - rect.left) / rect.width;\n const y = (e.clientY - rect.top) / rect.height;\n el.style.setProperty(\"--rx\", `${(0.5 - y) * 8}deg`);\n el.style.setProperty(\"--ry\", `${(x - 0.5) * 8}deg`);\n el.style.setProperty(\"--mx\", `${x * 100}%`);\n el.style.setProperty(\"--my\", `${y * 100}%`);\n };\n\n const handleLeave = () => {\n const el = frameRef.current;\n if (!el) return;\n el.style.setProperty(\"--rx\", \"0deg\");\n el.style.setProperty(\"--ry\", \"0deg\");\n };\n\n const displayName = name?.trim() || \"Untitled\";\n const monogram = displayName[0]?.toUpperCase() ?? \"M\";\n\n return (\n <div className={cn(\"group\", className)} style={{ perspective: \"1000px\" }}>\n <div\n ref={frameRef}\n onPointerMove={handleMove}\n onPointerLeave={handleLeave}\n className=\"rounded-[24px] p-[1.5px] transition-transform duration-200 ease-out will-change-transform\"\n style={{\n background: FRAME_GRADIENT,\n transform:\n \"rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg))\",\n transformStyle: \"preserve-3d\",\n }}\n >\n <div className=\"relative rounded-[22.5px] overflow-hidden bg-[#0a0e1f] text-white\">\n {/* Artwork */}\n <div className=\"relative aspect-[4/5] w-full overflow-hidden\">\n {image ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img src={image} alt={displayName} className=\"h-full w-full object-cover\" />\n ) : (\n <div\n className=\"h-full w-full flex items-center justify-center\"\n style={{ background: FRAME_GRADIENT, opacity: 0.9 }}\n >\n <span\n className=\"text-7xl font-black text-white/90\"\n style={{ fontFamily: \"var(--font-display, inherit)\" }}\n >\n {monogram}\n </span>\n </div>\n )}\n </div>\n\n {/* Holographic sheen — follows the pointer, brand spectrum tint */}\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-300\"\n style={{\n background: `radial-gradient(420px circle at var(--mx, 50%) var(--my, 35%), rgba(255,255,255,0.22), transparent 45%),\n linear-gradient(115deg, rgba(59,123,255,0.16), rgba(138,92,246,0.16) 35%, rgba(246,96,143,0.16) 65%, rgba(251,139,70,0.16))`,\n mixBlendMode: \"screen\",\n }}\n />\n\n {/* Meta */}\n <div className=\"relative p-4 pt-3.5\">\n <p\n className=\"text-[17px] font-bold leading-snug truncate\"\n style={{ fontFamily: \"var(--font-display, inherit)\" }}\n >\n {displayName}\n </p>\n {(collection || serial) && (\n <div className=\"mt-0.5 flex items-baseline gap-2\">\n {collection && (\n <p className=\"text-[12.5px] text-white/60 truncate\">{collection}</p>\n )}\n {serial && (\n <p className=\"ml-auto shrink-0 text-[12.5px] text-white/80 tabular-nums\">\n {serial}\n </p>\n )}\n </div>\n )}\n <div className=\"my-3 h-px bg-white/10\" />\n <div className=\"flex items-center gap-2\">\n <span\n aria-hidden\n className=\"h-3.5 w-3.5 rounded-full shrink-0\"\n style={{ background: FRAME_GRADIENT }}\n />\n <span className=\"text-[9px] font-bold tracking-[0.18em] text-white/50\">\n MEDIALANE\n </span>\n {creator && (\n <span className=\"ml-auto min-w-0 truncate text-[11px] text-white/60\">\n {creator}\n </span>\n )}\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/medialane-collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useRef } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface MedialaneCollectionCardProps {\n /** Resolved, browser-loadable image URL. Empty → brand-gradient placeholder. */\n image?: string | null;\n /** Asset or collection name. */\n name?: string;\n /** Secondary line under the name (collection name, symbol, ticker…). */\n collection?: string;\n /** Edition or serial shown as a pill, e.g. \"#42\" or \"1 / 300\". */\n serial?: string;\n /** Creator display name or shortened address. */\n creator?: string;\n className?: string;\n}\n\nconst FRAME_GRADIENT =\n \"linear-gradient(135deg, #3b7bff, #8a5cf6 38%, #f6608f 70%, #fb8b46)\";\n\n/** Foil tints on the card material — faint brand radials, like printed foil. */\nconst MATERIAL =\n `radial-gradient(120% 90% at 0% 0%, rgba(59,123,255,0.14), transparent 55%),\n radial-gradient(120% 90% at 100% 100%, rgba(251,139,70,0.10), transparent 55%),\n #0a0e1f`;\n\n/** The Medialane Collection Card — a branded collectors-card preview of an\n * asset or collection. A self-contained dark collectible object (identical in\n * both themes): brand-spectrum frame, inset artwork on foil-tinted material,\n * pointer-tracked 3D tilt + holographic sheen, display-face name, serial\n * pill, Medialane maker's mark. Fluid width — size it with the parent\n * container. Pure presentation. */\nexport function MedialaneCollectionCard({\n image,\n name,\n collection,\n serial,\n creator,\n className,\n}: MedialaneCollectionCardProps) {\n const frameRef = useRef<HTMLDivElement>(null);\n\n const handleMove = (e: React.PointerEvent<HTMLDivElement>) => {\n const el = frameRef.current;\n if (!el || e.pointerType !== \"mouse\") return;\n if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n const rect = el.getBoundingClientRect();\n const x = (e.clientX - rect.left) / rect.width;\n const y = (e.clientY - rect.top) / rect.height;\n el.style.setProperty(\"--rx\", `${(0.5 - y) * 9}deg`);\n el.style.setProperty(\"--ry\", `${(x - 0.5) * 9}deg`);\n el.style.setProperty(\"--mx\", `${x * 100}%`);\n el.style.setProperty(\"--my\", `${y * 100}%`);\n el.style.setProperty(\"--pop\", \"1.015\");\n };\n\n const handleLeave = () => {\n const el = frameRef.current;\n if (!el) return;\n el.style.setProperty(\"--rx\", \"0deg\");\n el.style.setProperty(\"--ry\", \"0deg\");\n el.style.setProperty(\"--pop\", \"1\");\n };\n\n const displayName = name?.trim() || \"Untitled\";\n\n return (\n <div className={cn(\"group\", className)} style={{ perspective: \"1000px\" }}>\n <div\n ref={frameRef}\n onPointerMove={handleMove}\n onPointerLeave={handleLeave}\n className=\"rounded-[24px] p-[1.5px] transition-transform duration-200 ease-out will-change-transform shadow-[0_16px_40px_-16px_rgba(91,76,230,0.45)]\"\n style={{\n background: FRAME_GRADIENT,\n transform:\n \"rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) scale(var(--pop, 1))\",\n transformStyle: \"preserve-3d\",\n }}\n >\n <div\n className=\"relative rounded-[22.5px] overflow-hidden text-white ring-1 ring-inset ring-white/[0.06]\"\n style={{ background: MATERIAL }}\n >\n {/* Artwork — inset like a printed trading card */}\n <div className=\"p-2.5 pb-0\">\n <div className=\"relative aspect-[4/5] w-full overflow-hidden rounded-[16px] ring-1 ring-white/10\">\n {image ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img src={image} alt={displayName} className=\"h-full w-full object-cover\" />\n ) : (\n <div\n className=\"h-full w-full\"\n style={{ background: FRAME_GRADIENT, opacity: 0.9 }}\n />\n )}\n {/* Bottom scrim for depth against the meta block */}\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-x-0 bottom-0 h-16\"\n style={{ background: \"linear-gradient(to top, rgba(10,14,31,0.45), transparent)\" }}\n />\n </div>\n </div>\n\n {/* Holographic sheen — visible at rest, blooms and tracks on hover */}\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0 opacity-40 group-hover:opacity-100 transition-opacity duration-300\"\n style={{\n background: `radial-gradient(420px circle at var(--mx, 70%) var(--my, 20%), rgba(255,255,255,0.20), transparent 45%),\n linear-gradient(115deg, rgba(59,123,255,0.14), rgba(138,92,246,0.14) 35%, rgba(246,96,143,0.14) 65%, rgba(251,139,70,0.14))`,\n mixBlendMode: \"screen\",\n }}\n />\n\n {/* Meta */}\n <div className=\"relative px-4 pt-3 pb-4\">\n <div className=\"flex items-start gap-2\">\n <p\n className=\"min-w-0 flex-1 text-[18px] font-bold leading-snug truncate\"\n style={{ fontFamily: \"var(--font-display, inherit)\" }}\n >\n {displayName}\n </p>\n {serial && (\n <span className=\"mt-0.5 shrink-0 rounded-full bg-white/10 px-2 py-0.5 text-[11px] font-semibold text-white/80 tabular-nums\">\n {serial}\n </span>\n )}\n </div>\n {collection && (\n <p className=\"mt-0.5 text-[12.5px] text-white/55 truncate\">{collection}</p>\n )}\n <div className=\"my-3 h-px bg-white/10\" />\n <div className=\"flex items-center gap-2\">\n <span\n aria-hidden\n className=\"h-3.5 w-3.5 rounded-full shrink-0\"\n style={{ background: FRAME_GRADIENT }}\n />\n <span className=\"text-[9px] font-bold tracking-[0.18em] text-white/50\">\n MEDIALANE\n </span>\n {creator && (\n <span className=\"ml-auto min-w-0 truncate text-[11px] text-white/55 tabular-nums\">\n {creator}\n </span>\n )}\n </div>\n </div>\n </div>\n </div>\n </div>\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.54.0",
3
+ "version": "0.55.1",
4
4
  "description": "Shared UI components for Medialane apps",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",