nextworks 0.2.0-alpha.2 → 0.2.0-alpha.21

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 (145) hide show
  1. package/README.md +280 -228
  2. package/dist/cli_manifests/blocks_manifest.json +193 -194
  3. package/dist/commands/blocks.d.ts +3 -0
  4. package/dist/commands/blocks.d.ts.map +1 -1
  5. package/dist/commands/blocks.js +128 -19
  6. package/dist/commands/blocks.js.map +1 -1
  7. package/dist/commands/doctor.d.ts +136 -0
  8. package/dist/commands/doctor.d.ts.map +1 -0
  9. package/dist/commands/doctor.js +696 -0
  10. package/dist/commands/doctor.js.map +1 -0
  11. package/dist/commands/remove-blocks.d.ts +4 -1
  12. package/dist/commands/remove-blocks.d.ts.map +1 -1
  13. package/dist/commands/remove-blocks.js +24 -6
  14. package/dist/commands/remove-blocks.js.map +1 -1
  15. package/dist/index.js +125 -4
  16. package/dist/index.js.map +1 -1
  17. package/dist/kits/blocks/.nextworks/docs/BLOCKS_QUICKSTART.md +104 -194
  18. package/dist/kits/blocks/.nextworks/docs/BLOCKS_README.md +115 -75
  19. package/dist/kits/blocks/.nextworks/docs/THEME_GUIDE.md +269 -251
  20. package/dist/kits/blocks/app/templates/digitalagency/PresetThemeVars.tsx +80 -80
  21. package/dist/kits/blocks/app/templates/digitalagency/README.md +42 -36
  22. package/dist/kits/blocks/app/templates/digitalagency/components/About.tsx +71 -99
  23. package/dist/kits/blocks/app/templates/digitalagency/components/CTA.tsx +40 -74
  24. package/dist/kits/blocks/app/templates/digitalagency/components/Contact.tsx +123 -227
  25. package/dist/kits/blocks/app/templates/digitalagency/components/Footer.tsx +89 -89
  26. package/dist/kits/blocks/app/templates/digitalagency/components/Hero.tsx +83 -90
  27. package/dist/kits/blocks/app/templates/digitalagency/components/Navbar.tsx +121 -168
  28. package/dist/kits/blocks/app/templates/digitalagency/components/NetworkPattern.tsx +288 -297
  29. package/dist/kits/blocks/app/templates/digitalagency/components/Portfolio.tsx +157 -157
  30. package/dist/kits/blocks/app/templates/digitalagency/components/Pricing.tsx +114 -114
  31. package/dist/kits/blocks/app/templates/digitalagency/components/Process.tsx +59 -59
  32. package/dist/kits/blocks/app/templates/digitalagency/components/Services.tsx +55 -55
  33. package/dist/kits/blocks/app/templates/digitalagency/components/Team.tsx +28 -28
  34. package/dist/kits/blocks/app/templates/digitalagency/components/Testimonials.tsx +65 -65
  35. package/dist/kits/blocks/app/templates/digitalagency/page.tsx +38 -38
  36. package/dist/kits/blocks/app/templates/gallery/PresetThemeVars.tsx +130 -85
  37. package/dist/kits/blocks/app/templates/gallery/page.tsx +357 -303
  38. package/dist/kits/blocks/app/templates/productlaunch/PresetThemeVars.tsx +75 -74
  39. package/dist/kits/blocks/app/templates/productlaunch/README.md +62 -55
  40. package/dist/kits/blocks/app/templates/productlaunch/components/About.tsx +84 -178
  41. package/dist/kits/blocks/app/templates/productlaunch/components/CTA.tsx +50 -93
  42. package/dist/kits/blocks/app/templates/productlaunch/components/Contact.tsx +231 -231
  43. package/dist/kits/blocks/app/templates/productlaunch/components/FAQ.tsx +86 -93
  44. package/dist/kits/blocks/app/templates/productlaunch/components/Features.tsx +83 -84
  45. package/dist/kits/blocks/app/templates/productlaunch/components/Footer.tsx +132 -132
  46. package/dist/kits/blocks/app/templates/productlaunch/components/Hero.tsx +88 -89
  47. package/dist/kits/blocks/app/templates/productlaunch/components/Navbar.tsx +116 -162
  48. package/dist/kits/blocks/app/templates/productlaunch/components/Pricing.tsx +106 -106
  49. package/dist/kits/blocks/app/templates/productlaunch/components/ProcessTimeline.tsx +110 -110
  50. package/dist/kits/blocks/app/templates/productlaunch/components/ServicesGrid.tsx +68 -68
  51. package/dist/kits/blocks/app/templates/productlaunch/components/Team.tsx +104 -104
  52. package/dist/kits/blocks/app/templates/productlaunch/components/Testimonials.tsx +90 -89
  53. package/dist/kits/blocks/app/templates/productlaunch/components/TrustBadges.tsx +76 -76
  54. package/dist/kits/blocks/app/templates/productlaunch/page.tsx +43 -43
  55. package/dist/kits/blocks/app/templates/saasdashboard/PresetThemeVars.tsx +80 -80
  56. package/dist/kits/blocks/app/templates/saasdashboard/README.md +44 -38
  57. package/dist/kits/blocks/app/templates/saasdashboard/components/Contact.tsx +129 -176
  58. package/dist/kits/blocks/app/templates/saasdashboard/components/Dashboard.tsx +293 -293
  59. package/dist/kits/blocks/app/templates/saasdashboard/components/FAQ.tsx +55 -55
  60. package/dist/kits/blocks/app/templates/saasdashboard/components/Features.tsx +90 -91
  61. package/dist/kits/blocks/app/templates/saasdashboard/components/Footer.tsx +77 -77
  62. package/dist/kits/blocks/app/templates/saasdashboard/components/Hero.tsx +104 -105
  63. package/dist/kits/blocks/app/templates/saasdashboard/components/Hero_mask.tsx +126 -127
  64. package/dist/kits/blocks/app/templates/saasdashboard/components/Navbar.tsx +117 -159
  65. package/dist/kits/blocks/app/templates/saasdashboard/components/Pricing.tsx +90 -90
  66. package/dist/kits/blocks/app/templates/saasdashboard/components/SmoothScroll.tsx +96 -97
  67. package/dist/kits/blocks/app/templates/saasdashboard/components/Testimonials.tsx +72 -72
  68. package/dist/kits/blocks/app/templates/saasdashboard/components/TrustBadges.tsx +53 -53
  69. package/dist/kits/blocks/app/templates/saasdashboard/page.tsx +39 -39
  70. package/dist/kits/blocks/components/enhanced-theme-provider.tsx +195 -183
  71. package/dist/kits/blocks/components/providers/BlocksAppProviders.tsx +27 -27
  72. package/dist/kits/blocks/components/sections/About.tsx +291 -291
  73. package/dist/kits/blocks/components/sections/CTA.tsx +257 -258
  74. package/dist/kits/blocks/components/sections/CommandShowcase.tsx +517 -0
  75. package/dist/kits/blocks/components/sections/Contact.tsx +267 -267
  76. package/dist/kits/blocks/components/sections/FAQ.tsx +214 -225
  77. package/dist/kits/blocks/components/sections/FeaturedProjectShowcase.tsx +687 -0
  78. package/dist/kits/blocks/components/sections/Features.tsx +268 -270
  79. package/dist/kits/blocks/components/sections/Footer.tsx +302 -302
  80. package/dist/kits/blocks/components/sections/HeroMotion.tsx +308 -308
  81. package/dist/kits/blocks/components/sections/HeroOverlay.tsx +358 -358
  82. package/dist/kits/blocks/components/sections/HeroProductDemo.tsx +246 -0
  83. package/dist/kits/blocks/components/sections/HeroSplit.tsx +352 -352
  84. package/dist/kits/blocks/components/sections/HeroWithVideo.tsx +495 -0
  85. package/dist/kits/blocks/components/sections/Navbar.tsx +352 -353
  86. package/dist/kits/blocks/components/sections/PortfolioSimple.tsx +549 -550
  87. package/dist/kits/blocks/components/sections/Pricing.tsx +264 -264
  88. package/dist/kits/blocks/components/sections/ProcessTimeline.tsx +325 -325
  89. package/dist/kits/blocks/components/sections/ProjectDeepDive.tsx +805 -0
  90. package/dist/kits/blocks/components/sections/SelectedWorkRail.tsx +485 -0
  91. package/dist/kits/blocks/components/sections/ServicesGrid.tsx +210 -210
  92. package/dist/kits/blocks/components/sections/Team.tsx +309 -309
  93. package/dist/kits/blocks/components/sections/Testimonials.tsx +158 -158
  94. package/dist/kits/blocks/components/sections/TrustBadges.tsx +162 -162
  95. package/dist/kits/blocks/components/sections/product-demo/ApprovalInboxPanel.tsx +128 -0
  96. package/dist/kits/blocks/components/sections/product-demo/DemoStage.tsx +519 -0
  97. package/dist/kits/blocks/components/sections/product-demo/DemoWindow.tsx +140 -0
  98. package/dist/kits/blocks/components/sections/product-demo/KnowledgePanel.tsx +130 -0
  99. package/dist/kits/blocks/components/sections/product-demo/RunConsolePanel.tsx +430 -0
  100. package/dist/kits/blocks/components/sections/product-demo/TaskListPanel.tsx +302 -0
  101. package/dist/kits/blocks/components/sections/product-demo/WorkflowStudioPanel.tsx +744 -0
  102. package/dist/kits/blocks/components/sections/product-demo/types.ts +262 -0
  103. package/dist/kits/blocks/components/theme-provider.tsx +1 -34
  104. package/dist/kits/blocks/components/ui/alert-dialog.tsx +134 -134
  105. package/dist/kits/blocks/components/ui/brand-node.tsx +121 -121
  106. package/dist/kits/blocks/components/ui/button.tsx +122 -122
  107. package/dist/kits/blocks/components/ui/card.tsx +95 -95
  108. package/dist/kits/blocks/components/ui/checkbox.tsx +30 -30
  109. package/dist/kits/blocks/components/ui/cta-button.tsx +125 -125
  110. package/dist/kits/blocks/components/ui/dropdown-menu.tsx +201 -201
  111. package/dist/kits/blocks/components/ui/feature-card.tsx +91 -91
  112. package/dist/kits/blocks/components/ui/input.tsx +27 -27
  113. package/dist/kits/blocks/components/ui/label.tsx +29 -29
  114. package/dist/kits/blocks/components/ui/pricing-card.tsx +120 -120
  115. package/dist/kits/blocks/components/ui/select.tsx +25 -25
  116. package/dist/kits/blocks/components/ui/skeleton.tsx +13 -13
  117. package/dist/kits/blocks/components/ui/table.tsx +98 -98
  118. package/dist/kits/blocks/components/ui/testimonial-card.tsx +108 -108
  119. package/dist/kits/blocks/components/ui/textarea.tsx +26 -26
  120. package/dist/kits/blocks/components/ui/theme-selector.tsx +243 -247
  121. package/dist/kits/blocks/components/ui/theme-toggle.tsx +74 -74
  122. package/dist/kits/blocks/components/ui/toaster.tsx +7 -7
  123. package/dist/kits/blocks/lib/themes.ts +400 -400
  124. package/dist/kits/blocks/lib/utils.ts +6 -9
  125. package/dist/kits/blocks/package-deps.json +40 -28
  126. package/dist/kits/blocks/tsconfig.json +11 -0
  127. package/dist/kits/blocks/tsconfig.tsbuildinfo +1 -0
  128. package/dist/utils/file-operations.d.ts +3 -1
  129. package/dist/utils/file-operations.d.ts.map +1 -1
  130. package/dist/utils/file-operations.js +84 -12
  131. package/dist/utils/file-operations.js.map +1 -1
  132. package/dist/utils/installation-tracker.d.ts +2 -2
  133. package/dist/utils/installation-tracker.d.ts.map +1 -1
  134. package/dist/utils/installation-tracker.js +11 -11
  135. package/dist/utils/installation-tracker.js.map +1 -1
  136. package/dist/utils/package-manager.d.ts +6 -0
  137. package/dist/utils/package-manager.d.ts.map +1 -0
  138. package/dist/utils/package-manager.js +58 -0
  139. package/dist/utils/package-manager.js.map +1 -0
  140. package/dist/utils/yarn-pnp.d.ts +6 -0
  141. package/dist/utils/yarn-pnp.d.ts.map +1 -0
  142. package/dist/utils/yarn-pnp.js +39 -0
  143. package/dist/utils/yarn-pnp.js.map +1 -0
  144. package/package.json +5 -2
  145. package/dist/kits/blocks/notes/THEME_GUIDE.md +0 -29
@@ -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
- // New structured image props (aligns with HeroSplit)
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 now support label/href (aligns with HeroSplit)
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
+ }