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,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
|
+
}
|