@medialane/ui 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/activity-feed-shell.cjs +90 -0
- package/dist/components/activity-feed-shell.cjs.map +1 -0
- package/dist/components/activity-feed-shell.d.cts +13 -0
- package/dist/components/activity-feed-shell.d.ts +13 -0
- package/dist/components/activity-feed-shell.js +56 -0
- package/dist/components/activity-feed-shell.js.map +1 -0
- package/dist/components/activity-row.cjs +95 -0
- package/dist/components/activity-row.cjs.map +1 -0
- package/dist/components/activity-row.d.cts +20 -0
- package/dist/components/activity-row.d.ts +20 -0
- package/dist/components/activity-row.js +61 -0
- package/dist/components/activity-row.js.map +1 -0
- package/dist/components/activity-ticker.cjs +92 -0
- package/dist/components/activity-ticker.cjs.map +1 -0
- package/dist/components/activity-ticker.d.cts +12 -0
- package/dist/components/activity-ticker.d.ts +12 -0
- package/dist/components/activity-ticker.js +58 -0
- package/dist/components/activity-ticker.js.map +1 -0
- package/dist/components/cta-card-grid.cjs +67 -0
- package/dist/components/cta-card-grid.cjs.map +1 -0
- package/dist/components/cta-card-grid.d.cts +23 -0
- package/dist/components/cta-card-grid.d.ts +23 -0
- package/dist/components/cta-card-grid.js +33 -0
- package/dist/components/cta-card-grid.js.map +1 -0
- package/dist/components/hero-slider.cjs +133 -0
- package/dist/components/hero-slider.cjs.map +1 -0
- package/dist/components/hero-slider.d.cts +12 -0
- package/dist/components/hero-slider.d.ts +12 -0
- package/dist/components/hero-slider.js +98 -0
- package/dist/components/hero-slider.js.map +1 -0
- package/dist/components/launchpad-grid.cjs +77 -0
- package/dist/components/launchpad-grid.cjs.map +1 -0
- package/dist/components/launchpad-grid.d.cts +20 -0
- package/dist/components/launchpad-grid.d.ts +20 -0
- package/dist/components/launchpad-grid.js +43 -0
- package/dist/components/launchpad-grid.js.map +1 -0
- package/dist/components/listing-card.cjs +146 -0
- package/dist/components/listing-card.cjs.map +1 -0
- package/dist/components/listing-card.d.cts +16 -0
- package/dist/components/listing-card.d.ts +16 -0
- package/dist/components/listing-card.js +111 -0
- package/dist/components/listing-card.js.map +1 -0
- package/dist/data/activity.cjs +48 -0
- package/dist/data/activity.cjs.map +1 -0
- package/dist/data/activity.d.cts +16 -0
- package/dist/data/activity.d.ts +16 -0
- package/dist/data/activity.js +23 -0
- package/dist/data/activity.js.map +1 -0
- package/dist/index.cjs +35 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +22 -1
- package/dist/index.js.map +1 -1
- package/dist/medialane.css +184 -0
- package/dist/utils/time.cjs +42 -0
- package/dist/utils/time.cjs.map +1 -0
- package/dist/utils/time.d.cts +7 -0
- package/dist/utils/time.d.ts +7 -0
- package/dist/utils/time.js +18 -0
- package/dist/utils/time.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import { CurrencyIcon } from "./currency-icon.js";
|
|
6
|
+
import { formatDisplayPrice } from "../utils/format.js";
|
|
7
|
+
import { ipfsToHttp } from "../utils/ipfs.js";
|
|
8
|
+
import { cn } from "../utils/cn.js";
|
|
9
|
+
function ActivityPill({ listing, getHref }) {
|
|
10
|
+
const [imgError, setImgError] = useState(false);
|
|
11
|
+
const image = listing.token?.image && !imgError ? ipfsToHttp(listing.token.image) : null;
|
|
12
|
+
return /* @__PURE__ */ jsxs(
|
|
13
|
+
Link,
|
|
14
|
+
{
|
|
15
|
+
href: getHref(listing),
|
|
16
|
+
className: "flex-shrink-0 flex items-center gap-2 rounded-xl border border-border bg-card px-3 py-2 hover:bg-muted/60 active:scale-[0.98] transition-all duration-150 group",
|
|
17
|
+
children: [
|
|
18
|
+
/* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-lg overflow-hidden bg-muted shrink-0", children: image ? /* @__PURE__ */ jsx(
|
|
19
|
+
"img",
|
|
20
|
+
{
|
|
21
|
+
src: image,
|
|
22
|
+
alt: "",
|
|
23
|
+
loading: "lazy",
|
|
24
|
+
className: "w-full h-full object-cover group-hover:scale-105 transition-transform duration-300",
|
|
25
|
+
onError: () => setImgError(true)
|
|
26
|
+
}
|
|
27
|
+
) : /* @__PURE__ */ jsx("div", { className: "w-full h-full bg-gradient-to-br from-brand-purple/20 to-brand-blue/20" }) }),
|
|
28
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
29
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs font-medium whitespace-nowrap max-w-[100px] truncate", children: listing.token?.name ?? `#${listing.nftTokenId}` }),
|
|
30
|
+
listing.price?.formatted && /* @__PURE__ */ jsxs("p", { className: "text-[10px] font-bold text-brand-orange whitespace-nowrap flex items-center gap-0.5", children: [
|
|
31
|
+
listing.price.currency && /* @__PURE__ */ jsx(CurrencyIcon, { symbol: listing.price.currency, size: 10 }),
|
|
32
|
+
formatDisplayPrice(listing.price.formatted),
|
|
33
|
+
" ",
|
|
34
|
+
listing.price.currency
|
|
35
|
+
] })
|
|
36
|
+
] })
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
function ActivityTicker({ orders, minItems = 3, className }) {
|
|
42
|
+
if (orders.length < minItems) return null;
|
|
43
|
+
const getHref = (order) => `/asset/${order.nftContract}/${order.nftTokenId}`;
|
|
44
|
+
return /* @__PURE__ */ jsx("div", { className: cn(className), children: /* @__PURE__ */ jsx("div", { className: "relative overflow-hidden py-2.5", children: /* @__PURE__ */ jsx(
|
|
45
|
+
"div",
|
|
46
|
+
{
|
|
47
|
+
className: "flex gap-2 w-max px-2",
|
|
48
|
+
style: { animation: "scroll-strip 50s linear infinite" },
|
|
49
|
+
onMouseEnter: (e) => e.currentTarget.style.animationPlayState = "paused",
|
|
50
|
+
onMouseLeave: (e) => e.currentTarget.style.animationPlayState = "running",
|
|
51
|
+
children: [...orders, ...orders].map((listing, i) => /* @__PURE__ */ jsx(ActivityPill, { listing, getHref }, `${listing.orderHash}-${i}`))
|
|
52
|
+
}
|
|
53
|
+
) }) });
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
ActivityTicker
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=activity-ticker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/activity-ticker.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiOrder } from \"@medialane/sdk\";\n\nexport interface ActivityTickerProps {\n orders: ApiOrder[];\n /** Hide ticker if fewer items than this threshold. Default: 3 */\n minItems?: number;\n className?: string;\n}\n\nfunction ActivityPill({ listing, getHref }: { listing: ApiOrder; getHref: (order: ApiOrder) => string }) {\n const [imgError, setImgError] = useState(false);\n const image = listing.token?.image && !imgError ? ipfsToHttp(listing.token.image) : null;\n\n return (\n <Link\n href={getHref(listing)}\n className=\"flex-shrink-0 flex items-center gap-2 rounded-xl border border-border bg-card px-3 py-2 hover:bg-muted/60 active:scale-[0.98] transition-all duration-150 group\"\n >\n <div className=\"h-8 w-8 rounded-lg overflow-hidden bg-muted shrink-0\">\n {image ? (\n <img\n src={image}\n alt=\"\"\n loading=\"lazy\"\n className=\"w-full h-full object-cover group-hover:scale-105 transition-transform duration-300\"\n onError={() => setImgError(true)}\n />\n ) : (\n <div className=\"w-full h-full bg-gradient-to-br from-brand-purple/20 to-brand-blue/20\" />\n )}\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-xs font-medium whitespace-nowrap max-w-[100px] truncate\">\n {listing.token?.name ?? `#${listing.nftTokenId}`}\n </p>\n {listing.price?.formatted && (\n <p className=\"text-[10px] font-bold text-brand-orange whitespace-nowrap flex items-center gap-0.5\">\n {listing.price.currency && <CurrencyIcon symbol={listing.price.currency} size={10} />}\n {formatDisplayPrice(listing.price.formatted)} {listing.price.currency}\n </p>\n )}\n </div>\n </Link>\n );\n}\n\nexport function ActivityTicker({ orders, minItems = 3, className }: ActivityTickerProps) {\n if (orders.length < minItems) return null;\n\n const getHref = (order: ApiOrder) => `/asset/${order.nftContract}/${order.nftTokenId}`;\n\n return (\n <div className={cn(className)}>\n <div className=\"relative overflow-hidden py-2.5\">\n <div\n className=\"flex gap-2 w-max px-2\"\n style={{ animation: \"scroll-strip 50s linear infinite\" }}\n onMouseEnter={(e) => (e.currentTarget.style.animationPlayState = \"paused\")}\n onMouseLeave={(e) => (e.currentTarget.style.animationPlayState = \"running\")}\n >\n {[...orders, ...orders].map((listing, i) => (\n <ActivityPill key={`${listing.orderHash}-${i}`} listing={listing} getHref={getHref} />\n ))}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";AA4BU,cAgBA,YAhBA;AA1BV,SAAS,gBAAgB;AACzB,OAAO,UAAU;AACjB,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,kBAAkB;AAC3B,SAAS,UAAU;AAUnB,SAAS,aAAa,EAAE,SAAS,QAAQ,GAAgE;AACvG,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,QAAQ,QAAQ,OAAO,SAAS,CAAC,WAAW,WAAW,QAAQ,MAAM,KAAK,IAAI;AAEpF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,QAAQ,OAAO;AAAA,MACrB,WAAU;AAAA,MAEV;AAAA,4BAAC,SAAI,WAAU,wDACZ,kBACC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAI;AAAA,YACJ,SAAQ;AAAA,YACR,WAAU;AAAA,YACV,SAAS,MAAM,YAAY,IAAI;AAAA;AAAA,QACjC,IAEA,oBAAC,SAAI,WAAU,yEAAwE,GAE3F;AAAA,QACA,qBAAC,SAAI,WAAU,WACb;AAAA,8BAAC,OAAE,WAAU,gEACV,kBAAQ,OAAO,QAAQ,IAAI,QAAQ,UAAU,IAChD;AAAA,UACC,QAAQ,OAAO,aACd,qBAAC,OAAE,WAAU,uFACV;AAAA,oBAAQ,MAAM,YAAY,oBAAC,gBAAa,QAAQ,QAAQ,MAAM,UAAU,MAAM,IAAI;AAAA,YAClF,mBAAmB,QAAQ,MAAM,SAAS;AAAA,YAAE;AAAA,YAAE,QAAQ,MAAM;AAAA,aAC/D;AAAA,WAEJ;AAAA;AAAA;AAAA,EACF;AAEJ;AAEO,SAAS,eAAe,EAAE,QAAQ,WAAW,GAAG,UAAU,GAAwB;AACvF,MAAI,OAAO,SAAS,SAAU,QAAO;AAErC,QAAM,UAAU,CAAC,UAAoB,UAAU,MAAM,WAAW,IAAI,MAAM,UAAU;AAEpF,SACE,oBAAC,SAAI,WAAW,GAAG,SAAS,GAC1B,8BAAC,SAAI,WAAU,mCACb;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO,EAAE,WAAW,mCAAmC;AAAA,MACvD,cAAc,CAAC,MAAO,EAAE,cAAc,MAAM,qBAAqB;AAAA,MACjE,cAAc,CAAC,MAAO,EAAE,cAAc,MAAM,qBAAqB;AAAA,MAEhE,WAAC,GAAG,QAAQ,GAAG,MAAM,EAAE,IAAI,CAAC,SAAS,MACpC,oBAAC,gBAA+C,SAAkB,WAA/C,GAAG,QAAQ,SAAS,IAAI,CAAC,EAAwC,CACrF;AAAA;AAAA,EACH,GACF,GACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var cta_card_grid_exports = {};
|
|
30
|
+
__export(cta_card_grid_exports, {
|
|
31
|
+
CtaCardGrid: () => CtaCardGrid
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(cta_card_grid_exports);
|
|
34
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
35
|
+
var import_link = __toESM(require("next/link"), 1);
|
|
36
|
+
var import_lucide_react = require("lucide-react");
|
|
37
|
+
var import_cn = require("../utils/cn.js");
|
|
38
|
+
function CtaCard({ icon: Icon, title, description, links, href, gradient, iconGradient }) {
|
|
39
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bento-cell p-6 sm:p-8 flex flex-col gap-6 relative overflow-hidden group hover:border-border/80 transition-colors", children: [
|
|
40
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `absolute inset-0 opacity-[0.03] group-hover:opacity-[0.06] transition-opacity ${gradient} pointer-events-none` }),
|
|
41
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative z-10 space-y-3", children: [
|
|
42
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_cn.cn)("h-11 w-11 rounded-2xl flex items-center justify-center shadow-lg", iconGradient), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { className: "h-5 w-5 text-white" }) }),
|
|
43
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
44
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "text-xl font-black", children: title }),
|
|
45
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm text-muted-foreground leading-relaxed mt-1", children: description })
|
|
46
|
+
] })
|
|
47
|
+
] }),
|
|
48
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "relative z-10 space-y-2", children: links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_link.default, { href: link.href, className: "flex items-center gap-2.5 text-sm text-muted-foreground hover:text-foreground transition-colors group/link", children: [
|
|
49
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRight, { className: "h-3.5 w-3.5 text-primary opacity-0 group-hover/link:opacity-100 transition-opacity shrink-0 -ml-0.5" }),
|
|
50
|
+
link.label
|
|
51
|
+
] }) }, link.href)) }),
|
|
52
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative z-10 mt-auto", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_link.default, { href, className: "inline-flex items-center gap-1.5 text-sm border border-border rounded-md px-3 py-1.5 hover:border-primary/40 transition-colors group-hover:border-primary/40", children: [
|
|
53
|
+
"Explore ",
|
|
54
|
+
title,
|
|
55
|
+
" ",
|
|
56
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRight, { className: "h-3.5 w-3.5 ml-1.5" })
|
|
57
|
+
] }) })
|
|
58
|
+
] });
|
|
59
|
+
}
|
|
60
|
+
function CtaCardGrid({ cards }) {
|
|
61
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", { className: "space-y-5", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: cards.map((card) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CtaCard, { ...card }, card.title)) }) });
|
|
62
|
+
}
|
|
63
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
64
|
+
0 && (module.exports = {
|
|
65
|
+
CtaCardGrid
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=cta-card-grid.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/cta-card-grid.tsx"],"sourcesContent":["import type { ElementType } from \"react\";\nimport Link from \"next/link\";\nimport { ArrowRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface CtaCardItem {\n icon: ElementType;\n title: string;\n description: string;\n links: { label: string; href: string }[];\n href: string;\n /** Tailwind gradient class applied as a 3% opacity hover overlay */\n gradient: string;\n /** Tailwind gradient + shadow class for the icon pill */\n iconGradient: string;\n}\n\nexport interface CtaCardGridProps {\n cards: CtaCardItem[];\n}\n\nfunction CtaCard({ icon: Icon, title, description, links, href, gradient, iconGradient }: CtaCardItem) {\n return (\n <div className=\"bento-cell p-6 sm:p-8 flex flex-col gap-6 relative overflow-hidden group hover:border-border/80 transition-colors\">\n <div className={`absolute inset-0 opacity-[0.03] group-hover:opacity-[0.06] transition-opacity ${gradient} pointer-events-none`} />\n\n <div className=\"relative z-10 space-y-3\">\n <div className={cn(\"h-11 w-11 rounded-2xl flex items-center justify-center shadow-lg\", iconGradient)}>\n <Icon className=\"h-5 w-5 text-white\" />\n </div>\n <div>\n <h3 className=\"text-xl font-black\">{title}</h3>\n <p className=\"text-sm text-muted-foreground leading-relaxed mt-1\">{description}</p>\n </div>\n </div>\n\n <ul className=\"relative z-10 space-y-2\">\n {links.map((link) => (\n <li key={link.href}>\n <Link href={link.href} className=\"flex items-center gap-2.5 text-sm text-muted-foreground hover:text-foreground transition-colors group/link\">\n <ArrowRight className=\"h-3.5 w-3.5 text-primary opacity-0 group-hover/link:opacity-100 transition-opacity shrink-0 -ml-0.5\" />\n {link.label}\n </Link>\n </li>\n ))}\n </ul>\n\n <div className=\"relative z-10 mt-auto\">\n <Link href={href} className=\"inline-flex items-center gap-1.5 text-sm border border-border rounded-md px-3 py-1.5 hover:border-primary/40 transition-colors group-hover:border-primary/40\">\n Explore {title} <ArrowRight className=\"h-3.5 w-3.5 ml-1.5\" />\n </Link>\n </div>\n </div>\n );\n}\n\nexport function CtaCardGrid({ cards }: CtaCardGridProps) {\n return (\n <section className=\"space-y-5\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n {cards.map((card) => (\n <CtaCard key={card.title} {...card} />\n ))}\n </div>\n </section>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBM;AAvBN,kBAAiB;AACjB,0BAA2B;AAC3B,gBAAmB;AAkBnB,SAAS,QAAQ,EAAE,MAAM,MAAM,OAAO,aAAa,OAAO,MAAM,UAAU,aAAa,GAAgB;AACrG,SACE,6CAAC,SAAI,WAAU,qHACb;AAAA,gDAAC,SAAI,WAAW,iFAAiF,QAAQ,wBAAwB;AAAA,IAEjI,6CAAC,SAAI,WAAU,2BACb;AAAA,kDAAC,SAAI,eAAW,cAAG,oEAAoE,YAAY,GACjG,sDAAC,QAAK,WAAU,sBAAqB,GACvC;AAAA,MACA,6CAAC,SACC;AAAA,oDAAC,QAAG,WAAU,sBAAsB,iBAAM;AAAA,QAC1C,4CAAC,OAAE,WAAU,sDAAsD,uBAAY;AAAA,SACjF;AAAA,OACF;AAAA,IAEA,4CAAC,QAAG,WAAU,2BACX,gBAAM,IAAI,CAAC,SACV,4CAAC,QACC,uDAAC,YAAAA,SAAA,EAAK,MAAM,KAAK,MAAM,WAAU,8GAC/B;AAAA,kDAAC,kCAAW,WAAU,uGAAsG;AAAA,MAC3H,KAAK;AAAA,OACR,KAJO,KAAK,IAKd,CACD,GACH;AAAA,IAEA,4CAAC,SAAI,WAAU,yBACb,uDAAC,YAAAA,SAAA,EAAK,MAAY,WAAU,gKAA+J;AAAA;AAAA,MAChL;AAAA,MAAM;AAAA,MAAC,4CAAC,kCAAW,WAAU,sBAAqB;AAAA,OAC7D,GACF;AAAA,KACF;AAEJ;AAEO,SAAS,YAAY,EAAE,MAAM,GAAqB;AACvD,SACE,4CAAC,aAAQ,WAAU,aACjB,sDAAC,SAAI,WAAU,yCACZ,gBAAM,IAAI,CAAC,SACV,4CAAC,WAA0B,GAAG,QAAhB,KAAK,KAAiB,CACrC,GACH,GACF;AAEJ;","names":["Link"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ElementType } from 'react';
|
|
3
|
+
|
|
4
|
+
interface CtaCardItem {
|
|
5
|
+
icon: ElementType;
|
|
6
|
+
title: string;
|
|
7
|
+
description: string;
|
|
8
|
+
links: {
|
|
9
|
+
label: string;
|
|
10
|
+
href: string;
|
|
11
|
+
}[];
|
|
12
|
+
href: string;
|
|
13
|
+
/** Tailwind gradient class applied as a 3% opacity hover overlay */
|
|
14
|
+
gradient: string;
|
|
15
|
+
/** Tailwind gradient + shadow class for the icon pill */
|
|
16
|
+
iconGradient: string;
|
|
17
|
+
}
|
|
18
|
+
interface CtaCardGridProps {
|
|
19
|
+
cards: CtaCardItem[];
|
|
20
|
+
}
|
|
21
|
+
declare function CtaCardGrid({ cards }: CtaCardGridProps): react_jsx_runtime.JSX.Element;
|
|
22
|
+
|
|
23
|
+
export { CtaCardGrid, type CtaCardGridProps, type CtaCardItem };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ElementType } from 'react';
|
|
3
|
+
|
|
4
|
+
interface CtaCardItem {
|
|
5
|
+
icon: ElementType;
|
|
6
|
+
title: string;
|
|
7
|
+
description: string;
|
|
8
|
+
links: {
|
|
9
|
+
label: string;
|
|
10
|
+
href: string;
|
|
11
|
+
}[];
|
|
12
|
+
href: string;
|
|
13
|
+
/** Tailwind gradient class applied as a 3% opacity hover overlay */
|
|
14
|
+
gradient: string;
|
|
15
|
+
/** Tailwind gradient + shadow class for the icon pill */
|
|
16
|
+
iconGradient: string;
|
|
17
|
+
}
|
|
18
|
+
interface CtaCardGridProps {
|
|
19
|
+
cards: CtaCardItem[];
|
|
20
|
+
}
|
|
21
|
+
declare function CtaCardGrid({ cards }: CtaCardGridProps): react_jsx_runtime.JSX.Element;
|
|
22
|
+
|
|
23
|
+
export { CtaCardGrid, type CtaCardGridProps, type CtaCardItem };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import Link from "next/link";
|
|
3
|
+
import { ArrowRight } from "lucide-react";
|
|
4
|
+
import { cn } from "../utils/cn.js";
|
|
5
|
+
function CtaCard({ icon: Icon, title, description, links, href, gradient, iconGradient }) {
|
|
6
|
+
return /* @__PURE__ */ jsxs("div", { className: "bento-cell p-6 sm:p-8 flex flex-col gap-6 relative overflow-hidden group hover:border-border/80 transition-colors", children: [
|
|
7
|
+
/* @__PURE__ */ jsx("div", { className: `absolute inset-0 opacity-[0.03] group-hover:opacity-[0.06] transition-opacity ${gradient} pointer-events-none` }),
|
|
8
|
+
/* @__PURE__ */ jsxs("div", { className: "relative z-10 space-y-3", children: [
|
|
9
|
+
/* @__PURE__ */ jsx("div", { className: cn("h-11 w-11 rounded-2xl flex items-center justify-center shadow-lg", iconGradient), children: /* @__PURE__ */ jsx(Icon, { className: "h-5 w-5 text-white" }) }),
|
|
10
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
11
|
+
/* @__PURE__ */ jsx("h3", { className: "text-xl font-black", children: title }),
|
|
12
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground leading-relaxed mt-1", children: description })
|
|
13
|
+
] })
|
|
14
|
+
] }),
|
|
15
|
+
/* @__PURE__ */ jsx("ul", { className: "relative z-10 space-y-2", children: links.map((link) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Link, { href: link.href, className: "flex items-center gap-2.5 text-sm text-muted-foreground hover:text-foreground transition-colors group/link", children: [
|
|
16
|
+
/* @__PURE__ */ jsx(ArrowRight, { className: "h-3.5 w-3.5 text-primary opacity-0 group-hover/link:opacity-100 transition-opacity shrink-0 -ml-0.5" }),
|
|
17
|
+
link.label
|
|
18
|
+
] }) }, link.href)) }),
|
|
19
|
+
/* @__PURE__ */ jsx("div", { className: "relative z-10 mt-auto", children: /* @__PURE__ */ jsxs(Link, { href, className: "inline-flex items-center gap-1.5 text-sm border border-border rounded-md px-3 py-1.5 hover:border-primary/40 transition-colors group-hover:border-primary/40", children: [
|
|
20
|
+
"Explore ",
|
|
21
|
+
title,
|
|
22
|
+
" ",
|
|
23
|
+
/* @__PURE__ */ jsx(ArrowRight, { className: "h-3.5 w-3.5 ml-1.5" })
|
|
24
|
+
] }) })
|
|
25
|
+
] });
|
|
26
|
+
}
|
|
27
|
+
function CtaCardGrid({ cards }) {
|
|
28
|
+
return /* @__PURE__ */ jsx("section", { className: "space-y-5", children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: cards.map((card) => /* @__PURE__ */ jsx(CtaCard, { ...card }, card.title)) }) });
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
CtaCardGrid
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=cta-card-grid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/cta-card-grid.tsx"],"sourcesContent":["import type { ElementType } from \"react\";\nimport Link from \"next/link\";\nimport { ArrowRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface CtaCardItem {\n icon: ElementType;\n title: string;\n description: string;\n links: { label: string; href: string }[];\n href: string;\n /** Tailwind gradient class applied as a 3% opacity hover overlay */\n gradient: string;\n /** Tailwind gradient + shadow class for the icon pill */\n iconGradient: string;\n}\n\nexport interface CtaCardGridProps {\n cards: CtaCardItem[];\n}\n\nfunction CtaCard({ icon: Icon, title, description, links, href, gradient, iconGradient }: CtaCardItem) {\n return (\n <div className=\"bento-cell p-6 sm:p-8 flex flex-col gap-6 relative overflow-hidden group hover:border-border/80 transition-colors\">\n <div className={`absolute inset-0 opacity-[0.03] group-hover:opacity-[0.06] transition-opacity ${gradient} pointer-events-none`} />\n\n <div className=\"relative z-10 space-y-3\">\n <div className={cn(\"h-11 w-11 rounded-2xl flex items-center justify-center shadow-lg\", iconGradient)}>\n <Icon className=\"h-5 w-5 text-white\" />\n </div>\n <div>\n <h3 className=\"text-xl font-black\">{title}</h3>\n <p className=\"text-sm text-muted-foreground leading-relaxed mt-1\">{description}</p>\n </div>\n </div>\n\n <ul className=\"relative z-10 space-y-2\">\n {links.map((link) => (\n <li key={link.href}>\n <Link href={link.href} className=\"flex items-center gap-2.5 text-sm text-muted-foreground hover:text-foreground transition-colors group/link\">\n <ArrowRight className=\"h-3.5 w-3.5 text-primary opacity-0 group-hover/link:opacity-100 transition-opacity shrink-0 -ml-0.5\" />\n {link.label}\n </Link>\n </li>\n ))}\n </ul>\n\n <div className=\"relative z-10 mt-auto\">\n <Link href={href} className=\"inline-flex items-center gap-1.5 text-sm border border-border rounded-md px-3 py-1.5 hover:border-primary/40 transition-colors group-hover:border-primary/40\">\n Explore {title} <ArrowRight className=\"h-3.5 w-3.5 ml-1.5\" />\n </Link>\n </div>\n </div>\n );\n}\n\nexport function CtaCardGrid({ cards }: CtaCardGridProps) {\n return (\n <section className=\"space-y-5\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n {cards.map((card) => (\n <CtaCard key={card.title} {...card} />\n ))}\n </div>\n </section>\n );\n}\n"],"mappings":"AAwBM,cAME,YANF;AAvBN,OAAO,UAAU;AACjB,SAAS,kBAAkB;AAC3B,SAAS,UAAU;AAkBnB,SAAS,QAAQ,EAAE,MAAM,MAAM,OAAO,aAAa,OAAO,MAAM,UAAU,aAAa,GAAgB;AACrG,SACE,qBAAC,SAAI,WAAU,qHACb;AAAA,wBAAC,SAAI,WAAW,iFAAiF,QAAQ,wBAAwB;AAAA,IAEjI,qBAAC,SAAI,WAAU,2BACb;AAAA,0BAAC,SAAI,WAAW,GAAG,oEAAoE,YAAY,GACjG,8BAAC,QAAK,WAAU,sBAAqB,GACvC;AAAA,MACA,qBAAC,SACC;AAAA,4BAAC,QAAG,WAAU,sBAAsB,iBAAM;AAAA,QAC1C,oBAAC,OAAE,WAAU,sDAAsD,uBAAY;AAAA,SACjF;AAAA,OACF;AAAA,IAEA,oBAAC,QAAG,WAAU,2BACX,gBAAM,IAAI,CAAC,SACV,oBAAC,QACC,+BAAC,QAAK,MAAM,KAAK,MAAM,WAAU,8GAC/B;AAAA,0BAAC,cAAW,WAAU,uGAAsG;AAAA,MAC3H,KAAK;AAAA,OACR,KAJO,KAAK,IAKd,CACD,GACH;AAAA,IAEA,oBAAC,SAAI,WAAU,yBACb,+BAAC,QAAK,MAAY,WAAU,gKAA+J;AAAA;AAAA,MAChL;AAAA,MAAM;AAAA,MAAC,oBAAC,cAAW,WAAU,sBAAqB;AAAA,OAC7D,GACF;AAAA,KACF;AAEJ;AAEO,SAAS,YAAY,EAAE,MAAM,GAAqB;AACvD,SACE,oBAAC,aAAQ,WAAU,aACjB,8BAAC,SAAI,WAAU,yCACZ,gBAAM,IAAI,CAAC,SACV,oBAAC,WAA0B,GAAG,QAAhB,KAAK,KAAiB,CACrC,GACH,GACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var hero_slider_exports = {};
|
|
31
|
+
__export(hero_slider_exports, {
|
|
32
|
+
HeroSlider: () => HeroSlider,
|
|
33
|
+
HeroSliderSkeleton: () => HeroSliderSkeleton
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(hero_slider_exports);
|
|
36
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
37
|
+
var import_react = require("react");
|
|
38
|
+
var import_link = __toESM(require("next/link"), 1);
|
|
39
|
+
var import_image = __toESM(require("next/image"), 1);
|
|
40
|
+
var import_lucide_react = require("lucide-react");
|
|
41
|
+
var import_cn = require("../utils/cn.js");
|
|
42
|
+
function formatFloorPrice(price) {
|
|
43
|
+
if (!price) return "";
|
|
44
|
+
const n = parseFloat(price);
|
|
45
|
+
if (isNaN(n)) return price;
|
|
46
|
+
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
47
|
+
if (n >= 1) return n.toFixed(2);
|
|
48
|
+
return n.toPrecision(3);
|
|
49
|
+
}
|
|
50
|
+
function ipfsToHttp(uri) {
|
|
51
|
+
if (!uri) return "";
|
|
52
|
+
if (uri.startsWith("ipfs://")) return uri.replace("ipfs://", "https://gateway.pinata.cloud/ipfs/");
|
|
53
|
+
return uri;
|
|
54
|
+
}
|
|
55
|
+
function HeroPlaceholder() {
|
|
56
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/50 flex flex-col items-center justify-center gap-4 text-center px-6 overflow-hidden", children: [
|
|
57
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute aurora-purple w-[600px] h-[600px] opacity-20 -top-24 -left-24" }),
|
|
58
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute aurora-blue w-[400px] h-[400px] opacity-15 -bottom-16 -right-16" }),
|
|
59
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-4xl sm:text-6xl font-black gradient-text relative z-10", children: "Medialane" }),
|
|
60
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-muted-foreground text-lg relative z-10 max-w-md", children: "New monetization revenues for creative works" }),
|
|
61
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-3 relative z-10", children: [
|
|
62
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_link.default, { href: "/marketplace", className: "inline-flex items-center justify-center rounded-[11px] bg-brand-blue px-4 py-2 text-sm font-semibold text-white hover:brightness-110 active:scale-[0.98] transition-all", children: "Markets" }),
|
|
63
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_link.default, { href: "/create/asset", className: "inline-flex items-center justify-center rounded-[11px] border border-white/20 bg-background/20 backdrop-blur-sm px-4 py-2 text-sm font-semibold text-white hover:bg-white/10 transition-all", children: "Create" })
|
|
64
|
+
] })
|
|
65
|
+
] });
|
|
66
|
+
}
|
|
67
|
+
function HeroSlide({ collection, active, getHref }) {
|
|
68
|
+
const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;
|
|
69
|
+
const name = collection.name ?? "Collection";
|
|
70
|
+
const floor = collection.floorPrice;
|
|
71
|
+
const supply = collection.totalSupply;
|
|
72
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_cn.cn)("absolute inset-0 transition-opacity duration-700", active ? "opacity-100" : "opacity-0 pointer-events-none"), children: [
|
|
73
|
+
imageUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "animate-kenburns absolute inset-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_image.default, { src: imageUrl, alt: name, fill: true, className: "object-cover", priority: active, unoptimized: true }) }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 bg-gradient-to-br from-brand-purple/40 via-brand-blue/20 to-brand-navy/60" }),
|
|
74
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 bg-gradient-to-t from-black/40 via-black/30 to-black/0" }),
|
|
75
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "absolute bottom-0 left-0 right-0 p-6 sm:p-10 flex flex-col gap-3", children: [
|
|
76
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-4xl lg:text-5xl font-semibold text-white leading-tight", children: name }),
|
|
77
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-4 text-sm text-white/70", children: [
|
|
78
|
+
supply != null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
79
|
+
supply.toLocaleString(),
|
|
80
|
+
" items"
|
|
81
|
+
] }),
|
|
82
|
+
floor && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "text-white font-semibold", children: [
|
|
83
|
+
"Floor ",
|
|
84
|
+
formatFloorPrice(floor)
|
|
85
|
+
] })
|
|
86
|
+
] }),
|
|
87
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
88
|
+
import_link.default,
|
|
89
|
+
{
|
|
90
|
+
href: getHref(collection),
|
|
91
|
+
className: "self-start mt-2 inline-flex items-center gap-1.5 bg-white text-black hover:bg-white/90 font-semibold px-4 py-2 rounded-[11px] text-sm transition-all active:scale-[0.98]",
|
|
92
|
+
children: [
|
|
93
|
+
"View Collection ",
|
|
94
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRight, { className: "h-4 w-4" })
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
] })
|
|
99
|
+
] });
|
|
100
|
+
}
|
|
101
|
+
function HeroSliderSkeleton() {
|
|
102
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", { className: "relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] bg-muted animate-pulse" });
|
|
103
|
+
}
|
|
104
|
+
function HeroSlider({ collections, isLoading, getHref }) {
|
|
105
|
+
const [current, setCurrent] = (0, import_react.useState)(0);
|
|
106
|
+
const count = collections.length;
|
|
107
|
+
const next = (0, import_react.useCallback)(() => {
|
|
108
|
+
if (count > 1) setCurrent((c) => (c + 1) % count);
|
|
109
|
+
}, [count]);
|
|
110
|
+
const prev = (0, import_react.useCallback)(() => {
|
|
111
|
+
if (count > 1) setCurrent((c) => (c - 1 + count) % count);
|
|
112
|
+
}, [count]);
|
|
113
|
+
(0, import_react.useEffect)(() => {
|
|
114
|
+
if (count <= 1) return;
|
|
115
|
+
const id = setInterval(next, 7e3);
|
|
116
|
+
return () => clearInterval(id);
|
|
117
|
+
}, [count, next]);
|
|
118
|
+
if (isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HeroSliderSkeleton, {});
|
|
119
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", { className: "relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] overflow-hidden bg-muted", children: count === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HeroPlaceholder, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
120
|
+
collections.map((col, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HeroSlide, { collection: col, active: i === current, getHref }, col.contractAddress)),
|
|
121
|
+
count > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
122
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: prev, "aria-label": "Previous slide", className: "absolute left-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronLeft, { className: "h-5 w-5 text-white" }) }),
|
|
123
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: next, "aria-label": "Next slide", className: "absolute right-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronRight, { className: "h-5 w-5 text-white" }) }),
|
|
124
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-1.5 z-10", children: collections.map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: () => setCurrent(i), "aria-label": `Go to slide ${i + 1}`, className: (0, import_cn.cn)("h-1.5 rounded-full transition-all", i === current ? "w-6 bg-white" : "w-1.5 bg-white/40") }, i)) })
|
|
125
|
+
] })
|
|
126
|
+
] }) });
|
|
127
|
+
}
|
|
128
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
129
|
+
0 && (module.exports = {
|
|
130
|
+
HeroSlider,
|
|
131
|
+
HeroSliderSkeleton
|
|
132
|
+
});
|
|
133
|
+
//# sourceMappingURL=hero-slider.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/hero-slider.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { ChevronLeft, ChevronRight, ArrowRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\nexport interface HeroSliderProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n}\n\nfunction formatFloorPrice(price: string | null | undefined): string {\n if (!price) return \"\";\n const n = parseFloat(price);\n if (isNaN(n)) return price;\n if (n >= 1000) return `${(n / 1000).toFixed(1)}K`;\n if (n >= 1) return n.toFixed(2);\n return n.toPrecision(3);\n}\n\nfunction ipfsToHttp(uri: string): string {\n if (!uri) return \"\";\n if (uri.startsWith(\"ipfs://\")) return uri.replace(\"ipfs://\", \"https://gateway.pinata.cloud/ipfs/\");\n return uri;\n}\n\nfunction HeroPlaceholder() {\n return (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/50 flex flex-col items-center justify-center gap-4 text-center px-6 overflow-hidden\">\n <div className=\"absolute aurora-purple w-[600px] h-[600px] opacity-20 -top-24 -left-24\" />\n <div className=\"absolute aurora-blue w-[400px] h-[400px] opacity-15 -bottom-16 -right-16\" />\n <h2 className=\"text-4xl sm:text-6xl font-black gradient-text relative z-10\">Medialane</h2>\n <p className=\"text-muted-foreground text-lg relative z-10 max-w-md\">\n New monetization revenues for creative works\n </p>\n <div className=\"flex gap-3 relative z-10\">\n <Link href=\"/marketplace\" className=\"inline-flex items-center justify-center rounded-[11px] bg-brand-blue px-4 py-2 text-sm font-semibold text-white hover:brightness-110 active:scale-[0.98] transition-all\">\n Markets\n </Link>\n <Link href=\"/create/asset\" className=\"inline-flex items-center justify-center rounded-[11px] border border-white/20 bg-background/20 backdrop-blur-sm px-4 py-2 text-sm font-semibold text-white hover:bg-white/10 transition-all\">\n Create\n </Link>\n </div>\n </div>\n );\n}\n\nfunction HeroSlide({ collection, active, getHref }: { collection: ApiCollection; active: boolean; getHref: (col: ApiCollection) => string }) {\n const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;\n const name = collection.name ?? \"Collection\";\n const floor = collection.floorPrice;\n const supply = collection.totalSupply;\n\n return (\n <div className={cn(\"absolute inset-0 transition-opacity duration-700\", active ? \"opacity-100\" : \"opacity-0 pointer-events-none\")}>\n {imageUrl ? (\n <div className=\"absolute inset-0 overflow-hidden\">\n <div className=\"animate-kenburns absolute inset-0\">\n <Image src={imageUrl} alt={name} fill className=\"object-cover\" priority={active} unoptimized />\n </div>\n </div>\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/40 via-brand-blue/20 to-brand-navy/60\" />\n )}\n <div className=\"absolute inset-0 bg-gradient-to-t from-black/40 via-black/30 to-black/0\" />\n <div className=\"absolute bottom-0 left-0 right-0 p-6 sm:p-10 flex flex-col gap-3\">\n <h2 className=\"text-4xl lg:text-5xl font-semibold text-white leading-tight\">{name}</h2>\n <div className=\"flex items-center gap-4 text-sm text-white/70\">\n {supply != null && <span>{supply.toLocaleString()} items</span>}\n {floor && <span className=\"text-white font-semibold\">Floor {formatFloorPrice(floor)}</span>}\n </div>\n <Link\n href={getHref(collection)}\n className=\"self-start mt-2 inline-flex items-center gap-1.5 bg-white text-black hover:bg-white/90 font-semibold px-4 py-2 rounded-[11px] text-sm transition-all active:scale-[0.98]\"\n >\n View Collection <ArrowRight className=\"h-4 w-4\" />\n </Link>\n </div>\n </div>\n );\n}\n\nexport function HeroSliderSkeleton() {\n return <section className=\"relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] bg-muted animate-pulse\" />;\n}\n\nexport function HeroSlider({ collections, isLoading, getHref }: HeroSliderProps) {\n const [current, setCurrent] = useState(0);\n const count = collections.length;\n\n const next = useCallback(() => { if (count > 1) setCurrent((c) => (c + 1) % count); }, [count]);\n const prev = useCallback(() => { if (count > 1) setCurrent((c) => (c - 1 + count) % count); }, [count]);\n\n useEffect(() => {\n if (count <= 1) return;\n const id = setInterval(next, 7000);\n return () => clearInterval(id);\n }, [count, next]);\n\n if (isLoading) return <HeroSliderSkeleton />;\n\n return (\n <section className=\"relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] overflow-hidden bg-muted\">\n {count === 0 ? (\n <HeroPlaceholder />\n ) : (\n <>\n {collections.map((col, i) => (\n <HeroSlide key={col.contractAddress} collection={col} active={i === current} getHref={getHref} />\n ))}\n {count > 1 && (\n <>\n <button onClick={prev} aria-label=\"Previous slide\" className=\"absolute left-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors\">\n <ChevronLeft className=\"h-5 w-5 text-white\" />\n </button>\n <button onClick={next} aria-label=\"Next slide\" className=\"absolute right-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors\">\n <ChevronRight className=\"h-5 w-5 text-white\" />\n </button>\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-1.5 z-10\">\n {collections.map((_, i) => (\n <button key={i} onClick={() => setCurrent(i)} aria-label={`Go to slide ${i + 1}`} className={cn(\"h-1.5 rounded-full transition-all\", i === current ? \"w-6 bg-white\" : \"w-1.5 bg-white/40\")} />\n ))}\n </div>\n </>\n )}\n </>\n )}\n </section>\n );\n}\n"],"mappings":"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","names":["Link","Image"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ApiCollection } from '@medialane/sdk';
|
|
3
|
+
|
|
4
|
+
interface HeroSliderProps {
|
|
5
|
+
collections: ApiCollection[];
|
|
6
|
+
isLoading: boolean;
|
|
7
|
+
getHref: (collection: ApiCollection) => string;
|
|
8
|
+
}
|
|
9
|
+
declare function HeroSliderSkeleton(): react_jsx_runtime.JSX.Element;
|
|
10
|
+
declare function HeroSlider({ collections, isLoading, getHref }: HeroSliderProps): react_jsx_runtime.JSX.Element;
|
|
11
|
+
|
|
12
|
+
export { HeroSlider, type HeroSliderProps, HeroSliderSkeleton };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ApiCollection } from '@medialane/sdk';
|
|
3
|
+
|
|
4
|
+
interface HeroSliderProps {
|
|
5
|
+
collections: ApiCollection[];
|
|
6
|
+
isLoading: boolean;
|
|
7
|
+
getHref: (collection: ApiCollection) => string;
|
|
8
|
+
}
|
|
9
|
+
declare function HeroSliderSkeleton(): react_jsx_runtime.JSX.Element;
|
|
10
|
+
declare function HeroSlider({ collections, isLoading, getHref }: HeroSliderProps): react_jsx_runtime.JSX.Element;
|
|
11
|
+
|
|
12
|
+
export { HeroSlider, type HeroSliderProps, HeroSliderSkeleton };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useEffect, useCallback } from "react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import Image from "next/image";
|
|
6
|
+
import { ChevronLeft, ChevronRight, ArrowRight } from "lucide-react";
|
|
7
|
+
import { cn } from "../utils/cn.js";
|
|
8
|
+
function formatFloorPrice(price) {
|
|
9
|
+
if (!price) return "";
|
|
10
|
+
const n = parseFloat(price);
|
|
11
|
+
if (isNaN(n)) return price;
|
|
12
|
+
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
13
|
+
if (n >= 1) return n.toFixed(2);
|
|
14
|
+
return n.toPrecision(3);
|
|
15
|
+
}
|
|
16
|
+
function ipfsToHttp(uri) {
|
|
17
|
+
if (!uri) return "";
|
|
18
|
+
if (uri.startsWith("ipfs://")) return uri.replace("ipfs://", "https://gateway.pinata.cloud/ipfs/");
|
|
19
|
+
return uri;
|
|
20
|
+
}
|
|
21
|
+
function HeroPlaceholder() {
|
|
22
|
+
return /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/50 flex flex-col items-center justify-center gap-4 text-center px-6 overflow-hidden", children: [
|
|
23
|
+
/* @__PURE__ */ jsx("div", { className: "absolute aurora-purple w-[600px] h-[600px] opacity-20 -top-24 -left-24" }),
|
|
24
|
+
/* @__PURE__ */ jsx("div", { className: "absolute aurora-blue w-[400px] h-[400px] opacity-15 -bottom-16 -right-16" }),
|
|
25
|
+
/* @__PURE__ */ jsx("h2", { className: "text-4xl sm:text-6xl font-black gradient-text relative z-10", children: "Medialane" }),
|
|
26
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-lg relative z-10 max-w-md", children: "New monetization revenues for creative works" }),
|
|
27
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-3 relative z-10", children: [
|
|
28
|
+
/* @__PURE__ */ jsx(Link, { href: "/marketplace", className: "inline-flex items-center justify-center rounded-[11px] bg-brand-blue px-4 py-2 text-sm font-semibold text-white hover:brightness-110 active:scale-[0.98] transition-all", children: "Markets" }),
|
|
29
|
+
/* @__PURE__ */ jsx(Link, { href: "/create/asset", className: "inline-flex items-center justify-center rounded-[11px] border border-white/20 bg-background/20 backdrop-blur-sm px-4 py-2 text-sm font-semibold text-white hover:bg-white/10 transition-all", children: "Create" })
|
|
30
|
+
] })
|
|
31
|
+
] });
|
|
32
|
+
}
|
|
33
|
+
function HeroSlide({ collection, active, getHref }) {
|
|
34
|
+
const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;
|
|
35
|
+
const name = collection.name ?? "Collection";
|
|
36
|
+
const floor = collection.floorPrice;
|
|
37
|
+
const supply = collection.totalSupply;
|
|
38
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("absolute inset-0 transition-opacity duration-700", active ? "opacity-100" : "opacity-0 pointer-events-none"), children: [
|
|
39
|
+
imageUrl ? /* @__PURE__ */ jsx("div", { className: "absolute inset-0 overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "animate-kenburns absolute inset-0", children: /* @__PURE__ */ jsx(Image, { src: imageUrl, alt: name, fill: true, className: "object-cover", priority: active, unoptimized: true }) }) }) : /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-br from-brand-purple/40 via-brand-blue/20 to-brand-navy/60" }),
|
|
40
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/40 via-black/30 to-black/0" }),
|
|
41
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 left-0 right-0 p-6 sm:p-10 flex flex-col gap-3", children: [
|
|
42
|
+
/* @__PURE__ */ jsx("h2", { className: "text-4xl lg:text-5xl font-semibold text-white leading-tight", children: name }),
|
|
43
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 text-sm text-white/70", children: [
|
|
44
|
+
supply != null && /* @__PURE__ */ jsxs("span", { children: [
|
|
45
|
+
supply.toLocaleString(),
|
|
46
|
+
" items"
|
|
47
|
+
] }),
|
|
48
|
+
floor && /* @__PURE__ */ jsxs("span", { className: "text-white font-semibold", children: [
|
|
49
|
+
"Floor ",
|
|
50
|
+
formatFloorPrice(floor)
|
|
51
|
+
] })
|
|
52
|
+
] }),
|
|
53
|
+
/* @__PURE__ */ jsxs(
|
|
54
|
+
Link,
|
|
55
|
+
{
|
|
56
|
+
href: getHref(collection),
|
|
57
|
+
className: "self-start mt-2 inline-flex items-center gap-1.5 bg-white text-black hover:bg-white/90 font-semibold px-4 py-2 rounded-[11px] text-sm transition-all active:scale-[0.98]",
|
|
58
|
+
children: [
|
|
59
|
+
"View Collection ",
|
|
60
|
+
/* @__PURE__ */ jsx(ArrowRight, { className: "h-4 w-4" })
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
] })
|
|
65
|
+
] });
|
|
66
|
+
}
|
|
67
|
+
function HeroSliderSkeleton() {
|
|
68
|
+
return /* @__PURE__ */ jsx("section", { className: "relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] bg-muted animate-pulse" });
|
|
69
|
+
}
|
|
70
|
+
function HeroSlider({ collections, isLoading, getHref }) {
|
|
71
|
+
const [current, setCurrent] = useState(0);
|
|
72
|
+
const count = collections.length;
|
|
73
|
+
const next = useCallback(() => {
|
|
74
|
+
if (count > 1) setCurrent((c) => (c + 1) % count);
|
|
75
|
+
}, [count]);
|
|
76
|
+
const prev = useCallback(() => {
|
|
77
|
+
if (count > 1) setCurrent((c) => (c - 1 + count) % count);
|
|
78
|
+
}, [count]);
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (count <= 1) return;
|
|
81
|
+
const id = setInterval(next, 7e3);
|
|
82
|
+
return () => clearInterval(id);
|
|
83
|
+
}, [count, next]);
|
|
84
|
+
if (isLoading) return /* @__PURE__ */ jsx(HeroSliderSkeleton, {});
|
|
85
|
+
return /* @__PURE__ */ jsx("section", { className: "relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] overflow-hidden bg-muted", children: count === 0 ? /* @__PURE__ */ jsx(HeroPlaceholder, {}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
86
|
+
collections.map((col, i) => /* @__PURE__ */ jsx(HeroSlide, { collection: col, active: i === current, getHref }, col.contractAddress)),
|
|
87
|
+
count > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
88
|
+
/* @__PURE__ */ jsx("button", { onClick: prev, "aria-label": "Previous slide", className: "absolute left-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors", children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-5 w-5 text-white" }) }),
|
|
89
|
+
/* @__PURE__ */ jsx("button", { onClick: next, "aria-label": "Next slide", className: "absolute right-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors", children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-5 w-5 text-white" }) }),
|
|
90
|
+
/* @__PURE__ */ jsx("div", { className: "absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-1.5 z-10", children: collections.map((_, i) => /* @__PURE__ */ jsx("button", { onClick: () => setCurrent(i), "aria-label": `Go to slide ${i + 1}`, className: cn("h-1.5 rounded-full transition-all", i === current ? "w-6 bg-white" : "w-1.5 bg-white/40") }, i)) })
|
|
91
|
+
] })
|
|
92
|
+
] }) });
|
|
93
|
+
}
|
|
94
|
+
export {
|
|
95
|
+
HeroSlider,
|
|
96
|
+
HeroSliderSkeleton
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=hero-slider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/hero-slider.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { ChevronLeft, ChevronRight, ArrowRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\nexport interface HeroSliderProps {\n collections: ApiCollection[];\n isLoading: boolean;\n getHref: (collection: ApiCollection) => string;\n}\n\nfunction formatFloorPrice(price: string | null | undefined): string {\n if (!price) return \"\";\n const n = parseFloat(price);\n if (isNaN(n)) return price;\n if (n >= 1000) return `${(n / 1000).toFixed(1)}K`;\n if (n >= 1) return n.toFixed(2);\n return n.toPrecision(3);\n}\n\nfunction ipfsToHttp(uri: string): string {\n if (!uri) return \"\";\n if (uri.startsWith(\"ipfs://\")) return uri.replace(\"ipfs://\", \"https://gateway.pinata.cloud/ipfs/\");\n return uri;\n}\n\nfunction HeroPlaceholder() {\n return (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/50 flex flex-col items-center justify-center gap-4 text-center px-6 overflow-hidden\">\n <div className=\"absolute aurora-purple w-[600px] h-[600px] opacity-20 -top-24 -left-24\" />\n <div className=\"absolute aurora-blue w-[400px] h-[400px] opacity-15 -bottom-16 -right-16\" />\n <h2 className=\"text-4xl sm:text-6xl font-black gradient-text relative z-10\">Medialane</h2>\n <p className=\"text-muted-foreground text-lg relative z-10 max-w-md\">\n New monetization revenues for creative works\n </p>\n <div className=\"flex gap-3 relative z-10\">\n <Link href=\"/marketplace\" className=\"inline-flex items-center justify-center rounded-[11px] bg-brand-blue px-4 py-2 text-sm font-semibold text-white hover:brightness-110 active:scale-[0.98] transition-all\">\n Markets\n </Link>\n <Link href=\"/create/asset\" className=\"inline-flex items-center justify-center rounded-[11px] border border-white/20 bg-background/20 backdrop-blur-sm px-4 py-2 text-sm font-semibold text-white hover:bg-white/10 transition-all\">\n Create\n </Link>\n </div>\n </div>\n );\n}\n\nfunction HeroSlide({ collection, active, getHref }: { collection: ApiCollection; active: boolean; getHref: (col: ApiCollection) => string }) {\n const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;\n const name = collection.name ?? \"Collection\";\n const floor = collection.floorPrice;\n const supply = collection.totalSupply;\n\n return (\n <div className={cn(\"absolute inset-0 transition-opacity duration-700\", active ? \"opacity-100\" : \"opacity-0 pointer-events-none\")}>\n {imageUrl ? (\n <div className=\"absolute inset-0 overflow-hidden\">\n <div className=\"animate-kenburns absolute inset-0\">\n <Image src={imageUrl} alt={name} fill className=\"object-cover\" priority={active} unoptimized />\n </div>\n </div>\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/40 via-brand-blue/20 to-brand-navy/60\" />\n )}\n <div className=\"absolute inset-0 bg-gradient-to-t from-black/40 via-black/30 to-black/0\" />\n <div className=\"absolute bottom-0 left-0 right-0 p-6 sm:p-10 flex flex-col gap-3\">\n <h2 className=\"text-4xl lg:text-5xl font-semibold text-white leading-tight\">{name}</h2>\n <div className=\"flex items-center gap-4 text-sm text-white/70\">\n {supply != null && <span>{supply.toLocaleString()} items</span>}\n {floor && <span className=\"text-white font-semibold\">Floor {formatFloorPrice(floor)}</span>}\n </div>\n <Link\n href={getHref(collection)}\n className=\"self-start mt-2 inline-flex items-center gap-1.5 bg-white text-black hover:bg-white/90 font-semibold px-4 py-2 rounded-[11px] text-sm transition-all active:scale-[0.98]\"\n >\n View Collection <ArrowRight className=\"h-4 w-4\" />\n </Link>\n </div>\n </div>\n );\n}\n\nexport function HeroSliderSkeleton() {\n return <section className=\"relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] bg-muted animate-pulse\" />;\n}\n\nexport function HeroSlider({ collections, isLoading, getHref }: HeroSliderProps) {\n const [current, setCurrent] = useState(0);\n const count = collections.length;\n\n const next = useCallback(() => { if (count > 1) setCurrent((c) => (c + 1) % count); }, [count]);\n const prev = useCallback(() => { if (count > 1) setCurrent((c) => (c - 1 + count) % count); }, [count]);\n\n useEffect(() => {\n if (count <= 1) return;\n const id = setInterval(next, 7000);\n return () => clearInterval(id);\n }, [count, next]);\n\n if (isLoading) return <HeroSliderSkeleton />;\n\n return (\n <section className=\"relative w-full h-[78vw] min-h-[420px] max-h-[768px] sm:h-[72vh] sm:max-h-[816px] overflow-hidden bg-muted\">\n {count === 0 ? (\n <HeroPlaceholder />\n ) : (\n <>\n {collections.map((col, i) => (\n <HeroSlide key={col.contractAddress} collection={col} active={i === current} getHref={getHref} />\n ))}\n {count > 1 && (\n <>\n <button onClick={prev} aria-label=\"Previous slide\" className=\"absolute left-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors\">\n <ChevronLeft className=\"h-5 w-5 text-white\" />\n </button>\n <button onClick={next} aria-label=\"Next slide\" className=\"absolute right-3 top-1/2 -translate-y-1/2 z-10 h-9 w-9 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm flex items-center justify-center transition-colors\">\n <ChevronRight className=\"h-5 w-5 text-white\" />\n </button>\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-1.5 z-10\">\n {collections.map((_, i) => (\n <button key={i} onClick={() => setCurrent(i)} aria-label={`Go to slide ${i + 1}`} className={cn(\"h-1.5 rounded-full transition-all\", i === current ? \"w-6 bg-white\" : \"w-1.5 bg-white/40\")} />\n ))}\n </div>\n </>\n )}\n </>\n )}\n </section>\n );\n}\n"],"mappings":"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","names":[]}
|