{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pricing-card",
  "type": "registry:ui",
  "title": "Pricing Card",
  "description": "A beautiful glassmorphism pricing card component with nested card design, feature lists, and customizable accent colors.",
  "registryDependencies": [
    "icons"
  ],
  "files": [
    {
      "path": "registry/new-york/ui/pricing-card.tsx",
      "content": "\"use client\";\n\nimport type { FC, ReactNode } from \"react\";\nimport { CheckmarkCircle02Icon, HugeiconsIcon } from \"@/components/icons\";\nimport { cn } from \"@/lib/utils\";\nimport { RaisedButton } from \"@/registry/new-york/ui/raised-button\";\n\nexport interface PricingFeature {\n\ttext: string;\n\ticon?: ReactNode;\n}\n\nexport interface PricingCardProps {\n\t/** Plan title (e.g., \"Free\", \"Pro\", \"Enterprise\") */\n\ttitle: string;\n\t/** Price amount (e.g., 0, 9.99, 29) */\n\tprice: number;\n\t/** Currency symbol (default: \"$\") */\n\tcurrency?: string;\n\t/** Original price before discount (shows strikethrough on yearly) */\n\toriginalPrice?: number;\n\t/** Plan description/subtitle — always reserves two lines for row alignment */\n\tdescription?: string;\n\t/** Features included in this plan */\n\tfeatures?: (string | PricingFeature)[];\n\t/** Custom label above features list (rendered uppercase, muted) */\n\tfeaturesTitle?: ReactNode;\n\t/** Billing period: true for monthly, false for yearly */\n\tisMonthly?: boolean;\n\t/** Show \"Current Plan\" badge */\n\tisCurrentPlan?: boolean;\n\t/** Show \"Popular\" badge in header */\n\tisPopular?: boolean;\n\t/** Marks this card as the highlighted Pro tier (tints feature icons) */\n\tisPro?: boolean;\n\t/** Marks this card as the Enterprise tier (changes accent + suffix copy) */\n\tisEnterprise?: boolean;\n\t/** Optional plan illustration shown above the price */\n\tplanImage?: string;\n\t/** Override the price display (e.g., \"Custom\") */\n\tpriceLabel?: string;\n\t/** Override the line beneath the price (defaults to \"/ per month\" etc.) */\n\tpriceSuffix?: ReactNode;\n\t/** Button label (default depends on plan + state) */\n\tbuttonLabel?: string;\n\t/** Small text rendered under the CTA button */\n\tbuttonFootnote?: ReactNode;\n\t/** Button click handler */\n\tonButtonClick?: () => void;\n\t/** Whether button is disabled */\n\tisDisabled?: boolean;\n\t/** Whether button is in loading state */\n\tisLoading?: boolean;\n\t/** Accent color for button (CSS color value) */\n\taccentColor?: string;\n\t/** Additional CSS classes */\n\tclassName?: string;\n}\n\nconst formatPrice = (amount: number, currency: string): string => {\n\tif (amount === 0) return `${currency}0`;\n\treturn `${currency}${amount.toFixed(amount % 1 === 0 ? 0 : 2)}`;\n};\n\nexport const PricingCard: FC<PricingCardProps> = ({\n\ttitle,\n\tprice,\n\tcurrency = \"$\",\n\toriginalPrice,\n\tdescription,\n\tfeatures,\n\tfeaturesTitle,\n\tisMonthly = true,\n\tisCurrentPlan = false,\n\tisPopular = false,\n\tisPro = false,\n\tisEnterprise = false,\n\tplanImage,\n\tpriceLabel,\n\tpriceSuffix,\n\tbuttonLabel,\n\tbuttonFootnote,\n\tonButtonClick,\n\tisDisabled = false,\n\tisLoading = false,\n\taccentColor,\n\tclassName,\n}) => {\n\tconst isFree = price === 0 && !isEnterprise;\n\n\tconst formattedPrice = formatPrice(price, currency);\n\tconst formattedOriginalPrice = originalPrice\n\t\t? formatPrice(originalPrice, currency)\n\t\t: null;\n\n\t// Yearly Pro: show per-month equivalent above an \"/ mo, billed $X / year\" line\n\tconst monthlyEquivalent =\n\t\t!isMonthly && isPro && price > 0\n\t\t\t? formatPrice(Math.round(price / 12), currency)\n\t\t\t: null;\n\n\tconst resolvedAccent =\n\t\taccentColor ?? (isEnterprise ? \"#fa4b00\" : isFree ? \"#2a2a2a\" : \"#00bbff\");\n\n\tconst getButtonLabel = (): string => {\n\t\tif (isLoading) return \"Loading...\";\n\t\tif (buttonLabel) return buttonLabel;\n\t\tif (isCurrentPlan) return \"Current Plan\";\n\t\tif (isFree) return \"Start for Free\";\n\t\tif (isEnterprise) return \"Contact Sales\";\n\t\treturn \"Get Started\";\n\t};\n\n\tconst resolvedSuffix: ReactNode = (() => {\n\t\tif (priceSuffix !== undefined) return priceSuffix;\n\t\tif (isEnterprise) return \"Tailored pricing\";\n\t\tif (price <= 0) return \" \";\n\t\tif (monthlyEquivalent) return `/ mo, billed ${formattedPrice} / year`;\n\t\treturn isMonthly ? \"/ per month\" : \"/ per year\";\n\t})();\n\n\tconst resolvedFootnote: ReactNode = (() => {\n\t\tif (buttonFootnote !== undefined) return buttonFootnote;\n\t\tif (isEnterprise) return \"Reply within 24 hours\";\n\t\tif (isFree) return \"No credit card required\";\n\t\treturn \"Cancel anytime · Secure payment\";\n\t})();\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"flex h-full w-full flex-col overflow-hidden rounded-3xl\",\n\t\t\t\t\"bg-white/70 dark:bg-zinc-800/50 backdrop-blur-lg\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{/* Header: plan name + badges (reserves a fixed row height) */}\n\t\t\t<div className=\"flex flex-col gap-1.5 p-6 pb-4\">\n\t\t\t\t<div className=\"flex min-h-5 items-center justify-between\">\n\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t<span className=\"text-2xl font-semibold text-zinc-900 dark:text-white\">\n\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t{isCurrentPlan && (\n\t\t\t\t\t\t\t<span className=\"rounded-full bg-green-500/15 px-2 py-0.5 text-xs font-medium text-green-700 dark:text-green-400\">\n\t\t\t\t\t\t\t\tCurrent Plan\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t\t{isPopular && !isCurrentPlan && (\n\t\t\t\t\t\t<span className=\"rounded-full bg-primary/15 px-2 py-0.5 text-xs font-medium tracking-wide text-primary\">\n\t\t\t\t\t\t\tPopular\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\n\t\t\t\t{/* Description — always reserve two lines so cards align */}\n\t\t\t\t<p className=\"line-clamp-2 min-h-10 text-sm font-light leading-relaxed text-zinc-600 dark:text-zinc-400\">\n\t\t\t\t\t{description ?? \" \"}\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t{planImage && (\n\t\t\t\t<div className=\"px-6 pb-5\">\n\t\t\t\t\t<div className=\"relative h-40 w-full overflow-hidden rounded-2xl\">\n\t\t\t\t\t\t{/* eslint-disable-next-line @next/next/no-img-element */}\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tsrc={planImage}\n\t\t\t\t\t\t\talt={`${title} plan`}\n\t\t\t\t\t\t\tclassName=\"h-full w-full object-cover transition duration-300 hover:scale-125\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* Price */}\n\t\t\t<div className=\"px-6 pb-5\">\n\t\t\t\t<div className=\"flex items-baseline gap-2\">\n\t\t\t\t\t{formattedOriginalPrice && !isMonthly && !priceLabel && (\n\t\t\t\t\t\t<span className=\"text-2xl font-normal text-zinc-500 line-through\">\n\t\t\t\t\t\t\t{formattedOriginalPrice}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)}\n\t\t\t\t\t<span className=\"text-5xl font-semibold tracking-tight text-zinc-900 dark:text-white\">\n\t\t\t\t\t\t{priceLabel ?? monthlyEquivalent ?? formattedPrice}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<p className=\"mt-1 text-sm font-normal text-zinc-500 dark:text-zinc-400\">\n\t\t\t\t\t{resolvedSuffix}\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t{/* CTA */}\n\t\t\t<div className=\"px-6 pb-5\">\n\t\t\t\t<RaisedButton\n\t\t\t\t\tonClick={onButtonClick}\n\t\t\t\t\tdisabled={isDisabled || isLoading || isCurrentPlan}\n\t\t\t\t\tclassName=\"w-full\"\n\t\t\t\t\tcolor={resolvedAccent}\n\t\t\t\t>\n\t\t\t\t\t{getButtonLabel()}\n\t\t\t\t</RaisedButton>\n\t\t\t\t{resolvedFootnote && (\n\t\t\t\t\t<p className=\"mt-2 text-center text-xs font-light text-zinc-500\">\n\t\t\t\t\t\t{resolvedFootnote}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t</div>\n\n\t\t\t{/* Features — flex-1 so cards in a row equalize their height */}\n\t\t\t{(featuresTitle || (features && features.length > 0)) && (\n\t\t\t\t<div className=\"flex flex-1 flex-col gap-2.5 px-6 py-5\">\n\t\t\t\t\t{featuresTitle && (\n\t\t\t\t\t\t<p className=\"mb-0.5 text-xs font-normal uppercase text-zinc-500\">\n\t\t\t\t\t\t\t{featuresTitle}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{features?.map((feature) => {\n\t\t\t\t\t\tconst featureText =\n\t\t\t\t\t\t\ttypeof feature === \"string\" ? feature : feature.text;\n\t\t\t\t\t\tconst featureIcon =\n\t\t\t\t\t\t\ttypeof feature === \"object\" && feature.icon ? (\n\t\t\t\t\t\t\t\tfeature.icon\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<HugeiconsIcon\n\t\t\t\t\t\t\t\t\ticon={CheckmarkCircle02Icon}\n\t\t\t\t\t\t\t\t\tsize={15}\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\"mt-0.5 shrink-0\",\n\t\t\t\t\t\t\t\t\t\tisPro || isEnterprise\n\t\t\t\t\t\t\t\t\t\t\t? \"text-primary\"\n\t\t\t\t\t\t\t\t\t\t\t: \"text-zinc-500\",\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tkey={featureText}\n\t\t\t\t\t\t\t\tclassName=\"flex items-start gap-3 text-sm font-light text-zinc-700 dark:text-zinc-300\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span className=\"flex-shrink-0\">{featureIcon}</span>\n\t\t\t\t\t\t\t\t<span>{featureText}</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n};\n\nexport default PricingCard;\n",
      "type": "registry:ui"
    }
  ]
}