@nextworks/blocks-sections 0.1.0-alpha.0

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 (80) hide show
  1. package/README.md +44 -0
  2. package/dist/components/About.d.ts +93 -0
  3. package/dist/components/About.d.ts.map +1 -0
  4. package/dist/components/About.js +129 -0
  5. package/dist/components/About.jsx +153 -0
  6. package/dist/components/CTA.d.ts +118 -0
  7. package/dist/components/CTA.d.ts.map +1 -0
  8. package/dist/components/CTA.js +58 -0
  9. package/dist/components/CTA.jsx +88 -0
  10. package/dist/components/Contact.d.ts +111 -0
  11. package/dist/components/Contact.d.ts.map +1 -0
  12. package/dist/components/Contact.js +82 -0
  13. package/dist/components/Contact.jsx +107 -0
  14. package/dist/components/FAQ.d.ts +89 -0
  15. package/dist/components/FAQ.d.ts.map +1 -0
  16. package/dist/components/FAQ.js +78 -0
  17. package/dist/components/FAQ.jsx +98 -0
  18. package/dist/components/Features.d.ts +111 -0
  19. package/dist/components/Features.d.ts.map +1 -0
  20. package/dist/components/Features.js +109 -0
  21. package/dist/components/Features.jsx +122 -0
  22. package/dist/components/Footer.d.ts +120 -0
  23. package/dist/components/Footer.d.ts.map +1 -0
  24. package/dist/components/Footer.js +101 -0
  25. package/dist/components/Footer.jsx +138 -0
  26. package/dist/components/HeroMotion.d.ts +107 -0
  27. package/dist/components/HeroMotion.d.ts.map +1 -0
  28. package/dist/components/HeroMotion.js +55 -0
  29. package/dist/components/HeroMotion.jsx +95 -0
  30. package/dist/components/HeroOverlay.d.ts +116 -0
  31. package/dist/components/HeroOverlay.d.ts.map +1 -0
  32. package/dist/components/HeroOverlay.js +111 -0
  33. package/dist/components/HeroOverlay.jsx +141 -0
  34. package/dist/components/HeroSplit.d.ts +98 -0
  35. package/dist/components/HeroSplit.d.ts.map +1 -0
  36. package/dist/components/HeroSplit.js +100 -0
  37. package/dist/components/HeroSplit.jsx +134 -0
  38. package/dist/components/Navbar.d.ts +112 -0
  39. package/dist/components/Navbar.d.ts.map +1 -0
  40. package/dist/components/Navbar.js +80 -0
  41. package/dist/components/Navbar.jsx +127 -0
  42. package/dist/components/Newsletter.d.ts +59 -0
  43. package/dist/components/Newsletter.d.ts.map +1 -0
  44. package/dist/components/Newsletter.js +34 -0
  45. package/dist/components/Newsletter.jsx +54 -0
  46. package/dist/components/PortfolioSimple.d.ts +137 -0
  47. package/dist/components/PortfolioSimple.d.ts.map +1 -0
  48. package/dist/components/PortfolioSimple.js +180 -0
  49. package/dist/components/PortfolioSimple.jsx +259 -0
  50. package/dist/components/Pricing.d.ts +96 -0
  51. package/dist/components/Pricing.d.ts.map +1 -0
  52. package/dist/components/Pricing.js +91 -0
  53. package/dist/components/Pricing.jsx +103 -0
  54. package/dist/components/ProcessTimeline.d.ts +121 -0
  55. package/dist/components/ProcessTimeline.d.ts.map +1 -0
  56. package/dist/components/ProcessTimeline.js +88 -0
  57. package/dist/components/ProcessTimeline.jsx +151 -0
  58. package/dist/components/ServicesGrid.d.ts +64 -0
  59. package/dist/components/ServicesGrid.d.ts.map +1 -0
  60. package/dist/components/ServicesGrid.js +72 -0
  61. package/dist/components/ServicesGrid.jsx +97 -0
  62. package/dist/components/Team.d.ts +115 -0
  63. package/dist/components/Team.d.ts.map +1 -0
  64. package/dist/components/Team.js +107 -0
  65. package/dist/components/Team.jsx +135 -0
  66. package/dist/components/Testimonials.d.ts +81 -0
  67. package/dist/components/Testimonials.d.ts.map +1 -0
  68. package/dist/components/Testimonials.js +46 -0
  69. package/dist/components/Testimonials.jsx +58 -0
  70. package/dist/components/TrustBadges.d.ts +80 -0
  71. package/dist/components/TrustBadges.d.ts.map +1 -0
  72. package/dist/components/TrustBadges.js +46 -0
  73. package/dist/components/TrustBadges.jsx +64 -0
  74. package/dist/components/index.d.ts +21 -0
  75. package/dist/components/index.d.ts.map +1 -0
  76. package/dist/components/index.js +18 -0
  77. package/dist/index.d.ts +2 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +1 -0
  80. package/package.json +26 -0
@@ -0,0 +1,111 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import Image from "next/image";
4
+ import Link from "next/link";
5
+ import { Button } from "@nextworks/blocks-core";
6
+ import { cn } from "@nextworks/blocks-core";
7
+ /**
8
+ * Full-bleed image hero with color overlay, heading/subheading, and up to two CTAs.
9
+ *
10
+ * @remarks
11
+ * - Styling: slot-style overrides for container, imageContainer, overlay, content, textContainer.
12
+ * - Motion: enableMotion applies hover-lift transitions to CTA buttons only.
13
+ * - Accessibility: uses semantic <section> with aria-label; background image is
14
+ * decorative with overlay and text content provided separately.
15
+ *
16
+ * @example
17
+ * <HeroOverlay
18
+ * image={{ src: "/hero.png", alt: "" }}
19
+ * heading="Welcome"
20
+ * subheading="Build faster with our blocks"
21
+ * cta1={{ label: "Get Started", href: "#getstarted" }}
22
+ * />
23
+ */
24
+ export function HeroOverlay({ id, className,
25
+ // Deprecated flat image defaults (still supported)
26
+ imageSrc = "/hero.png", imageAlt = "Hero background image", imageObjectFit = "cover", imageObjectPosition = "center",
27
+ // New structured image (optional)
28
+ image,
29
+ // Keep string defaults; object form supported
30
+ heading = "Lorem ipsum dolor sit amet, consectetur", subheading = "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", overlayRGBA = "rgba(255, 255, 255, 0.8)", overlayDarkRGBA = "rgba(0, 0, 0, 0.8)",
31
+ // Deprecated CTA label/href (still supported)
32
+ ctaBtn1Label = "Get Started", ctaBtn1Href = "#getstarted", ctaBtn2Label, ctaBtn2Href,
33
+ // Layout containers
34
+ container = { className: "relative h-[440px] md:h-[500px] w-full" },
35
+ // container = { className: "relative h-[500px] md:h-[600px] w-full" },
36
+ section, imageContainer = { className: "absolute inset-0" }, overlay = { className: "absolute inset-0 z-10 pointer-events-none" }, content = {
37
+ className: "relative z-20 h-full w-full flex flex-col justify-start items-center pt-14 pb-8 px-8",
38
+ }, textContainer = { className: "max-w-4xl space-y-6 text-center" },
39
+ // Typography defaults (deprecated props still merged)
40
+ headingStyle = { className: "" }, subheadingStyle = { className: "" },
41
+ // CTA containers and variants
42
+ ctaContainer = {
43
+ className: "flex flex-col sm:flex-row gap-4 mt-6 justify-center items-center",
44
+ }, cta1, cta2, ariaLabel = "Hero section", enableMotion = true, }) {
45
+ var _a, _b, _c, _d, _e, _f;
46
+ // Merge new structured image with deprecated flat props
47
+ const effImage = {
48
+ src: (_a = image === null || image === void 0 ? void 0 : image.src) !== null && _a !== void 0 ? _a : imageSrc,
49
+ alt: (_b = image === null || image === void 0 ? void 0 : image.alt) !== null && _b !== void 0 ? _b : imageAlt,
50
+ objectFit: (_c = image === null || image === void 0 ? void 0 : image.objectFit) !== null && _c !== void 0 ? _c : imageObjectFit,
51
+ objectPosition: (_d = image === null || image === void 0 ? void 0 : image.objectPosition) !== null && _d !== void 0 ? _d : imageObjectPosition,
52
+ className: image === null || image === void 0 ? void 0 : image.className,
53
+ };
54
+ // Defaults and normalization like HeroSplit
55
+ const defaultHeading = {
56
+ text: "Lorem ipsum dolor sit amet, consectetur",
57
+ className: "text-4xl md:text-5xl font-bold text-center leading-tight text-foreground",
58
+ };
59
+ const defaultSubheading = {
60
+ text: "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
61
+ className: "text-xl md:text-2xl text-center text-foreground leading-relaxed",
62
+ };
63
+ const normalizedHeading = typeof heading === "string"
64
+ ? {
65
+ text: heading,
66
+ className: cn(defaultHeading.className, headingStyle === null || headingStyle === void 0 ? void 0 : headingStyle.className),
67
+ }
68
+ : {
69
+ text: (_e = heading === null || heading === void 0 ? void 0 : heading.text) !== null && _e !== void 0 ? _e : defaultHeading.text,
70
+ className: cn(defaultHeading.className, headingStyle === null || headingStyle === void 0 ? void 0 : headingStyle.className, heading === null || heading === void 0 ? void 0 : heading.className),
71
+ };
72
+ const normalizedSubheading = typeof subheading === "string"
73
+ ? {
74
+ text: subheading,
75
+ className: cn(defaultSubheading.className, subheadingStyle === null || subheadingStyle === void 0 ? void 0 : subheadingStyle.className),
76
+ }
77
+ : {
78
+ text: (_f = subheading === null || subheading === void 0 ? void 0 : subheading.text) !== null && _f !== void 0 ? _f : defaultSubheading.text,
79
+ className: cn(defaultSubheading.className, subheadingStyle === null || subheadingStyle === void 0 ? void 0 : subheadingStyle.className, subheading === null || subheading === void 0 ? void 0 : subheading.className),
80
+ };
81
+ // Motion class for CTA buttons
82
+ const buttonLift = enableMotion
83
+ ? "transition-all duration-200 hover:-translate-y-0.5"
84
+ : "transition-none hover:!translate-y-0";
85
+ // CTA defaults and normalization (merge, don't replace).
86
+ const defaultCta1 = {
87
+ label: ctaBtn1Label,
88
+ href: ctaBtn1Href,
89
+ variant: "default",
90
+ size: "lg",
91
+ className: "",
92
+ };
93
+ const defaultCta2 = {
94
+ label: ctaBtn2Label,
95
+ href: ctaBtn2Href,
96
+ variant: "outline",
97
+ size: "lg",
98
+ className: "",
99
+ };
100
+ const mergedCta1 = Object.assign(Object.assign(Object.assign({}, defaultCta1), (cta1 !== null && cta1 !== void 0 ? cta1 : {})), { className: cn(defaultCta1.className, cta1 === null || cta1 === void 0 ? void 0 : cta1.className, buttonLift) });
101
+ const mergedCta2 = cta2 || ctaBtn2Label || ctaBtn2Href
102
+ ? Object.assign(Object.assign(Object.assign({}, defaultCta2), (cta2 !== null && cta2 !== void 0 ? cta2 : {})), { className: cn(defaultCta2.className, cta2 === null || cta2 === void 0 ? void 0 : cta2.className, buttonLift) }) : undefined;
103
+ // buttonLift defined above
104
+ // Merge alias section.className with container.className
105
+ const finalContainerClass = cn(container.className, section === null || section === void 0 ? void 0 : section.className);
106
+ const showCta2 = !!(mergedCta2 === null || mergedCta2 === void 0 ? void 0 : mergedCta2.label);
107
+ return (_jsxs("section", { id: id, className: cn(finalContainerClass, className), "aria-label": ariaLabel, children: [_jsx("div", { className: imageContainer.className, children: _jsx(Image, { src: effImage.src, alt: effImage.alt, fill: true, sizes: "100vw", quality: 75, priority: true, className: effImage.className, style: {
108
+ objectFit: effImage.objectFit,
109
+ objectPosition: effImage.objectPosition,
110
+ } }) }), _jsx("div", { className: overlay.className, style: { backgroundColor: overlayRGBA }, "aria-hidden": true }), _jsx("div", { className: cn(overlay.className, "hidden dark:block"), style: { backgroundColor: overlayDarkRGBA }, "aria-hidden": true }), _jsx("div", { className: content.className, children: _jsxs("div", { className: textContainer.className, children: [_jsx("h1", { className: normalizedHeading.className, children: normalizedHeading.text }), _jsx("p", { className: normalizedSubheading.className, children: normalizedSubheading.text }), _jsxs("div", { className: ctaContainer.className, children: [mergedCta1.label && (_jsx(Button, { asChild: true, variant: mergedCta1.variant, size: mergedCta1.size, className: mergedCta1.className, unstyled: mergedCta1.unstyled, style: mergedCta1.style, children: _jsx(Link, { href: mergedCta1.href || "#", "aria-label": mergedCta1.label, children: mergedCta1.label }) })), showCta2 && (_jsx(Button, { asChild: true, variant: mergedCta2.variant, size: mergedCta2.size, className: mergedCta2.className, unstyled: mergedCta2.unstyled, style: mergedCta2.style, children: _jsx(Link, { href: mergedCta2.href || "#", "aria-label": mergedCta2.label, children: mergedCta2.label }) }))] })] }) })] }));
111
+ }
@@ -0,0 +1,141 @@
1
+ "use client";
2
+ import React from "react";
3
+ import Image from "next/image";
4
+ import Link from "next/link";
5
+ import { Button } from "@nextworks/blocks-core";
6
+ import { cn } from "@nextworks/blocks-core";
7
+ /**
8
+ * Full-bleed image hero with color overlay, heading/subheading, and up to two CTAs.
9
+ *
10
+ * @remarks
11
+ * - Styling: slot-style overrides for container, imageContainer, overlay, content, textContainer.
12
+ * - Motion: enableMotion applies hover-lift transitions to CTA buttons only.
13
+ * - Accessibility: uses semantic <section> with aria-label; background image is
14
+ * decorative with overlay and text content provided separately.
15
+ *
16
+ * @example
17
+ * <HeroOverlay
18
+ * image={{ src: "/hero.png", alt: "" }}
19
+ * heading="Welcome"
20
+ * subheading="Build faster with our blocks"
21
+ * cta1={{ label: "Get Started", href: "#getstarted" }}
22
+ * />
23
+ */
24
+ export function HeroOverlay({ id, className,
25
+ // Deprecated flat image defaults (still supported)
26
+ imageSrc = "/hero.png", imageAlt = "Hero background image", imageObjectFit = "cover", imageObjectPosition = "center",
27
+ // New structured image (optional)
28
+ image,
29
+ // Keep string defaults; object form supported
30
+ heading = "Lorem ipsum dolor sit amet, consectetur", subheading = "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", overlayRGBA = "rgba(255, 255, 255, 0.8)", overlayDarkRGBA = "rgba(0, 0, 0, 0.8)",
31
+ // Deprecated CTA label/href (still supported)
32
+ ctaBtn1Label = "Get Started", ctaBtn1Href = "#getstarted", ctaBtn2Label, ctaBtn2Href,
33
+ // Layout containers
34
+ container = { className: "relative h-[440px] md:h-[500px] w-full" },
35
+ // container = { className: "relative h-[500px] md:h-[600px] w-full" },
36
+ section, imageContainer = { className: "absolute inset-0" }, overlay = { className: "absolute inset-0 z-10 pointer-events-none" }, content = {
37
+ className: "relative z-20 h-full w-full flex flex-col justify-start items-center pt-14 pb-8 px-8",
38
+ }, textContainer = { className: "max-w-4xl space-y-6 text-center" },
39
+ // Typography defaults (deprecated props still merged)
40
+ headingStyle = { className: "" }, subheadingStyle = { className: "" },
41
+ // CTA containers and variants
42
+ ctaContainer = {
43
+ className: "flex flex-col sm:flex-row gap-4 mt-6 justify-center items-center",
44
+ }, cta1, cta2, ariaLabel = "Hero section", enableMotion = true, }) {
45
+ var _a, _b, _c, _d, _e, _f;
46
+ // Merge new structured image with deprecated flat props
47
+ const effImage = {
48
+ src: (_a = image === null || image === void 0 ? void 0 : image.src) !== null && _a !== void 0 ? _a : imageSrc,
49
+ alt: (_b = image === null || image === void 0 ? void 0 : image.alt) !== null && _b !== void 0 ? _b : imageAlt,
50
+ objectFit: (_c = image === null || image === void 0 ? void 0 : image.objectFit) !== null && _c !== void 0 ? _c : imageObjectFit,
51
+ objectPosition: (_d = image === null || image === void 0 ? void 0 : image.objectPosition) !== null && _d !== void 0 ? _d : imageObjectPosition,
52
+ className: image === null || image === void 0 ? void 0 : image.className,
53
+ };
54
+ // Defaults and normalization like HeroSplit
55
+ const defaultHeading = {
56
+ text: "Lorem ipsum dolor sit amet, consectetur",
57
+ className: "text-4xl md:text-5xl font-bold text-center leading-tight text-foreground",
58
+ };
59
+ const defaultSubheading = {
60
+ text: "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
61
+ className: "text-xl md:text-2xl text-center text-foreground leading-relaxed",
62
+ };
63
+ const normalizedHeading = typeof heading === "string"
64
+ ? {
65
+ text: heading,
66
+ className: cn(defaultHeading.className, headingStyle === null || headingStyle === void 0 ? void 0 : headingStyle.className),
67
+ }
68
+ : {
69
+ text: (_e = heading === null || heading === void 0 ? void 0 : heading.text) !== null && _e !== void 0 ? _e : defaultHeading.text,
70
+ className: cn(defaultHeading.className, headingStyle === null || headingStyle === void 0 ? void 0 : headingStyle.className, heading === null || heading === void 0 ? void 0 : heading.className),
71
+ };
72
+ const normalizedSubheading = typeof subheading === "string"
73
+ ? {
74
+ text: subheading,
75
+ className: cn(defaultSubheading.className, subheadingStyle === null || subheadingStyle === void 0 ? void 0 : subheadingStyle.className),
76
+ }
77
+ : {
78
+ text: (_f = subheading === null || subheading === void 0 ? void 0 : subheading.text) !== null && _f !== void 0 ? _f : defaultSubheading.text,
79
+ className: cn(defaultSubheading.className, subheadingStyle === null || subheadingStyle === void 0 ? void 0 : subheadingStyle.className, subheading === null || subheading === void 0 ? void 0 : subheading.className),
80
+ };
81
+ // Motion class for CTA buttons
82
+ const buttonLift = enableMotion
83
+ ? "transition-all duration-200 hover:-translate-y-0.5"
84
+ : "transition-none hover:!translate-y-0";
85
+ // CTA defaults and normalization (merge, don't replace).
86
+ const defaultCta1 = {
87
+ label: ctaBtn1Label,
88
+ href: ctaBtn1Href,
89
+ variant: "default",
90
+ size: "lg",
91
+ className: "",
92
+ };
93
+ const defaultCta2 = {
94
+ label: ctaBtn2Label,
95
+ href: ctaBtn2Href,
96
+ variant: "outline",
97
+ size: "lg",
98
+ className: "",
99
+ };
100
+ const mergedCta1 = Object.assign(Object.assign(Object.assign({}, defaultCta1), (cta1 !== null && cta1 !== void 0 ? cta1 : {})), { className: cn(defaultCta1.className, cta1 === null || cta1 === void 0 ? void 0 : cta1.className, buttonLift) });
101
+ const mergedCta2 = cta2 || ctaBtn2Label || ctaBtn2Href
102
+ ? Object.assign(Object.assign(Object.assign({}, defaultCta2), (cta2 !== null && cta2 !== void 0 ? cta2 : {})), { className: cn(defaultCta2.className, cta2 === null || cta2 === void 0 ? void 0 : cta2.className, buttonLift) }) : undefined;
103
+ // buttonLift defined above
104
+ // Merge alias section.className with container.className
105
+ const finalContainerClass = cn(container.className, section === null || section === void 0 ? void 0 : section.className);
106
+ const showCta2 = !!(mergedCta2 === null || mergedCta2 === void 0 ? void 0 : mergedCta2.label);
107
+ return (<section id={id} className={cn(finalContainerClass, className)} aria-label={ariaLabel}>
108
+ <div className={imageContainer.className}>
109
+ <Image src={effImage.src} alt={effImage.alt} fill sizes="100vw" quality={75} priority className={effImage.className} style={{
110
+ objectFit: effImage.objectFit,
111
+ objectPosition: effImage.objectPosition,
112
+ }}/>
113
+ </div>
114
+
115
+ <div className={overlay.className} style={{ backgroundColor: overlayRGBA }} aria-hidden/>
116
+ <div className={cn(overlay.className, "hidden dark:block")} style={{ backgroundColor: overlayDarkRGBA }} aria-hidden/>
117
+
118
+ <div className={content.className}>
119
+ <div className={textContainer.className}>
120
+ <h1 className={normalizedHeading.className}>
121
+ {normalizedHeading.text}
122
+ </h1>
123
+ <p className={normalizedSubheading.className}>
124
+ {normalizedSubheading.text}
125
+ </p>
126
+ <div className={ctaContainer.className}>
127
+ {mergedCta1.label && (<Button asChild variant={mergedCta1.variant} size={mergedCta1.size} className={mergedCta1.className} unstyled={mergedCta1.unstyled} style={mergedCta1.style}>
128
+ <Link href={mergedCta1.href || "#"} aria-label={mergedCta1.label}>
129
+ {mergedCta1.label}
130
+ </Link>
131
+ </Button>)}
132
+ {showCta2 && (<Button asChild variant={mergedCta2.variant} size={mergedCta2.size} className={mergedCta2.className} unstyled={mergedCta2.unstyled} style={mergedCta2.style}>
133
+ <Link href={mergedCta2.href || "#"} aria-label={mergedCta2.label}>
134
+ {mergedCta2.label}
135
+ </Link>
136
+ </Button>)}
137
+ </div>
138
+ </div>
139
+ </div>
140
+ </section>);
141
+ }
@@ -0,0 +1,98 @@
1
+ import React from "react";
2
+ /**
3
+ * Props for the HeroSplit component.
4
+ *
5
+ * @remarks
6
+ * - Layout: split hero with text and image. imageLayout controls whether the
7
+ * image is full-bleed or padded.
8
+ * - Styling: slot-style className overrides are merged via cn(). Heading and
9
+ * subheading accept either a string or a { text, className } object.
10
+ * - Motion: enableMotion toggles button hover lift transitions.
11
+ * - Accessibility: uses a semantic <section> with aria-label.
12
+ */
13
+ interface HeroSplitProps {
14
+ /** Optional id to attach to the root section element */
15
+ id?: string;
16
+ /** Optional top-level class to override the root */
17
+ className?: string;
18
+ /** Section slot override */
19
+ section?: {
20
+ className?: string;
21
+ };
22
+ /** Heading string or object with text and className */
23
+ heading?: string | {
24
+ text?: string;
25
+ className?: string;
26
+ };
27
+ /** Subheading string or object with text and className */
28
+ subheading?: string | {
29
+ text?: string;
30
+ className?: string;
31
+ };
32
+ /** Primary CTA configuration */
33
+ cta1?: {
34
+ label?: string;
35
+ href?: string;
36
+ variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link";
37
+ size?: "default" | "sm" | "lg" | "icon";
38
+ className?: string;
39
+ /** When true, renders the Button in unstyled mode to avoid token bleed from variants */
40
+ unstyled?: boolean;
41
+ /** Optional inline style forwarded to Button */
42
+ style?: React.CSSProperties;
43
+ };
44
+ /** Secondary CTA configuration */
45
+ cta2?: {
46
+ label?: string;
47
+ href?: string;
48
+ variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link";
49
+ size?: "default" | "sm" | "lg" | "icon";
50
+ className?: string;
51
+ /** When true, renders the Button in unstyled mode to avoid token bleed from variants */
52
+ unstyled?: boolean;
53
+ /** Optional inline style forwarded to Button */
54
+ style?: React.CSSProperties;
55
+ };
56
+ /** Image configuration */
57
+ image?: {
58
+ src?: string;
59
+ alt?: string;
60
+ className?: string;
61
+ };
62
+ /** Image container slot */
63
+ imageContainer?: {
64
+ className?: string;
65
+ };
66
+ /** Text container slot */
67
+ textContainer?: {
68
+ className?: string;
69
+ };
70
+ /** Buttons container slot */
71
+ buttonsContainer?: {
72
+ className?: string;
73
+ };
74
+ /** Text alignment at large breakpoints. @defaultValue "center" */
75
+ textAlign?: "left" | "center" | "right";
76
+ /** Fallback node shown when no image.src is provided */
77
+ fallback?: React.ReactNode;
78
+ /** ARIA label for the section. @defaultValue "Hero section" */
79
+ ariaLabel?: string;
80
+ /** When false, removes button hover lifts, keeps layout static */
81
+ enableMotion?: boolean;
82
+ /** "padded" keeps default gutters. "full-bleed" allows the image to touch page edges. @defaultValue "full-bleed" */
83
+ imageLayout?: "padded" | "full-bleed";
84
+ }
85
+ /**
86
+ * Split hero with text on one side and an image on the other.
87
+ *
88
+ * @remarks
89
+ * - Text props accept string or object forms to easily override classes.
90
+ * - Full-bleed layout absolutely positions the image on larger screens.
91
+ * - Motion only affects the subtle hover lift on CTA buttons.
92
+ *
93
+ * @example
94
+ * <HeroSplit heading="Build faster" subheading="Launch confidently" />
95
+ */
96
+ export declare function HeroSplit({ id, className, heading, subheading, section, cta1, cta2, image, imageContainer, textContainer, buttonsContainer, textAlign, fallback, ariaLabel, enableMotion, imageLayout, }: HeroSplitProps): React.JSX.Element;
97
+ export {};
98
+ //# sourceMappingURL=HeroSplit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HeroSplit.d.ts","sourceRoot":"","sources":["../../src/components/HeroSplit.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import Image from "next/image";
4
+ import Link from "next/link";
5
+ import { Button } from "@nextworks/blocks-core";
6
+ import { cn } from "@nextworks/blocks-core";
7
+ /**
8
+ * Split hero with text on one side and an image on the other.
9
+ *
10
+ * @remarks
11
+ * - Text props accept string or object forms to easily override classes.
12
+ * - Full-bleed layout absolutely positions the image on larger screens.
13
+ * - Motion only affects the subtle hover lift on CTA buttons.
14
+ *
15
+ * @example
16
+ * <HeroSplit heading="Build faster" subheading="Launch confidently" />
17
+ */
18
+ export function HeroSplit({ id, className, heading, subheading, section, cta1, cta2, image = {
19
+ src: "/placeholders/gallery/hero-pexels-broken-9945014.avif",
20
+ alt: "Hero image",
21
+ className: "object-contain",
22
+ }, imageContainer, textContainer = { className: "flex-1 p-5" }, buttonsContainer = { className: "flex flex-col md:flex-row gap-4 mt-6" }, textAlign = "center", fallback, ariaLabel = "Hero section", enableMotion = true, imageLayout = "full-bleed", }) {
23
+ var _a, _b;
24
+ const lgTextAlignClasses = {
25
+ left: "lg:text-left",
26
+ right: "lg:text-right",
27
+ center: "lg:text-center",
28
+ };
29
+ const lgItemsAlignClasses = {
30
+ left: "lg:items-start",
31
+ right: "lg:items-end",
32
+ center: "lg:items-center",
33
+ };
34
+ const lgJustifyAlignClasses = {
35
+ left: "lg:justify-start",
36
+ right: "lg:justify-end",
37
+ center: "lg:justify-center",
38
+ };
39
+ const buttonLift = enableMotion
40
+ ? "transition-all duration-200 hover:-translate-y-0.5"
41
+ : "transition-none hover:!translate-y-0";
42
+ // Defaults for text props (normalized below)
43
+ const defaultHeading = {
44
+ text: "Lorem ipsum dolor sit amet",
45
+ className: "text-3xl md:text-4xl font-bold leading-tight text-foreground",
46
+ };
47
+ const defaultSubheading = {
48
+ text: "Consectetur adipiscing elit, sed do eiusmod tempor.",
49
+ className: "text-lg md:text-xl text-foreground mt-4 mb-6",
50
+ };
51
+ const normalizedHeading = typeof heading === "string"
52
+ ? { text: heading, className: defaultHeading.className }
53
+ : {
54
+ text: (_a = heading === null || heading === void 0 ? void 0 : heading.text) !== null && _a !== void 0 ? _a : defaultHeading.text,
55
+ className: cn(defaultHeading.className, heading === null || heading === void 0 ? void 0 : heading.className),
56
+ };
57
+ const normalizedSubheading = typeof subheading === "string"
58
+ ? { text: subheading, className: defaultSubheading.className }
59
+ : {
60
+ text: (_b = subheading === null || subheading === void 0 ? void 0 : subheading.text) !== null && _b !== void 0 ? _b : defaultSubheading.text,
61
+ className: cn(defaultSubheading.className, subheading === null || subheading === void 0 ? void 0 : subheading.className),
62
+ };
63
+ // CTA defaults and normalization (merge, don't replace)
64
+ const defaultCta1 = {
65
+ label: "Get Started",
66
+ href: "#contact",
67
+ variant: "default",
68
+ size: "default",
69
+ className: "shadow-lg hover:shadow-xl transition-all duration-200 hover:-translate-y-0.5",
70
+ };
71
+ const mergedCta1 = Object.assign(Object.assign(Object.assign({}, defaultCta1), (cta1 !== null && cta1 !== void 0 ? cta1 : {})), { className: cn(defaultCta1.className, cta1 === null || cta1 === void 0 ? void 0 : cta1.className, buttonLift) });
72
+ const defaultCta2 = {
73
+ label: "Learn More",
74
+ href: "#",
75
+ variant: "outline",
76
+ size: "default",
77
+ className: "",
78
+ };
79
+ const mergedCta2 = cta2
80
+ ? Object.assign(Object.assign(Object.assign({}, defaultCta2), cta2), { className: cn(defaultCta2.className, cta2.className, buttonLift) }) : undefined;
81
+ const defaultSectionPadded = cn("px-8 pt-8 pb-8 md:min-h-[60vh] lg:min-h-[70vh]");
82
+ const defaultSectionFull = cn("relative overflow-hidden pt-0 pb-0 md:min-h-[60vh] lg:min-h-[70vh]");
83
+ const defaultImageContainerPadded = cn("relative mb-4 h-48 min-h-[12rem] w-full md:mb-0 md:h-72 md:w-1/2");
84
+ // For full-bleed: absolute positioning on large screens to break out completely
85
+ const defaultImageContainerFull = cn("relative h-48 w-full md:absolute md:inset-y-0 md:right-0 md:h-full md:w-1/2");
86
+ const baseSectionClass = imageLayout === "full-bleed" ? defaultSectionFull : defaultSectionPadded;
87
+ const finalSectionClass = cn(baseSectionClass, section === null || section === void 0 ? void 0 : section.className);
88
+ const baseImageContainerClass = imageLayout === "full-bleed"
89
+ ? defaultImageContainerFull
90
+ : defaultImageContainerPadded;
91
+ const finalImageContainerClass = cn(baseImageContainerClass, imageContainer === null || imageContainer === void 0 ? void 0 : imageContainer.className);
92
+ // -- This overrides the image.className that is passed from importing components ... devs should be able to decide on cover/contain from the importing component.
93
+ const finalImageClass = cn(image === null || image === void 0 ? void 0 : image.className, imageLayout === "full-bleed"
94
+ ? "object-cover object-center md:object-right"
95
+ : "object-contain object-center");
96
+ return (_jsx("section", { id: id, className: cn(finalSectionClass, className), "aria-label": ariaLabel, children: _jsxs("div", { className: cn("flex flex-col items-stretch", imageLayout === "full-bleed"
97
+ ? "md:block"
98
+ : "md:flex-row md:items-start"), children: [_jsx("div", { className: cn("w-full", imageLayout === "full-bleed" &&
99
+ "relative z-10 md:w-1/2 md:px-8 md:py-12", textContainer.className), children: _jsxs("div", { className: cn("flex flex-col items-center", lgItemsAlignClasses[textAlign]), children: [_jsx("h1", { className: cn("text-center", lgTextAlignClasses[textAlign], normalizedHeading.className), children: normalizedHeading.text }), _jsx("p", { className: cn("text-center", lgTextAlignClasses[textAlign], normalizedSubheading.className), children: normalizedSubheading.text }), _jsxs("div", { className: cn("flex flex-col items-center justify-center gap-4 sm:flex-row", lgJustifyAlignClasses[textAlign], lgItemsAlignClasses[textAlign], buttonsContainer.className), children: [mergedCta1.label && (_jsx(Button, { asChild: true, variant: mergedCta1.variant, size: mergedCta1.size, className: mergedCta1.className, unstyled: mergedCta1.unstyled, style: mergedCta1.style, children: _jsx(Link, { href: mergedCta1.href || "#", "aria-label": mergedCta1.label, children: mergedCta1.label }) })), (mergedCta2 === null || mergedCta2 === void 0 ? void 0 : mergedCta2.label) && (_jsx(Button, { asChild: true, variant: mergedCta2.variant, size: mergedCta2.size, className: mergedCta2.className, unstyled: mergedCta2.unstyled, style: mergedCta2.style, children: _jsx(Link, { href: mergedCta2.href || "#", "aria-label": mergedCta2.label, children: mergedCta2.label }) }))] })] }) }), _jsx("div", { className: cn(finalImageContainerClass), children: (image === null || image === void 0 ? void 0 : image.src) ? (_jsx(Image, { priority: true, fetchPriority: "high", src: image.src, alt: image.alt || "Hero image", className: finalImageClass, fill: true, sizes: "(min-width: 768px) 50vw, 100vw", quality: 75 })) : (_jsx("div", { className: "absolute inset-0", children: fallback || null })) })] }) }));
100
+ }
@@ -0,0 +1,134 @@
1
+ "use client";
2
+ import React from "react";
3
+ import Image from "next/image";
4
+ import Link from "next/link";
5
+ import { Button } from "@nextworks/blocks-core";
6
+ import { cn } from "@nextworks/blocks-core";
7
+ /**
8
+ * Split hero with text on one side and an image on the other.
9
+ *
10
+ * @remarks
11
+ * - Text props accept string or object forms to easily override classes.
12
+ * - Full-bleed layout absolutely positions the image on larger screens.
13
+ * - Motion only affects the subtle hover lift on CTA buttons.
14
+ *
15
+ * @example
16
+ * <HeroSplit heading="Build faster" subheading="Launch confidently" />
17
+ */
18
+ export function HeroSplit({ id, className, heading, subheading, section, cta1, cta2, image = {
19
+ src: "/placeholders/gallery/hero-pexels-broken-9945014.avif",
20
+ alt: "Hero image",
21
+ className: "object-contain",
22
+ }, imageContainer, textContainer = { className: "flex-1 p-5" }, buttonsContainer = { className: "flex flex-col md:flex-row gap-4 mt-6" }, textAlign = "center", fallback, ariaLabel = "Hero section", enableMotion = true, imageLayout = "full-bleed", }) {
23
+ var _a, _b;
24
+ const lgTextAlignClasses = {
25
+ left: "lg:text-left",
26
+ right: "lg:text-right",
27
+ center: "lg:text-center",
28
+ };
29
+ const lgItemsAlignClasses = {
30
+ left: "lg:items-start",
31
+ right: "lg:items-end",
32
+ center: "lg:items-center",
33
+ };
34
+ const lgJustifyAlignClasses = {
35
+ left: "lg:justify-start",
36
+ right: "lg:justify-end",
37
+ center: "lg:justify-center",
38
+ };
39
+ const buttonLift = enableMotion
40
+ ? "transition-all duration-200 hover:-translate-y-0.5"
41
+ : "transition-none hover:!translate-y-0";
42
+ // Defaults for text props (normalized below)
43
+ const defaultHeading = {
44
+ text: "Lorem ipsum dolor sit amet",
45
+ className: "text-3xl md:text-4xl font-bold leading-tight text-foreground",
46
+ };
47
+ const defaultSubheading = {
48
+ text: "Consectetur adipiscing elit, sed do eiusmod tempor.",
49
+ className: "text-lg md:text-xl text-foreground mt-4 mb-6",
50
+ };
51
+ const normalizedHeading = typeof heading === "string"
52
+ ? { text: heading, className: defaultHeading.className }
53
+ : {
54
+ text: (_a = heading === null || heading === void 0 ? void 0 : heading.text) !== null && _a !== void 0 ? _a : defaultHeading.text,
55
+ className: cn(defaultHeading.className, heading === null || heading === void 0 ? void 0 : heading.className),
56
+ };
57
+ const normalizedSubheading = typeof subheading === "string"
58
+ ? { text: subheading, className: defaultSubheading.className }
59
+ : {
60
+ text: (_b = subheading === null || subheading === void 0 ? void 0 : subheading.text) !== null && _b !== void 0 ? _b : defaultSubheading.text,
61
+ className: cn(defaultSubheading.className, subheading === null || subheading === void 0 ? void 0 : subheading.className),
62
+ };
63
+ // CTA defaults and normalization (merge, don't replace)
64
+ const defaultCta1 = {
65
+ label: "Get Started",
66
+ href: "#contact",
67
+ variant: "default",
68
+ size: "default",
69
+ className: "shadow-lg hover:shadow-xl transition-all duration-200 hover:-translate-y-0.5",
70
+ };
71
+ const mergedCta1 = Object.assign(Object.assign(Object.assign({}, defaultCta1), (cta1 !== null && cta1 !== void 0 ? cta1 : {})), { className: cn(defaultCta1.className, cta1 === null || cta1 === void 0 ? void 0 : cta1.className, buttonLift) });
72
+ const defaultCta2 = {
73
+ label: "Learn More",
74
+ href: "#",
75
+ variant: "outline",
76
+ size: "default",
77
+ className: "",
78
+ };
79
+ const mergedCta2 = cta2
80
+ ? Object.assign(Object.assign(Object.assign({}, defaultCta2), cta2), { className: cn(defaultCta2.className, cta2.className, buttonLift) }) : undefined;
81
+ const defaultSectionPadded = cn("px-8 pt-8 pb-8 md:min-h-[60vh] lg:min-h-[70vh]");
82
+ const defaultSectionFull = cn("relative overflow-hidden pt-0 pb-0 md:min-h-[60vh] lg:min-h-[70vh]");
83
+ const defaultImageContainerPadded = cn("relative mb-4 h-48 min-h-[12rem] w-full md:mb-0 md:h-72 md:w-1/2");
84
+ // For full-bleed: absolute positioning on large screens to break out completely
85
+ const defaultImageContainerFull = cn("relative h-48 w-full md:absolute md:inset-y-0 md:right-0 md:h-full md:w-1/2");
86
+ const baseSectionClass = imageLayout === "full-bleed" ? defaultSectionFull : defaultSectionPadded;
87
+ const finalSectionClass = cn(baseSectionClass, section === null || section === void 0 ? void 0 : section.className);
88
+ const baseImageContainerClass = imageLayout === "full-bleed"
89
+ ? defaultImageContainerFull
90
+ : defaultImageContainerPadded;
91
+ const finalImageContainerClass = cn(baseImageContainerClass, imageContainer === null || imageContainer === void 0 ? void 0 : imageContainer.className);
92
+ // -- This overrides the image.className that is passed from importing components ... devs should be able to decide on cover/contain from the importing component.
93
+ const finalImageClass = cn(image === null || image === void 0 ? void 0 : image.className, imageLayout === "full-bleed"
94
+ ? "object-cover object-center md:object-right"
95
+ : "object-contain object-center");
96
+ return (<section id={id} className={cn(finalSectionClass, className)} aria-label={ariaLabel}>
97
+ <div className={cn("flex flex-col items-stretch", imageLayout === "full-bleed"
98
+ ? "md:block"
99
+ : "md:flex-row md:items-start")}>
100
+ {/* Text container - takes up left side on large screens */}
101
+ <div className={cn("w-full", imageLayout === "full-bleed" &&
102
+ "relative z-10 md:w-1/2 md:px-8 md:py-12", textContainer.className)}>
103
+ <div className={cn("flex flex-col items-center", lgItemsAlignClasses[textAlign])}>
104
+ <h1 className={cn("text-center", lgTextAlignClasses[textAlign], normalizedHeading.className)}>
105
+ {normalizedHeading.text}
106
+ </h1>
107
+
108
+ <p className={cn("text-center", lgTextAlignClasses[textAlign], normalizedSubheading.className)}>
109
+ {normalizedSubheading.text}
110
+ </p>
111
+
112
+ <div className={cn("flex flex-col items-center justify-center gap-4 sm:flex-row", lgJustifyAlignClasses[textAlign], lgItemsAlignClasses[textAlign], buttonsContainer.className)}>
113
+ {mergedCta1.label && (<Button asChild variant={mergedCta1.variant} size={mergedCta1.size} className={mergedCta1.className} unstyled={mergedCta1.unstyled} style={mergedCta1.style}>
114
+ <Link href={mergedCta1.href || "#"} aria-label={mergedCta1.label}>
115
+ {mergedCta1.label}
116
+ </Link>
117
+ </Button>)}
118
+
119
+ {(mergedCta2 === null || mergedCta2 === void 0 ? void 0 : mergedCta2.label) && (<Button asChild variant={mergedCta2.variant} size={mergedCta2.size} className={mergedCta2.className} unstyled={mergedCta2.unstyled} style={mergedCta2.style}>
120
+ <Link href={mergedCta2.href || "#"} aria-label={mergedCta2.label}>
121
+ {mergedCta2.label}
122
+ </Link>
123
+ </Button>)}
124
+ </div>
125
+ </div>
126
+ </div>
127
+
128
+ {/* Image container - absolutely positioned on right side for full-bleed */}
129
+ <div className={cn(finalImageContainerClass)}>
130
+ {(image === null || image === void 0 ? void 0 : image.src) ? (<Image priority fetchPriority="high" src={image.src} alt={image.alt || "Hero image"} className={finalImageClass} fill sizes="(min-width: 768px) 50vw, 100vw" quality={75}/>) : (<div className="absolute inset-0">{fallback || null}</div>)}
131
+ </div>
132
+ </div>
133
+ </section>);
134
+ }