{"$schema":"https://ui.shadcn.com/schema/registry-item.json","type":"registry:block","registryDependencies":["button"],"name":"pricing-4","description":"Interactive pricing with frequency toggle and numeric animations.","dependencies":["motion","@number-flow/react"],"categories":["pricing"],"files":[{"path":"registry/blocks/pricing/4/pricing-section.tsx","type":"registry:component","content":"\"use client\";\nimport { cn } from \"@/lib/utils\";\nimport NumberFlow from \"@number-flow/react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport Link from \"next/link\";\nimport React from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport { type FREQUENCY, FrequencyToggle } from \"@/components/frequency-toggle\";\n\ntype Plan = {\n\tname: string;\n\tinfo: string;\n\tprice: {\n\t\tmonthly: number;\n\t\tyearly: number; // yearly per month\n\t};\n\tfeatures: string[];\n\tbtn: {\n\t\ttext: string;\n\t\thref: string;\n\t};\n\thighlighted?: boolean;\n};\n\nconst plans: Plan[] = [\n\t{\n\t\tname: \"Basic\",\n\t\tinfo: \"For most individuals\",\n\t\tprice: {\n\t\t\tmonthly: 7,\n\t\t\tyearly: 6,\n\t\t},\n\t\tfeatures: [\n\t\t\t\"Up to 3 Blog posts\",\n\t\t\t\"Up to 3 Transcriptions\",\n\t\t\t\"Up to 3 Posts stored\",\n\t\t\t\"Markdown support\",\n\t\t\t\"Community support\",\n\t\t\t\"AI powered suggestions\",\n\t\t],\n\t\tbtn: {\n\t\t\ttext: \"Start Your Free Trial\",\n\t\t\thref: \"#\",\n\t\t},\n\t},\n\t{\n\t\thighlighted: true,\n\t\tname: \"Pro\",\n\t\tinfo: \"For small businesses\",\n\t\tprice: {\n\t\t\tmonthly: 17,\n\t\t\tyearly: 14,\n\t\t},\n\t\tfeatures: [\n\t\t\t\"Up to 500 Blog Posts\",\n\t\t\t\"Up to 500 Transcriptions\",\n\t\t\t\"Up to 500 Posts stored\",\n\t\t\t\"Unlimited Markdown support\",\n\t\t\t\"SEO optimization tools\",\n\t\t\t\"Priority support\",\n\t\t\t\"AI powered suggestions\",\n\t\t],\n\t\tbtn: {\n\t\t\ttext: \"Get started\",\n\t\t\thref: \"#\",\n\t\t},\n\t},\n\t{\n\t\tname: \"Business\",\n\t\tinfo: \"For large organizations\",\n\t\tprice: {\n\t\t\tmonthly: 49,\n\t\t\tyearly: 40,\n\t\t},\n\t\tfeatures: [\n\t\t\t\"Unlimited Blog Posts\",\n\t\t\t\"Unlimited Transcriptions\",\n\t\t\t\"Unlimited Posts stored\",\n\t\t\t\"Unlimited Markdown support\",\n\t\t\t\"SEO optimization tools\",\n\t\t\t\"Priority support\",\n\t\t\t\"AI powered suggestions\",\n\t\t],\n\t\tbtn: {\n\t\t\ttext: \"Contact team\",\n\t\t\thref: \"#\",\n\t\t},\n\t},\n];\n\nexport function PricingSection() {\n\tconst [frequency, setFrequency] = React.useState<\"monthly\" | \"yearly\">(\n\t\t\"monthly\"\n\t);\n\n\treturn (\n\t\t<div className=\"flex w-full flex-col items-center justify-center space-y-7 p-4\">\n\t\t\t<div className=\"mx-auto max-w-xl space-y-2\">\n\t\t\t\t<h2 className=\"text-center font-bold text-2xl tracking-tight md:text-3xl lg:font-extrabold lg:text-4xl\">\n\t\t\t\t\tPlans that Scale with You\n\t\t\t\t</h2>\n\t\t\t\t<p className=\"text-center text-muted-foreground text-sm md:text-base\">\n\t\t\t\t\tWhether you're just starting out or growing fast, our flexible pricing\n\t\t\t\t\thas you covered — with no hidden costs.\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t<FrequencyToggle frequency={frequency} setFrequency={setFrequency} />\n\t\t\t<div className=\"mx-auto grid w-full max-w-4xl grid-cols-1 gap-6 md:grid-cols-3\">\n\t\t\t\t{plans.map((plan) => (\n\t\t\t\t\t<PricingCard frequency={frequency} key={plan.name} plan={plan} />\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\ntype PricingCardProps = React.ComponentProps<\"div\"> & {\n\tplan: Plan;\n\tfrequency?: FREQUENCY;\n};\n\nexport function PricingCard({\n\tplan,\n\tclassName,\n\tfrequency = \"monthly\",\n\t...props\n}: PricingCardProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"relative flex w-full flex-col overflow-hidden rounded-lg border shadow-xs\",\n\t\t\t\tplan.highlighted && \"scale-105\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\tkey={plan.name}\n\t\t\t{...props}\n\t\t>\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"border-b p-4\",\n\t\t\t\t\tplan.highlighted && \"bg-card dark:bg-card/80\"\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<AnimatePresence mode=\"wait\">\n\t\t\t\t\t<div className=\"absolute top-2 right-2 z-10 flex items-center gap-2\">\n\t\t\t\t\t\t{plan.highlighted && (\n\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\tclassName=\"flex items-center gap-1 rounded-md border bg-background px-2 py-0.5 text-xs\"\n\t\t\t\t\t\t\t\tkey=\"popular-badge\"\n\t\t\t\t\t\t\t\tlayout\n\t\t\t\t\t\t\t\ttransition={{ duration: 0.1 }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<IconPlaceholder\n\t\t\t\t\t\t\t\t\tclassName=\"size-3 fill-current\"\n\t\t\t\t\t\t\t\t\thugeicons=\"StarIcon\"\n\t\t\t\t\t\t\t\t\tlucide=\"StarIcon\"\n\t\t\t\t\t\t\t\t\tphosphor=\"StarIcon\"\n\t\t\t\t\t\t\t\t\tremixicon=\"RiStarLine\"\n\t\t\t\t\t\t\t\t\ttabler=\"IconStar\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\tPopular\n\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{frequency === \"yearly\" &&\n\t\t\t\t\t\t\tplan.price.monthly > plan.price.yearly && (\n\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\tclassName=\"flex items-center gap-1 rounded-md border bg-primary px-2 py-0.5 text-primary-foreground text-xs\"\n\t\t\t\t\t\t\t\t\texit={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\tkey=\"discount-badge\"\n\t\t\t\t\t\t\t\t\tlayout\n\t\t\t\t\t\t\t\t\ttransition={{ duration: 0.15 }}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{/* Calculate the actual discount percentage of the plan */}\n\t\t\t\t\t\t\t\t\t{Math.round(\n\t\t\t\t\t\t\t\t\t\t((plan.price.monthly - plan.price.yearly) /\n\t\t\t\t\t\t\t\t\t\t\tplan.price.monthly) *\n\t\t\t\t\t\t\t\t\t\t\t100\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t% off\n\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t</AnimatePresence>\n\n\t\t\t\t<div className=\"font-medium text-lg\">{plan.name}</div>\n\t\t\t\t<p className=\"font-normal text-muted-foreground text-sm\">{plan.info}</p>\n\t\t\t\t<h3 className=\"mt-6 mb-1 flex w-max items-end gap-1\">\n\t\t\t\t\t<NumberFlow\n\t\t\t\t\t\tclassName=\"font-extrabold text-3xl [&::part(suffix)]:font-normal [&::part(suffix)]:text-base [&::part(suffix)]:text-muted-foreground\"\n\t\t\t\t\t\tformat={{\n\t\t\t\t\t\t\tstyle: \"currency\",\n\t\t\t\t\t\t\tcurrency: \"USD\",\n\t\t\t\t\t\t\tnotation: \"compact\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tsuffix=\"/month\"\n\t\t\t\t\t\tvalue={plan.price[frequency]}\n\t\t\t\t\t/>\n\t\t\t\t</h3>\n\t\t\t\t<p className=\"mb-2 font-normal text-muted-foreground text-xs\">\n\t\t\t\t\tbilled {frequency}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"space-y-3 px-4 pt-6 pb-8 text-muted-foreground text-sm\",\n\t\t\t\t\tplan.highlighted && \"bg-muted/10\"\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{plan.features.map((feature) => (\n\t\t\t\t\t<div className=\"flex items-center gap-2\" key={feature}>\n\t\t\t\t\t\t<IconPlaceholder\n\t\t\t\t\t\t\tclassName=\"size-3.5 text-foreground\"\n\t\t\t\t\t\t\thugeicons=\"CheckmarkCircle04Icon\"\n\t\t\t\t\t\t\tlucide=\"CheckCircleIcon\"\n\t\t\t\t\t\t\tphosphor=\"CheckCircleIcon\"\n\t\t\t\t\t\t\tremixicon=\"RiCheckboxCircleLine\"\n\t\t\t\t\t\t\ttabler=\"IconCircleCheck\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<p>{feature}</p>\n\t\t\t\t\t</div>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"mt-auto w-full border-t p-3\",\n\t\t\t\t\tplan.highlighted && \"bg-card dark:bg-card/80\"\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<Button\n\t\t\t\t\tasChild\n\t\t\t\t\tclassName=\"w-full\"\n\t\t\t\t\tvariant={plan.highlighted ? \"default\" : \"outline\"}\n\t\t\t\t>\n\t\t\t\t\t<Link href={plan.btn.href}>{plan.btn.text}</Link>\n\t\t\t\t</Button>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"},{"path":"registry/blocks/pricing/4/frequency-toggle.tsx","type":"registry:component","content":"\"use client\";\nimport { cn } from \"@/lib/utils\";\nimport { motion } from \"motion/react\";\nimport type React from \"react\";\n\nexport type FREQUENCY = \"monthly\" | \"yearly\";\n\ntype FrequencyToggleProps = React.ComponentProps<\"div\"> & {\n\tfrequency: FREQUENCY;\n\tsetFrequency: React.Dispatch<React.SetStateAction<FREQUENCY>>;\n\tfrequencies?: FREQUENCY[];\n};\n\nexport function FrequencyToggle({\n\tfrequency,\n\tsetFrequency,\n\tfrequencies = [\"monthly\", \"yearly\"],\n\t...props\n}: FrequencyToggleProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"mx-auto flex w-fit rounded-xl border bg-card p-1 shadow-xs\",\n\t\t\t\tprops.className\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{frequencies.map((freq) => (\n\t\t\t\t<button\n\t\t\t\t\tclassName=\"relative px-4 py-1 text-sm capitalize\"\n\t\t\t\t\tkey={freq}\n\t\t\t\t\tonClick={() => setFrequency(freq)}\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t>\n\t\t\t\t\t<span className=\"relative z-10\">{freq}</span>\n\t\t\t\t\t{frequency === freq && (\n\t\t\t\t\t\t<motion.span\n\t\t\t\t\t\t\tclassName=\"absolute inset-0 z-10 rounded-xl bg-background mix-blend-difference dark:bg-foreground\"\n\t\t\t\t\t\t\tlayoutId=\"frequency\"\n\t\t\t\t\t\t\ttransition={{ type: \"spring\", duration: 0.4 }}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t</button>\n\t\t\t))}\n\t\t</div>\n\t);\n}\n"}]}