@medialane/ui 0.50.1 → 0.52.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/claim-rail.cjs +22 -16
- package/dist/components/claim-rail.cjs.map +1 -1
- package/dist/components/claim-rail.d.cts +3 -2
- package/dist/components/claim-rail.d.ts +3 -2
- package/dist/components/claim-rail.js +23 -17
- package/dist/components/claim-rail.js.map +1 -1
- package/dist/components/collection-card.cjs +2 -2
- package/dist/components/collection-card.cjs.map +1 -1
- package/dist/components/collection-card.d.cts +3 -1
- package/dist/components/collection-card.d.ts +3 -1
- package/dist/components/collection-card.js +2 -2
- package/dist/components/collection-card.js.map +1 -1
- package/dist/components/service-form-shell.cjs +2 -2
- package/dist/components/service-form-shell.cjs.map +1 -1
- package/dist/components/service-form-shell.d.cts +4 -4
- package/dist/components/service-form-shell.d.ts +4 -4
- package/dist/components/service-form-shell.js +2 -2
- package/dist/components/service-form-shell.js.map +1 -1
- package/dist/components/service-header.cjs +5 -2
- package/dist/components/service-header.cjs.map +1 -1
- package/dist/components/service-header.d.cts +7 -5
- package/dist/components/service-header.d.ts +7 -5
- package/dist/components/service-header.js +5 -2
- package/dist/components/service-header.js.map +1 -1
- package/package.json +1 -1
|
@@ -23,31 +23,37 @@ __export(claim_rail_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(claim_rail_exports);
|
|
24
24
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25
25
|
var import_lucide_react = require("lucide-react");
|
|
26
|
-
const
|
|
27
|
-
const CHIP = "h-8 w-8 rounded-lg bg-white/20 backdrop-blur-sm flex items-center justify-center shrink-0";
|
|
26
|
+
const MONO = '"Geist Mono", ui-monospace, SFMono-Regular, monospace';
|
|
28
27
|
function ClaimRail({ included, steps, trustLead, trust, trustIcon: TrustIcon = import_lucide_react.ShieldCheck }) {
|
|
29
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
30
|
-
included && included.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("
|
|
31
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className:
|
|
28
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rounded-2xl border border-border/60 bg-card divide-y divide-border/60 overflow-hidden", children: [
|
|
29
|
+
included && included.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "p-5", children: [
|
|
30
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "section-label", children: "What's included" }),
|
|
32
31
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "mt-4 space-y-4", children: included.map(({ icon: Icon, title, desc }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "flex items-start gap-3", children: [
|
|
33
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className:
|
|
32
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-8 w-8 rounded-lg bg-brand-blue/10 flex items-center justify-center shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { className: "h-4 w-4 text-brand-blue" }) }),
|
|
34
33
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0", children: [
|
|
35
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-semibold", children: title }),
|
|
36
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm text-
|
|
34
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-semibold text-foreground", children: title }),
|
|
35
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm text-muted-foreground leading-relaxed mt-0.5", children: desc })
|
|
37
36
|
] })
|
|
38
37
|
] }, title)) })
|
|
39
38
|
] }),
|
|
40
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("
|
|
41
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className:
|
|
39
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "p-5", children: [
|
|
40
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "section-label", children: "How it works" }),
|
|
42
41
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "mt-4 space-y-3", children: steps.map((label, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "flex items-center gap-3", children: [
|
|
43
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
44
|
-
|
|
42
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
43
|
+
"span",
|
|
44
|
+
{
|
|
45
|
+
className: "h-8 w-8 rounded-lg bg-brand-purple/10 text-brand-purple flex items-center justify-center shrink-0 text-[13px] font-bold",
|
|
46
|
+
style: { fontFamily: MONO },
|
|
47
|
+
children: i + 1
|
|
48
|
+
}
|
|
49
|
+
),
|
|
50
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm text-foreground/90", children: label })
|
|
45
51
|
] }, label)) })
|
|
46
52
|
] }),
|
|
47
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("
|
|
48
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TrustIcon, { className: "h-5 w-5 text-
|
|
49
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-sm text-
|
|
50
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-semibold", children: trustLead }),
|
|
53
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "p-5 bg-muted/40 flex items-start gap-3", children: [
|
|
54
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TrustIcon, { className: "h-5 w-5 text-brand-orange shrink-0 mt-0.5" }),
|
|
55
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-sm text-muted-foreground leading-relaxed", children: [
|
|
56
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-semibold text-foreground", children: trustLead }),
|
|
51
57
|
" ",
|
|
52
58
|
trust
|
|
53
59
|
] })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/claim-rail.tsx"],"sourcesContent":["import { ShieldCheck, type LucideIcon } from \"lucide-react\";\n\nexport interface ClaimRailProps {\n /** \"What's included\" benefits. Omit to hide that panel (e.g. when a live\n * preview is the rail's first panel instead). */\n included?: { icon: LucideIcon; title: string; desc: string }[];\n /** \"How it works\" ordered steps. */\n steps: string[];\n /** Trust/assurance note: bold lead + the rest of the sentence. */\n trustLead: string;\n trust: string;\n /** Trust glyph — defaults to a shield. */\n trustIcon?: LucideIcon;\n}\n\nconst
|
|
1
|
+
{"version":3,"sources":["../../src/components/claim-rail.tsx"],"sourcesContent":["import { ShieldCheck, type LucideIcon } from \"lucide-react\";\n\nexport interface ClaimRailProps {\n /** \"What's included\" benefits. Omit to hide that panel (e.g. when a live\n * preview is the rail's first panel instead). */\n included?: { icon: LucideIcon; title: string; desc: string }[];\n /** \"How it works\" ordered steps. */\n steps: string[];\n /** Trust/assurance note: bold lead + the rest of the sentence. */\n trustLead: string;\n trust: string;\n /** Trust glyph — defaults to a shield. */\n trustIcon?: LucideIcon;\n}\n\nconst MONO = '\"Geist Mono\", ui-monospace, SFMono-Regular, monospace';\n\n/** Right-rail for launchpad/claim pages — one quiet sectioned card\n * (What's included · How it works · trust). The brand spectrum appears only\n * as tints: blue benefit chips → purple step numerals → orange trust glyph.\n * Pure presentation; the consuming app passes the per-surface content. */\nexport function ClaimRail({ included, steps, trustLead, trust, trustIcon: TrustIcon = ShieldCheck }: ClaimRailProps) {\n return (\n <div className=\"rounded-2xl border border-border/60 bg-card divide-y divide-border/60 overflow-hidden\">\n {included && included.length > 0 && (\n <section className=\"p-5\">\n <p className=\"section-label\">What's included</p>\n <ul className=\"mt-4 space-y-4\">\n {included.map(({ icon: Icon, title, desc }) => (\n <li key={title} className=\"flex items-start gap-3\">\n <div className=\"h-8 w-8 rounded-lg bg-brand-blue/10 flex items-center justify-center shrink-0\">\n <Icon className=\"h-4 w-4 text-brand-blue\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-sm font-semibold text-foreground\">{title}</p>\n <p className=\"text-sm text-muted-foreground leading-relaxed mt-0.5\">{desc}</p>\n </div>\n </li>\n ))}\n </ul>\n </section>\n )}\n\n <section className=\"p-5\">\n <p className=\"section-label\">How it works</p>\n <ol className=\"mt-4 space-y-3\">\n {steps.map((label, i) => (\n <li key={label} className=\"flex items-center gap-3\">\n <span\n className=\"h-8 w-8 rounded-lg bg-brand-purple/10 text-brand-purple flex items-center justify-center shrink-0 text-[13px] font-bold\"\n style={{ fontFamily: MONO }}\n >\n {i + 1}\n </span>\n <span className=\"text-sm text-foreground/90\">{label}</span>\n </li>\n ))}\n </ol>\n </section>\n\n <section className=\"p-5 bg-muted/40 flex items-start gap-3\">\n <TrustIcon className=\"h-5 w-5 text-brand-orange shrink-0 mt-0.5\" />\n <p className=\"text-sm text-muted-foreground leading-relaxed\">\n <span className=\"font-semibold text-foreground\">{trustLead}</span> {trust}\n </p>\n </section>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BU;AA1BV,0BAA6C;AAe7C,MAAM,OAAO;AAMN,SAAS,UAAU,EAAE,UAAU,OAAO,WAAW,OAAO,WAAW,YAAY,gCAAY,GAAmB;AACnH,SACE,6CAAC,SAAI,WAAU,yFACZ;AAAA,gBAAY,SAAS,SAAS,KAC7B,6CAAC,aAAQ,WAAU,OACjB;AAAA,kDAAC,OAAE,WAAU,iBAAgB,6BAAoB;AAAA,MACjD,4CAAC,QAAG,WAAU,kBACX,mBAAS,IAAI,CAAC,EAAE,MAAM,MAAM,OAAO,KAAK,MACvC,6CAAC,QAAe,WAAU,0BACxB;AAAA,oDAAC,SAAI,WAAU,iFACb,sDAAC,QAAK,WAAU,2BAA0B,GAC5C;AAAA,QACA,6CAAC,SAAI,WAAU,WACb;AAAA,sDAAC,OAAE,WAAU,yCAAyC,iBAAM;AAAA,UAC5D,4CAAC,OAAE,WAAU,wDAAwD,gBAAK;AAAA,WAC5E;AAAA,WAPO,KAQT,CACD,GACH;AAAA,OACF;AAAA,IAGF,6CAAC,aAAQ,WAAU,OACjB;AAAA,kDAAC,OAAE,WAAU,iBAAgB,0BAAY;AAAA,MACzC,4CAAC,QAAG,WAAU,kBACX,gBAAM,IAAI,CAAC,OAAO,MACjB,6CAAC,QAAe,WAAU,2BACxB;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,YAAY,KAAK;AAAA,YAEzB,cAAI;AAAA;AAAA,QACP;AAAA,QACA,4CAAC,UAAK,WAAU,8BAA8B,iBAAM;AAAA,WAP7C,KAQT,CACD,GACH;AAAA,OACF;AAAA,IAEA,6CAAC,aAAQ,WAAU,0CACjB;AAAA,kDAAC,aAAU,WAAU,6CAA4C;AAAA,MACjE,6CAAC,OAAE,WAAU,iDACX;AAAA,oDAAC,UAAK,WAAU,iCAAiC,qBAAU;AAAA,QAAO;AAAA,QAAE;AAAA,SACtE;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -17,8 +17,9 @@ interface ClaimRailProps {
|
|
|
17
17
|
/** Trust glyph — defaults to a shield. */
|
|
18
18
|
trustIcon?: LucideIcon;
|
|
19
19
|
}
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
20
|
+
/** Right-rail for launchpad/claim pages — one quiet sectioned card
|
|
21
|
+
* (What's included · How it works · trust). The brand spectrum appears only
|
|
22
|
+
* as tints: blue benefit chips → purple step numerals → orange trust glyph.
|
|
22
23
|
* Pure presentation; the consuming app passes the per-surface content. */
|
|
23
24
|
declare function ClaimRail({ included, steps, trustLead, trust, trustIcon: TrustIcon }: ClaimRailProps): react_jsx_runtime.JSX.Element;
|
|
24
25
|
|
|
@@ -17,8 +17,9 @@ interface ClaimRailProps {
|
|
|
17
17
|
/** Trust glyph — defaults to a shield. */
|
|
18
18
|
trustIcon?: LucideIcon;
|
|
19
19
|
}
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
20
|
+
/** Right-rail for launchpad/claim pages — one quiet sectioned card
|
|
21
|
+
* (What's included · How it works · trust). The brand spectrum appears only
|
|
22
|
+
* as tints: blue benefit chips → purple step numerals → orange trust glyph.
|
|
22
23
|
* Pure presentation; the consuming app passes the per-surface content. */
|
|
23
24
|
declare function ClaimRail({ included, steps, trustLead, trust, trustIcon: TrustIcon }: ClaimRailProps): react_jsx_runtime.JSX.Element;
|
|
24
25
|
|
|
@@ -1,30 +1,36 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ShieldCheck } from "lucide-react";
|
|
3
|
-
const
|
|
4
|
-
const CHIP = "h-8 w-8 rounded-lg bg-white/20 backdrop-blur-sm flex items-center justify-center shrink-0";
|
|
3
|
+
const MONO = '"Geist Mono", ui-monospace, SFMono-Regular, monospace';
|
|
5
4
|
function ClaimRail({ included, steps, trustLead, trust, trustIcon: TrustIcon = ShieldCheck }) {
|
|
6
|
-
return /* @__PURE__ */ jsxs(
|
|
7
|
-
included && included.length > 0 && /* @__PURE__ */ jsxs("
|
|
8
|
-
/* @__PURE__ */ jsx("p", { className:
|
|
5
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border border-border/60 bg-card divide-y divide-border/60 overflow-hidden", children: [
|
|
6
|
+
included && included.length > 0 && /* @__PURE__ */ jsxs("section", { className: "p-5", children: [
|
|
7
|
+
/* @__PURE__ */ jsx("p", { className: "section-label", children: "What's included" }),
|
|
9
8
|
/* @__PURE__ */ jsx("ul", { className: "mt-4 space-y-4", children: included.map(({ icon: Icon, title, desc }) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-3", children: [
|
|
10
|
-
/* @__PURE__ */ jsx("div", { className:
|
|
9
|
+
/* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-lg bg-brand-blue/10 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 text-brand-blue" }) }),
|
|
11
10
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
12
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: title }),
|
|
13
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-
|
|
11
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-foreground", children: title }),
|
|
12
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground leading-relaxed mt-0.5", children: desc })
|
|
14
13
|
] })
|
|
15
14
|
] }, title)) })
|
|
16
15
|
] }),
|
|
17
|
-
/* @__PURE__ */ jsxs("
|
|
18
|
-
/* @__PURE__ */ jsx("p", { className:
|
|
16
|
+
/* @__PURE__ */ jsxs("section", { className: "p-5", children: [
|
|
17
|
+
/* @__PURE__ */ jsx("p", { className: "section-label", children: "How it works" }),
|
|
19
18
|
/* @__PURE__ */ jsx("ol", { className: "mt-4 space-y-3", children: steps.map((label, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-3", children: [
|
|
20
|
-
/* @__PURE__ */ jsx(
|
|
21
|
-
|
|
19
|
+
/* @__PURE__ */ jsx(
|
|
20
|
+
"span",
|
|
21
|
+
{
|
|
22
|
+
className: "h-8 w-8 rounded-lg bg-brand-purple/10 text-brand-purple flex items-center justify-center shrink-0 text-[13px] font-bold",
|
|
23
|
+
style: { fontFamily: MONO },
|
|
24
|
+
children: i + 1
|
|
25
|
+
}
|
|
26
|
+
),
|
|
27
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-foreground/90", children: label })
|
|
22
28
|
] }, label)) })
|
|
23
29
|
] }),
|
|
24
|
-
/* @__PURE__ */ jsxs("
|
|
25
|
-
/* @__PURE__ */ jsx(TrustIcon, { className: "h-5 w-5 text-
|
|
26
|
-
/* @__PURE__ */ jsxs("p", { className: "text-sm text-
|
|
27
|
-
/* @__PURE__ */ jsx("span", { className: "font-semibold", children: trustLead }),
|
|
30
|
+
/* @__PURE__ */ jsxs("section", { className: "p-5 bg-muted/40 flex items-start gap-3", children: [
|
|
31
|
+
/* @__PURE__ */ jsx(TrustIcon, { className: "h-5 w-5 text-brand-orange shrink-0 mt-0.5" }),
|
|
32
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground leading-relaxed", children: [
|
|
33
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: trustLead }),
|
|
28
34
|
" ",
|
|
29
35
|
trust
|
|
30
36
|
] })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/claim-rail.tsx"],"sourcesContent":["import { ShieldCheck, type LucideIcon } from \"lucide-react\";\n\nexport interface ClaimRailProps {\n /** \"What's included\" benefits. Omit to hide that panel (e.g. when a live\n * preview is the rail's first panel instead). */\n included?: { icon: LucideIcon; title: string; desc: string }[];\n /** \"How it works\" ordered steps. */\n steps: string[];\n /** Trust/assurance note: bold lead + the rest of the sentence. */\n trustLead: string;\n trust: string;\n /** Trust glyph — defaults to a shield. */\n trustIcon?: LucideIcon;\n}\n\nconst
|
|
1
|
+
{"version":3,"sources":["../../src/components/claim-rail.tsx"],"sourcesContent":["import { ShieldCheck, type LucideIcon } from \"lucide-react\";\n\nexport interface ClaimRailProps {\n /** \"What's included\" benefits. Omit to hide that panel (e.g. when a live\n * preview is the rail's first panel instead). */\n included?: { icon: LucideIcon; title: string; desc: string }[];\n /** \"How it works\" ordered steps. */\n steps: string[];\n /** Trust/assurance note: bold lead + the rest of the sentence. */\n trustLead: string;\n trust: string;\n /** Trust glyph — defaults to a shield. */\n trustIcon?: LucideIcon;\n}\n\nconst MONO = '\"Geist Mono\", ui-monospace, SFMono-Regular, monospace';\n\n/** Right-rail for launchpad/claim pages — one quiet sectioned card\n * (What's included · How it works · trust). The brand spectrum appears only\n * as tints: blue benefit chips → purple step numerals → orange trust glyph.\n * Pure presentation; the consuming app passes the per-surface content. */\nexport function ClaimRail({ included, steps, trustLead, trust, trustIcon: TrustIcon = ShieldCheck }: ClaimRailProps) {\n return (\n <div className=\"rounded-2xl border border-border/60 bg-card divide-y divide-border/60 overflow-hidden\">\n {included && included.length > 0 && (\n <section className=\"p-5\">\n <p className=\"section-label\">What's included</p>\n <ul className=\"mt-4 space-y-4\">\n {included.map(({ icon: Icon, title, desc }) => (\n <li key={title} className=\"flex items-start gap-3\">\n <div className=\"h-8 w-8 rounded-lg bg-brand-blue/10 flex items-center justify-center shrink-0\">\n <Icon className=\"h-4 w-4 text-brand-blue\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-sm font-semibold text-foreground\">{title}</p>\n <p className=\"text-sm text-muted-foreground leading-relaxed mt-0.5\">{desc}</p>\n </div>\n </li>\n ))}\n </ul>\n </section>\n )}\n\n <section className=\"p-5\">\n <p className=\"section-label\">How it works</p>\n <ol className=\"mt-4 space-y-3\">\n {steps.map((label, i) => (\n <li key={label} className=\"flex items-center gap-3\">\n <span\n className=\"h-8 w-8 rounded-lg bg-brand-purple/10 text-brand-purple flex items-center justify-center shrink-0 text-[13px] font-bold\"\n style={{ fontFamily: MONO }}\n >\n {i + 1}\n </span>\n <span className=\"text-sm text-foreground/90\">{label}</span>\n </li>\n ))}\n </ol>\n </section>\n\n <section className=\"p-5 bg-muted/40 flex items-start gap-3\">\n <TrustIcon className=\"h-5 w-5 text-brand-orange shrink-0 mt-0.5\" />\n <p className=\"text-sm text-muted-foreground leading-relaxed\">\n <span className=\"font-semibold text-foreground\">{trustLead}</span> {trust}\n </p>\n </section>\n </div>\n );\n}\n"],"mappings":"AA0BU,cAOM,YAPN;AA1BV,SAAS,mBAAoC;AAe7C,MAAM,OAAO;AAMN,SAAS,UAAU,EAAE,UAAU,OAAO,WAAW,OAAO,WAAW,YAAY,YAAY,GAAmB;AACnH,SACE,qBAAC,SAAI,WAAU,yFACZ;AAAA,gBAAY,SAAS,SAAS,KAC7B,qBAAC,aAAQ,WAAU,OACjB;AAAA,0BAAC,OAAE,WAAU,iBAAgB,6BAAoB;AAAA,MACjD,oBAAC,QAAG,WAAU,kBACX,mBAAS,IAAI,CAAC,EAAE,MAAM,MAAM,OAAO,KAAK,MACvC,qBAAC,QAAe,WAAU,0BACxB;AAAA,4BAAC,SAAI,WAAU,iFACb,8BAAC,QAAK,WAAU,2BAA0B,GAC5C;AAAA,QACA,qBAAC,SAAI,WAAU,WACb;AAAA,8BAAC,OAAE,WAAU,yCAAyC,iBAAM;AAAA,UAC5D,oBAAC,OAAE,WAAU,wDAAwD,gBAAK;AAAA,WAC5E;AAAA,WAPO,KAQT,CACD,GACH;AAAA,OACF;AAAA,IAGF,qBAAC,aAAQ,WAAU,OACjB;AAAA,0BAAC,OAAE,WAAU,iBAAgB,0BAAY;AAAA,MACzC,oBAAC,QAAG,WAAU,kBACX,gBAAM,IAAI,CAAC,OAAO,MACjB,qBAAC,QAAe,WAAU,2BACxB;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,YAAY,KAAK;AAAA,YAEzB,cAAI;AAAA;AAAA,QACP;AAAA,QACA,oBAAC,UAAK,WAAU,8BAA8B,iBAAM;AAAA,WAP7C,KAQT,CACD,GACH;AAAA,OACF;AAAA,IAEA,qBAAC,aAAQ,WAAU,0CACjB;AAAA,0BAAC,aAAU,WAAU,6CAA4C;AAAA,MACjE,qBAAC,OAAE,WAAU,iDACX;AAAA,4BAAC,UAAK,WAAU,iCAAiC,qBAAU;AAAA,QAAO;AAAA,QAAE;AAAA,SACtE;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -52,7 +52,7 @@ function parseFloorPrice(floor) {
|
|
|
52
52
|
const amount = parts.slice(0, -1).join(" ");
|
|
53
53
|
return { amount, symbol };
|
|
54
54
|
}
|
|
55
|
-
function CollectionCard({ collection, settingsHref, className }) {
|
|
55
|
+
function CollectionCard({ collection, href, settingsHref, className }) {
|
|
56
56
|
const [imgError, setImgError] = (0, import_react.useState)(false);
|
|
57
57
|
const imageUrl = collection.image ? (0, import_ipfs.ipfsToHttp)(collection.image) : null;
|
|
58
58
|
const showImage = imageUrl && !imgError;
|
|
@@ -70,7 +70,7 @@ function CollectionCard({ collection, settingsHref, className }) {
|
|
|
70
70
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Settings2, { className: "h-3.5 w-3.5" })
|
|
71
71
|
}
|
|
72
72
|
),
|
|
73
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_link.default, { href: `/collections/${collection.contractAddress}`, className: "block relative h-full", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative aspect-[3/4] w-full overflow-hidden bg-muted", children: [
|
|
73
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_link.default, { href: href ?? `/collections/${collection.contractAddress}`, className: "block relative h-full", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative aspect-[3/4] w-full overflow-hidden bg-muted", children: [
|
|
74
74
|
showImage ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
75
75
|
import_image.default,
|
|
76
76
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { Loader2, Settings2 } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { MotionCard } from \"./motion-primitives.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\n/** \"0.990000 USDC\" → { amount: \"0.99\", symbol: \"USDC\" } */\nfunction parseFloorPrice(floor: string | null | undefined): { amount: string; symbol: string } | null {\n if (!floor) return null;\n const formatted = formatDisplayPrice(floor);\n const parts = formatted.trim().split(/\\s+/);\n if (parts.length < 2) return null;\n const symbol = parts[parts.length - 1];\n const amount = parts.slice(0, -1).join(\" \");\n return { amount, symbol };\n}\n\n/** ui's pinned SDK lags the apps — extend structurally for newer fields. */\ntype CollectionWithProfile = ApiCollection & {\n profile?: { hasGatedContent?: boolean } | null;\n};\n\nexport interface CollectionCardProps {\n collection: ApiCollection;\n /** Shows settings gear icon linking to this path — used in portfolio pages */\n settingsHref?: string;\n className?: string;\n}\n\nexport function CollectionCard({ collection, settingsHref, className }: CollectionCardProps) {\n const [imgError, setImgError] = useState(false);\n const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;\n const showImage = imageUrl && !imgError;\n const initial = (collection.name ?? collection.contractAddress).charAt(0).toUpperCase();\n const floor = parseFloorPrice(collection.floorPrice);\n const hasExclusiveContent = !!(collection as CollectionWithProfile).profile?.hasGatedContent;\n\n return (\n <div className={cn(hasExclusiveContent && \"card-exclusive-wrapper btn-border-animated\")}>\n <MotionCard className={cn(\"card-base group relative\", className)}>\n {settingsHref && (\n <Link\n href={settingsHref}\n onClick={(e) => e.stopPropagation()}\n className=\"absolute top-2 right-2 z-10 h-7 w-7 rounded-full bg-black/40 backdrop-blur-sm flex items-center justify-center text-white/70 hover:text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Collection settings\"\n >\n <Settings2 className=\"h-3.5 w-3.5\" />\n </Link>\n )}\n\n <Link href={`/collections/${collection.contractAddress}`} className=\"block relative h-full\">\n <div className=\"relative aspect-[3/4] w-full overflow-hidden bg-muted\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={collection.name ?? \"Collection\"}\n fill\n className=\"object-cover transition-transform duration-500 group-hover:scale-105\"\n onError={() => setImgError(true)}\n unoptimized\n />\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/40 flex items-center justify-center\">\n <span className=\"text-8xl font-black text-white/10 select-none tracking-tighter\">\n {initial}\n </span>\n </div>\n )}\n\n <div className=\"absolute bottom-0 left-0 right-0 px-3 pb-3 flex flex-col gap-1.5 items-start\">\n {!collection.name && collection.metadataStatus === \"PENDING\" ? (\n <span className=\"flex items-center gap-1 text-[10px] text-white/60 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n <Loader2 className=\"h-2.5 w-2.5 animate-spin\" />\n Indexing…\n </span>\n ) : (\n <p\n className=\"font-bold text-sm text-white leading-tight backdrop-blur-md bg-black/30 rounded-lg px-2.5 py-1 max-w-full truncate\"\n style={{ textShadow: \"0 1px 6px rgba(0,0,0,0.5)\" }}\n >\n {collection.name ?? \"Unnamed Collection\"}\n </p>\n )}\n\n <div className=\"flex items-center gap-1.5 flex-wrap\">\n {collection.totalSupply != null && (\n <span className=\"text-[10px] font-medium text-white/80 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n {collection.totalSupply.toLocaleString()} items\n </span>\n )}\n {floor && (\n <span className=\"inline-flex items-center gap-1 text-[10px] font-bold text-white/90 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n Floor\n <CurrencyIcon symbol={floor.symbol} size={10} />\n {floor.amount}\n </span>\n )}\n {hasExclusiveContent && (\n <span className=\"inline-flex items-center gap-1 text-[10px] font-bold text-white backdrop-blur-md bg-black/50 rounded-full px-2 py-0.5\">\n ✦ Exclusive\n </span>\n )}\n </div>\n </div>\n </div>\n </Link>\n </MotionCard>\n </div>\n );\n}\n\nexport function CollectionCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"relative aspect-[3/4] w-full overflow-hidden bg-muted\">\n <div className=\"absolute inset-0 animate-pulse bg-muted\" />\n <div className=\"absolute bottom-3 left-3 right-3 space-y-1.5\">\n <div className=\"h-4 w-2/3 rounded-md bg-muted-foreground/20 animate-pulse\" />\n <div className=\"h-3 w-1/3 rounded-md bg-muted-foreground/20 animate-pulse\" />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
1
|
+
{"version":3,"sources":["../../src/components/collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { Loader2, Settings2 } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { MotionCard } from \"./motion-primitives.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\n/** \"0.990000 USDC\" → { amount: \"0.99\", symbol: \"USDC\" } */\nfunction parseFloorPrice(floor: string | null | undefined): { amount: string; symbol: string } | null {\n if (!floor) return null;\n const formatted = formatDisplayPrice(floor);\n const parts = formatted.trim().split(/\\s+/);\n if (parts.length < 2) return null;\n const symbol = parts[parts.length - 1];\n const amount = parts.slice(0, -1).join(\" \");\n return { amount, symbol };\n}\n\n/** ui's pinned SDK lags the apps — extend structurally for newer fields. */\ntype CollectionWithProfile = ApiCollection & {\n profile?: { hasGatedContent?: boolean } | null;\n};\n\nexport interface CollectionCardProps {\n collection: ApiCollection;\n /** Override the card link destination. Defaults to /collections/:contractAddress. */\n href?: string;\n /** Shows settings gear icon linking to this path — used in portfolio pages */\n settingsHref?: string;\n className?: string;\n}\n\nexport function CollectionCard({ collection, href, settingsHref, className }: CollectionCardProps) {\n const [imgError, setImgError] = useState(false);\n const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;\n const showImage = imageUrl && !imgError;\n const initial = (collection.name ?? collection.contractAddress).charAt(0).toUpperCase();\n const floor = parseFloorPrice(collection.floorPrice);\n const hasExclusiveContent = !!(collection as CollectionWithProfile).profile?.hasGatedContent;\n\n return (\n <div className={cn(hasExclusiveContent && \"card-exclusive-wrapper btn-border-animated\")}>\n <MotionCard className={cn(\"card-base group relative\", className)}>\n {settingsHref && (\n <Link\n href={settingsHref}\n onClick={(e) => e.stopPropagation()}\n className=\"absolute top-2 right-2 z-10 h-7 w-7 rounded-full bg-black/40 backdrop-blur-sm flex items-center justify-center text-white/70 hover:text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Collection settings\"\n >\n <Settings2 className=\"h-3.5 w-3.5\" />\n </Link>\n )}\n\n <Link href={href ?? `/collections/${collection.contractAddress}`} className=\"block relative h-full\">\n <div className=\"relative aspect-[3/4] w-full overflow-hidden bg-muted\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={collection.name ?? \"Collection\"}\n fill\n className=\"object-cover transition-transform duration-500 group-hover:scale-105\"\n onError={() => setImgError(true)}\n unoptimized\n />\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/40 flex items-center justify-center\">\n <span className=\"text-8xl font-black text-white/10 select-none tracking-tighter\">\n {initial}\n </span>\n </div>\n )}\n\n <div className=\"absolute bottom-0 left-0 right-0 px-3 pb-3 flex flex-col gap-1.5 items-start\">\n {!collection.name && collection.metadataStatus === \"PENDING\" ? (\n <span className=\"flex items-center gap-1 text-[10px] text-white/60 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n <Loader2 className=\"h-2.5 w-2.5 animate-spin\" />\n Indexing…\n </span>\n ) : (\n <p\n className=\"font-bold text-sm text-white leading-tight backdrop-blur-md bg-black/30 rounded-lg px-2.5 py-1 max-w-full truncate\"\n style={{ textShadow: \"0 1px 6px rgba(0,0,0,0.5)\" }}\n >\n {collection.name ?? \"Unnamed Collection\"}\n </p>\n )}\n\n <div className=\"flex items-center gap-1.5 flex-wrap\">\n {collection.totalSupply != null && (\n <span className=\"text-[10px] font-medium text-white/80 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n {collection.totalSupply.toLocaleString()} items\n </span>\n )}\n {floor && (\n <span className=\"inline-flex items-center gap-1 text-[10px] font-bold text-white/90 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n Floor\n <CurrencyIcon symbol={floor.symbol} size={10} />\n {floor.amount}\n </span>\n )}\n {hasExclusiveContent && (\n <span className=\"inline-flex items-center gap-1 text-[10px] font-bold text-white backdrop-blur-md bg-black/50 rounded-full px-2 py-0.5\">\n ✦ Exclusive\n </span>\n )}\n </div>\n </div>\n </div>\n </Link>\n </MotionCard>\n </div>\n );\n}\n\nexport function CollectionCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"relative aspect-[3/4] w-full overflow-hidden bg-muted\">\n <div className=\"absolute inset-0 animate-pulse bg-muted\" />\n <div className=\"absolute bottom-3 left-3 right-3 space-y-1.5\">\n <div className=\"h-4 w-2/3 rounded-md bg-muted-foreground/20 animate-pulse\" />\n <div className=\"h-3 w-1/3 rounded-md bg-muted-foreground/20 animate-pulse\" />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["Link","Image"]}
|
|
@@ -3,11 +3,13 @@ import { ApiCollection } from '@medialane/sdk';
|
|
|
3
3
|
|
|
4
4
|
interface CollectionCardProps {
|
|
5
5
|
collection: ApiCollection;
|
|
6
|
+
/** Override the card link destination. Defaults to /collections/:contractAddress. */
|
|
7
|
+
href?: string;
|
|
6
8
|
/** Shows settings gear icon linking to this path — used in portfolio pages */
|
|
7
9
|
settingsHref?: string;
|
|
8
10
|
className?: string;
|
|
9
11
|
}
|
|
10
|
-
declare function CollectionCard({ collection, settingsHref, className }: CollectionCardProps): react_jsx_runtime.JSX.Element;
|
|
12
|
+
declare function CollectionCard({ collection, href, settingsHref, className }: CollectionCardProps): react_jsx_runtime.JSX.Element;
|
|
11
13
|
declare function CollectionCardSkeleton(): react_jsx_runtime.JSX.Element;
|
|
12
14
|
|
|
13
15
|
export { CollectionCard, type CollectionCardProps, CollectionCardSkeleton };
|
|
@@ -3,11 +3,13 @@ import { ApiCollection } from '@medialane/sdk';
|
|
|
3
3
|
|
|
4
4
|
interface CollectionCardProps {
|
|
5
5
|
collection: ApiCollection;
|
|
6
|
+
/** Override the card link destination. Defaults to /collections/:contractAddress. */
|
|
7
|
+
href?: string;
|
|
6
8
|
/** Shows settings gear icon linking to this path — used in portfolio pages */
|
|
7
9
|
settingsHref?: string;
|
|
8
10
|
className?: string;
|
|
9
11
|
}
|
|
10
|
-
declare function CollectionCard({ collection, settingsHref, className }: CollectionCardProps): react_jsx_runtime.JSX.Element;
|
|
12
|
+
declare function CollectionCard({ collection, href, settingsHref, className }: CollectionCardProps): react_jsx_runtime.JSX.Element;
|
|
11
13
|
declare function CollectionCardSkeleton(): react_jsx_runtime.JSX.Element;
|
|
12
14
|
|
|
13
15
|
export { CollectionCard, type CollectionCardProps, CollectionCardSkeleton };
|
|
@@ -18,7 +18,7 @@ function parseFloorPrice(floor) {
|
|
|
18
18
|
const amount = parts.slice(0, -1).join(" ");
|
|
19
19
|
return { amount, symbol };
|
|
20
20
|
}
|
|
21
|
-
function CollectionCard({ collection, settingsHref, className }) {
|
|
21
|
+
function CollectionCard({ collection, href, settingsHref, className }) {
|
|
22
22
|
const [imgError, setImgError] = useState(false);
|
|
23
23
|
const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;
|
|
24
24
|
const showImage = imageUrl && !imgError;
|
|
@@ -36,7 +36,7 @@ function CollectionCard({ collection, settingsHref, className }) {
|
|
|
36
36
|
children: /* @__PURE__ */ jsx(Settings2, { className: "h-3.5 w-3.5" })
|
|
37
37
|
}
|
|
38
38
|
),
|
|
39
|
-
/* @__PURE__ */ jsx(Link, { href: `/collections/${collection.contractAddress}`, className: "block relative h-full", children: /* @__PURE__ */ jsxs("div", { className: "relative aspect-[3/4] w-full overflow-hidden bg-muted", children: [
|
|
39
|
+
/* @__PURE__ */ jsx(Link, { href: href ?? `/collections/${collection.contractAddress}`, className: "block relative h-full", children: /* @__PURE__ */ jsxs("div", { className: "relative aspect-[3/4] w-full overflow-hidden bg-muted", children: [
|
|
40
40
|
showImage ? /* @__PURE__ */ jsx(
|
|
41
41
|
Image,
|
|
42
42
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { Loader2, Settings2 } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { MotionCard } from \"./motion-primitives.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\n/** \"0.990000 USDC\" → { amount: \"0.99\", symbol: \"USDC\" } */\nfunction parseFloorPrice(floor: string | null | undefined): { amount: string; symbol: string } | null {\n if (!floor) return null;\n const formatted = formatDisplayPrice(floor);\n const parts = formatted.trim().split(/\\s+/);\n if (parts.length < 2) return null;\n const symbol = parts[parts.length - 1];\n const amount = parts.slice(0, -1).join(\" \");\n return { amount, symbol };\n}\n\n/** ui's pinned SDK lags the apps — extend structurally for newer fields. */\ntype CollectionWithProfile = ApiCollection & {\n profile?: { hasGatedContent?: boolean } | null;\n};\n\nexport interface CollectionCardProps {\n collection: ApiCollection;\n /** Shows settings gear icon linking to this path — used in portfolio pages */\n settingsHref?: string;\n className?: string;\n}\n\nexport function CollectionCard({ collection, settingsHref, className }: CollectionCardProps) {\n const [imgError, setImgError] = useState(false);\n const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;\n const showImage = imageUrl && !imgError;\n const initial = (collection.name ?? collection.contractAddress).charAt(0).toUpperCase();\n const floor = parseFloorPrice(collection.floorPrice);\n const hasExclusiveContent = !!(collection as CollectionWithProfile).profile?.hasGatedContent;\n\n return (\n <div className={cn(hasExclusiveContent && \"card-exclusive-wrapper btn-border-animated\")}>\n <MotionCard className={cn(\"card-base group relative\", className)}>\n {settingsHref && (\n <Link\n href={settingsHref}\n onClick={(e) => e.stopPropagation()}\n className=\"absolute top-2 right-2 z-10 h-7 w-7 rounded-full bg-black/40 backdrop-blur-sm flex items-center justify-center text-white/70 hover:text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Collection settings\"\n >\n <Settings2 className=\"h-3.5 w-3.5\" />\n </Link>\n )}\n\n <Link href={`/collections/${collection.contractAddress}`} className=\"block relative h-full\">\n <div className=\"relative aspect-[3/4] w-full overflow-hidden bg-muted\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={collection.name ?? \"Collection\"}\n fill\n className=\"object-cover transition-transform duration-500 group-hover:scale-105\"\n onError={() => setImgError(true)}\n unoptimized\n />\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/40 flex items-center justify-center\">\n <span className=\"text-8xl font-black text-white/10 select-none tracking-tighter\">\n {initial}\n </span>\n </div>\n )}\n\n <div className=\"absolute bottom-0 left-0 right-0 px-3 pb-3 flex flex-col gap-1.5 items-start\">\n {!collection.name && collection.metadataStatus === \"PENDING\" ? (\n <span className=\"flex items-center gap-1 text-[10px] text-white/60 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n <Loader2 className=\"h-2.5 w-2.5 animate-spin\" />\n Indexing…\n </span>\n ) : (\n <p\n className=\"font-bold text-sm text-white leading-tight backdrop-blur-md bg-black/30 rounded-lg px-2.5 py-1 max-w-full truncate\"\n style={{ textShadow: \"0 1px 6px rgba(0,0,0,0.5)\" }}\n >\n {collection.name ?? \"Unnamed Collection\"}\n </p>\n )}\n\n <div className=\"flex items-center gap-1.5 flex-wrap\">\n {collection.totalSupply != null && (\n <span className=\"text-[10px] font-medium text-white/80 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n {collection.totalSupply.toLocaleString()} items\n </span>\n )}\n {floor && (\n <span className=\"inline-flex items-center gap-1 text-[10px] font-bold text-white/90 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n Floor\n <CurrencyIcon symbol={floor.symbol} size={10} />\n {floor.amount}\n </span>\n )}\n {hasExclusiveContent && (\n <span className=\"inline-flex items-center gap-1 text-[10px] font-bold text-white backdrop-blur-md bg-black/50 rounded-full px-2 py-0.5\">\n ✦ Exclusive\n </span>\n )}\n </div>\n </div>\n </div>\n </Link>\n </MotionCard>\n </div>\n );\n}\n\nexport function CollectionCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"relative aspect-[3/4] w-full overflow-hidden bg-muted\">\n <div className=\"absolute inset-0 animate-pulse bg-muted\" />\n <div className=\"absolute bottom-3 left-3 right-3 space-y-1.5\">\n <div className=\"h-4 w-2/3 rounded-md bg-muted-foreground/20 animate-pulse\" />\n <div className=\"h-3 w-1/3 rounded-md bg-muted-foreground/20 animate-pulse\" />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../src/components/collection-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { Loader2, Settings2 } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { MotionCard } from \"./motion-primitives.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\n/** \"0.990000 USDC\" → { amount: \"0.99\", symbol: \"USDC\" } */\nfunction parseFloorPrice(floor: string | null | undefined): { amount: string; symbol: string } | null {\n if (!floor) return null;\n const formatted = formatDisplayPrice(floor);\n const parts = formatted.trim().split(/\\s+/);\n if (parts.length < 2) return null;\n const symbol = parts[parts.length - 1];\n const amount = parts.slice(0, -1).join(\" \");\n return { amount, symbol };\n}\n\n/** ui's pinned SDK lags the apps — extend structurally for newer fields. */\ntype CollectionWithProfile = ApiCollection & {\n profile?: { hasGatedContent?: boolean } | null;\n};\n\nexport interface CollectionCardProps {\n collection: ApiCollection;\n /** Override the card link destination. Defaults to /collections/:contractAddress. */\n href?: string;\n /** Shows settings gear icon linking to this path — used in portfolio pages */\n settingsHref?: string;\n className?: string;\n}\n\nexport function CollectionCard({ collection, href, settingsHref, className }: CollectionCardProps) {\n const [imgError, setImgError] = useState(false);\n const imageUrl = collection.image ? ipfsToHttp(collection.image) : null;\n const showImage = imageUrl && !imgError;\n const initial = (collection.name ?? collection.contractAddress).charAt(0).toUpperCase();\n const floor = parseFloorPrice(collection.floorPrice);\n const hasExclusiveContent = !!(collection as CollectionWithProfile).profile?.hasGatedContent;\n\n return (\n <div className={cn(hasExclusiveContent && \"card-exclusive-wrapper btn-border-animated\")}>\n <MotionCard className={cn(\"card-base group relative\", className)}>\n {settingsHref && (\n <Link\n href={settingsHref}\n onClick={(e) => e.stopPropagation()}\n className=\"absolute top-2 right-2 z-10 h-7 w-7 rounded-full bg-black/40 backdrop-blur-sm flex items-center justify-center text-white/70 hover:text-white hover:bg-black/60 transition-colors\"\n aria-label=\"Collection settings\"\n >\n <Settings2 className=\"h-3.5 w-3.5\" />\n </Link>\n )}\n\n <Link href={href ?? `/collections/${collection.contractAddress}`} className=\"block relative h-full\">\n <div className=\"relative aspect-[3/4] w-full overflow-hidden bg-muted\">\n {showImage ? (\n <Image\n src={imageUrl}\n alt={collection.name ?? \"Collection\"}\n fill\n className=\"object-cover transition-transform duration-500 group-hover:scale-105\"\n onError={() => setImgError(true)}\n unoptimized\n />\n ) : (\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/30 via-brand-blue/20 to-brand-navy/40 flex items-center justify-center\">\n <span className=\"text-8xl font-black text-white/10 select-none tracking-tighter\">\n {initial}\n </span>\n </div>\n )}\n\n <div className=\"absolute bottom-0 left-0 right-0 px-3 pb-3 flex flex-col gap-1.5 items-start\">\n {!collection.name && collection.metadataStatus === \"PENDING\" ? (\n <span className=\"flex items-center gap-1 text-[10px] text-white/60 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n <Loader2 className=\"h-2.5 w-2.5 animate-spin\" />\n Indexing…\n </span>\n ) : (\n <p\n className=\"font-bold text-sm text-white leading-tight backdrop-blur-md bg-black/30 rounded-lg px-2.5 py-1 max-w-full truncate\"\n style={{ textShadow: \"0 1px 6px rgba(0,0,0,0.5)\" }}\n >\n {collection.name ?? \"Unnamed Collection\"}\n </p>\n )}\n\n <div className=\"flex items-center gap-1.5 flex-wrap\">\n {collection.totalSupply != null && (\n <span className=\"text-[10px] font-medium text-white/80 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n {collection.totalSupply.toLocaleString()} items\n </span>\n )}\n {floor && (\n <span className=\"inline-flex items-center gap-1 text-[10px] font-bold text-white/90 backdrop-blur-md bg-black/30 rounded-full px-2 py-0.5\">\n Floor\n <CurrencyIcon symbol={floor.symbol} size={10} />\n {floor.amount}\n </span>\n )}\n {hasExclusiveContent && (\n <span className=\"inline-flex items-center gap-1 text-[10px] font-bold text-white backdrop-blur-md bg-black/50 rounded-full px-2 py-0.5\">\n ✦ Exclusive\n </span>\n )}\n </div>\n </div>\n </div>\n </Link>\n </MotionCard>\n </div>\n );\n}\n\nexport function CollectionCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"relative aspect-[3/4] w-full overflow-hidden bg-muted\">\n <div className=\"absolute inset-0 animate-pulse bg-muted\" />\n <div className=\"absolute bottom-3 left-3 right-3 space-y-1.5\">\n <div className=\"h-4 w-2/3 rounded-md bg-muted-foreground/20 animate-pulse\" />\n <div className=\"h-3 w-1/3 rounded-md bg-muted-foreground/20 animate-pulse\" />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -25,8 +25,8 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
25
25
|
var import_cn = require("../utils/cn.js");
|
|
26
26
|
var import_service_header = require("./service-header.js");
|
|
27
27
|
function ServiceFormShell({ icon, title, subtitle, headerAccessory, backSlot, aside, aboveForm, children }) {
|
|
28
|
-
const header = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_service_header.ServiceHeader, {
|
|
29
|
-
const form = aside ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "
|
|
28
|
+
const header = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_service_header.ServiceHeader, { bare: true, icon, title, subtitle, headerAccessory });
|
|
29
|
+
const form = aside ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rounded-2xl border border-border/60 bg-card p-5 sm:p-6", children }) : children;
|
|
30
30
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_cn.cn)("container mx-auto px-4 sm:px-6 py-10 space-y-6 pb-20", aside ? "max-w-5xl" : "max-w-3xl"), children: [
|
|
31
31
|
backSlot,
|
|
32
32
|
aside ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid gap-4 lg:grid-cols-12 lg:items-start", children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/service-form-shell.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ServiceHeader } from \"./service-header.js\";\n\nexport interface ServiceFormShellProps {\n /** Rendered icon element for the header, e.g. <Coins className=\"h-4 w-4 text-white\" />. */\n icon: ReactNode;\n title: string;\n subtitle: string;\n /** Optional element under the header subtitle (e.g. a URL pill). */\n headerAccessory?: ReactNode;\n /** Rendered above the header — the app's own back button (router-specific). */\n backSlot?: ReactNode;\n /** Right-rail panels (e.g. <ClaimRail/>). When present, lays out an 8/4 bento. */\n aside?: ReactNode;\n /** Rendered in the left column between the header and the form — e.g. a\n * <StepNav/> for multi-step flows. Only used in the aside (8/4) layout. */\n aboveForm?: ReactNode;\n /** The form. **Already gated by the app** — wrap it in your own auth/wallet\n * gate before passing. This component stays presentation-only (no auth,\n * no router) so both apps can share it. */\n children: ReactNode;\n}\n\n/** Shared launchpad/claim form layout: back slot +
|
|
1
|
+
{"version":3,"sources":["../../src/components/service-form-shell.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ServiceHeader } from \"./service-header.js\";\n\nexport interface ServiceFormShellProps {\n /** Rendered icon element for the header, e.g. <Coins className=\"h-4 w-4 text-white\" />. */\n icon: ReactNode;\n title: string;\n subtitle: string;\n /** Optional element under the header subtitle (e.g. a URL pill). */\n headerAccessory?: ReactNode;\n /** Rendered above the header — the app's own back button (router-specific). */\n backSlot?: ReactNode;\n /** Right-rail panels (e.g. <ClaimRail/>). When present, lays out an 8/4 bento. */\n aside?: ReactNode;\n /** Rendered in the left column between the header and the form — e.g. a\n * <StepNav/> for multi-step flows. Only used in the aside (8/4) layout. */\n aboveForm?: ReactNode;\n /** The form. **Already gated by the app** — wrap it in your own auth/wallet\n * gate before passing. This component stays presentation-only (no auth,\n * no router) so both apps can share it. */\n children: ReactNode;\n}\n\n/** Shared launchpad/claim form layout: back slot + bare header (no card), then\n * the form in a quiet hairline card. With an `aside` it lays out an 8/4 bento\n * (form left, rail right); without, a single centered column. The brand\n * gradient belongs to the form's action button, not to any container. */\nexport function ServiceFormShell({ icon, title, subtitle, headerAccessory, backSlot, aside, aboveForm, children }: ServiceFormShellProps) {\n // Bare header: the form card is the page's only panel.\n const header = <ServiceHeader bare icon={icon} title={title} subtitle={subtitle} headerAccessory={headerAccessory} />;\n\n const form = aside ? (\n <div className=\"rounded-2xl border border-border/60 bg-card p-5 sm:p-6\">{children}</div>\n ) : (\n children\n );\n\n return (\n <div className={cn(\"container mx-auto px-4 sm:px-6 py-10 space-y-6 pb-20\", aside ? \"max-w-5xl\" : \"max-w-3xl\")}>\n {backSlot}\n {aside ? (\n <div className=\"grid gap-4 lg:grid-cols-12 lg:items-start\">\n <div className=\"space-y-4 lg:col-span-8\">\n {header}\n {aboveForm}\n {form}\n </div>\n <div className=\"space-y-4 lg:col-span-4 lg:sticky lg:top-24\">{aside}</div>\n </div>\n ) : (\n <div className=\"space-y-6\">\n {header}\n {form}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BiB;AA7BjB,gBAAmB;AACnB,4BAA8B;AA0BvB,SAAS,iBAAiB,EAAE,MAAM,OAAO,UAAU,iBAAiB,UAAU,OAAO,WAAW,SAAS,GAA0B;AAExI,QAAM,SAAS,4CAAC,uCAAc,MAAI,MAAC,MAAY,OAAc,UAAoB,iBAAkC;AAEnH,QAAM,OAAO,QACX,4CAAC,SAAI,WAAU,0DAA0D,UAAS,IAElF;AAGF,SACE,6CAAC,SAAI,eAAW,cAAG,wDAAwD,QAAQ,cAAc,WAAW,GACzG;AAAA;AAAA,IACA,QACC,6CAAC,SAAI,WAAU,6CACb;AAAA,mDAAC,SAAI,WAAU,2BACZ;AAAA;AAAA,QACA;AAAA,QACA;AAAA,SACH;AAAA,MACA,4CAAC,SAAI,WAAU,+CAA+C,iBAAM;AAAA,OACtE,IAEA,6CAAC,SAAI,WAAU,aACZ;AAAA;AAAA,MACA;AAAA,OACH;AAAA,KAEJ;AAEJ;","names":[]}
|
|
@@ -20,10 +20,10 @@ interface ServiceFormShellProps {
|
|
|
20
20
|
* no router) so both apps can share it. */
|
|
21
21
|
children: ReactNode;
|
|
22
22
|
}
|
|
23
|
-
/** Shared launchpad/claim form layout: back slot +
|
|
24
|
-
* form
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
/** Shared launchpad/claim form layout: back slot + bare header (no card), then
|
|
24
|
+
* the form in a quiet hairline card. With an `aside` it lays out an 8/4 bento
|
|
25
|
+
* (form left, rail right); without, a single centered column. The brand
|
|
26
|
+
* gradient belongs to the form's action button, not to any container. */
|
|
27
27
|
declare function ServiceFormShell({ icon, title, subtitle, headerAccessory, backSlot, aside, aboveForm, children }: ServiceFormShellProps): react_jsx_runtime.JSX.Element;
|
|
28
28
|
|
|
29
29
|
export { ServiceFormShell, type ServiceFormShellProps };
|
|
@@ -20,10 +20,10 @@ interface ServiceFormShellProps {
|
|
|
20
20
|
* no router) so both apps can share it. */
|
|
21
21
|
children: ReactNode;
|
|
22
22
|
}
|
|
23
|
-
/** Shared launchpad/claim form layout: back slot +
|
|
24
|
-
* form
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
/** Shared launchpad/claim form layout: back slot + bare header (no card), then
|
|
24
|
+
* the form in a quiet hairline card. With an `aside` it lays out an 8/4 bento
|
|
25
|
+
* (form left, rail right); without, a single centered column. The brand
|
|
26
|
+
* gradient belongs to the form's action button, not to any container. */
|
|
27
27
|
declare function ServiceFormShell({ icon, title, subtitle, headerAccessory, backSlot, aside, aboveForm, children }: ServiceFormShellProps): react_jsx_runtime.JSX.Element;
|
|
28
28
|
|
|
29
29
|
export { ServiceFormShell, type ServiceFormShellProps };
|
|
@@ -2,8 +2,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { cn } from "../utils/cn.js";
|
|
3
3
|
import { ServiceHeader } from "./service-header.js";
|
|
4
4
|
function ServiceFormShell({ icon, title, subtitle, headerAccessory, backSlot, aside, aboveForm, children }) {
|
|
5
|
-
const header = /* @__PURE__ */ jsx(ServiceHeader, {
|
|
6
|
-
const form = aside ? /* @__PURE__ */ jsx("div", { className: "
|
|
5
|
+
const header = /* @__PURE__ */ jsx(ServiceHeader, { bare: true, icon, title, subtitle, headerAccessory });
|
|
6
|
+
const form = aside ? /* @__PURE__ */ jsx("div", { className: "rounded-2xl border border-border/60 bg-card p-5 sm:p-6", children }) : children;
|
|
7
7
|
return /* @__PURE__ */ jsxs("div", { className: cn("container mx-auto px-4 sm:px-6 py-10 space-y-6 pb-20", aside ? "max-w-5xl" : "max-w-3xl"), children: [
|
|
8
8
|
backSlot,
|
|
9
9
|
aside ? /* @__PURE__ */ jsxs("div", { className: "grid gap-4 lg:grid-cols-12 lg:items-start", children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/service-form-shell.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ServiceHeader } from \"./service-header.js\";\n\nexport interface ServiceFormShellProps {\n /** Rendered icon element for the header, e.g. <Coins className=\"h-4 w-4 text-white\" />. */\n icon: ReactNode;\n title: string;\n subtitle: string;\n /** Optional element under the header subtitle (e.g. a URL pill). */\n headerAccessory?: ReactNode;\n /** Rendered above the header — the app's own back button (router-specific). */\n backSlot?: ReactNode;\n /** Right-rail panels (e.g. <ClaimRail/>). When present, lays out an 8/4 bento. */\n aside?: ReactNode;\n /** Rendered in the left column between the header and the form — e.g. a\n * <StepNav/> for multi-step flows. Only used in the aside (8/4) layout. */\n aboveForm?: ReactNode;\n /** The form. **Already gated by the app** — wrap it in your own auth/wallet\n * gate before passing. This component stays presentation-only (no auth,\n * no router) so both apps can share it. */\n children: ReactNode;\n}\n\n/** Shared launchpad/claim form layout: back slot +
|
|
1
|
+
{"version":3,"sources":["../../src/components/service-form-shell.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn.js\";\nimport { ServiceHeader } from \"./service-header.js\";\n\nexport interface ServiceFormShellProps {\n /** Rendered icon element for the header, e.g. <Coins className=\"h-4 w-4 text-white\" />. */\n icon: ReactNode;\n title: string;\n subtitle: string;\n /** Optional element under the header subtitle (e.g. a URL pill). */\n headerAccessory?: ReactNode;\n /** Rendered above the header — the app's own back button (router-specific). */\n backSlot?: ReactNode;\n /** Right-rail panels (e.g. <ClaimRail/>). When present, lays out an 8/4 bento. */\n aside?: ReactNode;\n /** Rendered in the left column between the header and the form — e.g. a\n * <StepNav/> for multi-step flows. Only used in the aside (8/4) layout. */\n aboveForm?: ReactNode;\n /** The form. **Already gated by the app** — wrap it in your own auth/wallet\n * gate before passing. This component stays presentation-only (no auth,\n * no router) so both apps can share it. */\n children: ReactNode;\n}\n\n/** Shared launchpad/claim form layout: back slot + bare header (no card), then\n * the form in a quiet hairline card. With an `aside` it lays out an 8/4 bento\n * (form left, rail right); without, a single centered column. The brand\n * gradient belongs to the form's action button, not to any container. */\nexport function ServiceFormShell({ icon, title, subtitle, headerAccessory, backSlot, aside, aboveForm, children }: ServiceFormShellProps) {\n // Bare header: the form card is the page's only panel.\n const header = <ServiceHeader bare icon={icon} title={title} subtitle={subtitle} headerAccessory={headerAccessory} />;\n\n const form = aside ? (\n <div className=\"rounded-2xl border border-border/60 bg-card p-5 sm:p-6\">{children}</div>\n ) : (\n children\n );\n\n return (\n <div className={cn(\"container mx-auto px-4 sm:px-6 py-10 space-y-6 pb-20\", aside ? \"max-w-5xl\" : \"max-w-3xl\")}>\n {backSlot}\n {aside ? (\n <div className=\"grid gap-4 lg:grid-cols-12 lg:items-start\">\n <div className=\"space-y-4 lg:col-span-8\">\n {header}\n {aboveForm}\n {form}\n </div>\n <div className=\"space-y-4 lg:col-span-4 lg:sticky lg:top-24\">{aside}</div>\n </div>\n ) : (\n <div className=\"space-y-6\">\n {header}\n {form}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"AA8BiB,cAaP,YAbO;AA7BjB,SAAS,UAAU;AACnB,SAAS,qBAAqB;AA0BvB,SAAS,iBAAiB,EAAE,MAAM,OAAO,UAAU,iBAAiB,UAAU,OAAO,WAAW,SAAS,GAA0B;AAExI,QAAM,SAAS,oBAAC,iBAAc,MAAI,MAAC,MAAY,OAAc,UAAoB,iBAAkC;AAEnH,QAAM,OAAO,QACX,oBAAC,SAAI,WAAU,0DAA0D,UAAS,IAElF;AAGF,SACE,qBAAC,SAAI,WAAW,GAAG,wDAAwD,QAAQ,cAAc,WAAW,GACzG;AAAA;AAAA,IACA,QACC,qBAAC,SAAI,WAAU,6CACb;AAAA,2BAAC,SAAI,WAAU,2BACZ;AAAA;AAAA,QACA;AAAA,QACA;AAAA,SACH;AAAA,MACA,oBAAC,SAAI,WAAU,+CAA+C,iBAAM;AAAA,OACtE,IAEA,qBAAC,SAAI,WAAU,aACZ;AAAA;AAAA,MACA;AAAA,OACH;AAAA,KAEJ;AAEJ;","names":[]}
|
|
@@ -23,15 +23,18 @@ __export(service_header_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(service_header_exports);
|
|
24
24
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25
25
|
var import_cn = require("../utils/cn.js");
|
|
26
|
-
function ServiceHeader({ icon, title, subtitle, headerAccessory, className, plain = false }) {
|
|
26
|
+
function ServiceHeader({ icon, title, subtitle, headerAccessory, className, plain = false, bare = false }) {
|
|
27
27
|
const body = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
28
28
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2.5", children: [
|
|
29
29
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-9 w-9 rounded-xl bg-primary flex items-center justify-center shrink-0", children: icon }),
|
|
30
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "text-2xl sm:text-3xl font-black", children: title })
|
|
30
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "text-2xl sm:text-3xl font-black tracking-tight", children: title })
|
|
31
31
|
] }),
|
|
32
32
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mt-1.5 text-sm text-muted-foreground max-w-xl", children: subtitle }),
|
|
33
33
|
headerAccessory && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-4", children: headerAccessory })
|
|
34
34
|
] });
|
|
35
|
+
if (bare) {
|
|
36
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, children: body });
|
|
37
|
+
}
|
|
35
38
|
if (plain) {
|
|
36
39
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_cn.cn)("rounded-2xl border border-border/60 bg-card p-6 sm:p-7", className), children: body });
|
|
37
40
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/service-header.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface ServiceHeaderProps {\n /** Rendered icon element, e.g. <Coins className=\"h-4 w-4 text-white\" />. */\n icon: ReactNode;\n title: string;\n subtitle: string;\n /** Optional element shown under the subtitle (e.g. a URL pill). */\n headerAccessory?: ReactNode;\n className?: string;\n /** Drop the brand gradient border for a plain neutral-bordered card
|
|
1
|
+
{"version":3,"sources":["../../src/components/service-header.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface ServiceHeaderProps {\n /** Rendered icon element, e.g. <Coins className=\"h-4 w-4 text-white\" />. */\n icon: ReactNode;\n title: string;\n subtitle: string;\n /** Optional element shown under the subtitle (e.g. a URL pill). */\n headerAccessory?: ReactNode;\n className?: string;\n /** Drop the brand gradient border for a plain neutral-bordered card.\n * Standalone headers (browse pages, coin page, /claim hub) keep the\n * gradient by default. */\n plain?: boolean;\n /** No card at all — icon chip + title + subtitle on the page background.\n * Used by ServiceFormShell so the form card is the page's only panel. */\n bare?: boolean;\n}\n\n/** Shared launchpad/claim page header: a dark card with a solid primary icon\n * chip, title + subtitle. By default it sits on a static brand gradient\n * border; pass `plain` for a neutral-bordered card. Pure presentation —\n * consuming app supplies the icon and (optionally) a header accessory. */\nexport function ServiceHeader({ icon, title, subtitle, headerAccessory, className, plain = false, bare = false }: ServiceHeaderProps) {\n const body = (\n <>\n <div className=\"flex items-center gap-2.5\">\n <div className=\"h-9 w-9 rounded-xl bg-primary flex items-center justify-center shrink-0\">\n {icon}\n </div>\n <h1 className=\"text-2xl sm:text-3xl font-black tracking-tight\">{title}</h1>\n </div>\n <p className=\"mt-1.5 text-sm text-muted-foreground max-w-xl\">{subtitle}</p>\n {headerAccessory && <div className=\"mt-4\">{headerAccessory}</div>}\n </>\n );\n\n if (bare) {\n return <div className={className}>{body}</div>;\n }\n\n if (plain) {\n return <div className={cn(\"rounded-2xl border border-border/60 bg-card p-6 sm:p-7\", className)}>{body}</div>;\n }\n\n return (\n <div className={cn(\"rounded-2xl p-[1.5px] bg-gradient-to-br from-brand-blue via-brand-purple to-brand-rose\", className)}>\n <div className=\"rounded-[15px] bg-card p-6 sm:p-7\">{body}</div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BI;AAzBJ,gBAAmB;AAuBZ,SAAS,cAAc,EAAE,MAAM,OAAO,UAAU,iBAAiB,WAAW,QAAQ,OAAO,OAAO,MAAM,GAAuB;AACpI,QAAM,OACJ,4EACE;AAAA,iDAAC,SAAI,WAAU,6BACb;AAAA,kDAAC,SAAI,WAAU,2EACZ,gBACH;AAAA,MACA,4CAAC,QAAG,WAAU,kDAAkD,iBAAM;AAAA,OACxE;AAAA,IACA,4CAAC,OAAE,WAAU,iDAAiD,oBAAS;AAAA,IACtE,mBAAmB,4CAAC,SAAI,WAAU,QAAQ,2BAAgB;AAAA,KAC7D;AAGF,MAAI,MAAM;AACR,WAAO,4CAAC,SAAI,WAAuB,gBAAK;AAAA,EAC1C;AAEA,MAAI,OAAO;AACT,WAAO,4CAAC,SAAI,eAAW,cAAG,0DAA0D,SAAS,GAAI,gBAAK;AAAA,EACxG;AAEA,SACE,4CAAC,SAAI,eAAW,cAAG,0FAA0F,SAAS,GACpH,sDAAC,SAAI,WAAU,qCAAqC,gBAAK,GAC3D;AAEJ;","names":[]}
|
|
@@ -9,16 +9,18 @@ interface ServiceHeaderProps {
|
|
|
9
9
|
/** Optional element shown under the subtitle (e.g. a URL pill). */
|
|
10
10
|
headerAccessory?: ReactNode;
|
|
11
11
|
className?: string;
|
|
12
|
-
/** Drop the brand gradient border for a plain neutral-bordered card.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* headers (browse pages, coin page, /claim hub) keep the gradient. */
|
|
12
|
+
/** Drop the brand gradient border for a plain neutral-bordered card.
|
|
13
|
+
* Standalone headers (browse pages, coin page, /claim hub) keep the
|
|
14
|
+
* gradient by default. */
|
|
16
15
|
plain?: boolean;
|
|
16
|
+
/** No card at all — icon chip + title + subtitle on the page background.
|
|
17
|
+
* Used by ServiceFormShell so the form card is the page's only panel. */
|
|
18
|
+
bare?: boolean;
|
|
17
19
|
}
|
|
18
20
|
/** Shared launchpad/claim page header: a dark card with a solid primary icon
|
|
19
21
|
* chip, title + subtitle. By default it sits on a static brand gradient
|
|
20
22
|
* border; pass `plain` for a neutral-bordered card. Pure presentation —
|
|
21
23
|
* consuming app supplies the icon and (optionally) a header accessory. */
|
|
22
|
-
declare function ServiceHeader({ icon, title, subtitle, headerAccessory, className, plain }: ServiceHeaderProps): react_jsx_runtime.JSX.Element;
|
|
24
|
+
declare function ServiceHeader({ icon, title, subtitle, headerAccessory, className, plain, bare }: ServiceHeaderProps): react_jsx_runtime.JSX.Element;
|
|
23
25
|
|
|
24
26
|
export { ServiceHeader, type ServiceHeaderProps };
|
|
@@ -9,16 +9,18 @@ interface ServiceHeaderProps {
|
|
|
9
9
|
/** Optional element shown under the subtitle (e.g. a URL pill). */
|
|
10
10
|
headerAccessory?: ReactNode;
|
|
11
11
|
className?: string;
|
|
12
|
-
/** Drop the brand gradient border for a plain neutral-bordered card.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* headers (browse pages, coin page, /claim hub) keep the gradient. */
|
|
12
|
+
/** Drop the brand gradient border for a plain neutral-bordered card.
|
|
13
|
+
* Standalone headers (browse pages, coin page, /claim hub) keep the
|
|
14
|
+
* gradient by default. */
|
|
16
15
|
plain?: boolean;
|
|
16
|
+
/** No card at all — icon chip + title + subtitle on the page background.
|
|
17
|
+
* Used by ServiceFormShell so the form card is the page's only panel. */
|
|
18
|
+
bare?: boolean;
|
|
17
19
|
}
|
|
18
20
|
/** Shared launchpad/claim page header: a dark card with a solid primary icon
|
|
19
21
|
* chip, title + subtitle. By default it sits on a static brand gradient
|
|
20
22
|
* border; pass `plain` for a neutral-bordered card. Pure presentation —
|
|
21
23
|
* consuming app supplies the icon and (optionally) a header accessory. */
|
|
22
|
-
declare function ServiceHeader({ icon, title, subtitle, headerAccessory, className, plain }: ServiceHeaderProps): react_jsx_runtime.JSX.Element;
|
|
24
|
+
declare function ServiceHeader({ icon, title, subtitle, headerAccessory, className, plain, bare }: ServiceHeaderProps): react_jsx_runtime.JSX.Element;
|
|
23
25
|
|
|
24
26
|
export { ServiceHeader, type ServiceHeaderProps };
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "../utils/cn.js";
|
|
3
|
-
function ServiceHeader({ icon, title, subtitle, headerAccessory, className, plain = false }) {
|
|
3
|
+
function ServiceHeader({ icon, title, subtitle, headerAccessory, className, plain = false, bare = false }) {
|
|
4
4
|
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5
5
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
6
6
|
/* @__PURE__ */ jsx("div", { className: "h-9 w-9 rounded-xl bg-primary flex items-center justify-center shrink-0", children: icon }),
|
|
7
|
-
/* @__PURE__ */ jsx("h1", { className: "text-2xl sm:text-3xl font-black", children: title })
|
|
7
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl sm:text-3xl font-black tracking-tight", children: title })
|
|
8
8
|
] }),
|
|
9
9
|
/* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm text-muted-foreground max-w-xl", children: subtitle }),
|
|
10
10
|
headerAccessory && /* @__PURE__ */ jsx("div", { className: "mt-4", children: headerAccessory })
|
|
11
11
|
] });
|
|
12
|
+
if (bare) {
|
|
13
|
+
return /* @__PURE__ */ jsx("div", { className, children: body });
|
|
14
|
+
}
|
|
12
15
|
if (plain) {
|
|
13
16
|
return /* @__PURE__ */ jsx("div", { className: cn("rounded-2xl border border-border/60 bg-card p-6 sm:p-7", className), children: body });
|
|
14
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/service-header.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface ServiceHeaderProps {\n /** Rendered icon element, e.g. <Coins className=\"h-4 w-4 text-white\" />. */\n icon: ReactNode;\n title: string;\n subtitle: string;\n /** Optional element shown under the subtitle (e.g. a URL pill). */\n headerAccessory?: ReactNode;\n className?: string;\n /** Drop the brand gradient border for a plain neutral-bordered card
|
|
1
|
+
{"version":3,"sources":["../../src/components/service-header.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface ServiceHeaderProps {\n /** Rendered icon element, e.g. <Coins className=\"h-4 w-4 text-white\" />. */\n icon: ReactNode;\n title: string;\n subtitle: string;\n /** Optional element shown under the subtitle (e.g. a URL pill). */\n headerAccessory?: ReactNode;\n className?: string;\n /** Drop the brand gradient border for a plain neutral-bordered card.\n * Standalone headers (browse pages, coin page, /claim hub) keep the\n * gradient by default. */\n plain?: boolean;\n /** No card at all — icon chip + title + subtitle on the page background.\n * Used by ServiceFormShell so the form card is the page's only panel. */\n bare?: boolean;\n}\n\n/** Shared launchpad/claim page header: a dark card with a solid primary icon\n * chip, title + subtitle. By default it sits on a static brand gradient\n * border; pass `plain` for a neutral-bordered card. Pure presentation —\n * consuming app supplies the icon and (optionally) a header accessory. */\nexport function ServiceHeader({ icon, title, subtitle, headerAccessory, className, plain = false, bare = false }: ServiceHeaderProps) {\n const body = (\n <>\n <div className=\"flex items-center gap-2.5\">\n <div className=\"h-9 w-9 rounded-xl bg-primary flex items-center justify-center shrink-0\">\n {icon}\n </div>\n <h1 className=\"text-2xl sm:text-3xl font-black tracking-tight\">{title}</h1>\n </div>\n <p className=\"mt-1.5 text-sm text-muted-foreground max-w-xl\">{subtitle}</p>\n {headerAccessory && <div className=\"mt-4\">{headerAccessory}</div>}\n </>\n );\n\n if (bare) {\n return <div className={className}>{body}</div>;\n }\n\n if (plain) {\n return <div className={cn(\"rounded-2xl border border-border/60 bg-card p-6 sm:p-7\", className)}>{body}</div>;\n }\n\n return (\n <div className={cn(\"rounded-2xl p-[1.5px] bg-gradient-to-br from-brand-blue via-brand-purple to-brand-rose\", className)}>\n <div className=\"rounded-[15px] bg-card p-6 sm:p-7\">{body}</div>\n </div>\n );\n}\n"],"mappings":"AA0BI,mBAEI,KADF,YADF;AAzBJ,SAAS,UAAU;AAuBZ,SAAS,cAAc,EAAE,MAAM,OAAO,UAAU,iBAAiB,WAAW,QAAQ,OAAO,OAAO,MAAM,GAAuB;AACpI,QAAM,OACJ,iCACE;AAAA,yBAAC,SAAI,WAAU,6BACb;AAAA,0BAAC,SAAI,WAAU,2EACZ,gBACH;AAAA,MACA,oBAAC,QAAG,WAAU,kDAAkD,iBAAM;AAAA,OACxE;AAAA,IACA,oBAAC,OAAE,WAAU,iDAAiD,oBAAS;AAAA,IACtE,mBAAmB,oBAAC,SAAI,WAAU,QAAQ,2BAAgB;AAAA,KAC7D;AAGF,MAAI,MAAM;AACR,WAAO,oBAAC,SAAI,WAAuB,gBAAK;AAAA,EAC1C;AAEA,MAAI,OAAO;AACT,WAAO,oBAAC,SAAI,WAAW,GAAG,0DAA0D,SAAS,GAAI,gBAAK;AAAA,EACxG;AAEA,SACE,oBAAC,SAAI,WAAW,GAAG,0FAA0F,SAAS,GACpH,8BAAC,SAAI,WAAU,qCAAqC,gBAAK,GAC3D;AAEJ;","names":[]}
|