nextworks 0.2.0-alpha.11 → 0.2.0-alpha.13
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/README.md +283 -282
- package/dist/cli_manifests/blocks_manifest.json +198 -175
- package/dist/kits/blocks/.nextworks/docs/BLOCKS_QUICKSTART.md +101 -100
- package/dist/kits/blocks/.nextworks/docs/BLOCKS_README.md +105 -104
- package/dist/kits/blocks/.nextworks/docs/THEME_GUIDE.md +1 -1
- package/dist/kits/blocks/app/templates/aiworkflow/PresetThemeVars.tsx +58 -0
- package/dist/kits/blocks/app/templates/aiworkflow/README.md +46 -0
- package/dist/kits/blocks/app/templates/aiworkflow/components/CTA.tsx +44 -0
- package/dist/kits/blocks/app/templates/aiworkflow/components/Contact.tsx +105 -0
- package/dist/kits/blocks/app/templates/aiworkflow/components/FAQ.tsx +63 -0
- package/dist/kits/blocks/app/templates/aiworkflow/components/Features.tsx +65 -0
- package/dist/kits/blocks/app/templates/aiworkflow/components/Footer.tsx +109 -0
- package/dist/kits/blocks/app/templates/aiworkflow/components/Hero.tsx +636 -0
- package/dist/kits/blocks/app/templates/aiworkflow/components/Navbar.tsx +90 -0
- package/dist/kits/blocks/app/templates/aiworkflow/components/Pricing.tsx +86 -0
- package/dist/kits/blocks/app/templates/aiworkflow/components/ProcessTimeline.tsx +103 -0
- package/dist/kits/blocks/app/templates/aiworkflow/components/Testimonials.tsx +56 -0
- package/dist/kits/blocks/app/templates/aiworkflow/components/TrustBadges.tsx +59 -0
- package/dist/kits/blocks/app/templates/aiworkflow/page.tsx +43 -0
- package/dist/kits/blocks/app/templates/digitalagency/PresetThemeVars.tsx +80 -80
- package/dist/kits/blocks/app/templates/digitalagency/README.md +42 -42
- package/dist/kits/blocks/app/templates/digitalagency/components/Pricing.tsx +114 -114
- package/dist/kits/blocks/app/templates/digitalagency/components/Process.tsx +59 -59
- package/dist/kits/blocks/app/templates/digitalagency/components/Services.tsx +55 -55
- package/dist/kits/blocks/app/templates/digitalagency/components/Team.tsx +28 -28
- package/dist/kits/blocks/app/templates/digitalagency/components/Testimonials.tsx +65 -65
- package/dist/kits/blocks/app/templates/digitalagency/page.tsx +38 -38
- package/dist/kits/blocks/app/templates/gallery/PresetThemeVars.tsx +84 -84
- package/dist/kits/blocks/app/templates/productlaunch/PresetThemeVars.tsx +75 -75
- package/dist/kits/blocks/app/templates/productlaunch/README.md +62 -62
- package/dist/kits/blocks/app/templates/productlaunch/components/About.tsx +84 -84
- package/dist/kits/blocks/app/templates/productlaunch/components/CTA.tsx +50 -50
- package/dist/kits/blocks/app/templates/productlaunch/components/Contact.tsx +231 -231
- package/dist/kits/blocks/app/templates/productlaunch/components/FAQ.tsx +86 -86
- package/dist/kits/blocks/app/templates/productlaunch/components/Features.tsx +83 -83
- package/dist/kits/blocks/app/templates/productlaunch/components/Footer.tsx +132 -132
- package/dist/kits/blocks/app/templates/productlaunch/components/Hero.tsx +88 -88
- package/dist/kits/blocks/app/templates/productlaunch/components/Navbar.tsx +116 -116
- package/dist/kits/blocks/app/templates/productlaunch/components/Pricing.tsx +106 -106
- package/dist/kits/blocks/app/templates/productlaunch/components/ProcessTimeline.tsx +110 -110
- package/dist/kits/blocks/app/templates/productlaunch/components/ServicesGrid.tsx +68 -68
- package/dist/kits/blocks/app/templates/productlaunch/components/Team.tsx +104 -104
- package/dist/kits/blocks/app/templates/productlaunch/components/Testimonials.tsx +90 -90
- package/dist/kits/blocks/app/templates/productlaunch/components/TrustBadges.tsx +76 -76
- package/dist/kits/blocks/app/templates/productlaunch/page.tsx +43 -43
- package/dist/kits/blocks/app/templates/saasdashboard/PresetThemeVars.tsx +80 -80
- package/dist/kits/blocks/app/templates/saasdashboard/README.md +44 -44
- package/dist/kits/blocks/app/templates/saasdashboard/components/Contact.tsx +129 -129
- package/dist/kits/blocks/app/templates/saasdashboard/components/Dashboard.tsx +293 -293
- package/dist/kits/blocks/app/templates/saasdashboard/components/FAQ.tsx +55 -55
- package/dist/kits/blocks/app/templates/saasdashboard/components/Features.tsx +90 -90
- package/dist/kits/blocks/app/templates/saasdashboard/components/Footer.tsx +77 -77
- package/dist/kits/blocks/app/templates/saasdashboard/components/Hero.tsx +104 -104
- package/dist/kits/blocks/app/templates/saasdashboard/components/Hero_mask.tsx +126 -126
- package/dist/kits/blocks/app/templates/saasdashboard/components/Navbar.tsx +117 -117
- package/dist/kits/blocks/app/templates/saasdashboard/components/Pricing.tsx +90 -90
- package/dist/kits/blocks/app/templates/saasdashboard/components/SmoothScroll.tsx +96 -96
- package/dist/kits/blocks/app/templates/saasdashboard/components/Testimonials.tsx +72 -72
- package/dist/kits/blocks/app/templates/saasdashboard/components/TrustBadges.tsx +53 -53
- package/dist/kits/blocks/app/templates/saasdashboard/page.tsx +39 -39
- package/dist/kits/blocks/components/enhanced-theme-provider.tsx +195 -195
- package/dist/kits/blocks/components/providers/BlocksAppProviders.tsx +27 -27
- package/dist/kits/blocks/components/sections/About.tsx +291 -291
- package/dist/kits/blocks/components/sections/CTA.tsx +257 -257
- package/dist/kits/blocks/components/sections/Contact.tsx +267 -267
- package/dist/kits/blocks/components/sections/FAQ.tsx +214 -214
- package/dist/kits/blocks/components/sections/Features.tsx +268 -268
- package/dist/kits/blocks/components/sections/Footer.tsx +302 -302
- package/dist/kits/blocks/components/sections/HeroMotion.tsx +308 -308
- package/dist/kits/blocks/components/sections/HeroOverlay.tsx +358 -358
- package/dist/kits/blocks/components/sections/HeroProductDemo.tsx +236 -0
- package/dist/kits/blocks/components/sections/HeroSplit.tsx +352 -352
- package/dist/kits/blocks/components/sections/Navbar.tsx +350 -350
- package/dist/kits/blocks/components/sections/PortfolioSimple.tsx +549 -549
- package/dist/kits/blocks/components/sections/Pricing.tsx +264 -264
- package/dist/kits/blocks/components/sections/ProcessTimeline.tsx +325 -325
- package/dist/kits/blocks/components/sections/ServicesGrid.tsx +210 -210
- package/dist/kits/blocks/components/sections/Team.tsx +309 -309
- package/dist/kits/blocks/components/sections/Testimonials.tsx +158 -158
- package/dist/kits/blocks/components/sections/TrustBadges.tsx +162 -162
- package/dist/kits/blocks/components/sections/product-demo/ApprovalInboxPanel.tsx +125 -0
- package/dist/kits/blocks/components/sections/product-demo/DemoStage.tsx +397 -0
- package/dist/kits/blocks/components/sections/product-demo/DemoWindow.tsx +128 -0
- package/dist/kits/blocks/components/sections/product-demo/KnowledgePanel.tsx +127 -0
- package/dist/kits/blocks/components/sections/product-demo/RunConsolePanel.tsx +150 -0
- package/dist/kits/blocks/components/sections/product-demo/WorkflowStudioPanel.tsx +191 -0
- package/dist/kits/blocks/components/sections/product-demo/types.ts +193 -0
- package/dist/kits/blocks/components/theme-provider.tsx +1 -1
- package/dist/kits/blocks/components/ui/alert-dialog.tsx +134 -134
- package/dist/kits/blocks/components/ui/brand-node.tsx +121 -121
- package/dist/kits/blocks/components/ui/button.tsx +122 -122
- package/dist/kits/blocks/components/ui/card.tsx +95 -95
- package/dist/kits/blocks/components/ui/checkbox.tsx +30 -30
- package/dist/kits/blocks/components/ui/cta-button.tsx +125 -125
- package/dist/kits/blocks/components/ui/dropdown-menu.tsx +201 -201
- package/dist/kits/blocks/components/ui/feature-card.tsx +91 -91
- package/dist/kits/blocks/components/ui/input.tsx +27 -27
- package/dist/kits/blocks/components/ui/label.tsx +29 -29
- package/dist/kits/blocks/components/ui/pricing-card.tsx +120 -120
- package/dist/kits/blocks/components/ui/select.tsx +25 -25
- package/dist/kits/blocks/components/ui/skeleton.tsx +13 -13
- package/dist/kits/blocks/components/ui/table.tsx +98 -98
- package/dist/kits/blocks/components/ui/testimonial-card.tsx +108 -108
- package/dist/kits/blocks/components/ui/textarea.tsx +26 -26
- package/dist/kits/blocks/components/ui/theme-selector.tsx +243 -243
- package/dist/kits/blocks/components/ui/theme-toggle.tsx +74 -74
- package/dist/kits/blocks/components/ui/toaster.tsx +7 -7
- package/dist/kits/blocks/lib/themes.ts +400 -400
- package/dist/kits/blocks/lib/utils.ts +6 -6
- package/dist/kits/blocks/package-deps.json +3 -3
- package/package.json +1 -1
|
@@ -1,264 +1,264 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import React from "react";
|
|
4
|
-
import { motion } from "motion/react";
|
|
5
|
-
import { cn } from "@/lib/utils";
|
|
6
|
-
import { PricingCard } from "@/components/ui/pricing-card";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Represents individual pricing plan data.
|
|
10
|
-
* @public
|
|
11
|
-
*/
|
|
12
|
-
export interface PricingData {
|
|
13
|
-
/** Title of the plan (e.g., "Pro") */
|
|
14
|
-
pricingPlanHeaderText?: string;
|
|
15
|
-
/** Display price (e.g., "$19.99") */
|
|
16
|
-
pricingPlanPrice?: string;
|
|
17
|
-
/** Feature list bullets */
|
|
18
|
-
pricingPlanFeatures?: string[];
|
|
19
|
-
/** CTA button label */
|
|
20
|
-
pricingPlanCTALabel?: string;
|
|
21
|
-
/** CTA button href */
|
|
22
|
-
pricingPlanCTAHref?: string;
|
|
23
|
-
/** Whether this plan should be highlighted */
|
|
24
|
-
isPopular?: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Props for the Pricing section component.
|
|
29
|
-
*
|
|
30
|
-
* @remarks
|
|
31
|
-
* - Styling: slot-style className overrides are merged after defaults via cn().
|
|
32
|
-
* - Motion: enableMotion toggles entrance animations and hover transitions.
|
|
33
|
-
* - Accessibility: uses a semantic <section> with an aria-label.
|
|
34
|
-
*/
|
|
35
|
-
interface PricingProps {
|
|
36
|
-
/** Optional id on root. @defaultValue "pricing" */
|
|
37
|
-
id?: string;
|
|
38
|
-
/** Merge-in class for root */
|
|
39
|
-
className?: string;
|
|
40
|
-
|
|
41
|
-
/** Heading text displayed at the top of the pricing section. @defaultValue "Choose Your Plan" */
|
|
42
|
-
pricingHeadingText?: string;
|
|
43
|
-
/** Array of individual pricing plans to display. @defaultValue defaultPricingData */
|
|
44
|
-
pricingPlans?: PricingData[];
|
|
45
|
-
|
|
46
|
-
/** When false, disables entrance animations and hover transitions */
|
|
47
|
-
enableMotion?: boolean;
|
|
48
|
-
|
|
49
|
-
/** Styling configuration objects */
|
|
50
|
-
section?: {
|
|
51
|
-
className?: string;
|
|
52
|
-
};
|
|
53
|
-
container?: {
|
|
54
|
-
className?: string;
|
|
55
|
-
};
|
|
56
|
-
heading?: {
|
|
57
|
-
className?: string;
|
|
58
|
-
};
|
|
59
|
-
grid?: {
|
|
60
|
-
className?: string;
|
|
61
|
-
};
|
|
62
|
-
card?: {
|
|
63
|
-
className?: string;
|
|
64
|
-
};
|
|
65
|
-
header?: {
|
|
66
|
-
className?: string;
|
|
67
|
-
};
|
|
68
|
-
title?: {
|
|
69
|
-
className?: string;
|
|
70
|
-
};
|
|
71
|
-
price?: {
|
|
72
|
-
className?: string;
|
|
73
|
-
};
|
|
74
|
-
features?: {
|
|
75
|
-
className?: string;
|
|
76
|
-
};
|
|
77
|
-
featureItem?: {
|
|
78
|
-
className?: string;
|
|
79
|
-
};
|
|
80
|
-
cta?: {
|
|
81
|
-
unstyled?: boolean;
|
|
82
|
-
style?: React.CSSProperties;
|
|
83
|
-
variant?:
|
|
84
|
-
| "default"
|
|
85
|
-
| "destructive"
|
|
86
|
-
| "outline"
|
|
87
|
-
| "secondary"
|
|
88
|
-
| "ghost"
|
|
89
|
-
| "link";
|
|
90
|
-
size?: "default" | "sm" | "lg" | "icon";
|
|
91
|
-
className?: string;
|
|
92
|
-
};
|
|
93
|
-
popularBadge?: {
|
|
94
|
-
className?: string;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
/** ARIA label for the pricing section */
|
|
98
|
-
ariaLabel?: string;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Default pricing plans used if none are passed in.
|
|
103
|
-
*/
|
|
104
|
-
const defaultPricingData: PricingData[] = [
|
|
105
|
-
{
|
|
106
|
-
pricingPlanHeaderText: "Basic",
|
|
107
|
-
pricingPlanPrice: "$9.99",
|
|
108
|
-
pricingPlanFeatures: ["Feature 1", "Feature 2", "Feature 3"],
|
|
109
|
-
pricingPlanCTALabel: "Select Plan",
|
|
110
|
-
pricingPlanCTAHref: "#contact",
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
pricingPlanHeaderText: "Pro",
|
|
114
|
-
pricingPlanPrice: "$19.99",
|
|
115
|
-
pricingPlanFeatures: ["Feature 1", "Feature 2", "Feature 3", "Feature 4"],
|
|
116
|
-
pricingPlanCTALabel: "Select Plan",
|
|
117
|
-
pricingPlanCTAHref: "#contact",
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
pricingPlanHeaderText: "Enterprise",
|
|
121
|
-
pricingPlanPrice: "$49.99",
|
|
122
|
-
pricingPlanFeatures: [
|
|
123
|
-
"Feature 1",
|
|
124
|
-
"Feature 2",
|
|
125
|
-
"Feature 3",
|
|
126
|
-
"Feature 4",
|
|
127
|
-
"Feature 5",
|
|
128
|
-
],
|
|
129
|
-
pricingPlanCTALabel: "Select Plan",
|
|
130
|
-
pricingPlanCTAHref: "#contact",
|
|
131
|
-
},
|
|
132
|
-
];
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Responsive pricing grid using PricingCard with optional motion.
|
|
136
|
-
*
|
|
137
|
-
* @remarks
|
|
138
|
-
* - Styling: exposes slot-style overrides (card, header, title, price, etc.).
|
|
139
|
-
* - Motion: enableMotion controls entrance animations and hover transitions.
|
|
140
|
-
* - Accessibility: semantic <section> with aria-label.
|
|
141
|
-
*
|
|
142
|
-
* @example
|
|
143
|
-
* <Pricing pricingPlans={[{ pricingPlanHeaderText: 'Pro', pricingPlanPrice: '$19' }]} />
|
|
144
|
-
*/
|
|
145
|
-
export function Pricing({
|
|
146
|
-
id,
|
|
147
|
-
className,
|
|
148
|
-
pricingPlans = defaultPricingData,
|
|
149
|
-
pricingHeadingText = "Choose Your Plan",
|
|
150
|
-
enableMotion = true,
|
|
151
|
-
section = {
|
|
152
|
-
className: "pt-20 pb-5 bg-background text-foreground",
|
|
153
|
-
},
|
|
154
|
-
container = {
|
|
155
|
-
className: "max-w-7xl mx-auto px-6",
|
|
156
|
-
},
|
|
157
|
-
heading = {
|
|
158
|
-
className:
|
|
159
|
-
"text-3xl font-bold font-poppins text-center text-foreground mb-8",
|
|
160
|
-
},
|
|
161
|
-
grid = {
|
|
162
|
-
className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mt-8",
|
|
163
|
-
},
|
|
164
|
-
card = {
|
|
165
|
-
className:
|
|
166
|
-
"relative bg-card border border-border rounded-lg shadow-md hover:shadow-lg transition-shadow duration-200 bg-[var(--card-bg)] text-[var(--card-fg)] border-[var(--card-border)] shadow-[var(--card-shadow)]",
|
|
167
|
-
},
|
|
168
|
-
header = {
|
|
169
|
-
className: "p-6 text-center border-b border-[var(--card-border)]",
|
|
170
|
-
},
|
|
171
|
-
title = {
|
|
172
|
-
className:
|
|
173
|
-
"text-xl font-bold font-poppins text-card-foreground mb-2 text-[var(--card-title-fg)]",
|
|
174
|
-
},
|
|
175
|
-
price = {
|
|
176
|
-
className:
|
|
177
|
-
"text-3xl font-bold font-poppins text-card-foreground mb-4 text-[var(--card-title-fg)]",
|
|
178
|
-
},
|
|
179
|
-
features = {
|
|
180
|
-
className: "p-6 space-y-3 font-inter",
|
|
181
|
-
},
|
|
182
|
-
featureItem = {
|
|
183
|
-
className:
|
|
184
|
-
"flex items-center text-muted-foreground text-sm text-[var(--card-muted-fg)]",
|
|
185
|
-
},
|
|
186
|
-
cta = {
|
|
187
|
-
variant: "default",
|
|
188
|
-
size: "lg",
|
|
189
|
-
className:
|
|
190
|
-
"w-full bg-primary hover:bg-primary/90 dark:bg-primary dark:hover:bg-primary/90 text-primary-foreground font-medium shadow-md hover:shadow-lg transition-all duration-200 hover:-translate-y-0.5 border-[var(--btn-border)] focus-visible:ring-[var(--btn-ring)]",
|
|
191
|
-
},
|
|
192
|
-
popularBadge = {
|
|
193
|
-
className:
|
|
194
|
-
"absolute -top-3 left-1/2 transform -translate-x-1/2 bg-primary text-primary-foreground px-4 py-1 rounded-full text-sm font-medium bg-[var(--badge-bg)] text-[var(--badge-fg)] border-[var(--badge-border)]",
|
|
195
|
-
},
|
|
196
|
-
ariaLabel = "Pricing section",
|
|
197
|
-
}: PricingProps) {
|
|
198
|
-
return (
|
|
199
|
-
<section
|
|
200
|
-
id={id || "pricing"}
|
|
201
|
-
className={cn(section.className, className)}
|
|
202
|
-
aria-label={ariaLabel}
|
|
203
|
-
>
|
|
204
|
-
<div className={container.className}>
|
|
205
|
-
{/* Section heading */}
|
|
206
|
-
<h2 className={heading.className}>{pricingHeadingText}</h2>
|
|
207
|
-
|
|
208
|
-
{/* Pricing cards grid */}
|
|
209
|
-
<div className={grid.className}>
|
|
210
|
-
{pricingPlans.map((plan, index) => (
|
|
211
|
-
<motion.div
|
|
212
|
-
key={index}
|
|
213
|
-
initial={
|
|
214
|
-
enableMotion ? { opacity: 0, y: 12 } : { opacity: 1, y: 0 }
|
|
215
|
-
}
|
|
216
|
-
whileInView={{ opacity: 1, y: 0 }}
|
|
217
|
-
viewport={
|
|
218
|
-
enableMotion
|
|
219
|
-
? { once: true, amount: 0.2 }
|
|
220
|
-
: { once: true, amount: 0 }
|
|
221
|
-
}
|
|
222
|
-
transition={
|
|
223
|
-
enableMotion
|
|
224
|
-
? {
|
|
225
|
-
type: "spring",
|
|
226
|
-
stiffness: 125,
|
|
227
|
-
damping: 50,
|
|
228
|
-
mass: 1,
|
|
229
|
-
delay: 0.12 + index * 0.06,
|
|
230
|
-
}
|
|
231
|
-
: { type: "tween", duration: 0 }
|
|
232
|
-
}
|
|
233
|
-
className="motion-reduce:transform-none motion-reduce:transition-none"
|
|
234
|
-
>
|
|
235
|
-
<PricingCard
|
|
236
|
-
pricingCardTitle={plan.pricingPlanHeaderText}
|
|
237
|
-
pricingCardPrice={plan.pricingPlanPrice}
|
|
238
|
-
pricingCardFeatures={plan.pricingPlanFeatures}
|
|
239
|
-
pricingCardCTALabel={plan.pricingPlanCTALabel}
|
|
240
|
-
pricingCardCTAHref={plan.pricingPlanCTAHref}
|
|
241
|
-
isPopular={plan.isPopular}
|
|
242
|
-
card={{
|
|
243
|
-
className: cn(
|
|
244
|
-
card.className,
|
|
245
|
-
enableMotion
|
|
246
|
-
? "transition-all duration-200 hover:-translate-y-1 motion-reduce:transform-none motion-reduce:transition-none"
|
|
247
|
-
: "transition-none hover:!translate-y-0 hover:shadow-none",
|
|
248
|
-
),
|
|
249
|
-
}}
|
|
250
|
-
header={header}
|
|
251
|
-
title={title}
|
|
252
|
-
price={price}
|
|
253
|
-
features={features}
|
|
254
|
-
featureItem={featureItem}
|
|
255
|
-
cta={cta}
|
|
256
|
-
popularBadge={popularBadge}
|
|
257
|
-
/>
|
|
258
|
-
</motion.div>
|
|
259
|
-
))}
|
|
260
|
-
</div>
|
|
261
|
-
</div>
|
|
262
|
-
</section>
|
|
263
|
-
);
|
|
264
|
-
}
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { motion } from "motion/react";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
import { PricingCard } from "@/components/ui/pricing-card";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Represents individual pricing plan data.
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export interface PricingData {
|
|
13
|
+
/** Title of the plan (e.g., "Pro") */
|
|
14
|
+
pricingPlanHeaderText?: string;
|
|
15
|
+
/** Display price (e.g., "$19.99") */
|
|
16
|
+
pricingPlanPrice?: string;
|
|
17
|
+
/** Feature list bullets */
|
|
18
|
+
pricingPlanFeatures?: string[];
|
|
19
|
+
/** CTA button label */
|
|
20
|
+
pricingPlanCTALabel?: string;
|
|
21
|
+
/** CTA button href */
|
|
22
|
+
pricingPlanCTAHref?: string;
|
|
23
|
+
/** Whether this plan should be highlighted */
|
|
24
|
+
isPopular?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Props for the Pricing section component.
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
* - Styling: slot-style className overrides are merged after defaults via cn().
|
|
32
|
+
* - Motion: enableMotion toggles entrance animations and hover transitions.
|
|
33
|
+
* - Accessibility: uses a semantic <section> with an aria-label.
|
|
34
|
+
*/
|
|
35
|
+
interface PricingProps {
|
|
36
|
+
/** Optional id on root. @defaultValue "pricing" */
|
|
37
|
+
id?: string;
|
|
38
|
+
/** Merge-in class for root */
|
|
39
|
+
className?: string;
|
|
40
|
+
|
|
41
|
+
/** Heading text displayed at the top of the pricing section. @defaultValue "Choose Your Plan" */
|
|
42
|
+
pricingHeadingText?: string;
|
|
43
|
+
/** Array of individual pricing plans to display. @defaultValue defaultPricingData */
|
|
44
|
+
pricingPlans?: PricingData[];
|
|
45
|
+
|
|
46
|
+
/** When false, disables entrance animations and hover transitions */
|
|
47
|
+
enableMotion?: boolean;
|
|
48
|
+
|
|
49
|
+
/** Styling configuration objects */
|
|
50
|
+
section?: {
|
|
51
|
+
className?: string;
|
|
52
|
+
};
|
|
53
|
+
container?: {
|
|
54
|
+
className?: string;
|
|
55
|
+
};
|
|
56
|
+
heading?: {
|
|
57
|
+
className?: string;
|
|
58
|
+
};
|
|
59
|
+
grid?: {
|
|
60
|
+
className?: string;
|
|
61
|
+
};
|
|
62
|
+
card?: {
|
|
63
|
+
className?: string;
|
|
64
|
+
};
|
|
65
|
+
header?: {
|
|
66
|
+
className?: string;
|
|
67
|
+
};
|
|
68
|
+
title?: {
|
|
69
|
+
className?: string;
|
|
70
|
+
};
|
|
71
|
+
price?: {
|
|
72
|
+
className?: string;
|
|
73
|
+
};
|
|
74
|
+
features?: {
|
|
75
|
+
className?: string;
|
|
76
|
+
};
|
|
77
|
+
featureItem?: {
|
|
78
|
+
className?: string;
|
|
79
|
+
};
|
|
80
|
+
cta?: {
|
|
81
|
+
unstyled?: boolean;
|
|
82
|
+
style?: React.CSSProperties;
|
|
83
|
+
variant?:
|
|
84
|
+
| "default"
|
|
85
|
+
| "destructive"
|
|
86
|
+
| "outline"
|
|
87
|
+
| "secondary"
|
|
88
|
+
| "ghost"
|
|
89
|
+
| "link";
|
|
90
|
+
size?: "default" | "sm" | "lg" | "icon";
|
|
91
|
+
className?: string;
|
|
92
|
+
};
|
|
93
|
+
popularBadge?: {
|
|
94
|
+
className?: string;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/** ARIA label for the pricing section */
|
|
98
|
+
ariaLabel?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Default pricing plans used if none are passed in.
|
|
103
|
+
*/
|
|
104
|
+
const defaultPricingData: PricingData[] = [
|
|
105
|
+
{
|
|
106
|
+
pricingPlanHeaderText: "Basic",
|
|
107
|
+
pricingPlanPrice: "$9.99",
|
|
108
|
+
pricingPlanFeatures: ["Feature 1", "Feature 2", "Feature 3"],
|
|
109
|
+
pricingPlanCTALabel: "Select Plan",
|
|
110
|
+
pricingPlanCTAHref: "#contact",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
pricingPlanHeaderText: "Pro",
|
|
114
|
+
pricingPlanPrice: "$19.99",
|
|
115
|
+
pricingPlanFeatures: ["Feature 1", "Feature 2", "Feature 3", "Feature 4"],
|
|
116
|
+
pricingPlanCTALabel: "Select Plan",
|
|
117
|
+
pricingPlanCTAHref: "#contact",
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
pricingPlanHeaderText: "Enterprise",
|
|
121
|
+
pricingPlanPrice: "$49.99",
|
|
122
|
+
pricingPlanFeatures: [
|
|
123
|
+
"Feature 1",
|
|
124
|
+
"Feature 2",
|
|
125
|
+
"Feature 3",
|
|
126
|
+
"Feature 4",
|
|
127
|
+
"Feature 5",
|
|
128
|
+
],
|
|
129
|
+
pricingPlanCTALabel: "Select Plan",
|
|
130
|
+
pricingPlanCTAHref: "#contact",
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Responsive pricing grid using PricingCard with optional motion.
|
|
136
|
+
*
|
|
137
|
+
* @remarks
|
|
138
|
+
* - Styling: exposes slot-style overrides (card, header, title, price, etc.).
|
|
139
|
+
* - Motion: enableMotion controls entrance animations and hover transitions.
|
|
140
|
+
* - Accessibility: semantic <section> with aria-label.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* <Pricing pricingPlans={[{ pricingPlanHeaderText: 'Pro', pricingPlanPrice: '$19' }]} />
|
|
144
|
+
*/
|
|
145
|
+
export function Pricing({
|
|
146
|
+
id,
|
|
147
|
+
className,
|
|
148
|
+
pricingPlans = defaultPricingData,
|
|
149
|
+
pricingHeadingText = "Choose Your Plan",
|
|
150
|
+
enableMotion = true,
|
|
151
|
+
section = {
|
|
152
|
+
className: "pt-20 pb-5 bg-background text-foreground",
|
|
153
|
+
},
|
|
154
|
+
container = {
|
|
155
|
+
className: "max-w-7xl mx-auto px-6",
|
|
156
|
+
},
|
|
157
|
+
heading = {
|
|
158
|
+
className:
|
|
159
|
+
"text-3xl font-bold font-poppins text-center text-foreground mb-8",
|
|
160
|
+
},
|
|
161
|
+
grid = {
|
|
162
|
+
className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mt-8",
|
|
163
|
+
},
|
|
164
|
+
card = {
|
|
165
|
+
className:
|
|
166
|
+
"relative bg-card border border-border rounded-lg shadow-md hover:shadow-lg transition-shadow duration-200 bg-[var(--card-bg)] text-[var(--card-fg)] border-[var(--card-border)] shadow-[var(--card-shadow)]",
|
|
167
|
+
},
|
|
168
|
+
header = {
|
|
169
|
+
className: "p-6 text-center border-b border-[var(--card-border)]",
|
|
170
|
+
},
|
|
171
|
+
title = {
|
|
172
|
+
className:
|
|
173
|
+
"text-xl font-bold font-poppins text-card-foreground mb-2 text-[var(--card-title-fg)]",
|
|
174
|
+
},
|
|
175
|
+
price = {
|
|
176
|
+
className:
|
|
177
|
+
"text-3xl font-bold font-poppins text-card-foreground mb-4 text-[var(--card-title-fg)]",
|
|
178
|
+
},
|
|
179
|
+
features = {
|
|
180
|
+
className: "p-6 space-y-3 font-inter",
|
|
181
|
+
},
|
|
182
|
+
featureItem = {
|
|
183
|
+
className:
|
|
184
|
+
"flex items-center text-muted-foreground text-sm text-[var(--card-muted-fg)]",
|
|
185
|
+
},
|
|
186
|
+
cta = {
|
|
187
|
+
variant: "default",
|
|
188
|
+
size: "lg",
|
|
189
|
+
className:
|
|
190
|
+
"w-full bg-primary hover:bg-primary/90 dark:bg-primary dark:hover:bg-primary/90 text-primary-foreground font-medium shadow-md hover:shadow-lg transition-all duration-200 hover:-translate-y-0.5 border-[var(--btn-border)] focus-visible:ring-[var(--btn-ring)]",
|
|
191
|
+
},
|
|
192
|
+
popularBadge = {
|
|
193
|
+
className:
|
|
194
|
+
"absolute -top-3 left-1/2 transform -translate-x-1/2 bg-primary text-primary-foreground px-4 py-1 rounded-full text-sm font-medium bg-[var(--badge-bg)] text-[var(--badge-fg)] border-[var(--badge-border)]",
|
|
195
|
+
},
|
|
196
|
+
ariaLabel = "Pricing section",
|
|
197
|
+
}: PricingProps) {
|
|
198
|
+
return (
|
|
199
|
+
<section
|
|
200
|
+
id={id || "pricing"}
|
|
201
|
+
className={cn(section.className, className)}
|
|
202
|
+
aria-label={ariaLabel}
|
|
203
|
+
>
|
|
204
|
+
<div className={container.className}>
|
|
205
|
+
{/* Section heading */}
|
|
206
|
+
<h2 className={heading.className}>{pricingHeadingText}</h2>
|
|
207
|
+
|
|
208
|
+
{/* Pricing cards grid */}
|
|
209
|
+
<div className={grid.className}>
|
|
210
|
+
{pricingPlans.map((plan, index) => (
|
|
211
|
+
<motion.div
|
|
212
|
+
key={index}
|
|
213
|
+
initial={
|
|
214
|
+
enableMotion ? { opacity: 0, y: 12 } : { opacity: 1, y: 0 }
|
|
215
|
+
}
|
|
216
|
+
whileInView={{ opacity: 1, y: 0 }}
|
|
217
|
+
viewport={
|
|
218
|
+
enableMotion
|
|
219
|
+
? { once: true, amount: 0.2 }
|
|
220
|
+
: { once: true, amount: 0 }
|
|
221
|
+
}
|
|
222
|
+
transition={
|
|
223
|
+
enableMotion
|
|
224
|
+
? {
|
|
225
|
+
type: "spring",
|
|
226
|
+
stiffness: 125,
|
|
227
|
+
damping: 50,
|
|
228
|
+
mass: 1,
|
|
229
|
+
delay: 0.12 + index * 0.06,
|
|
230
|
+
}
|
|
231
|
+
: { type: "tween", duration: 0 }
|
|
232
|
+
}
|
|
233
|
+
className="motion-reduce:transform-none motion-reduce:transition-none"
|
|
234
|
+
>
|
|
235
|
+
<PricingCard
|
|
236
|
+
pricingCardTitle={plan.pricingPlanHeaderText}
|
|
237
|
+
pricingCardPrice={plan.pricingPlanPrice}
|
|
238
|
+
pricingCardFeatures={plan.pricingPlanFeatures}
|
|
239
|
+
pricingCardCTALabel={plan.pricingPlanCTALabel}
|
|
240
|
+
pricingCardCTAHref={plan.pricingPlanCTAHref}
|
|
241
|
+
isPopular={plan.isPopular}
|
|
242
|
+
card={{
|
|
243
|
+
className: cn(
|
|
244
|
+
card.className,
|
|
245
|
+
enableMotion
|
|
246
|
+
? "transition-all duration-200 hover:-translate-y-1 motion-reduce:transform-none motion-reduce:transition-none"
|
|
247
|
+
: "transition-none hover:!translate-y-0 hover:shadow-none",
|
|
248
|
+
),
|
|
249
|
+
}}
|
|
250
|
+
header={header}
|
|
251
|
+
title={title}
|
|
252
|
+
price={price}
|
|
253
|
+
features={features}
|
|
254
|
+
featureItem={featureItem}
|
|
255
|
+
cta={cta}
|
|
256
|
+
popularBadge={popularBadge}
|
|
257
|
+
/>
|
|
258
|
+
</motion.div>
|
|
259
|
+
))}
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
</section>
|
|
263
|
+
);
|
|
264
|
+
}
|