@medialane/ui 0.152.0 → 0.154.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/collection-hero-banner.cjs.map +1 -1
- package/dist/components/collection-hero-banner.d.cts +0 -2
- package/dist/components/collection-hero-banner.d.ts +0 -2
- package/dist/components/collection-hero-banner.js.map +1 -1
- package/dist/components/drop-preview-card.test.d.cts +3 -2
- package/dist/components/drop-preview-card.test.d.ts +3 -2
- package/dist/components/dual-price.cjs +0 -2
- package/dist/components/dual-price.cjs.map +1 -1
- package/dist/components/dual-price.d.cts +0 -2
- package/dist/components/dual-price.d.ts +0 -2
- package/dist/components/dual-price.js +0 -2
- package/dist/components/dual-price.js.map +1 -1
- package/dist/components/fast-mint/fast-mint.d.cts +2 -2
- package/dist/components/fast-mint/fast-mint.d.ts +2 -2
- package/dist/components/image.cjs.map +1 -1
- package/dist/components/image.js.map +1 -1
- package/dist/components/ip-type-fields.cjs.map +1 -1
- package/dist/components/ip-type-fields.d.cts +0 -6
- package/dist/components/ip-type-fields.d.ts +0 -6
- package/dist/components/ip-type-fields.js.map +1 -1
- package/dist/components/launchpad-cta-banner.cjs.map +1 -1
- package/dist/components/launchpad-cta-banner.d.cts +0 -4
- package/dist/components/launchpad-cta-banner.d.ts +0 -4
- package/dist/components/launchpad-cta-banner.js.map +1 -1
- package/dist/components/launchpad-services.cjs.map +1 -1
- package/dist/components/launchpad-services.d.cts +0 -3
- package/dist/components/launchpad-services.d.ts +0 -3
- package/dist/components/launchpad-services.js.map +1 -1
- package/dist/components/link.cjs.map +1 -1
- package/dist/components/link.d.cts +0 -2
- package/dist/components/link.d.ts +0 -2
- package/dist/components/link.js.map +1 -1
- package/dist/components/medialane-collection-card.cjs.map +1 -1
- package/dist/components/medialane-collection-card.d.cts +0 -1
- package/dist/components/medialane-collection-card.d.ts +0 -1
- package/dist/components/medialane-collection-card.js.map +1 -1
- package/dist/components/portfolio-section.cjs.map +1 -1
- package/dist/components/portfolio-section.d.cts +0 -4
- package/dist/components/portfolio-section.d.ts +0 -4
- package/dist/components/portfolio-section.js.map +1 -1
- package/dist/components/router.cjs.map +1 -1
- package/dist/components/router.js.map +1 -1
- package/dist/data/coins.cjs.map +1 -1
- package/dist/data/coins.d.cts +0 -2
- package/dist/data/coins.d.ts +0 -2
- package/dist/data/coins.js.map +1 -1
- package/dist/medialane.css +1 -47
- package/dist/utils/ipfs.cjs.map +1 -1
- package/dist/utils/ipfs.d.cts +0 -7
- package/dist/utils/ipfs.d.ts +0 -7
- package/dist/utils/ipfs.js.map +1 -1
- package/dist/utils/profile-identity.cjs +1 -1
- package/dist/utils/profile-identity.cjs.map +1 -1
- package/dist/utils/profile-identity.d.cts +1 -13
- package/dist/utils/profile-identity.d.ts +1 -13
- package/dist/utils/profile-identity.js +1 -1
- package/dist/utils/profile-identity.js.map +1 -1
- package/dist/utils/use-usd-prices.cjs.map +1 -1
- package/dist/utils/use-usd-prices.d.cts +0 -2
- package/dist/utils/use-usd-prices.d.ts +0 -2
- package/dist/utils/use-usd-prices.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/collection-hero-banner.tsx"],"sourcesContent":["\"use client\";\n\nimport { motion, useScroll, useTransform, useReducedMotion } from \"framer-motion\";\nimport { cn } from \"../utils/cn.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { Skeleton } from \"./skeleton.js\";\n\nexport interface CollectionHeroStat {\n label: string;\n display: string;\n\n symbol?: string | null;\n}\n\nexport interface CollectionHeroBannerProps {\n bannerUrl: string | null;\n loading?: boolean;\n standard?: string | null;\n symbol?: string | null;\n name: string;\n stats: CollectionHeroStat[];\n className?: string;\n\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/collection-hero-banner.tsx"],"sourcesContent":["\"use client\";\n\nimport { motion, useScroll, useTransform, useReducedMotion } from \"framer-motion\";\nimport { cn } from \"../utils/cn.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { Skeleton } from \"./skeleton.js\";\n\nexport interface CollectionHeroStat {\n label: string;\n display: string;\n\n symbol?: string | null;\n}\n\nexport interface CollectionHeroBannerProps {\n bannerUrl: string | null;\n loading?: boolean;\n standard?: string | null;\n symbol?: string | null;\n name: string;\n stats: CollectionHeroStat[];\n className?: string;\n\n eyebrowSlot?: React.ReactNode;\n}\n\nexport function CollectionHeroBanner({\n bannerUrl,\n loading = false,\n standard,\n symbol,\n name,\n stats,\n className,\n eyebrowSlot,\n}: CollectionHeroBannerProps) {\n const { scrollY } = useScroll();\n const shouldReduce = useReducedMotion();\n const y = useTransform(scrollY, [0, 500], [0, shouldReduce ? 0 : 150]);\n\n return (\n <>\n\n <div className=\"fixed inset-0 -z-10 overflow-hidden pointer-events-none\">\n {bannerUrl && (\n <img\n src={bannerUrl}\n alt=\"\"\n aria-hidden\n loading=\"lazy\"\n decoding=\"async\"\n className=\"absolute inset-0 w-full h-full object-cover opacity-20 scale-110\"\n style={{ filter: \"blur(60px) saturate(1.5)\" }}\n />\n )}\n </div>\n\n {loading ? (\n <Skeleton className={cn(\"w-full h-[50svh]\", className)} />\n ) : (\n <div className={cn(\"relative w-full overflow-hidden h-[50svh]\", className)}>\n {bannerUrl ? (\n <motion.img\n src={bannerUrl}\n alt=\"\"\n aria-hidden\n style={{ y }}\n className=\"absolute inset-0 w-full h-full object-cover scale-110\"\n />\n ) : (\n <div className=\"absolute inset-0 w-full h-full bg-muted\" />\n )}\n\n <div className=\"absolute bottom-0 left-0 right-0 px-4 sm:px-6 pb-4 sm:pb-6 space-y-3 z-10\">\n {(standard || symbol || eyebrowSlot) && (\n <div className=\"flex items-center gap-2 flex-wrap\">\n {standard === \"ERC1155\" ? (\n <Eyebrow>Multi-edition NFT</Eyebrow>\n ) : standard === \"ERC721\" ? (\n <Eyebrow>Single NFT</Eyebrow>\n ) : null}\n {symbol && <Eyebrow className=\"tabular-nums\">{symbol}</Eyebrow>}\n {eyebrowSlot}\n </div>\n )}\n\n <h1\n className=\"text-3xl sm:text-5xl lg:text-7xl font-bold text-white leading-tight\"\n style={{ textShadow: \"0 1px 12px rgba(0,0,0,0.4)\" }}\n >\n {name}\n </h1>\n\n <div className=\"flex gap-2 flex-wrap\">\n {stats.map(({ label, display, symbol: statSymbol }) => (\n <div\n key={label}\n className={cn(\n \"bg-white/15 backdrop-blur-md rounded-xl px-3 py-2 flex flex-col justify-center shrink-0\",\n statSymbol ? \"min-w-[80px]\" : \"min-w-[60px] items-center text-center\"\n )}\n >\n <p className=\"text-[9px] text-white/70 mb-1\">{label}</p>\n {statSymbol ? (\n <div className=\"flex items-center gap-1.5\">\n <CurrencyIcon symbol={statSymbol} size={15} />\n <p className=\"text-sm sm:text-base font-bold text-white tabular-nums leading-tight truncate\">\n {display}\n </p>\n </div>\n ) : (\n <p className=\"text-base sm:text-lg font-bold text-white tabular-nums leading-tight\">{display}</p>\n )}\n </div>\n ))}\n </div>\n </div>\n </div>\n )}\n </>\n );\n}\n\nfunction Eyebrow({ children, className }: { children: React.ReactNode; className?: string }) {\n return (\n <span\n className={cn(\n \"text-[11px] font-semibold text-white/90 bg-white/15 backdrop-blur-md rounded-full px-2.5 py-0.5\",\n className\n )}\n >\n {children}\n </span>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyCI;AAvCJ,2BAAkE;AAClE,gBAAmB;AACnB,2BAA6B;AAC7B,sBAAyB;AAqBlB,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA8B;AAC5B,QAAM,EAAE,QAAQ,QAAI,gCAAU;AAC9B,QAAM,mBAAe,uCAAiB;AACtC,QAAM,QAAI,mCAAa,SAAS,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,eAAe,IAAI,GAAG,CAAC;AAErE,SACE,4EAEE;AAAA,gDAAC,SAAI,WAAU,2DACZ,uBACC;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,KAAI;AAAA,QACJ,eAAW;AAAA,QACX,SAAQ;AAAA,QACR,UAAS;AAAA,QACT,WAAU;AAAA,QACV,OAAO,EAAE,QAAQ,2BAA2B;AAAA;AAAA,IAC9C,GAEJ;AAAA,IAEC,UACC,4CAAC,4BAAS,eAAW,cAAG,oBAAoB,SAAS,GAAG,IAExD,6CAAC,SAAI,eAAW,cAAG,6CAA6C,SAAS,GACtE;AAAA,kBACC;AAAA,QAAC,4BAAO;AAAA,QAAP;AAAA,UACC,KAAK;AAAA,UACL,KAAI;AAAA,UACJ,eAAW;AAAA,UACX,OAAO,EAAE,EAAE;AAAA,UACX,WAAU;AAAA;AAAA,MACZ,IAEA,4CAAC,SAAI,WAAU,2CAA0C;AAAA,MAG3D,6CAAC,SAAI,WAAU,6EACX;AAAA,qBAAY,UAAU,gBACtB,6CAAC,SAAI,WAAU,qCACZ;AAAA,uBAAa,YACZ,4CAAC,WAAQ,+BAAiB,IACxB,aAAa,WACf,4CAAC,WAAQ,wBAAU,IACjB;AAAA,UACH,UAAU,4CAAC,WAAQ,WAAU,gBAAgB,kBAAO;AAAA,UACpD;AAAA,WACH;AAAA,QAGF;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,YAAY,6BAA6B;AAAA,YAEjD;AAAA;AAAA,QACH;AAAA,QAEA,4CAAC,SAAI,WAAU,wBACZ,gBAAM,IAAI,CAAC,EAAE,OAAO,SAAS,QAAQ,WAAW,MAC/C;AAAA,UAAC;AAAA;AAAA,YAEC,eAAW;AAAA,cACT;AAAA,cACA,aAAa,iBAAiB;AAAA,YAChC;AAAA,YAEA;AAAA,0DAAC,OAAE,WAAU,iCAAiC,iBAAM;AAAA,cACnD,aACC,6CAAC,SAAI,WAAU,6BACb;AAAA,4DAAC,qCAAa,QAAQ,YAAY,MAAM,IAAI;AAAA,gBAC5C,4CAAC,OAAE,WAAU,iFACV,mBACH;AAAA,iBACF,IAEA,4CAAC,OAAE,WAAU,wEAAwE,mBAAQ;AAAA;AAAA;AAAA,UAf1F;AAAA,QAiBP,CACD,GACH;AAAA,SACF;AAAA,OACF;AAAA,KAEJ;AAEJ;AAEA,SAAS,QAAQ,EAAE,UAAU,UAAU,GAAsD;AAC3F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;","names":[]}
|
|
@@ -13,8 +13,6 @@ interface CollectionHeroBannerProps {
|
|
|
13
13
|
name: string;
|
|
14
14
|
stats: CollectionHeroStat[];
|
|
15
15
|
className?: string;
|
|
16
|
-
/** Extra content rendered alongside the standard/symbol eyebrow pills —
|
|
17
|
-
* e.g. a creator level badge on a creator profile reusing this banner. */
|
|
18
16
|
eyebrowSlot?: React.ReactNode;
|
|
19
17
|
}
|
|
20
18
|
declare function CollectionHeroBanner({ bannerUrl, loading, standard, symbol, name, stats, className, eyebrowSlot, }: CollectionHeroBannerProps): react_jsx_runtime.JSX.Element;
|
|
@@ -13,8 +13,6 @@ interface CollectionHeroBannerProps {
|
|
|
13
13
|
name: string;
|
|
14
14
|
stats: CollectionHeroStat[];
|
|
15
15
|
className?: string;
|
|
16
|
-
/** Extra content rendered alongside the standard/symbol eyebrow pills —
|
|
17
|
-
* e.g. a creator level badge on a creator profile reusing this banner. */
|
|
18
16
|
eyebrowSlot?: React.ReactNode;
|
|
19
17
|
}
|
|
20
18
|
declare function CollectionHeroBanner({ bannerUrl, loading, standard, symbol, name, stats, className, eyebrowSlot, }: CollectionHeroBannerProps): react_jsx_runtime.JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/collection-hero-banner.tsx"],"sourcesContent":["\"use client\";\n\nimport { motion, useScroll, useTransform, useReducedMotion } from \"framer-motion\";\nimport { cn } from \"../utils/cn.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { Skeleton } from \"./skeleton.js\";\n\nexport interface CollectionHeroStat {\n label: string;\n display: string;\n\n symbol?: string | null;\n}\n\nexport interface CollectionHeroBannerProps {\n bannerUrl: string | null;\n loading?: boolean;\n standard?: string | null;\n symbol?: string | null;\n name: string;\n stats: CollectionHeroStat[];\n className?: string;\n\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/collection-hero-banner.tsx"],"sourcesContent":["\"use client\";\n\nimport { motion, useScroll, useTransform, useReducedMotion } from \"framer-motion\";\nimport { cn } from \"../utils/cn.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { Skeleton } from \"./skeleton.js\";\n\nexport interface CollectionHeroStat {\n label: string;\n display: string;\n\n symbol?: string | null;\n}\n\nexport interface CollectionHeroBannerProps {\n bannerUrl: string | null;\n loading?: boolean;\n standard?: string | null;\n symbol?: string | null;\n name: string;\n stats: CollectionHeroStat[];\n className?: string;\n\n eyebrowSlot?: React.ReactNode;\n}\n\nexport function CollectionHeroBanner({\n bannerUrl,\n loading = false,\n standard,\n symbol,\n name,\n stats,\n className,\n eyebrowSlot,\n}: CollectionHeroBannerProps) {\n const { scrollY } = useScroll();\n const shouldReduce = useReducedMotion();\n const y = useTransform(scrollY, [0, 500], [0, shouldReduce ? 0 : 150]);\n\n return (\n <>\n\n <div className=\"fixed inset-0 -z-10 overflow-hidden pointer-events-none\">\n {bannerUrl && (\n <img\n src={bannerUrl}\n alt=\"\"\n aria-hidden\n loading=\"lazy\"\n decoding=\"async\"\n className=\"absolute inset-0 w-full h-full object-cover opacity-20 scale-110\"\n style={{ filter: \"blur(60px) saturate(1.5)\" }}\n />\n )}\n </div>\n\n {loading ? (\n <Skeleton className={cn(\"w-full h-[50svh]\", className)} />\n ) : (\n <div className={cn(\"relative w-full overflow-hidden h-[50svh]\", className)}>\n {bannerUrl ? (\n <motion.img\n src={bannerUrl}\n alt=\"\"\n aria-hidden\n style={{ y }}\n className=\"absolute inset-0 w-full h-full object-cover scale-110\"\n />\n ) : (\n <div className=\"absolute inset-0 w-full h-full bg-muted\" />\n )}\n\n <div className=\"absolute bottom-0 left-0 right-0 px-4 sm:px-6 pb-4 sm:pb-6 space-y-3 z-10\">\n {(standard || symbol || eyebrowSlot) && (\n <div className=\"flex items-center gap-2 flex-wrap\">\n {standard === \"ERC1155\" ? (\n <Eyebrow>Multi-edition NFT</Eyebrow>\n ) : standard === \"ERC721\" ? (\n <Eyebrow>Single NFT</Eyebrow>\n ) : null}\n {symbol && <Eyebrow className=\"tabular-nums\">{symbol}</Eyebrow>}\n {eyebrowSlot}\n </div>\n )}\n\n <h1\n className=\"text-3xl sm:text-5xl lg:text-7xl font-bold text-white leading-tight\"\n style={{ textShadow: \"0 1px 12px rgba(0,0,0,0.4)\" }}\n >\n {name}\n </h1>\n\n <div className=\"flex gap-2 flex-wrap\">\n {stats.map(({ label, display, symbol: statSymbol }) => (\n <div\n key={label}\n className={cn(\n \"bg-white/15 backdrop-blur-md rounded-xl px-3 py-2 flex flex-col justify-center shrink-0\",\n statSymbol ? \"min-w-[80px]\" : \"min-w-[60px] items-center text-center\"\n )}\n >\n <p className=\"text-[9px] text-white/70 mb-1\">{label}</p>\n {statSymbol ? (\n <div className=\"flex items-center gap-1.5\">\n <CurrencyIcon symbol={statSymbol} size={15} />\n <p className=\"text-sm sm:text-base font-bold text-white tabular-nums leading-tight truncate\">\n {display}\n </p>\n </div>\n ) : (\n <p className=\"text-base sm:text-lg font-bold text-white tabular-nums leading-tight\">{display}</p>\n )}\n </div>\n ))}\n </div>\n </div>\n </div>\n )}\n </>\n );\n}\n\nfunction Eyebrow({ children, className }: { children: React.ReactNode; className?: string }) {\n return (\n <span\n className={cn(\n \"text-[11px] font-semibold text-white/90 bg-white/15 backdrop-blur-md rounded-full px-2.5 py-0.5\",\n className\n )}\n >\n {children}\n </span>\n );\n}\n"],"mappings":";AAyCI,mBAIM,KA8BI,YAlCV;AAvCJ,SAAS,QAAQ,WAAW,cAAc,wBAAwB;AAClE,SAAS,UAAU;AACnB,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB;AAqBlB,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA8B;AAC5B,QAAM,EAAE,QAAQ,IAAI,UAAU;AAC9B,QAAM,eAAe,iBAAiB;AACtC,QAAM,IAAI,aAAa,SAAS,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,eAAe,IAAI,GAAG,CAAC;AAErE,SACE,iCAEE;AAAA,wBAAC,SAAI,WAAU,2DACZ,uBACC;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,KAAI;AAAA,QACJ,eAAW;AAAA,QACX,SAAQ;AAAA,QACR,UAAS;AAAA,QACT,WAAU;AAAA,QACV,OAAO,EAAE,QAAQ,2BAA2B;AAAA;AAAA,IAC9C,GAEJ;AAAA,IAEC,UACC,oBAAC,YAAS,WAAW,GAAG,oBAAoB,SAAS,GAAG,IAExD,qBAAC,SAAI,WAAW,GAAG,6CAA6C,SAAS,GACtE;AAAA,kBACC;AAAA,QAAC,OAAO;AAAA,QAAP;AAAA,UACC,KAAK;AAAA,UACL,KAAI;AAAA,UACJ,eAAW;AAAA,UACX,OAAO,EAAE,EAAE;AAAA,UACX,WAAU;AAAA;AAAA,MACZ,IAEA,oBAAC,SAAI,WAAU,2CAA0C;AAAA,MAG3D,qBAAC,SAAI,WAAU,6EACX;AAAA,qBAAY,UAAU,gBACtB,qBAAC,SAAI,WAAU,qCACZ;AAAA,uBAAa,YACZ,oBAAC,WAAQ,+BAAiB,IACxB,aAAa,WACf,oBAAC,WAAQ,wBAAU,IACjB;AAAA,UACH,UAAU,oBAAC,WAAQ,WAAU,gBAAgB,kBAAO;AAAA,UACpD;AAAA,WACH;AAAA,QAGF;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,YAAY,6BAA6B;AAAA,YAEjD;AAAA;AAAA,QACH;AAAA,QAEA,oBAAC,SAAI,WAAU,wBACZ,gBAAM,IAAI,CAAC,EAAE,OAAO,SAAS,QAAQ,WAAW,MAC/C;AAAA,UAAC;AAAA;AAAA,YAEC,WAAW;AAAA,cACT;AAAA,cACA,aAAa,iBAAiB;AAAA,YAChC;AAAA,YAEA;AAAA,kCAAC,OAAE,WAAU,iCAAiC,iBAAM;AAAA,cACnD,aACC,qBAAC,SAAI,WAAU,6BACb;AAAA,oCAAC,gBAAa,QAAQ,YAAY,MAAM,IAAI;AAAA,gBAC5C,oBAAC,OAAE,WAAU,iFACV,mBACH;AAAA,iBACF,IAEA,oBAAC,OAAE,WAAU,wEAAwE,mBAAQ;AAAA;AAAA;AAAA,UAf1F;AAAA,QAiBP,CACD,GACH;AAAA,SACF;AAAA,OACF;AAAA,KAEJ;AAEJ;AAEA,SAAS,QAAQ,EAAE,UAAU,UAAU,GAAsD;AAC3F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;","names":[]}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import 'next/image';
|
|
2
|
+
import 'next/link';
|
|
3
|
+
import 'next/navigation';
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import 'next/image';
|
|
2
|
+
import 'next/link';
|
|
3
|
+
import 'next/navigation';
|
|
@@ -127,8 +127,6 @@ function DualPrice({
|
|
|
127
127
|
const CHIP_TONES = {
|
|
128
128
|
"overlay-dark": { dot: "text-white/30", text: "text-white/65" },
|
|
129
129
|
card: { dot: "text-muted-foreground/50", text: "text-muted-foreground" },
|
|
130
|
-
/** Same solid color as the primary USD figure — for cards that want a
|
|
131
|
-
* single consistent shade instead of a muted secondary currency. */
|
|
132
130
|
solid: { dot: "text-foreground/40", text: "text-foreground" }
|
|
133
131
|
};
|
|
134
132
|
function PriceChipContent({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/dual-price.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { formatDisplayPrice, isStableCurrency } from \"../utils/format.js\";\n\nexport function CoinChip({ symbol, size }: { symbol: string | null | undefined; size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06]\"\n style={{ width: size + 10, height: size + 10 }}\n >\n <CurrencyIcon symbol={symbol ?? \"\"} size={size} />\n </span>\n );\n}\n\nfunction FiatChip({ size }: { size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06] font-extrabold leading-none text-foreground/80\"\n style={{ width: size + 10, height: size + 10, fontSize: size }}\n >\n $\n </span>\n );\n}\n\nfunction stripDollarSign(usdValue: string): string {\n return usdValue.replace(\"$\", \"\");\n}\n\nconst DISPLAY_FACE = \"font-extrabold tracking-tight tabular-nums\";\n\nconst DUAL_PRICE_SCALES = {\n\n hero: { amount: \"text-3xl\", chip: 18, stableChip: 14, divider: \"h-7\", showLabel: true },\n\n card: { amount: \"text-base\", chip: 13, stableChip: 10, divider: \"h-4\", showLabel: false },\n} as const;\n\nfunction PriceUnit({\n chip,\n amount,\n label,\n amountClassName,\n}: {\n chip: ReactNode;\n amount: string;\n label?: string;\n amountClassName: string;\n}) {\n return (\n <span className=\"inline-flex items-center gap-1.5\">\n {chip}\n <span className=\"flex items-baseline gap-1.5\">\n <span className={amountClassName}>{amount}</span>\n {label && <span className=\"text-sm font-semibold text-muted-foreground/70\">{label}</span>}\n </span>\n </span>\n );\n}\n\nexport function DualPrice({\n amountFormatted,\n currency,\n usdValue,\n scale,\n trailing,\n secondaryClassName,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n scale: keyof typeof DUAL_PRICE_SCALES;\n trailing?: ReactNode;\n secondaryClassName?: string;\n}) {\n if (!amountFormatted) return null;\n const s = DUAL_PRICE_SCALES[scale];\n const cryptoDisplay = formatDisplayPrice(amountFormatted);\n const amountClass = `${DISPLAY_FACE} ${s.amount}`;\n\n if (!usdValue) {\n return (\n <div className=\"flex items-center gap-2.5\">\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n }\n\n const stable = isStableCurrency(currency);\n return (\n <div className=\"flex items-center gap-2.5\">\n <PriceUnit\n chip={<FiatChip size={s.chip} />}\n amount={stripDollarSign(usdValue)}\n label={s.showLabel ? \"USD\" : undefined}\n amountClassName={amountClass}\n />\n <span className={`items-center gap-2.5 ${secondaryClassName ?? \"flex\"}`}>\n {!stable && <span className={`${s.divider} w-px bg-border/60 shrink-0`} />}\n {stable ? (\n <span className=\"inline-flex items-center gap-1.5\">\n <CoinChip symbol={currency} size={s.stableChip} />\n <span className=\"text-sm font-semibold text-muted-foreground\">{currency}</span>\n </span>\n ) : (\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\n )}\n </span>\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n}\n\nconst CHIP_TONES = {\n\n \"overlay-dark\": { dot: \"text-white/30\", text: \"text-white/65\" },\n\n card: { dot: \"text-muted-foreground/50\", text: \"text-muted-foreground\" },\n\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/dual-price.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { formatDisplayPrice, isStableCurrency } from \"../utils/format.js\";\n\nexport function CoinChip({ symbol, size }: { symbol: string | null | undefined; size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06]\"\n style={{ width: size + 10, height: size + 10 }}\n >\n <CurrencyIcon symbol={symbol ?? \"\"} size={size} />\n </span>\n );\n}\n\nfunction FiatChip({ size }: { size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06] font-extrabold leading-none text-foreground/80\"\n style={{ width: size + 10, height: size + 10, fontSize: size }}\n >\n $\n </span>\n );\n}\n\nfunction stripDollarSign(usdValue: string): string {\n return usdValue.replace(\"$\", \"\");\n}\n\nconst DISPLAY_FACE = \"font-extrabold tracking-tight tabular-nums\";\n\nconst DUAL_PRICE_SCALES = {\n\n hero: { amount: \"text-3xl\", chip: 18, stableChip: 14, divider: \"h-7\", showLabel: true },\n\n card: { amount: \"text-base\", chip: 13, stableChip: 10, divider: \"h-4\", showLabel: false },\n} as const;\n\nfunction PriceUnit({\n chip,\n amount,\n label,\n amountClassName,\n}: {\n chip: ReactNode;\n amount: string;\n label?: string;\n amountClassName: string;\n}) {\n return (\n <span className=\"inline-flex items-center gap-1.5\">\n {chip}\n <span className=\"flex items-baseline gap-1.5\">\n <span className={amountClassName}>{amount}</span>\n {label && <span className=\"text-sm font-semibold text-muted-foreground/70\">{label}</span>}\n </span>\n </span>\n );\n}\n\nexport function DualPrice({\n amountFormatted,\n currency,\n usdValue,\n scale,\n trailing,\n secondaryClassName,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n scale: keyof typeof DUAL_PRICE_SCALES;\n trailing?: ReactNode;\n secondaryClassName?: string;\n}) {\n if (!amountFormatted) return null;\n const s = DUAL_PRICE_SCALES[scale];\n const cryptoDisplay = formatDisplayPrice(amountFormatted);\n const amountClass = `${DISPLAY_FACE} ${s.amount}`;\n\n if (!usdValue) {\n return (\n <div className=\"flex items-center gap-2.5\">\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n }\n\n const stable = isStableCurrency(currency);\n return (\n <div className=\"flex items-center gap-2.5\">\n <PriceUnit\n chip={<FiatChip size={s.chip} />}\n amount={stripDollarSign(usdValue)}\n label={s.showLabel ? \"USD\" : undefined}\n amountClassName={amountClass}\n />\n <span className={`items-center gap-2.5 ${secondaryClassName ?? \"flex\"}`}>\n {!stable && <span className={`${s.divider} w-px bg-border/60 shrink-0`} />}\n {stable ? (\n <span className=\"inline-flex items-center gap-1.5\">\n <CoinChip symbol={currency} size={s.stableChip} />\n <span className=\"text-sm font-semibold text-muted-foreground\">{currency}</span>\n </span>\n ) : (\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\n )}\n </span>\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n}\n\nconst CHIP_TONES = {\n\n \"overlay-dark\": { dot: \"text-white/30\", text: \"text-white/65\" },\n\n card: { dot: \"text-muted-foreground/50\", text: \"text-muted-foreground\" },\n\n solid: { dot: \"text-foreground/40\", text: \"text-foreground\" },\n} as const;\n\nexport function PriceChipContent({\n amountFormatted,\n currency,\n usdValue,\n tone,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n tone: keyof typeof CHIP_TONES;\n}) {\n if (!amountFormatted) return null;\n const cryptoDisplay = formatDisplayPrice(amountFormatted);\n const stable = isStableCurrency(currency);\n\n if (!usdValue) {\n return (\n <>\n {currency && <CurrencyIcon symbol={currency} size={13} />}\n {cryptoDisplay}\n </>\n );\n }\n\n const t = CHIP_TONES[tone];\n return (\n <>\n {stripDollarSign(usdValue)}\n <span className={`font-semibold ${t.text}`}>USD</span>\n <span className={t.dot}>·</span>\n <span className={`inline-flex items-center gap-1 font-semibold ${t.text}`}>\n {currency && <CurrencyIcon symbol={currency} size={12} />}\n {stable ? currency : cryptoDisplay}\n </span>\n </>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -38,8 +38,6 @@ declare const CHIP_TONES: {
|
|
|
38
38
|
readonly dot: "text-muted-foreground/50";
|
|
39
39
|
readonly text: "text-muted-foreground";
|
|
40
40
|
};
|
|
41
|
-
/** Same solid color as the primary USD figure — for cards that want a
|
|
42
|
-
* single consistent shade instead of a muted secondary currency. */
|
|
43
41
|
readonly solid: {
|
|
44
42
|
readonly dot: "text-foreground/40";
|
|
45
43
|
readonly text: "text-foreground";
|
|
@@ -38,8 +38,6 @@ declare const CHIP_TONES: {
|
|
|
38
38
|
readonly dot: "text-muted-foreground/50";
|
|
39
39
|
readonly text: "text-muted-foreground";
|
|
40
40
|
};
|
|
41
|
-
/** Same solid color as the primary USD figure — for cards that want a
|
|
42
|
-
* single consistent shade instead of a muted secondary currency. */
|
|
43
41
|
readonly solid: {
|
|
44
42
|
readonly dot: "text-foreground/40";
|
|
45
43
|
readonly text: "text-foreground";
|
|
@@ -102,8 +102,6 @@ function DualPrice({
|
|
|
102
102
|
const CHIP_TONES = {
|
|
103
103
|
"overlay-dark": { dot: "text-white/30", text: "text-white/65" },
|
|
104
104
|
card: { dot: "text-muted-foreground/50", text: "text-muted-foreground" },
|
|
105
|
-
/** Same solid color as the primary USD figure — for cards that want a
|
|
106
|
-
* single consistent shade instead of a muted secondary currency. */
|
|
107
105
|
solid: { dot: "text-foreground/40", text: "text-foreground" }
|
|
108
106
|
};
|
|
109
107
|
function PriceChipContent({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/dual-price.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { formatDisplayPrice, isStableCurrency } from \"../utils/format.js\";\n\nexport function CoinChip({ symbol, size }: { symbol: string | null | undefined; size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06]\"\n style={{ width: size + 10, height: size + 10 }}\n >\n <CurrencyIcon symbol={symbol ?? \"\"} size={size} />\n </span>\n );\n}\n\nfunction FiatChip({ size }: { size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06] font-extrabold leading-none text-foreground/80\"\n style={{ width: size + 10, height: size + 10, fontSize: size }}\n >\n $\n </span>\n );\n}\n\nfunction stripDollarSign(usdValue: string): string {\n return usdValue.replace(\"$\", \"\");\n}\n\nconst DISPLAY_FACE = \"font-extrabold tracking-tight tabular-nums\";\n\nconst DUAL_PRICE_SCALES = {\n\n hero: { amount: \"text-3xl\", chip: 18, stableChip: 14, divider: \"h-7\", showLabel: true },\n\n card: { amount: \"text-base\", chip: 13, stableChip: 10, divider: \"h-4\", showLabel: false },\n} as const;\n\nfunction PriceUnit({\n chip,\n amount,\n label,\n amountClassName,\n}: {\n chip: ReactNode;\n amount: string;\n label?: string;\n amountClassName: string;\n}) {\n return (\n <span className=\"inline-flex items-center gap-1.5\">\n {chip}\n <span className=\"flex items-baseline gap-1.5\">\n <span className={amountClassName}>{amount}</span>\n {label && <span className=\"text-sm font-semibold text-muted-foreground/70\">{label}</span>}\n </span>\n </span>\n );\n}\n\nexport function DualPrice({\n amountFormatted,\n currency,\n usdValue,\n scale,\n trailing,\n secondaryClassName,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n scale: keyof typeof DUAL_PRICE_SCALES;\n trailing?: ReactNode;\n secondaryClassName?: string;\n}) {\n if (!amountFormatted) return null;\n const s = DUAL_PRICE_SCALES[scale];\n const cryptoDisplay = formatDisplayPrice(amountFormatted);\n const amountClass = `${DISPLAY_FACE} ${s.amount}`;\n\n if (!usdValue) {\n return (\n <div className=\"flex items-center gap-2.5\">\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n }\n\n const stable = isStableCurrency(currency);\n return (\n <div className=\"flex items-center gap-2.5\">\n <PriceUnit\n chip={<FiatChip size={s.chip} />}\n amount={stripDollarSign(usdValue)}\n label={s.showLabel ? \"USD\" : undefined}\n amountClassName={amountClass}\n />\n <span className={`items-center gap-2.5 ${secondaryClassName ?? \"flex\"}`}>\n {!stable && <span className={`${s.divider} w-px bg-border/60 shrink-0`} />}\n {stable ? (\n <span className=\"inline-flex items-center gap-1.5\">\n <CoinChip symbol={currency} size={s.stableChip} />\n <span className=\"text-sm font-semibold text-muted-foreground\">{currency}</span>\n </span>\n ) : (\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\n )}\n </span>\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n}\n\nconst CHIP_TONES = {\n\n \"overlay-dark\": { dot: \"text-white/30\", text: \"text-white/65\" },\n\n card: { dot: \"text-muted-foreground/50\", text: \"text-muted-foreground\" },\n\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/dual-price.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { formatDisplayPrice, isStableCurrency } from \"../utils/format.js\";\n\nexport function CoinChip({ symbol, size }: { symbol: string | null | undefined; size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06]\"\n style={{ width: size + 10, height: size + 10 }}\n >\n <CurrencyIcon symbol={symbol ?? \"\"} size={size} />\n </span>\n );\n}\n\nfunction FiatChip({ size }: { size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06] font-extrabold leading-none text-foreground/80\"\n style={{ width: size + 10, height: size + 10, fontSize: size }}\n >\n $\n </span>\n );\n}\n\nfunction stripDollarSign(usdValue: string): string {\n return usdValue.replace(\"$\", \"\");\n}\n\nconst DISPLAY_FACE = \"font-extrabold tracking-tight tabular-nums\";\n\nconst DUAL_PRICE_SCALES = {\n\n hero: { amount: \"text-3xl\", chip: 18, stableChip: 14, divider: \"h-7\", showLabel: true },\n\n card: { amount: \"text-base\", chip: 13, stableChip: 10, divider: \"h-4\", showLabel: false },\n} as const;\n\nfunction PriceUnit({\n chip,\n amount,\n label,\n amountClassName,\n}: {\n chip: ReactNode;\n amount: string;\n label?: string;\n amountClassName: string;\n}) {\n return (\n <span className=\"inline-flex items-center gap-1.5\">\n {chip}\n <span className=\"flex items-baseline gap-1.5\">\n <span className={amountClassName}>{amount}</span>\n {label && <span className=\"text-sm font-semibold text-muted-foreground/70\">{label}</span>}\n </span>\n </span>\n );\n}\n\nexport function DualPrice({\n amountFormatted,\n currency,\n usdValue,\n scale,\n trailing,\n secondaryClassName,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n scale: keyof typeof DUAL_PRICE_SCALES;\n trailing?: ReactNode;\n secondaryClassName?: string;\n}) {\n if (!amountFormatted) return null;\n const s = DUAL_PRICE_SCALES[scale];\n const cryptoDisplay = formatDisplayPrice(amountFormatted);\n const amountClass = `${DISPLAY_FACE} ${s.amount}`;\n\n if (!usdValue) {\n return (\n <div className=\"flex items-center gap-2.5\">\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n }\n\n const stable = isStableCurrency(currency);\n return (\n <div className=\"flex items-center gap-2.5\">\n <PriceUnit\n chip={<FiatChip size={s.chip} />}\n amount={stripDollarSign(usdValue)}\n label={s.showLabel ? \"USD\" : undefined}\n amountClassName={amountClass}\n />\n <span className={`items-center gap-2.5 ${secondaryClassName ?? \"flex\"}`}>\n {!stable && <span className={`${s.divider} w-px bg-border/60 shrink-0`} />}\n {stable ? (\n <span className=\"inline-flex items-center gap-1.5\">\n <CoinChip symbol={currency} size={s.stableChip} />\n <span className=\"text-sm font-semibold text-muted-foreground\">{currency}</span>\n </span>\n ) : (\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\n )}\n </span>\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n}\n\nconst CHIP_TONES = {\n\n \"overlay-dark\": { dot: \"text-white/30\", text: \"text-white/65\" },\n\n card: { dot: \"text-muted-foreground/50\", text: \"text-muted-foreground\" },\n\n solid: { dot: \"text-foreground/40\", text: \"text-foreground\" },\n} as const;\n\nexport function PriceChipContent({\n amountFormatted,\n currency,\n usdValue,\n tone,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n tone: keyof typeof CHIP_TONES;\n}) {\n if (!amountFormatted) return null;\n const cryptoDisplay = formatDisplayPrice(amountFormatted);\n const stable = isStableCurrency(currency);\n\n if (!usdValue) {\n return (\n <>\n {currency && <CurrencyIcon symbol={currency} size={13} />}\n {cryptoDisplay}\n </>\n );\n }\n\n const t = CHIP_TONES[tone];\n return (\n <>\n {stripDollarSign(usdValue)}\n <span className={`font-semibold ${t.text}`}>USD</span>\n <span className={t.dot}>·</span>\n <span className={`inline-flex items-center gap-1 font-semibold ${t.text}`}>\n {currency && <CurrencyIcon symbol={currency} size={12} />}\n {stable ? currency : cryptoDisplay}\n </span>\n </>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
3
|
import { FastMintProps } from './types.cjs';
|
|
4
4
|
import 'starknet';
|
|
5
5
|
import '@medialane/sdk';
|
|
6
6
|
import '@medialane/sdk/starknet';
|
|
7
7
|
|
|
8
|
-
declare function FastMint(props: FastMintProps): string | number | bigint | boolean |
|
|
8
|
+
declare function FastMint(props: FastMintProps): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
|
|
9
9
|
|
|
10
10
|
export { FastMint };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
3
|
import { FastMintProps } from './types.js';
|
|
4
4
|
import 'starknet';
|
|
5
5
|
import '@medialane/sdk';
|
|
6
6
|
import '@medialane/sdk/starknet';
|
|
7
7
|
|
|
8
|
-
declare function FastMint(props: FastMintProps): string | number | bigint | boolean |
|
|
8
|
+
declare function FastMint(props: FastMintProps): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
|
|
9
9
|
|
|
10
10
|
export { FastMint };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/image.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../src/components/image.tsx"],"sourcesContent":["export { default } from \"next/image\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAwB;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/image.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../src/components/image.tsx"],"sourcesContent":["export { default } from \"next/image\";\n"],"mappings":"AAAA,SAAS,WAAAA,gBAAe;","names":["default"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/ip-type-fields.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { IPType } from \"../data/ip.js\";\nimport {\n IP_TEMPLATES,\n EMBED_PLATFORM_META,\n SOCIAL_PLATFORM_META,\n type TraitSuggestion,\n} from \"../data/ip-templates.js\";\nimport { Label } from \"./label.js\";\nimport { Input } from \"./input.js\";\nimport { Button } from \"./button.js\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"./select.js\";\nimport { Check, FileText, FileUp, Loader2, Plus, Trash2, X } from \"lucide-react\";\n\nexport type MetadataField = {\n traitType: string;\n value: string;\n};\n\ntype TraitRow = {\n id: string;\n key: string;\n value: string;\n options?: string[];\n};\n\nconst createId = () =>\n globalThis.crypto?.randomUUID?.() ?? `trait-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\nconst looksLikeUrl = (v: string) => /^https?:\\/\\/\\S+/i.test(v.trim());\n\nexport interface IPTypeFieldsProps {\n ipType: IPType | null;\n onChange: (fields: MetadataField[]) => void;\n\n uploadDocument?: (file: File) => Promise<string>;\n\n /**\n * When the primary asset being minted is already the document this IP\n * type would otherwise ask to upload (e.g. a Documents/Publications type\n * whose main file is a PDF), pass it here to skip the redundant picker\n * and show it as already attached instead.\n */\n existingDocument?: { uri: string; name: string } | null;\n}\n\nexport function IPTypeFields({ ipType, onChange, uploadDocument, existingDocument }: IPTypeFieldsProps) {\n const template = ipType ? IP_TEMPLATES[ipType] : null;\n\n const [embedValues, setEmbedValues] = useState<Record<string, string>>({});\n const [socialValues, setSocialValues] = useState<Record<string, string>>({});\n\n const [traits, setTraits] = useState<TraitRow[]>([]);\n\n const [docUri, setDocUri] = useState<string | null>(null);\n const [docName, setDocName] = useState<string | null>(null);\n const [docUploading, setDocUploading] = useState(false);\n const [docError, setDocError] = useState<string | null>(null);\n const docInputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n setEmbedValues({});\n setSocialValues({});\n setDocUri(null);\n setDocName(null);\n setDocError(null);\n }, [ipType]);\n\n const effectiveDocUri = existingDocument?.uri ?? docUri;\n const effectiveDocName = existingDocument?.name ?? docName;\n\n const docTraitType = template?.docUpload?.traitType ?? null;\n\n const metadataFields = useMemo(() => {\n const fields: MetadataField[] = [];\n const seen = new Set<string>();\n const add = (traitType: string, value: string) => {\n const t = traitType.trim();\n const v = value.trim();\n const k = t.toLowerCase();\n if (!t || !v || seen.has(k)) return;\n seen.add(k);\n fields.push({ traitType: t, value: v });\n };\n if (docTraitType && effectiveDocUri) add(docTraitType, effectiveDocUri);\n Object.entries(embedValues).forEach(([key, value]) => add(key, value));\n Object.entries(socialValues).forEach(([key, value]) => add(key, value));\n traits.forEach((row) => add(row.key, row.value));\n return fields;\n }, [embedValues, socialValues, traits, docTraitType, effectiveDocUri]);\n\n useEffect(() => {\n onChange(metadataFields);\n }, [metadataFields, onChange]);\n\n const addedKeys = useMemo(\n () => new Set(traits.map((t) => t.key.trim().toLowerCase())),\n [traits]\n );\n\n const addSuggestion = (s: TraitSuggestion) => {\n setTraits((cur) => [\n ...cur,\n { id: createId(), key: s.key, value: \"\", options: s.options },\n ]);\n };\n const addCustomTrait = () =>\n setTraits((cur) => [...cur, { id: createId(), key: \"\", value: \"\" }]);\n const updateTrait = (id: string, patch: Partial<TraitRow>) =>\n setTraits((cur) => cur.map((t) => (t.id === id ? { ...t, ...patch } : t)));\n const removeTrait = (id: string) =>\n setTraits((cur) => cur.filter((t) => t.id !== id));\n\n if (!template) return null;\n\n const Icon = template.icon;\n const docUpload = template.docUpload;\n\n const handleDocPick = async (file: File) => {\n if (!uploadDocument || !docUpload) return;\n if (file.size > docUpload.maxMb * 1024 * 1024) {\n setDocError(`File must be under ${docUpload.maxMb} MB`);\n return;\n }\n setDocError(null);\n setDocUploading(true);\n try {\n const uri = await uploadDocument(file);\n setDocUri(uri);\n setDocName(file.name);\n } catch (err) {\n setDocError(err instanceof Error ? err.message : \"Document upload failed\");\n } finally {\n setDocUploading(false);\n if (docInputRef.current) docInputRef.current.value = \"\";\n }\n };\n\n const clearDoc = () => {\n setDocUri(null);\n setDocName(null);\n setDocError(null);\n };\n\n return (\n <div className=\"space-y-5\">\n <div className=\"flex items-center gap-2\">\n <Icon className={`h-4 w-4 ${template.color.text}`} />\n <p className=\"text-sm font-semibold\">{template.label} Details</p>\n </div>\n\n {docUpload && (uploadDocument || existingDocument) && (\n <section className=\"space-y-2\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">\n Document\n </p>\n {existingDocument ? (\n <div className=\"flex items-center gap-3 rounded-xl border border-emerald-500/30 bg-emerald-500/5 px-4 py-3\">\n <FileText className=\"h-5 w-5 text-emerald-500 shrink-0\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{effectiveDocName}</p>\n <p className=\"text-xs text-muted-foreground\">Already attached as your uploaded file</p>\n </div>\n </div>\n ) : docUri ? (\n <div className=\"flex items-center gap-3 rounded-xl border border-emerald-500/30 bg-emerald-500/5 px-4 py-3\">\n <FileText className=\"h-5 w-5 text-emerald-500 shrink-0\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{docName}</p>\n <p className=\"text-xs text-muted-foreground truncate\">{docUri}</p>\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 shrink-0 text-muted-foreground hover:text-destructive\"\n onClick={clearDoc}\n aria-label=\"Remove document\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ) : (\n <div className=\"space-y-1.5\">\n <input\n ref={docInputRef}\n type=\"file\"\n accept={docUpload.accept}\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) void handleDocPick(f);\n }}\n />\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={docUploading}\n onClick={() => docInputRef.current?.click()}\n >\n {docUploading ? (\n <>\n <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" />\n Uploading…\n </>\n ) : (\n <>\n <FileUp className=\"mr-1.5 h-3.5 w-3.5\" />\n Upload document\n </>\n )}\n </Button>\n {docError && <p className=\"text-xs text-destructive\">{docError}</p>}\n <p className=\"text-xs text-muted-foreground leading-relaxed\">{docUpload.hint}</p>\n </div>\n )}\n </section>\n )}\n\n {template.embeds && template.embeds.length > 0 && (\n <section className=\"space-y-3\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">Embeds</p>\n {template.embeds.map((platform) => {\n const meta = EMBED_PLATFORM_META[platform];\n const PIcon = meta.icon;\n const value = embedValues[meta.traitKey] ?? \"\";\n return (\n <div key={platform} className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <PIcon className=\"h-3.5 w-3.5\" />\n {meta.label}\n {looksLikeUrl(value) && (\n <span className=\"ml-1 inline-flex items-center gap-0.5 text-[10px] font-medium text-emerald-400\">\n <Check className=\"h-3 w-3\" /> connected\n </span>\n )}\n </Label>\n <Input\n type=\"url\"\n inputMode=\"url\"\n placeholder={meta.placeholder}\n value={value}\n onChange={(e) =>\n setEmbedValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value }))\n }\n className=\"h-10 text-sm\"\n />\n </div>\n );\n })}\n </section>\n )}\n\n {template.socials && template.socials.length > 0 && (\n <section className=\"space-y-3\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">Social links</p>\n {template.socials.map((platform) => {\n const meta = SOCIAL_PLATFORM_META[platform];\n const PIcon = meta.icon;\n const value = socialValues[meta.traitKey] ?? \"\";\n return (\n <div key={platform} className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <PIcon className=\"h-3.5 w-3.5\" />\n {meta.label}\n </Label>\n <Input\n type=\"url\"\n inputMode=\"url\"\n placeholder={meta.placeholder}\n value={value}\n onChange={(e) =>\n setSocialValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value }))\n }\n className=\"h-10 text-sm\"\n />\n </div>\n );\n })}\n </section>\n )}\n\n <section className=\"space-y-3 border-t border-border/60 pt-4\">\n <p className=\"text-sm font-semibold\">Traits</p>\n\n {template.traitSuggestions && template.traitSuggestions.length > 0 && (\n <div className=\"flex flex-wrap gap-2\">\n {template.traitSuggestions\n .filter((s) => !addedKeys.has(s.key.toLowerCase()))\n .map((s) => (\n <button\n key={s.key}\n type=\"button\"\n onClick={() => addSuggestion(s)}\n className=\"inline-flex items-center gap-1 rounded-full border border-border bg-muted/40 px-3 py-1 text-xs font-medium text-muted-foreground transition-colors hover:border-primary/40 hover:text-foreground\"\n >\n <Plus className=\"h-3 w-3\" />\n {s.key}\n </button>\n ))}\n </div>\n )}\n\n {traits.length > 0 && (\n <div className=\"space-y-2\">\n {traits.map((row) => (\n <div\n key={row.id}\n className=\"grid grid-cols-[1fr_1fr_auto] items-center gap-2\"\n >\n <Input\n value={row.key}\n onChange={(e) => updateTrait(row.id, { key: e.target.value })}\n placeholder=\"Trait name\"\n className=\"h-9 text-sm\"\n maxLength={64}\n />\n {row.options ? (\n <Select\n value={row.value}\n onValueChange={(v) => updateTrait(row.id, { value: v })}\n >\n <SelectTrigger className=\"h-9 text-sm\">\n <SelectValue placeholder=\"Value\" />\n </SelectTrigger>\n <SelectContent>\n {row.options.map((opt) => (\n <SelectItem key={opt} value={opt}>{opt}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : (\n <Input\n value={row.value}\n onChange={(e) => updateTrait(row.id, { value: e.target.value })}\n placeholder=\"Value\"\n className=\"h-9 text-sm\"\n maxLength={512}\n />\n )}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9 shrink-0 text-muted-foreground hover:text-destructive\"\n onClick={() => removeTrait(row.id)}\n aria-label=\"Remove trait\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n )}\n\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addCustomTrait}>\n <Plus className=\"mr-1.5 h-3.5 w-3.5\" />\n Add custom trait\n </Button>\n </section>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/ip-type-fields.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { IPType } from \"../data/ip.js\";\nimport {\n IP_TEMPLATES,\n EMBED_PLATFORM_META,\n SOCIAL_PLATFORM_META,\n type TraitSuggestion,\n} from \"../data/ip-templates.js\";\nimport { Label } from \"./label.js\";\nimport { Input } from \"./input.js\";\nimport { Button } from \"./button.js\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"./select.js\";\nimport { Check, FileText, FileUp, Loader2, Plus, Trash2, X } from \"lucide-react\";\n\nexport type MetadataField = {\n traitType: string;\n value: string;\n};\n\ntype TraitRow = {\n id: string;\n key: string;\n value: string;\n options?: string[];\n};\n\nconst createId = () =>\n globalThis.crypto?.randomUUID?.() ?? `trait-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\nconst looksLikeUrl = (v: string) => /^https?:\\/\\/\\S+/i.test(v.trim());\n\nexport interface IPTypeFieldsProps {\n ipType: IPType | null;\n onChange: (fields: MetadataField[]) => void;\n\n uploadDocument?: (file: File) => Promise<string>;\n\n existingDocument?: { uri: string; name: string } | null;\n}\n\nexport function IPTypeFields({ ipType, onChange, uploadDocument, existingDocument }: IPTypeFieldsProps) {\n const template = ipType ? IP_TEMPLATES[ipType] : null;\n\n const [embedValues, setEmbedValues] = useState<Record<string, string>>({});\n const [socialValues, setSocialValues] = useState<Record<string, string>>({});\n\n const [traits, setTraits] = useState<TraitRow[]>([]);\n\n const [docUri, setDocUri] = useState<string | null>(null);\n const [docName, setDocName] = useState<string | null>(null);\n const [docUploading, setDocUploading] = useState(false);\n const [docError, setDocError] = useState<string | null>(null);\n const docInputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n setEmbedValues({});\n setSocialValues({});\n setDocUri(null);\n setDocName(null);\n setDocError(null);\n }, [ipType]);\n\n const effectiveDocUri = existingDocument?.uri ?? docUri;\n const effectiveDocName = existingDocument?.name ?? docName;\n\n const docTraitType = template?.docUpload?.traitType ?? null;\n\n const metadataFields = useMemo(() => {\n const fields: MetadataField[] = [];\n const seen = new Set<string>();\n const add = (traitType: string, value: string) => {\n const t = traitType.trim();\n const v = value.trim();\n const k = t.toLowerCase();\n if (!t || !v || seen.has(k)) return;\n seen.add(k);\n fields.push({ traitType: t, value: v });\n };\n if (docTraitType && effectiveDocUri) add(docTraitType, effectiveDocUri);\n Object.entries(embedValues).forEach(([key, value]) => add(key, value));\n Object.entries(socialValues).forEach(([key, value]) => add(key, value));\n traits.forEach((row) => add(row.key, row.value));\n return fields;\n }, [embedValues, socialValues, traits, docTraitType, effectiveDocUri]);\n\n useEffect(() => {\n onChange(metadataFields);\n }, [metadataFields, onChange]);\n\n const addedKeys = useMemo(\n () => new Set(traits.map((t) => t.key.trim().toLowerCase())),\n [traits]\n );\n\n const addSuggestion = (s: TraitSuggestion) => {\n setTraits((cur) => [\n ...cur,\n { id: createId(), key: s.key, value: \"\", options: s.options },\n ]);\n };\n const addCustomTrait = () =>\n setTraits((cur) => [...cur, { id: createId(), key: \"\", value: \"\" }]);\n const updateTrait = (id: string, patch: Partial<TraitRow>) =>\n setTraits((cur) => cur.map((t) => (t.id === id ? { ...t, ...patch } : t)));\n const removeTrait = (id: string) =>\n setTraits((cur) => cur.filter((t) => t.id !== id));\n\n if (!template) return null;\n\n const Icon = template.icon;\n const docUpload = template.docUpload;\n\n const handleDocPick = async (file: File) => {\n if (!uploadDocument || !docUpload) return;\n if (file.size > docUpload.maxMb * 1024 * 1024) {\n setDocError(`File must be under ${docUpload.maxMb} MB`);\n return;\n }\n setDocError(null);\n setDocUploading(true);\n try {\n const uri = await uploadDocument(file);\n setDocUri(uri);\n setDocName(file.name);\n } catch (err) {\n setDocError(err instanceof Error ? err.message : \"Document upload failed\");\n } finally {\n setDocUploading(false);\n if (docInputRef.current) docInputRef.current.value = \"\";\n }\n };\n\n const clearDoc = () => {\n setDocUri(null);\n setDocName(null);\n setDocError(null);\n };\n\n return (\n <div className=\"space-y-5\">\n <div className=\"flex items-center gap-2\">\n <Icon className={`h-4 w-4 ${template.color.text}`} />\n <p className=\"text-sm font-semibold\">{template.label} Details</p>\n </div>\n\n {docUpload && (uploadDocument || existingDocument) && (\n <section className=\"space-y-2\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">\n Document\n </p>\n {existingDocument ? (\n <div className=\"flex items-center gap-3 rounded-xl border border-emerald-500/30 bg-emerald-500/5 px-4 py-3\">\n <FileText className=\"h-5 w-5 text-emerald-500 shrink-0\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{effectiveDocName}</p>\n <p className=\"text-xs text-muted-foreground\">Already attached as your uploaded file</p>\n </div>\n </div>\n ) : docUri ? (\n <div className=\"flex items-center gap-3 rounded-xl border border-emerald-500/30 bg-emerald-500/5 px-4 py-3\">\n <FileText className=\"h-5 w-5 text-emerald-500 shrink-0\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{docName}</p>\n <p className=\"text-xs text-muted-foreground truncate\">{docUri}</p>\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 shrink-0 text-muted-foreground hover:text-destructive\"\n onClick={clearDoc}\n aria-label=\"Remove document\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ) : (\n <div className=\"space-y-1.5\">\n <input\n ref={docInputRef}\n type=\"file\"\n accept={docUpload.accept}\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) void handleDocPick(f);\n }}\n />\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={docUploading}\n onClick={() => docInputRef.current?.click()}\n >\n {docUploading ? (\n <>\n <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" />\n Uploading…\n </>\n ) : (\n <>\n <FileUp className=\"mr-1.5 h-3.5 w-3.5\" />\n Upload document\n </>\n )}\n </Button>\n {docError && <p className=\"text-xs text-destructive\">{docError}</p>}\n <p className=\"text-xs text-muted-foreground leading-relaxed\">{docUpload.hint}</p>\n </div>\n )}\n </section>\n )}\n\n {template.embeds && template.embeds.length > 0 && (\n <section className=\"space-y-3\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">Embeds</p>\n {template.embeds.map((platform) => {\n const meta = EMBED_PLATFORM_META[platform];\n const PIcon = meta.icon;\n const value = embedValues[meta.traitKey] ?? \"\";\n return (\n <div key={platform} className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <PIcon className=\"h-3.5 w-3.5\" />\n {meta.label}\n {looksLikeUrl(value) && (\n <span className=\"ml-1 inline-flex items-center gap-0.5 text-[10px] font-medium text-emerald-400\">\n <Check className=\"h-3 w-3\" /> connected\n </span>\n )}\n </Label>\n <Input\n type=\"url\"\n inputMode=\"url\"\n placeholder={meta.placeholder}\n value={value}\n onChange={(e) =>\n setEmbedValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value }))\n }\n className=\"h-10 text-sm\"\n />\n </div>\n );\n })}\n </section>\n )}\n\n {template.socials && template.socials.length > 0 && (\n <section className=\"space-y-3\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">Social links</p>\n {template.socials.map((platform) => {\n const meta = SOCIAL_PLATFORM_META[platform];\n const PIcon = meta.icon;\n const value = socialValues[meta.traitKey] ?? \"\";\n return (\n <div key={platform} className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <PIcon className=\"h-3.5 w-3.5\" />\n {meta.label}\n </Label>\n <Input\n type=\"url\"\n inputMode=\"url\"\n placeholder={meta.placeholder}\n value={value}\n onChange={(e) =>\n setSocialValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value }))\n }\n className=\"h-10 text-sm\"\n />\n </div>\n );\n })}\n </section>\n )}\n\n <section className=\"space-y-3 border-t border-border/60 pt-4\">\n <p className=\"text-sm font-semibold\">Traits</p>\n\n {template.traitSuggestions && template.traitSuggestions.length > 0 && (\n <div className=\"flex flex-wrap gap-2\">\n {template.traitSuggestions\n .filter((s) => !addedKeys.has(s.key.toLowerCase()))\n .map((s) => (\n <button\n key={s.key}\n type=\"button\"\n onClick={() => addSuggestion(s)}\n className=\"inline-flex items-center gap-1 rounded-full border border-border bg-muted/40 px-3 py-1 text-xs font-medium text-muted-foreground transition-colors hover:border-primary/40 hover:text-foreground\"\n >\n <Plus className=\"h-3 w-3\" />\n {s.key}\n </button>\n ))}\n </div>\n )}\n\n {traits.length > 0 && (\n <div className=\"space-y-2\">\n {traits.map((row) => (\n <div\n key={row.id}\n className=\"grid grid-cols-[1fr_1fr_auto] items-center gap-2\"\n >\n <Input\n value={row.key}\n onChange={(e) => updateTrait(row.id, { key: e.target.value })}\n placeholder=\"Trait name\"\n className=\"h-9 text-sm\"\n maxLength={64}\n />\n {row.options ? (\n <Select\n value={row.value}\n onValueChange={(v) => updateTrait(row.id, { value: v })}\n >\n <SelectTrigger className=\"h-9 text-sm\">\n <SelectValue placeholder=\"Value\" />\n </SelectTrigger>\n <SelectContent>\n {row.options.map((opt) => (\n <SelectItem key={opt} value={opt}>{opt}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : (\n <Input\n value={row.value}\n onChange={(e) => updateTrait(row.id, { value: e.target.value })}\n placeholder=\"Value\"\n className=\"h-9 text-sm\"\n maxLength={512}\n />\n )}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9 shrink-0 text-muted-foreground hover:text-destructive\"\n onClick={() => removeTrait(row.id)}\n aria-label=\"Remove trait\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n )}\n\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addCustomTrait}>\n <Plus className=\"mr-1.5 h-3.5 w-3.5\" />\n Add custom trait\n </Button>\n </section>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -9,12 +9,6 @@ interface IPTypeFieldsProps {
|
|
|
9
9
|
ipType: IPType | null;
|
|
10
10
|
onChange: (fields: MetadataField[]) => void;
|
|
11
11
|
uploadDocument?: (file: File) => Promise<string>;
|
|
12
|
-
/**
|
|
13
|
-
* When the primary asset being minted is already the document this IP
|
|
14
|
-
* type would otherwise ask to upload (e.g. a Documents/Publications type
|
|
15
|
-
* whose main file is a PDF), pass it here to skip the redundant picker
|
|
16
|
-
* and show it as already attached instead.
|
|
17
|
-
*/
|
|
18
12
|
existingDocument?: {
|
|
19
13
|
uri: string;
|
|
20
14
|
name: string;
|
|
@@ -9,12 +9,6 @@ interface IPTypeFieldsProps {
|
|
|
9
9
|
ipType: IPType | null;
|
|
10
10
|
onChange: (fields: MetadataField[]) => void;
|
|
11
11
|
uploadDocument?: (file: File) => Promise<string>;
|
|
12
|
-
/**
|
|
13
|
-
* When the primary asset being minted is already the document this IP
|
|
14
|
-
* type would otherwise ask to upload (e.g. a Documents/Publications type
|
|
15
|
-
* whose main file is a PDF), pass it here to skip the redundant picker
|
|
16
|
-
* and show it as already attached instead.
|
|
17
|
-
*/
|
|
18
12
|
existingDocument?: {
|
|
19
13
|
uri: string;
|
|
20
14
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/ip-type-fields.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { IPType } from \"../data/ip.js\";\nimport {\n IP_TEMPLATES,\n EMBED_PLATFORM_META,\n SOCIAL_PLATFORM_META,\n type TraitSuggestion,\n} from \"../data/ip-templates.js\";\nimport { Label } from \"./label.js\";\nimport { Input } from \"./input.js\";\nimport { Button } from \"./button.js\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"./select.js\";\nimport { Check, FileText, FileUp, Loader2, Plus, Trash2, X } from \"lucide-react\";\n\nexport type MetadataField = {\n traitType: string;\n value: string;\n};\n\ntype TraitRow = {\n id: string;\n key: string;\n value: string;\n options?: string[];\n};\n\nconst createId = () =>\n globalThis.crypto?.randomUUID?.() ?? `trait-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\nconst looksLikeUrl = (v: string) => /^https?:\\/\\/\\S+/i.test(v.trim());\n\nexport interface IPTypeFieldsProps {\n ipType: IPType | null;\n onChange: (fields: MetadataField[]) => void;\n\n uploadDocument?: (file: File) => Promise<string>;\n\n /**\n * When the primary asset being minted is already the document this IP\n * type would otherwise ask to upload (e.g. a Documents/Publications type\n * whose main file is a PDF), pass it here to skip the redundant picker\n * and show it as already attached instead.\n */\n existingDocument?: { uri: string; name: string } | null;\n}\n\nexport function IPTypeFields({ ipType, onChange, uploadDocument, existingDocument }: IPTypeFieldsProps) {\n const template = ipType ? IP_TEMPLATES[ipType] : null;\n\n const [embedValues, setEmbedValues] = useState<Record<string, string>>({});\n const [socialValues, setSocialValues] = useState<Record<string, string>>({});\n\n const [traits, setTraits] = useState<TraitRow[]>([]);\n\n const [docUri, setDocUri] = useState<string | null>(null);\n const [docName, setDocName] = useState<string | null>(null);\n const [docUploading, setDocUploading] = useState(false);\n const [docError, setDocError] = useState<string | null>(null);\n const docInputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n setEmbedValues({});\n setSocialValues({});\n setDocUri(null);\n setDocName(null);\n setDocError(null);\n }, [ipType]);\n\n const effectiveDocUri = existingDocument?.uri ?? docUri;\n const effectiveDocName = existingDocument?.name ?? docName;\n\n const docTraitType = template?.docUpload?.traitType ?? null;\n\n const metadataFields = useMemo(() => {\n const fields: MetadataField[] = [];\n const seen = new Set<string>();\n const add = (traitType: string, value: string) => {\n const t = traitType.trim();\n const v = value.trim();\n const k = t.toLowerCase();\n if (!t || !v || seen.has(k)) return;\n seen.add(k);\n fields.push({ traitType: t, value: v });\n };\n if (docTraitType && effectiveDocUri) add(docTraitType, effectiveDocUri);\n Object.entries(embedValues).forEach(([key, value]) => add(key, value));\n Object.entries(socialValues).forEach(([key, value]) => add(key, value));\n traits.forEach((row) => add(row.key, row.value));\n return fields;\n }, [embedValues, socialValues, traits, docTraitType, effectiveDocUri]);\n\n useEffect(() => {\n onChange(metadataFields);\n }, [metadataFields, onChange]);\n\n const addedKeys = useMemo(\n () => new Set(traits.map((t) => t.key.trim().toLowerCase())),\n [traits]\n );\n\n const addSuggestion = (s: TraitSuggestion) => {\n setTraits((cur) => [\n ...cur,\n { id: createId(), key: s.key, value: \"\", options: s.options },\n ]);\n };\n const addCustomTrait = () =>\n setTraits((cur) => [...cur, { id: createId(), key: \"\", value: \"\" }]);\n const updateTrait = (id: string, patch: Partial<TraitRow>) =>\n setTraits((cur) => cur.map((t) => (t.id === id ? { ...t, ...patch } : t)));\n const removeTrait = (id: string) =>\n setTraits((cur) => cur.filter((t) => t.id !== id));\n\n if (!template) return null;\n\n const Icon = template.icon;\n const docUpload = template.docUpload;\n\n const handleDocPick = async (file: File) => {\n if (!uploadDocument || !docUpload) return;\n if (file.size > docUpload.maxMb * 1024 * 1024) {\n setDocError(`File must be under ${docUpload.maxMb} MB`);\n return;\n }\n setDocError(null);\n setDocUploading(true);\n try {\n const uri = await uploadDocument(file);\n setDocUri(uri);\n setDocName(file.name);\n } catch (err) {\n setDocError(err instanceof Error ? err.message : \"Document upload failed\");\n } finally {\n setDocUploading(false);\n if (docInputRef.current) docInputRef.current.value = \"\";\n }\n };\n\n const clearDoc = () => {\n setDocUri(null);\n setDocName(null);\n setDocError(null);\n };\n\n return (\n <div className=\"space-y-5\">\n <div className=\"flex items-center gap-2\">\n <Icon className={`h-4 w-4 ${template.color.text}`} />\n <p className=\"text-sm font-semibold\">{template.label} Details</p>\n </div>\n\n {docUpload && (uploadDocument || existingDocument) && (\n <section className=\"space-y-2\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">\n Document\n </p>\n {existingDocument ? (\n <div className=\"flex items-center gap-3 rounded-xl border border-emerald-500/30 bg-emerald-500/5 px-4 py-3\">\n <FileText className=\"h-5 w-5 text-emerald-500 shrink-0\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{effectiveDocName}</p>\n <p className=\"text-xs text-muted-foreground\">Already attached as your uploaded file</p>\n </div>\n </div>\n ) : docUri ? (\n <div className=\"flex items-center gap-3 rounded-xl border border-emerald-500/30 bg-emerald-500/5 px-4 py-3\">\n <FileText className=\"h-5 w-5 text-emerald-500 shrink-0\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{docName}</p>\n <p className=\"text-xs text-muted-foreground truncate\">{docUri}</p>\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 shrink-0 text-muted-foreground hover:text-destructive\"\n onClick={clearDoc}\n aria-label=\"Remove document\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ) : (\n <div className=\"space-y-1.5\">\n <input\n ref={docInputRef}\n type=\"file\"\n accept={docUpload.accept}\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) void handleDocPick(f);\n }}\n />\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={docUploading}\n onClick={() => docInputRef.current?.click()}\n >\n {docUploading ? (\n <>\n <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" />\n Uploading…\n </>\n ) : (\n <>\n <FileUp className=\"mr-1.5 h-3.5 w-3.5\" />\n Upload document\n </>\n )}\n </Button>\n {docError && <p className=\"text-xs text-destructive\">{docError}</p>}\n <p className=\"text-xs text-muted-foreground leading-relaxed\">{docUpload.hint}</p>\n </div>\n )}\n </section>\n )}\n\n {template.embeds && template.embeds.length > 0 && (\n <section className=\"space-y-3\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">Embeds</p>\n {template.embeds.map((platform) => {\n const meta = EMBED_PLATFORM_META[platform];\n const PIcon = meta.icon;\n const value = embedValues[meta.traitKey] ?? \"\";\n return (\n <div key={platform} className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <PIcon className=\"h-3.5 w-3.5\" />\n {meta.label}\n {looksLikeUrl(value) && (\n <span className=\"ml-1 inline-flex items-center gap-0.5 text-[10px] font-medium text-emerald-400\">\n <Check className=\"h-3 w-3\" /> connected\n </span>\n )}\n </Label>\n <Input\n type=\"url\"\n inputMode=\"url\"\n placeholder={meta.placeholder}\n value={value}\n onChange={(e) =>\n setEmbedValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value }))\n }\n className=\"h-10 text-sm\"\n />\n </div>\n );\n })}\n </section>\n )}\n\n {template.socials && template.socials.length > 0 && (\n <section className=\"space-y-3\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">Social links</p>\n {template.socials.map((platform) => {\n const meta = SOCIAL_PLATFORM_META[platform];\n const PIcon = meta.icon;\n const value = socialValues[meta.traitKey] ?? \"\";\n return (\n <div key={platform} className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <PIcon className=\"h-3.5 w-3.5\" />\n {meta.label}\n </Label>\n <Input\n type=\"url\"\n inputMode=\"url\"\n placeholder={meta.placeholder}\n value={value}\n onChange={(e) =>\n setSocialValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value }))\n }\n className=\"h-10 text-sm\"\n />\n </div>\n );\n })}\n </section>\n )}\n\n <section className=\"space-y-3 border-t border-border/60 pt-4\">\n <p className=\"text-sm font-semibold\">Traits</p>\n\n {template.traitSuggestions && template.traitSuggestions.length > 0 && (\n <div className=\"flex flex-wrap gap-2\">\n {template.traitSuggestions\n .filter((s) => !addedKeys.has(s.key.toLowerCase()))\n .map((s) => (\n <button\n key={s.key}\n type=\"button\"\n onClick={() => addSuggestion(s)}\n className=\"inline-flex items-center gap-1 rounded-full border border-border bg-muted/40 px-3 py-1 text-xs font-medium text-muted-foreground transition-colors hover:border-primary/40 hover:text-foreground\"\n >\n <Plus className=\"h-3 w-3\" />\n {s.key}\n </button>\n ))}\n </div>\n )}\n\n {traits.length > 0 && (\n <div className=\"space-y-2\">\n {traits.map((row) => (\n <div\n key={row.id}\n className=\"grid grid-cols-[1fr_1fr_auto] items-center gap-2\"\n >\n <Input\n value={row.key}\n onChange={(e) => updateTrait(row.id, { key: e.target.value })}\n placeholder=\"Trait name\"\n className=\"h-9 text-sm\"\n maxLength={64}\n />\n {row.options ? (\n <Select\n value={row.value}\n onValueChange={(v) => updateTrait(row.id, { value: v })}\n >\n <SelectTrigger className=\"h-9 text-sm\">\n <SelectValue placeholder=\"Value\" />\n </SelectTrigger>\n <SelectContent>\n {row.options.map((opt) => (\n <SelectItem key={opt} value={opt}>{opt}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : (\n <Input\n value={row.value}\n onChange={(e) => updateTrait(row.id, { value: e.target.value })}\n placeholder=\"Value\"\n className=\"h-9 text-sm\"\n maxLength={512}\n />\n )}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9 shrink-0 text-muted-foreground hover:text-destructive\"\n onClick={() => removeTrait(row.id)}\n aria-label=\"Remove trait\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n )}\n\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addCustomTrait}>\n <Plus className=\"mr-1.5 h-3.5 w-3.5\" />\n Add custom trait\n </Button>\n </section>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/ip-type-fields.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { IPType } from \"../data/ip.js\";\nimport {\n IP_TEMPLATES,\n EMBED_PLATFORM_META,\n SOCIAL_PLATFORM_META,\n type TraitSuggestion,\n} from \"../data/ip-templates.js\";\nimport { Label } from \"./label.js\";\nimport { Input } from \"./input.js\";\nimport { Button } from \"./button.js\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"./select.js\";\nimport { Check, FileText, FileUp, Loader2, Plus, Trash2, X } from \"lucide-react\";\n\nexport type MetadataField = {\n traitType: string;\n value: string;\n};\n\ntype TraitRow = {\n id: string;\n key: string;\n value: string;\n options?: string[];\n};\n\nconst createId = () =>\n globalThis.crypto?.randomUUID?.() ?? `trait-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\nconst looksLikeUrl = (v: string) => /^https?:\\/\\/\\S+/i.test(v.trim());\n\nexport interface IPTypeFieldsProps {\n ipType: IPType | null;\n onChange: (fields: MetadataField[]) => void;\n\n uploadDocument?: (file: File) => Promise<string>;\n\n existingDocument?: { uri: string; name: string } | null;\n}\n\nexport function IPTypeFields({ ipType, onChange, uploadDocument, existingDocument }: IPTypeFieldsProps) {\n const template = ipType ? IP_TEMPLATES[ipType] : null;\n\n const [embedValues, setEmbedValues] = useState<Record<string, string>>({});\n const [socialValues, setSocialValues] = useState<Record<string, string>>({});\n\n const [traits, setTraits] = useState<TraitRow[]>([]);\n\n const [docUri, setDocUri] = useState<string | null>(null);\n const [docName, setDocName] = useState<string | null>(null);\n const [docUploading, setDocUploading] = useState(false);\n const [docError, setDocError] = useState<string | null>(null);\n const docInputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n setEmbedValues({});\n setSocialValues({});\n setDocUri(null);\n setDocName(null);\n setDocError(null);\n }, [ipType]);\n\n const effectiveDocUri = existingDocument?.uri ?? docUri;\n const effectiveDocName = existingDocument?.name ?? docName;\n\n const docTraitType = template?.docUpload?.traitType ?? null;\n\n const metadataFields = useMemo(() => {\n const fields: MetadataField[] = [];\n const seen = new Set<string>();\n const add = (traitType: string, value: string) => {\n const t = traitType.trim();\n const v = value.trim();\n const k = t.toLowerCase();\n if (!t || !v || seen.has(k)) return;\n seen.add(k);\n fields.push({ traitType: t, value: v });\n };\n if (docTraitType && effectiveDocUri) add(docTraitType, effectiveDocUri);\n Object.entries(embedValues).forEach(([key, value]) => add(key, value));\n Object.entries(socialValues).forEach(([key, value]) => add(key, value));\n traits.forEach((row) => add(row.key, row.value));\n return fields;\n }, [embedValues, socialValues, traits, docTraitType, effectiveDocUri]);\n\n useEffect(() => {\n onChange(metadataFields);\n }, [metadataFields, onChange]);\n\n const addedKeys = useMemo(\n () => new Set(traits.map((t) => t.key.trim().toLowerCase())),\n [traits]\n );\n\n const addSuggestion = (s: TraitSuggestion) => {\n setTraits((cur) => [\n ...cur,\n { id: createId(), key: s.key, value: \"\", options: s.options },\n ]);\n };\n const addCustomTrait = () =>\n setTraits((cur) => [...cur, { id: createId(), key: \"\", value: \"\" }]);\n const updateTrait = (id: string, patch: Partial<TraitRow>) =>\n setTraits((cur) => cur.map((t) => (t.id === id ? { ...t, ...patch } : t)));\n const removeTrait = (id: string) =>\n setTraits((cur) => cur.filter((t) => t.id !== id));\n\n if (!template) return null;\n\n const Icon = template.icon;\n const docUpload = template.docUpload;\n\n const handleDocPick = async (file: File) => {\n if (!uploadDocument || !docUpload) return;\n if (file.size > docUpload.maxMb * 1024 * 1024) {\n setDocError(`File must be under ${docUpload.maxMb} MB`);\n return;\n }\n setDocError(null);\n setDocUploading(true);\n try {\n const uri = await uploadDocument(file);\n setDocUri(uri);\n setDocName(file.name);\n } catch (err) {\n setDocError(err instanceof Error ? err.message : \"Document upload failed\");\n } finally {\n setDocUploading(false);\n if (docInputRef.current) docInputRef.current.value = \"\";\n }\n };\n\n const clearDoc = () => {\n setDocUri(null);\n setDocName(null);\n setDocError(null);\n };\n\n return (\n <div className=\"space-y-5\">\n <div className=\"flex items-center gap-2\">\n <Icon className={`h-4 w-4 ${template.color.text}`} />\n <p className=\"text-sm font-semibold\">{template.label} Details</p>\n </div>\n\n {docUpload && (uploadDocument || existingDocument) && (\n <section className=\"space-y-2\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">\n Document\n </p>\n {existingDocument ? (\n <div className=\"flex items-center gap-3 rounded-xl border border-emerald-500/30 bg-emerald-500/5 px-4 py-3\">\n <FileText className=\"h-5 w-5 text-emerald-500 shrink-0\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{effectiveDocName}</p>\n <p className=\"text-xs text-muted-foreground\">Already attached as your uploaded file</p>\n </div>\n </div>\n ) : docUri ? (\n <div className=\"flex items-center gap-3 rounded-xl border border-emerald-500/30 bg-emerald-500/5 px-4 py-3\">\n <FileText className=\"h-5 w-5 text-emerald-500 shrink-0\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{docName}</p>\n <p className=\"text-xs text-muted-foreground truncate\">{docUri}</p>\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 shrink-0 text-muted-foreground hover:text-destructive\"\n onClick={clearDoc}\n aria-label=\"Remove document\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ) : (\n <div className=\"space-y-1.5\">\n <input\n ref={docInputRef}\n type=\"file\"\n accept={docUpload.accept}\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) void handleDocPick(f);\n }}\n />\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={docUploading}\n onClick={() => docInputRef.current?.click()}\n >\n {docUploading ? (\n <>\n <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" />\n Uploading…\n </>\n ) : (\n <>\n <FileUp className=\"mr-1.5 h-3.5 w-3.5\" />\n Upload document\n </>\n )}\n </Button>\n {docError && <p className=\"text-xs text-destructive\">{docError}</p>}\n <p className=\"text-xs text-muted-foreground leading-relaxed\">{docUpload.hint}</p>\n </div>\n )}\n </section>\n )}\n\n {template.embeds && template.embeds.length > 0 && (\n <section className=\"space-y-3\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">Embeds</p>\n {template.embeds.map((platform) => {\n const meta = EMBED_PLATFORM_META[platform];\n const PIcon = meta.icon;\n const value = embedValues[meta.traitKey] ?? \"\";\n return (\n <div key={platform} className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <PIcon className=\"h-3.5 w-3.5\" />\n {meta.label}\n {looksLikeUrl(value) && (\n <span className=\"ml-1 inline-flex items-center gap-0.5 text-[10px] font-medium text-emerald-400\">\n <Check className=\"h-3 w-3\" /> connected\n </span>\n )}\n </Label>\n <Input\n type=\"url\"\n inputMode=\"url\"\n placeholder={meta.placeholder}\n value={value}\n onChange={(e) =>\n setEmbedValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value }))\n }\n className=\"h-10 text-sm\"\n />\n </div>\n );\n })}\n </section>\n )}\n\n {template.socials && template.socials.length > 0 && (\n <section className=\"space-y-3\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">Social links</p>\n {template.socials.map((platform) => {\n const meta = SOCIAL_PLATFORM_META[platform];\n const PIcon = meta.icon;\n const value = socialValues[meta.traitKey] ?? \"\";\n return (\n <div key={platform} className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <PIcon className=\"h-3.5 w-3.5\" />\n {meta.label}\n </Label>\n <Input\n type=\"url\"\n inputMode=\"url\"\n placeholder={meta.placeholder}\n value={value}\n onChange={(e) =>\n setSocialValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value }))\n }\n className=\"h-10 text-sm\"\n />\n </div>\n );\n })}\n </section>\n )}\n\n <section className=\"space-y-3 border-t border-border/60 pt-4\">\n <p className=\"text-sm font-semibold\">Traits</p>\n\n {template.traitSuggestions && template.traitSuggestions.length > 0 && (\n <div className=\"flex flex-wrap gap-2\">\n {template.traitSuggestions\n .filter((s) => !addedKeys.has(s.key.toLowerCase()))\n .map((s) => (\n <button\n key={s.key}\n type=\"button\"\n onClick={() => addSuggestion(s)}\n className=\"inline-flex items-center gap-1 rounded-full border border-border bg-muted/40 px-3 py-1 text-xs font-medium text-muted-foreground transition-colors hover:border-primary/40 hover:text-foreground\"\n >\n <Plus className=\"h-3 w-3\" />\n {s.key}\n </button>\n ))}\n </div>\n )}\n\n {traits.length > 0 && (\n <div className=\"space-y-2\">\n {traits.map((row) => (\n <div\n key={row.id}\n className=\"grid grid-cols-[1fr_1fr_auto] items-center gap-2\"\n >\n <Input\n value={row.key}\n onChange={(e) => updateTrait(row.id, { key: e.target.value })}\n placeholder=\"Trait name\"\n className=\"h-9 text-sm\"\n maxLength={64}\n />\n {row.options ? (\n <Select\n value={row.value}\n onValueChange={(v) => updateTrait(row.id, { value: v })}\n >\n <SelectTrigger className=\"h-9 text-sm\">\n <SelectValue placeholder=\"Value\" />\n </SelectTrigger>\n <SelectContent>\n {row.options.map((opt) => (\n <SelectItem key={opt} value={opt}>{opt}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : (\n <Input\n value={row.value}\n onChange={(e) => updateTrait(row.id, { value: e.target.value })}\n placeholder=\"Value\"\n className=\"h-9 text-sm\"\n maxLength={512}\n />\n )}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9 shrink-0 text-muted-foreground hover:text-destructive\"\n onClick={() => removeTrait(row.id)}\n aria-label=\"Remove trait\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n )}\n\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addCustomTrait}>\n <Plus className=\"mr-1.5 h-3.5 w-3.5\" />\n Add custom trait\n </Button>\n </section>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/launchpad-cta-banner.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { ArrowRight, ExternalLink } from \"lucide-react\";\nimport Link from \"./link.js\";\nimport { Button } from \"./button.js\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface LaunchpadCtaBannerProps {\n eyebrow: string;\n title: string;\n description: string;\n href: string;\n ctaLabel: string;\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/launchpad-cta-banner.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { ArrowRight, ExternalLink } from \"lucide-react\";\nimport Link from \"./link.js\";\nimport { Button } from \"./button.js\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface LaunchpadCtaBannerProps {\n eyebrow: string;\n title: string;\n description: string;\n href: string;\n ctaLabel: string;\n\n external?: boolean;\n\n tone?: \"primary\" | \"manage\";\n className?: string;\n}\n\nconst TONE_GRADIENT: Record<NonNullable<LaunchpadCtaBannerProps[\"tone\"]>, string> = {\n primary: \"bg-gradient-to-r from-brand-blue/10 to-brand-purple/10\",\n manage: \"bg-gradient-to-r from-brand-navy/10 to-brand-purple/10\",\n};\n\nexport function LaunchpadCtaBanner({\n eyebrow,\n title,\n description,\n href,\n ctaLabel,\n external = false,\n tone = \"primary\",\n className,\n}: LaunchpadCtaBannerProps) {\n const icon: ReactNode = external\n ? <ExternalLink className=\"h-3.5 w-3.5 ml-1.5\" />\n : <ArrowRight className=\"h-3.5 w-3.5 ml-1.5\" />;\n\n return (\n <div\n className={cn(\n \"rounded-2xl border border-border/40 p-5 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4\",\n TONE_GRADIENT[tone],\n className\n )}\n >\n <div>\n <p className=\"section-label\">{eyebrow}</p>\n <p className=\"font-bold text-base mt-0.5\">{title}</p>\n <p className=\"text-sm text-muted-foreground mt-1\">{description}</p>\n </div>\n <Button variant=\"outline\" asChild className=\"shrink-0\">\n {external ? (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\">\n {ctaLabel} {icon}\n </a>\n ) : (\n <Link href={href}>\n {ctaLabel} {icon}\n </Link>\n )}\n </Button>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCM;AAlCN,0BAAyC;AACzC,kBAAiB;AACjB,oBAAuB;AACvB,gBAAmB;AAenB,MAAM,gBAA8E;AAAA,EAClF,SAAS;AAAA,EACT,QAAQ;AACV;AAEO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,OAAO;AAAA,EACP;AACF,GAA4B;AAC1B,QAAM,OAAkB,WACpB,4CAAC,oCAAa,WAAU,sBAAqB,IAC7C,4CAAC,kCAAW,WAAU,sBAAqB;AAE/C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW;AAAA,QACT;AAAA,QACA,cAAc,IAAI;AAAA,QAClB;AAAA,MACF;AAAA,MAEA;AAAA,qDAAC,SACC;AAAA,sDAAC,OAAE,WAAU,iBAAiB,mBAAQ;AAAA,UACtC,4CAAC,OAAE,WAAU,8BAA8B,iBAAM;AAAA,UACjD,4CAAC,OAAE,WAAU,sCAAsC,uBAAY;AAAA,WACjE;AAAA,QACA,4CAAC,wBAAO,SAAQ,WAAU,SAAO,MAAC,WAAU,YACzC,qBACC,6CAAC,OAAE,MAAY,QAAO,UAAS,KAAI,uBAChC;AAAA;AAAA,UAAS;AAAA,UAAE;AAAA,WACd,IAEA,6CAAC,YAAAA,SAAA,EAAK,MACH;AAAA;AAAA,UAAS;AAAA,UAAE;AAAA,WACd,GAEJ;AAAA;AAAA;AAAA,EACF;AAEJ;","names":["Link"]}
|
|
@@ -6,11 +6,7 @@ interface LaunchpadCtaBannerProps {
|
|
|
6
6
|
description: string;
|
|
7
7
|
href: string;
|
|
8
8
|
ctaLabel: string;
|
|
9
|
-
/** External links render a plain <a target="_blank"> with an ExternalLink
|
|
10
|
-
* icon; internal links route through next/link with an ArrowRight icon. */
|
|
11
9
|
external?: boolean;
|
|
12
|
-
/** Swaps the background gradient tint — "primary" for cross-app CTAs,
|
|
13
|
-
* "manage" for account/portfolio-management CTAs. */
|
|
14
10
|
tone?: "primary" | "manage";
|
|
15
11
|
className?: string;
|
|
16
12
|
}
|
|
@@ -6,11 +6,7 @@ interface LaunchpadCtaBannerProps {
|
|
|
6
6
|
description: string;
|
|
7
7
|
href: string;
|
|
8
8
|
ctaLabel: string;
|
|
9
|
-
/** External links render a plain <a target="_blank"> with an ExternalLink
|
|
10
|
-
* icon; internal links route through next/link with an ArrowRight icon. */
|
|
11
9
|
external?: boolean;
|
|
12
|
-
/** Swaps the background gradient tint — "primary" for cross-app CTAs,
|
|
13
|
-
* "manage" for account/portfolio-management CTAs. */
|
|
14
10
|
tone?: "primary" | "manage";
|
|
15
11
|
className?: string;
|
|
16
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/launchpad-cta-banner.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { ArrowRight, ExternalLink } from \"lucide-react\";\nimport Link from \"./link.js\";\nimport { Button } from \"./button.js\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface LaunchpadCtaBannerProps {\n eyebrow: string;\n title: string;\n description: string;\n href: string;\n ctaLabel: string;\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/launchpad-cta-banner.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { ArrowRight, ExternalLink } from \"lucide-react\";\nimport Link from \"./link.js\";\nimport { Button } from \"./button.js\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface LaunchpadCtaBannerProps {\n eyebrow: string;\n title: string;\n description: string;\n href: string;\n ctaLabel: string;\n\n external?: boolean;\n\n tone?: \"primary\" | \"manage\";\n className?: string;\n}\n\nconst TONE_GRADIENT: Record<NonNullable<LaunchpadCtaBannerProps[\"tone\"]>, string> = {\n primary: \"bg-gradient-to-r from-brand-blue/10 to-brand-purple/10\",\n manage: \"bg-gradient-to-r from-brand-navy/10 to-brand-purple/10\",\n};\n\nexport function LaunchpadCtaBanner({\n eyebrow,\n title,\n description,\n href,\n ctaLabel,\n external = false,\n tone = \"primary\",\n className,\n}: LaunchpadCtaBannerProps) {\n const icon: ReactNode = external\n ? <ExternalLink className=\"h-3.5 w-3.5 ml-1.5\" />\n : <ArrowRight className=\"h-3.5 w-3.5 ml-1.5\" />;\n\n return (\n <div\n className={cn(\n \"rounded-2xl border border-border/40 p-5 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4\",\n TONE_GRADIENT[tone],\n className\n )}\n >\n <div>\n <p className=\"section-label\">{eyebrow}</p>\n <p className=\"font-bold text-base mt-0.5\">{title}</p>\n <p className=\"text-sm text-muted-foreground mt-1\">{description}</p>\n </div>\n <Button variant=\"outline\" asChild className=\"shrink-0\">\n {external ? (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\">\n {ctaLabel} {icon}\n </a>\n ) : (\n <Link href={href}>\n {ctaLabel} {icon}\n </Link>\n )}\n </Button>\n </div>\n );\n}\n"],"mappings":"AAmCM,cAWA,YAXA;AAlCN,SAAS,YAAY,oBAAoB;AACzC,OAAO,UAAU;AACjB,SAAS,cAAc;AACvB,SAAS,UAAU;AAenB,MAAM,gBAA8E;AAAA,EAClF,SAAS;AAAA,EACT,QAAQ;AACV;AAEO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,OAAO;AAAA,EACP;AACF,GAA4B;AAC1B,QAAM,OAAkB,WACpB,oBAAC,gBAAa,WAAU,sBAAqB,IAC7C,oBAAC,cAAW,WAAU,sBAAqB;AAE/C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,cAAc,IAAI;AAAA,QAClB;AAAA,MACF;AAAA,MAEA;AAAA,6BAAC,SACC;AAAA,8BAAC,OAAE,WAAU,iBAAiB,mBAAQ;AAAA,UACtC,oBAAC,OAAE,WAAU,8BAA8B,iBAAM;AAAA,UACjD,oBAAC,OAAE,WAAU,sCAAsC,uBAAY;AAAA,WACjE;AAAA,QACA,oBAAC,UAAO,SAAQ,WAAU,SAAO,MAAC,WAAU,YACzC,qBACC,qBAAC,OAAE,MAAY,QAAO,UAAS,KAAI,uBAChC;AAAA;AAAA,UAAS;AAAA,UAAE;AAAA,WACd,IAEA,qBAAC,QAAK,MACH;AAAA;AAAA,UAAS;AAAA,UAAE;AAAA,WACd,GAEJ;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
|