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.
Files changed (111) hide show
  1. package/README.md +283 -282
  2. package/dist/cli_manifests/blocks_manifest.json +198 -175
  3. package/dist/kits/blocks/.nextworks/docs/BLOCKS_QUICKSTART.md +101 -100
  4. package/dist/kits/blocks/.nextworks/docs/BLOCKS_README.md +105 -104
  5. package/dist/kits/blocks/.nextworks/docs/THEME_GUIDE.md +1 -1
  6. package/dist/kits/blocks/app/templates/aiworkflow/PresetThemeVars.tsx +58 -0
  7. package/dist/kits/blocks/app/templates/aiworkflow/README.md +46 -0
  8. package/dist/kits/blocks/app/templates/aiworkflow/components/CTA.tsx +44 -0
  9. package/dist/kits/blocks/app/templates/aiworkflow/components/Contact.tsx +105 -0
  10. package/dist/kits/blocks/app/templates/aiworkflow/components/FAQ.tsx +63 -0
  11. package/dist/kits/blocks/app/templates/aiworkflow/components/Features.tsx +65 -0
  12. package/dist/kits/blocks/app/templates/aiworkflow/components/Footer.tsx +109 -0
  13. package/dist/kits/blocks/app/templates/aiworkflow/components/Hero.tsx +636 -0
  14. package/dist/kits/blocks/app/templates/aiworkflow/components/Navbar.tsx +90 -0
  15. package/dist/kits/blocks/app/templates/aiworkflow/components/Pricing.tsx +86 -0
  16. package/dist/kits/blocks/app/templates/aiworkflow/components/ProcessTimeline.tsx +103 -0
  17. package/dist/kits/blocks/app/templates/aiworkflow/components/Testimonials.tsx +56 -0
  18. package/dist/kits/blocks/app/templates/aiworkflow/components/TrustBadges.tsx +59 -0
  19. package/dist/kits/blocks/app/templates/aiworkflow/page.tsx +43 -0
  20. package/dist/kits/blocks/app/templates/digitalagency/PresetThemeVars.tsx +80 -80
  21. package/dist/kits/blocks/app/templates/digitalagency/README.md +42 -42
  22. package/dist/kits/blocks/app/templates/digitalagency/components/Pricing.tsx +114 -114
  23. package/dist/kits/blocks/app/templates/digitalagency/components/Process.tsx +59 -59
  24. package/dist/kits/blocks/app/templates/digitalagency/components/Services.tsx +55 -55
  25. package/dist/kits/blocks/app/templates/digitalagency/components/Team.tsx +28 -28
  26. package/dist/kits/blocks/app/templates/digitalagency/components/Testimonials.tsx +65 -65
  27. package/dist/kits/blocks/app/templates/digitalagency/page.tsx +38 -38
  28. package/dist/kits/blocks/app/templates/gallery/PresetThemeVars.tsx +84 -84
  29. package/dist/kits/blocks/app/templates/productlaunch/PresetThemeVars.tsx +75 -75
  30. package/dist/kits/blocks/app/templates/productlaunch/README.md +62 -62
  31. package/dist/kits/blocks/app/templates/productlaunch/components/About.tsx +84 -84
  32. package/dist/kits/blocks/app/templates/productlaunch/components/CTA.tsx +50 -50
  33. package/dist/kits/blocks/app/templates/productlaunch/components/Contact.tsx +231 -231
  34. package/dist/kits/blocks/app/templates/productlaunch/components/FAQ.tsx +86 -86
  35. package/dist/kits/blocks/app/templates/productlaunch/components/Features.tsx +83 -83
  36. package/dist/kits/blocks/app/templates/productlaunch/components/Footer.tsx +132 -132
  37. package/dist/kits/blocks/app/templates/productlaunch/components/Hero.tsx +88 -88
  38. package/dist/kits/blocks/app/templates/productlaunch/components/Navbar.tsx +116 -116
  39. package/dist/kits/blocks/app/templates/productlaunch/components/Pricing.tsx +106 -106
  40. package/dist/kits/blocks/app/templates/productlaunch/components/ProcessTimeline.tsx +110 -110
  41. package/dist/kits/blocks/app/templates/productlaunch/components/ServicesGrid.tsx +68 -68
  42. package/dist/kits/blocks/app/templates/productlaunch/components/Team.tsx +104 -104
  43. package/dist/kits/blocks/app/templates/productlaunch/components/Testimonials.tsx +90 -90
  44. package/dist/kits/blocks/app/templates/productlaunch/components/TrustBadges.tsx +76 -76
  45. package/dist/kits/blocks/app/templates/productlaunch/page.tsx +43 -43
  46. package/dist/kits/blocks/app/templates/saasdashboard/PresetThemeVars.tsx +80 -80
  47. package/dist/kits/blocks/app/templates/saasdashboard/README.md +44 -44
  48. package/dist/kits/blocks/app/templates/saasdashboard/components/Contact.tsx +129 -129
  49. package/dist/kits/blocks/app/templates/saasdashboard/components/Dashboard.tsx +293 -293
  50. package/dist/kits/blocks/app/templates/saasdashboard/components/FAQ.tsx +55 -55
  51. package/dist/kits/blocks/app/templates/saasdashboard/components/Features.tsx +90 -90
  52. package/dist/kits/blocks/app/templates/saasdashboard/components/Footer.tsx +77 -77
  53. package/dist/kits/blocks/app/templates/saasdashboard/components/Hero.tsx +104 -104
  54. package/dist/kits/blocks/app/templates/saasdashboard/components/Hero_mask.tsx +126 -126
  55. package/dist/kits/blocks/app/templates/saasdashboard/components/Navbar.tsx +117 -117
  56. package/dist/kits/blocks/app/templates/saasdashboard/components/Pricing.tsx +90 -90
  57. package/dist/kits/blocks/app/templates/saasdashboard/components/SmoothScroll.tsx +96 -96
  58. package/dist/kits/blocks/app/templates/saasdashboard/components/Testimonials.tsx +72 -72
  59. package/dist/kits/blocks/app/templates/saasdashboard/components/TrustBadges.tsx +53 -53
  60. package/dist/kits/blocks/app/templates/saasdashboard/page.tsx +39 -39
  61. package/dist/kits/blocks/components/enhanced-theme-provider.tsx +195 -195
  62. package/dist/kits/blocks/components/providers/BlocksAppProviders.tsx +27 -27
  63. package/dist/kits/blocks/components/sections/About.tsx +291 -291
  64. package/dist/kits/blocks/components/sections/CTA.tsx +257 -257
  65. package/dist/kits/blocks/components/sections/Contact.tsx +267 -267
  66. package/dist/kits/blocks/components/sections/FAQ.tsx +214 -214
  67. package/dist/kits/blocks/components/sections/Features.tsx +268 -268
  68. package/dist/kits/blocks/components/sections/Footer.tsx +302 -302
  69. package/dist/kits/blocks/components/sections/HeroMotion.tsx +308 -308
  70. package/dist/kits/blocks/components/sections/HeroOverlay.tsx +358 -358
  71. package/dist/kits/blocks/components/sections/HeroProductDemo.tsx +236 -0
  72. package/dist/kits/blocks/components/sections/HeroSplit.tsx +352 -352
  73. package/dist/kits/blocks/components/sections/Navbar.tsx +350 -350
  74. package/dist/kits/blocks/components/sections/PortfolioSimple.tsx +549 -549
  75. package/dist/kits/blocks/components/sections/Pricing.tsx +264 -264
  76. package/dist/kits/blocks/components/sections/ProcessTimeline.tsx +325 -325
  77. package/dist/kits/blocks/components/sections/ServicesGrid.tsx +210 -210
  78. package/dist/kits/blocks/components/sections/Team.tsx +309 -309
  79. package/dist/kits/blocks/components/sections/Testimonials.tsx +158 -158
  80. package/dist/kits/blocks/components/sections/TrustBadges.tsx +162 -162
  81. package/dist/kits/blocks/components/sections/product-demo/ApprovalInboxPanel.tsx +125 -0
  82. package/dist/kits/blocks/components/sections/product-demo/DemoStage.tsx +397 -0
  83. package/dist/kits/blocks/components/sections/product-demo/DemoWindow.tsx +128 -0
  84. package/dist/kits/blocks/components/sections/product-demo/KnowledgePanel.tsx +127 -0
  85. package/dist/kits/blocks/components/sections/product-demo/RunConsolePanel.tsx +150 -0
  86. package/dist/kits/blocks/components/sections/product-demo/WorkflowStudioPanel.tsx +191 -0
  87. package/dist/kits/blocks/components/sections/product-demo/types.ts +193 -0
  88. package/dist/kits/blocks/components/theme-provider.tsx +1 -1
  89. package/dist/kits/blocks/components/ui/alert-dialog.tsx +134 -134
  90. package/dist/kits/blocks/components/ui/brand-node.tsx +121 -121
  91. package/dist/kits/blocks/components/ui/button.tsx +122 -122
  92. package/dist/kits/blocks/components/ui/card.tsx +95 -95
  93. package/dist/kits/blocks/components/ui/checkbox.tsx +30 -30
  94. package/dist/kits/blocks/components/ui/cta-button.tsx +125 -125
  95. package/dist/kits/blocks/components/ui/dropdown-menu.tsx +201 -201
  96. package/dist/kits/blocks/components/ui/feature-card.tsx +91 -91
  97. package/dist/kits/blocks/components/ui/input.tsx +27 -27
  98. package/dist/kits/blocks/components/ui/label.tsx +29 -29
  99. package/dist/kits/blocks/components/ui/pricing-card.tsx +120 -120
  100. package/dist/kits/blocks/components/ui/select.tsx +25 -25
  101. package/dist/kits/blocks/components/ui/skeleton.tsx +13 -13
  102. package/dist/kits/blocks/components/ui/table.tsx +98 -98
  103. package/dist/kits/blocks/components/ui/testimonial-card.tsx +108 -108
  104. package/dist/kits/blocks/components/ui/textarea.tsx +26 -26
  105. package/dist/kits/blocks/components/ui/theme-selector.tsx +243 -243
  106. package/dist/kits/blocks/components/ui/theme-toggle.tsx +74 -74
  107. package/dist/kits/blocks/components/ui/toaster.tsx +7 -7
  108. package/dist/kits/blocks/lib/themes.ts +400 -400
  109. package/dist/kits/blocks/lib/utils.ts +6 -6
  110. package/dist/kits/blocks/package-deps.json +3 -3
  111. package/package.json +1 -1
@@ -1,358 +1,358 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import Image from "next/image";
5
- import Link from "next/link";
6
- import { Button } from "@/components/ui/button";
7
- import { cn } from "@/lib/utils";
8
-
9
- /**
10
- * Props for the HeroOverlay component.
11
- *
12
- * @remarks
13
- * - Prefer the structured image prop (image) over deprecated flat props.
14
- * - Slot-style className overrides are merged after defaults via cn().
15
- * - Motion controls affect CTA hover transitions.
16
- *
17
- * @public
18
- */
19
- export interface HeroOverlayProps {
20
- id?: string;
21
- className?: string;
22
-
23
- // Structured image props
24
- image?: {
25
- src?: string;
26
- alt?: string;
27
- className?: string;
28
- objectFit?: React.CSSProperties["objectFit"];
29
- objectPosition?: React.CSSProperties["objectPosition"];
30
- };
31
-
32
- // Deprecated flat image props (kept for backward compatibility)
33
- /** @deprecated Use image.src instead */
34
- imageSrc?: string;
35
- /** @deprecated Use image.alt instead */
36
- imageAlt?: string;
37
- /** @deprecated Use image.objectFit instead */
38
- imageObjectFit?: React.CSSProperties["objectFit"];
39
- /** @deprecated Use image.objectPosition instead */
40
- imageObjectPosition?: React.CSSProperties["objectPosition"];
41
-
42
- // Allow string or object form like HeroSplit
43
- heading?: string | { text?: string; className?: string };
44
- subheading?: string | { text?: string; className?: string };
45
- overlayRGBA?: string;
46
- overlayDarkRGBA?: string;
47
-
48
- // Alias to match HeroSplit naming
49
- section?: { className?: string };
50
- container?: { className?: string };
51
- imageContainer?: { className?: string };
52
- overlay?: { className?: string };
53
- content?: { className?: string };
54
- textContainer?: { className?: string };
55
-
56
- // Retained styles; merged with heading/subheading.className when provided
57
- /** @deprecated Use heading.className */
58
- headingStyle?: { className?: string };
59
- /** @deprecated Use subheading.className */
60
- subheadingStyle?: { className?: string };
61
-
62
- ctaContainer?: { className?: string };
63
-
64
- // CTA objects support label/href
65
- cta1?: {
66
- label?: string;
67
- href?: string;
68
- variant?:
69
- | "default"
70
- | "destructive"
71
- | "outline"
72
- | "secondary"
73
- | "ghost"
74
- | "link";
75
- size?: "default" | "sm" | "lg" | "icon";
76
- className?: string;
77
- unstyled?: boolean;
78
- style?: React.CSSProperties;
79
- };
80
- cta2?: {
81
- label?: string;
82
- href?: string;
83
- variant?:
84
- | "default"
85
- | "destructive"
86
- | "outline"
87
- | "secondary"
88
- | "ghost"
89
- | "link";
90
- size?: "default" | "sm" | "lg" | "icon";
91
- className?: string;
92
- unstyled?: boolean;
93
- style?: React.CSSProperties;
94
- };
95
-
96
- // Deprecated CTA props (kept for backward compatibility)
97
- /** @deprecated Use cta1.label instead */
98
- ctaBtn1Label?: string;
99
- /** @deprecated Use cta1.href instead */
100
- ctaBtn1Href?: string;
101
- /** @deprecated Use cta2.label instead */
102
- ctaBtn2Label?: string;
103
- /** @deprecated Use cta2.href instead */
104
- ctaBtn2Href?: string;
105
-
106
- ariaLabel?: string;
107
-
108
- // Motion control for CTA buttons
109
- enableMotion?: boolean;
110
- }
111
-
112
- /**
113
- * Full-bleed image hero with color overlay, heading/subheading, and up to two CTAs.
114
- *
115
- * @remarks
116
- * - Styling: slot-style overrides for container, imageContainer, overlay, content, textContainer.
117
- * - Motion: enableMotion applies hover-lift transitions to CTA buttons only.
118
- * - Accessibility: uses semantic <section> with aria-label; background image is
119
- * decorative with overlay and text content provided separately.
120
- *
121
- * @example
122
- * <HeroOverlay
123
- * image={{ src: "/hero.png", alt: "" }}
124
- * heading="Welcome"
125
- * subheading="Build faster with our blocks"
126
- * cta1={{ label: "Get Started", href: "#getstarted" }}
127
- * />
128
- */
129
- export function HeroOverlay({
130
- id,
131
- className,
132
-
133
- // Deprecated flat image defaults (still supported)
134
- imageSrc = "/hero.png",
135
- imageAlt = "Hero background image",
136
- imageObjectFit = "cover",
137
- imageObjectPosition = "center",
138
-
139
- // New structured image (optional)
140
- image,
141
-
142
- // Keep string defaults; object form supported
143
- heading = "Lorem ipsum dolor sit amet, consectetur",
144
- subheading = "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
145
- overlayRGBA = "rgba(255, 255, 255, 0.8)",
146
- overlayDarkRGBA = "rgba(0, 0, 0, 0.8)",
147
-
148
- // Deprecated CTA label/href (still supported)
149
- ctaBtn1Label = "Get Started",
150
- ctaBtn1Href = "#getstarted",
151
- ctaBtn2Label,
152
- ctaBtn2Href,
153
-
154
- // Layout containers
155
- container = { className: "relative h-[440px] md:h-[500px] w-full" },
156
- // container = { className: "relative h-[500px] md:h-[600px] w-full" },
157
- section,
158
- imageContainer = { className: "absolute inset-0" },
159
- overlay = { className: "absolute inset-0 z-10 pointer-events-none" },
160
- content = {
161
- className:
162
- "relative z-20 h-full w-full flex flex-col justify-start items-center pt-14 pb-8 px-8",
163
- },
164
- textContainer = { className: "max-w-4xl space-y-6 text-center" },
165
-
166
- // Typography defaults (deprecated props still merged)
167
- headingStyle = { className: "" },
168
- subheadingStyle = { className: "" },
169
-
170
- // CTA containers and variants
171
- ctaContainer = {
172
- className:
173
- "flex flex-col sm:flex-row gap-4 mt-6 justify-center items-center",
174
- },
175
- cta1,
176
- cta2,
177
-
178
- ariaLabel = "Hero section",
179
- enableMotion = true,
180
- }: HeroOverlayProps) {
181
- // Merge new structured image with deprecated flat props
182
- const effImage = {
183
- src: image?.src ?? imageSrc,
184
- alt: image?.alt ?? imageAlt,
185
- objectFit: image?.objectFit ?? imageObjectFit,
186
- objectPosition: image?.objectPosition ?? imageObjectPosition,
187
- className: image?.className,
188
- };
189
-
190
- // Defaults and normalization like HeroSplit
191
- const defaultHeading = {
192
- text: "Lorem ipsum dolor sit amet, consectetur",
193
- className:
194
- "text-4xl md:text-5xl font-bold text-center leading-tight text-foreground",
195
- };
196
- const defaultSubheading = {
197
- text: "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
198
- className:
199
- "text-xl md:text-2xl text-center text-foreground leading-relaxed",
200
- };
201
-
202
- const normalizedHeading =
203
- typeof heading === "string"
204
- ? {
205
- text: heading,
206
- className: cn(defaultHeading.className, headingStyle?.className),
207
- }
208
- : {
209
- text: heading?.text ?? defaultHeading.text,
210
- className: cn(
211
- defaultHeading.className,
212
- headingStyle?.className,
213
- heading?.className,
214
- ),
215
- };
216
-
217
- const normalizedSubheading =
218
- typeof subheading === "string"
219
- ? {
220
- text: subheading,
221
- className: cn(
222
- defaultSubheading.className,
223
- subheadingStyle?.className,
224
- ),
225
- }
226
- : {
227
- text: subheading?.text ?? defaultSubheading.text,
228
- className: cn(
229
- defaultSubheading.className,
230
- subheadingStyle?.className,
231
- subheading?.className,
232
- ),
233
- };
234
-
235
- // Motion class for CTA buttons
236
- const buttonLift = enableMotion
237
- ? "transition-all duration-200 hover:-translate-y-0.5"
238
- : "transition-none hover:!translate-y-0";
239
-
240
- // CTA defaults and normalization (merge, don't replace).
241
- const defaultCta1 = {
242
- label: ctaBtn1Label,
243
- href: ctaBtn1Href,
244
- variant: "default" as const,
245
- size: "lg" as const,
246
- className: "",
247
- };
248
- const defaultCta2 = {
249
- label: ctaBtn2Label,
250
- href: ctaBtn2Href,
251
- variant: "outline" as const,
252
- size: "lg" as const,
253
- className: "",
254
- };
255
-
256
- const mergedCta1 = {
257
- ...defaultCta1,
258
- ...(cta1 ?? {}),
259
- className: cn(defaultCta1.className, cta1?.className, buttonLift),
260
- };
261
- const mergedCta2 =
262
- cta2 || ctaBtn2Label || ctaBtn2Href
263
- ? {
264
- ...defaultCta2,
265
- ...(cta2 ?? {}),
266
- className: cn(defaultCta2.className, cta2?.className, buttonLift),
267
- }
268
- : undefined;
269
-
270
- // buttonLift defined above
271
-
272
- // Merge alias section.className with container.className
273
- const finalContainerClass = cn(container.className, section?.className);
274
-
275
- const showCta2 = !!mergedCta2?.label;
276
-
277
- return (
278
- <section
279
- id={id}
280
- className={cn(finalContainerClass, className)}
281
- aria-label={ariaLabel}
282
- >
283
- <div className={imageContainer.className}>
284
- <Image
285
- src={effImage.src!}
286
- alt={effImage.alt!}
287
- fill
288
- sizes="100vw"
289
- quality={75}
290
- priority
291
- className={effImage.className}
292
- style={{
293
- objectFit: effImage.objectFit,
294
- objectPosition: effImage.objectPosition,
295
- }}
296
- />
297
- </div>
298
-
299
- <div
300
- className={overlay.className}
301
- style={{ backgroundColor: overlayRGBA }}
302
- aria-hidden
303
- />
304
- <div
305
- className={cn(overlay.className, "hidden dark:block")}
306
- style={{ backgroundColor: overlayDarkRGBA }}
307
- aria-hidden
308
- />
309
-
310
- <div className={content.className}>
311
- <div className={textContainer.className}>
312
- <h1 className={normalizedHeading.className}>
313
- {normalizedHeading.text}
314
- </h1>
315
- <p className={normalizedSubheading.className}>
316
- {normalizedSubheading.text}
317
- </p>
318
- <div className={ctaContainer.className}>
319
- {mergedCta1.label && (
320
- <Button
321
- asChild
322
- variant={mergedCta1.variant}
323
- size={mergedCta1.size}
324
- className={mergedCta1.className}
325
- unstyled={mergedCta1.unstyled}
326
- style={mergedCta1.style}
327
- >
328
- <Link
329
- href={mergedCta1.href || "#"}
330
- aria-label={mergedCta1.label}
331
- >
332
- {mergedCta1.label}
333
- </Link>
334
- </Button>
335
- )}
336
- {showCta2 && (
337
- <Button
338
- asChild
339
- variant={mergedCta2!.variant}
340
- size={mergedCta2!.size}
341
- className={mergedCta2!.className}
342
- unstyled={mergedCta2!.unstyled}
343
- style={mergedCta2!.style}
344
- >
345
- <Link
346
- href={mergedCta2!.href || "#"}
347
- aria-label={mergedCta2!.label}
348
- >
349
- {mergedCta2!.label}
350
- </Link>
351
- </Button>
352
- )}
353
- </div>
354
- </div>
355
- </div>
356
- </section>
357
- );
358
- }
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import Image from "next/image";
5
+ import Link from "next/link";
6
+ import { Button } from "@/components/ui/button";
7
+ import { cn } from "@/lib/utils";
8
+
9
+ /**
10
+ * Props for the HeroOverlay component.
11
+ *
12
+ * @remarks
13
+ * - Prefer the structured image prop (image) over deprecated flat props.
14
+ * - Slot-style className overrides are merged after defaults via cn().
15
+ * - Motion controls affect CTA hover transitions.
16
+ *
17
+ * @public
18
+ */
19
+ export interface HeroOverlayProps {
20
+ id?: string;
21
+ className?: string;
22
+
23
+ // Structured image props
24
+ image?: {
25
+ src?: string;
26
+ alt?: string;
27
+ className?: string;
28
+ objectFit?: React.CSSProperties["objectFit"];
29
+ objectPosition?: React.CSSProperties["objectPosition"];
30
+ };
31
+
32
+ // Deprecated flat image props (kept for backward compatibility)
33
+ /** @deprecated Use image.src instead */
34
+ imageSrc?: string;
35
+ /** @deprecated Use image.alt instead */
36
+ imageAlt?: string;
37
+ /** @deprecated Use image.objectFit instead */
38
+ imageObjectFit?: React.CSSProperties["objectFit"];
39
+ /** @deprecated Use image.objectPosition instead */
40
+ imageObjectPosition?: React.CSSProperties["objectPosition"];
41
+
42
+ // Allow string or object form like HeroSplit
43
+ heading?: string | { text?: string; className?: string };
44
+ subheading?: string | { text?: string; className?: string };
45
+ overlayRGBA?: string;
46
+ overlayDarkRGBA?: string;
47
+
48
+ // Alias to match HeroSplit naming
49
+ section?: { className?: string };
50
+ container?: { className?: string };
51
+ imageContainer?: { className?: string };
52
+ overlay?: { className?: string };
53
+ content?: { className?: string };
54
+ textContainer?: { className?: string };
55
+
56
+ // Retained styles; merged with heading/subheading.className when provided
57
+ /** @deprecated Use heading.className */
58
+ headingStyle?: { className?: string };
59
+ /** @deprecated Use subheading.className */
60
+ subheadingStyle?: { className?: string };
61
+
62
+ ctaContainer?: { className?: string };
63
+
64
+ // CTA objects support label/href
65
+ cta1?: {
66
+ label?: string;
67
+ href?: string;
68
+ variant?:
69
+ | "default"
70
+ | "destructive"
71
+ | "outline"
72
+ | "secondary"
73
+ | "ghost"
74
+ | "link";
75
+ size?: "default" | "sm" | "lg" | "icon";
76
+ className?: string;
77
+ unstyled?: boolean;
78
+ style?: React.CSSProperties;
79
+ };
80
+ cta2?: {
81
+ label?: string;
82
+ href?: string;
83
+ variant?:
84
+ | "default"
85
+ | "destructive"
86
+ | "outline"
87
+ | "secondary"
88
+ | "ghost"
89
+ | "link";
90
+ size?: "default" | "sm" | "lg" | "icon";
91
+ className?: string;
92
+ unstyled?: boolean;
93
+ style?: React.CSSProperties;
94
+ };
95
+
96
+ // Deprecated CTA props (kept for backward compatibility)
97
+ /** @deprecated Use cta1.label instead */
98
+ ctaBtn1Label?: string;
99
+ /** @deprecated Use cta1.href instead */
100
+ ctaBtn1Href?: string;
101
+ /** @deprecated Use cta2.label instead */
102
+ ctaBtn2Label?: string;
103
+ /** @deprecated Use cta2.href instead */
104
+ ctaBtn2Href?: string;
105
+
106
+ ariaLabel?: string;
107
+
108
+ // Motion control for CTA buttons
109
+ enableMotion?: boolean;
110
+ }
111
+
112
+ /**
113
+ * Full-bleed image hero with color overlay, heading/subheading, and up to two CTAs.
114
+ *
115
+ * @remarks
116
+ * - Styling: slot-style overrides for container, imageContainer, overlay, content, textContainer.
117
+ * - Motion: enableMotion applies hover-lift transitions to CTA buttons only.
118
+ * - Accessibility: uses semantic <section> with aria-label; background image is
119
+ * decorative with overlay and text content provided separately.
120
+ *
121
+ * @example
122
+ * <HeroOverlay
123
+ * image={{ src: "/hero.png", alt: "" }}
124
+ * heading="Welcome"
125
+ * subheading="Build faster with our blocks"
126
+ * cta1={{ label: "Get Started", href: "#getstarted" }}
127
+ * />
128
+ */
129
+ export function HeroOverlay({
130
+ id,
131
+ className,
132
+
133
+ // Deprecated flat image defaults (still supported)
134
+ imageSrc = "/hero.png",
135
+ imageAlt = "Hero background image",
136
+ imageObjectFit = "cover",
137
+ imageObjectPosition = "center",
138
+
139
+ // New structured image (optional)
140
+ image,
141
+
142
+ // Keep string defaults; object form supported
143
+ heading = "Lorem ipsum dolor sit amet, consectetur",
144
+ subheading = "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
145
+ overlayRGBA = "rgba(255, 255, 255, 0.8)",
146
+ overlayDarkRGBA = "rgba(0, 0, 0, 0.8)",
147
+
148
+ // Deprecated CTA label/href (still supported)
149
+ ctaBtn1Label = "Get Started",
150
+ ctaBtn1Href = "#getstarted",
151
+ ctaBtn2Label,
152
+ ctaBtn2Href,
153
+
154
+ // Layout containers
155
+ container = { className: "relative h-[440px] md:h-[500px] w-full" },
156
+ // container = { className: "relative h-[500px] md:h-[600px] w-full" },
157
+ section,
158
+ imageContainer = { className: "absolute inset-0" },
159
+ overlay = { className: "absolute inset-0 z-10 pointer-events-none" },
160
+ content = {
161
+ className:
162
+ "relative z-20 h-full w-full flex flex-col justify-start items-center pt-14 pb-8 px-8",
163
+ },
164
+ textContainer = { className: "max-w-4xl space-y-6 text-center" },
165
+
166
+ // Typography defaults (deprecated props still merged)
167
+ headingStyle = { className: "" },
168
+ subheadingStyle = { className: "" },
169
+
170
+ // CTA containers and variants
171
+ ctaContainer = {
172
+ className:
173
+ "flex flex-col sm:flex-row gap-4 mt-6 justify-center items-center",
174
+ },
175
+ cta1,
176
+ cta2,
177
+
178
+ ariaLabel = "Hero section",
179
+ enableMotion = true,
180
+ }: HeroOverlayProps) {
181
+ // Merge new structured image with deprecated flat props
182
+ const effImage = {
183
+ src: image?.src ?? imageSrc,
184
+ alt: image?.alt ?? imageAlt,
185
+ objectFit: image?.objectFit ?? imageObjectFit,
186
+ objectPosition: image?.objectPosition ?? imageObjectPosition,
187
+ className: image?.className,
188
+ };
189
+
190
+ // Defaults and normalization like HeroSplit
191
+ const defaultHeading = {
192
+ text: "Lorem ipsum dolor sit amet, consectetur",
193
+ className:
194
+ "text-4xl md:text-5xl font-bold text-center leading-tight text-foreground",
195
+ };
196
+ const defaultSubheading = {
197
+ text: "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
198
+ className:
199
+ "text-xl md:text-2xl text-center text-foreground leading-relaxed",
200
+ };
201
+
202
+ const normalizedHeading =
203
+ typeof heading === "string"
204
+ ? {
205
+ text: heading,
206
+ className: cn(defaultHeading.className, headingStyle?.className),
207
+ }
208
+ : {
209
+ text: heading?.text ?? defaultHeading.text,
210
+ className: cn(
211
+ defaultHeading.className,
212
+ headingStyle?.className,
213
+ heading?.className,
214
+ ),
215
+ };
216
+
217
+ const normalizedSubheading =
218
+ typeof subheading === "string"
219
+ ? {
220
+ text: subheading,
221
+ className: cn(
222
+ defaultSubheading.className,
223
+ subheadingStyle?.className,
224
+ ),
225
+ }
226
+ : {
227
+ text: subheading?.text ?? defaultSubheading.text,
228
+ className: cn(
229
+ defaultSubheading.className,
230
+ subheadingStyle?.className,
231
+ subheading?.className,
232
+ ),
233
+ };
234
+
235
+ // Motion class for CTA buttons
236
+ const buttonLift = enableMotion
237
+ ? "transition-all duration-200 hover:-translate-y-0.5"
238
+ : "transition-none hover:!translate-y-0";
239
+
240
+ // CTA defaults and normalization (merge, don't replace).
241
+ const defaultCta1 = {
242
+ label: ctaBtn1Label,
243
+ href: ctaBtn1Href,
244
+ variant: "default" as const,
245
+ size: "lg" as const,
246
+ className: "",
247
+ };
248
+ const defaultCta2 = {
249
+ label: ctaBtn2Label,
250
+ href: ctaBtn2Href,
251
+ variant: "outline" as const,
252
+ size: "lg" as const,
253
+ className: "",
254
+ };
255
+
256
+ const mergedCta1 = {
257
+ ...defaultCta1,
258
+ ...(cta1 ?? {}),
259
+ className: cn(defaultCta1.className, cta1?.className, buttonLift),
260
+ };
261
+ const mergedCta2 =
262
+ cta2 || ctaBtn2Label || ctaBtn2Href
263
+ ? {
264
+ ...defaultCta2,
265
+ ...(cta2 ?? {}),
266
+ className: cn(defaultCta2.className, cta2?.className, buttonLift),
267
+ }
268
+ : undefined;
269
+
270
+ // buttonLift defined above
271
+
272
+ // Merge alias section.className with container.className
273
+ const finalContainerClass = cn(container.className, section?.className);
274
+
275
+ const showCta2 = !!mergedCta2?.label;
276
+
277
+ return (
278
+ <section
279
+ id={id}
280
+ className={cn(finalContainerClass, className)}
281
+ aria-label={ariaLabel}
282
+ >
283
+ <div className={imageContainer.className}>
284
+ <Image
285
+ src={effImage.src!}
286
+ alt={effImage.alt!}
287
+ fill
288
+ sizes="100vw"
289
+ quality={75}
290
+ priority
291
+ className={effImage.className}
292
+ style={{
293
+ objectFit: effImage.objectFit,
294
+ objectPosition: effImage.objectPosition,
295
+ }}
296
+ />
297
+ </div>
298
+
299
+ <div
300
+ className={overlay.className}
301
+ style={{ backgroundColor: overlayRGBA }}
302
+ aria-hidden
303
+ />
304
+ <div
305
+ className={cn(overlay.className, "hidden dark:block")}
306
+ style={{ backgroundColor: overlayDarkRGBA }}
307
+ aria-hidden
308
+ />
309
+
310
+ <div className={content.className}>
311
+ <div className={textContainer.className}>
312
+ <h1 className={normalizedHeading.className}>
313
+ {normalizedHeading.text}
314
+ </h1>
315
+ <p className={normalizedSubheading.className}>
316
+ {normalizedSubheading.text}
317
+ </p>
318
+ <div className={ctaContainer.className}>
319
+ {mergedCta1.label && (
320
+ <Button
321
+ asChild
322
+ variant={mergedCta1.variant}
323
+ size={mergedCta1.size}
324
+ className={mergedCta1.className}
325
+ unstyled={mergedCta1.unstyled}
326
+ style={mergedCta1.style}
327
+ >
328
+ <Link
329
+ href={mergedCta1.href || "#"}
330
+ aria-label={mergedCta1.label}
331
+ >
332
+ {mergedCta1.label}
333
+ </Link>
334
+ </Button>
335
+ )}
336
+ {showCta2 && (
337
+ <Button
338
+ asChild
339
+ variant={mergedCta2!.variant}
340
+ size={mergedCta2!.size}
341
+ className={mergedCta2!.className}
342
+ unstyled={mergedCta2!.unstyled}
343
+ style={mergedCta2!.style}
344
+ >
345
+ <Link
346
+ href={mergedCta2!.href || "#"}
347
+ aria-label={mergedCta2!.label}
348
+ >
349
+ {mergedCta2!.label}
350
+ </Link>
351
+ </Button>
352
+ )}
353
+ </div>
354
+ </div>
355
+ </div>
356
+ </section>
357
+ );
358
+ }