@gosalesdeal/blog 0.2.0 → 0.3.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 (43) hide show
  1. package/README.md +265 -34
  2. package/dist/client/blogClient.js +36 -7
  3. package/dist/client/blogClient.js.map +1 -1
  4. package/dist/components/BlogPost.js +7 -8
  5. package/dist/components/BlogPost.js.map +1 -1
  6. package/dist/components/landing/BlogLayoutComponents.d.ts +14 -0
  7. package/dist/components/landing/BlogLayoutComponents.js +198 -0
  8. package/dist/components/landing/BlogLayoutComponents.js.map +1 -0
  9. package/dist/components/landing/FlexibleLayoutComponent.d.ts +40 -0
  10. package/dist/components/landing/FlexibleLayoutComponent.js +352 -0
  11. package/dist/components/landing/FlexibleLayoutComponent.js.map +1 -0
  12. package/dist/components/landing/HeroFeatureBanner.d.ts +36 -0
  13. package/dist/components/landing/HeroFeatureBanner.js +88 -0
  14. package/dist/components/landing/HeroFeatureBanner.js.map +1 -0
  15. package/dist/components/landing/HeroFeatureBannerComponent.d.ts +4 -0
  16. package/dist/components/landing/HeroFeatureBannerComponent.js +100 -0
  17. package/dist/components/landing/HeroFeatureBannerComponent.js.map +1 -0
  18. package/dist/components/landing/HeroFeatureBannerVideo.d.ts +34 -0
  19. package/dist/components/landing/HeroFeatureBannerVideo.js +261 -0
  20. package/dist/components/landing/HeroFeatureBannerVideo.js.map +1 -0
  21. package/dist/components/landing/HeroFeatureBannerVideoComponent.d.ts +5 -0
  22. package/dist/components/landing/HeroFeatureBannerVideoComponent.js +69 -0
  23. package/dist/components/landing/HeroFeatureBannerVideoComponent.js.map +1 -0
  24. package/dist/components/landing/VarietyReviewslistComponent.d.ts +4 -0
  25. package/dist/components/landing/VarietyReviewslistComponent.js +172 -0
  26. package/dist/components/landing/VarietyReviewslistComponent.js.map +1 -0
  27. package/dist/index.d.ts +11 -0
  28. package/dist/index.js +21 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/lib/resolveMediaSrc.d.ts +2 -0
  31. package/dist/lib/resolveMediaSrc.js +21 -0
  32. package/dist/lib/resolveMediaSrc.js.map +1 -0
  33. package/dist/render/BlockRenderer.js +5 -0
  34. package/dist/render/BlockRenderer.js.map +1 -1
  35. package/dist/render/LandingPageRenderer.d.ts +5 -0
  36. package/dist/render/LandingPageRenderer.js +50 -0
  37. package/dist/render/LandingPageRenderer.js.map +1 -0
  38. package/dist/render/landingPageHtml.d.ts +3 -1
  39. package/dist/render/landingPageHtml.js +18 -2
  40. package/dist/render/landingPageHtml.js.map +1 -1
  41. package/dist/styles.css +13 -0
  42. package/dist/types/blog.d.ts +5 -2
  43. package/package.json +6 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlexibleLayoutComponent.js","sources":["../../../src/components/landing/FlexibleLayoutComponent.tsx"],"sourcesContent":["import React from 'react';\n\ninterface ColumnElement {\n id: string;\n type: string;\n [key: string]: any;\n}\n\ninterface Column {\n id: string;\n elements: ColumnElement[];\n width?: string;\n backgroundColor?: string;\n padding?: string;\n alignment?: 'top' | 'center' | 'bottom';\n}\n\ninterface FlexibleLayoutProps {\n props: {\n columnCount?: number;\n columns?: Column[];\n columnRatio?: string;\n containerMaxWidth?: string;\n containerPadding?: string;\n containerMarginTop?: string;\n containerMarginBottom?: string;\n containerBackgroundColor?: string;\n containerBorderRadius?: string;\n columnGap?: string;\n rowGap?: string;\n stackOnMobile?: boolean;\n stackOnTablet?: boolean;\n reverseOnMobile?: boolean;\n mobileBreakpoint?: string;\n tabletBreakpoint?: string;\n customCSS?: string;\n className?: string;\n containerClass?: string;\n columnsWrapperClass?: string;\n };\n}\n\nexport const FlexibleLayoutComponent: React.FC<FlexibleLayoutProps> = ({ props }) => {\n const {\n columnCount = 2,\n columns = [],\n columnRatio = '50-50',\n containerMaxWidth = '1200px',\n containerPadding = '0rem',\n containerMarginTop = '0rem',\n containerMarginBottom = '0rem',\n containerBackgroundColor = 'transparent',\n containerBorderRadius = '0px',\n columnGap = '2rem',\n rowGap = '1rem',\n stackOnMobile = true,\n stackOnTablet = false,\n reverseOnMobile = false,\n mobileBreakpoint = '768px',\n tabletBreakpoint = '1024px',\n customCSS = '',\n className = '',\n containerClass = '',\n columnsWrapperClass = '',\n } = props;\n\n void containerMaxWidth;\n void containerPadding;\n void containerMarginTop;\n void containerMarginBottom;\n void containerBackgroundColor;\n void containerBorderRadius;\n\n // Parse column ratios and ensure they match columnCount\n let ratios = columnRatio.split('-').map((r: string) => `${r}%`);\n \n // Safety check: if ratios don't match columnCount, use equal distribution\n if (ratios.length !== columnCount) {\n const equalRatio = `${Math.floor(100 / columnCount)}%`;\n ratios = Array(columnCount).fill(equalRatio);\n }\n\n const renderElement = (element: ColumnElement) => {\n const commonStyle: React.CSSProperties = {\n marginTop: element.marginTop || '0',\n marginBottom: element.marginBottom || '0',\n };\n\n switch (element.type) {\n case 'heading': {\n const level = element.headingLevel || 'h2';\n const headingProps = {\n key: element.id,\n className: element.customClass,\n style: {\n ...commonStyle,\n color: element.headingColor,\n fontSize: element.headingSize,\n fontWeight: element.headingWeight,\n textAlign: element.headingAlign as any,\n },\n };\n \n switch (level) {\n case 'h1': return <h1 {...headingProps}>{element.headingText}</h1>;\n case 'h2': return <h2 {...headingProps}>{element.headingText}</h2>;\n case 'h3': return <h3 {...headingProps}>{element.headingText}</h3>;\n case 'h4': return <h4 {...headingProps}>{element.headingText}</h4>;\n case 'h5': return <h5 {...headingProps}>{element.headingText}</h5>;\n case 'h6': return <h6 {...headingProps}>{element.headingText}</h6>;\n default: return <h2 {...headingProps}>{element.headingText}</h2>;\n }\n }\n\n case 'paragraph':\n return (\n <p\n key={element.id}\n className={element.customClass}\n style={{\n ...commonStyle,\n color: element.paragraphColor,\n fontSize: element.paragraphSize,\n textAlign: element.paragraphAlign as any,\n lineHeight: element.paragraphLineHeight,\n }}\n >\n {element.paragraphText}\n </p>\n );\n\n case 'image':\n return (\n <div key={element.id} className={element.customClass} style={commonStyle}>\n <img\n src={element.imageUrl || 'https://via.placeholder.com/400x300'}\n alt={element.imageAlt || 'Image'}\n style={{\n width: element.imageWidth || '100%',\n height: element.imageHeight || 'auto',\n objectFit: element.imageObjectFit as any,\n borderRadius: element.imageBorderRadius,\n display: 'block',\n }}\n />\n {element.imageCaption && (\n <p style={{ fontSize: '0.875rem', color: '#6b7280', marginTop: '0.5rem', textAlign: 'center' }}>\n {element.imageCaption}\n </p>\n )}\n </div>\n );\n\n case 'video': {\n const getVideoEmbedUrl = (url: string, type: string) => {\n if (type === 'youtube') {\n const videoId = url.includes('v=') ? url.split('v=')[1]?.split('&')[0] : url.split('/').pop();\n return `https://www.youtube.com/embed/${videoId}`;\n } else if (type === 'vimeo') {\n const videoId = url.split('/').pop();\n return `https://player.vimeo.com/video/${videoId}`;\n }\n return url;\n };\n\n return (\n <div key={element.id} className={element.customClass} style={commonStyle}>\n {element.videoType === 'direct' ? (\n <video\n src={element.videoUrl}\n controls={element.videoControls}\n autoPlay={element.videoAutoplay}\n style={{\n width: element.videoWidth || '100%',\n height: element.videoHeight || 'auto',\n borderRadius: '8px',\n }}\n />\n ) : (\n <iframe\n src={getVideoEmbedUrl(element.videoUrl || '', element.videoType || 'youtube')}\n style={{\n width: element.videoWidth || '100%',\n height: element.videoHeight || '400px',\n border: 'none',\n borderRadius: '8px',\n }}\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\"\n allowFullScreen\n />\n )}\n </div>\n );\n }\n\n case 'button':\n return (\n <a\n key={element.id}\n href={element.buttonUrl || '#'}\n target={element.buttonTarget}\n className={element.customClass}\n style={{\n ...commonStyle,\n display: element.buttonFullWidth ? 'block' : 'inline-block',\n padding: element.buttonSize === 'small' ? '0.5rem 1rem' : element.buttonSize === 'large' ? '1rem 2rem' : '0.75rem 1.5rem',\n backgroundColor: element.buttonBgColor || '#3b82f6',\n color: element.buttonTextColor || '#ffffff',\n textDecoration: 'none',\n borderRadius: '6px',\n fontWeight: '500',\n textAlign: 'center',\n border: element.buttonStyle === 'outline' ? '2px solid currentColor' : 'none',\n background: element.buttonStyle === 'outline' || element.buttonStyle === 'text' ? 'transparent' : element.buttonBgColor,\n }}\n >\n {element.buttonText}\n </a>\n );\n\n case 'list': {\n const listProps = {\n key: element.id,\n className: element.customClass,\n style: {\n ...commonStyle,\n listStyle: element.listStyle === 'default' ? undefined : 'none',\n paddingLeft: element.listStyle === 'default' ? '1.5rem' : '0',\n },\n };\n \n const items = (element.listItems || []).map((item: string, idx: number) => (\n <li key={idx} style={{ marginBottom: '0.5rem' }}>\n {item}\n </li>\n ));\n \n return element.listType === 'ordered' ? (\n <ol {...listProps}>{items}</ol>\n ) : (\n <ul {...listProps}>{items}</ul>\n );\n }\n\n case 'quote':\n return (\n <blockquote\n key={element.id}\n className={element.customClass}\n style={{\n ...commonStyle,\n borderLeft: `4px solid ${element.quoteBorderColor || '#3b82f6'}`,\n paddingLeft: '1.5rem',\n fontStyle: 'italic',\n color: '#374151',\n }}\n >\n <p style={{ marginBottom: '0.5rem' }}>{element.quoteText}</p>\n {element.quoteAuthor && (\n <footer style={{ fontSize: '0.875rem', color: '#6b7280' }}>— {element.quoteAuthor}</footer>\n )}\n </blockquote>\n );\n\n case 'divider':\n return (\n <hr\n key={element.id}\n className={element.customClass}\n style={{\n ...commonStyle,\n border: 'none',\n borderTop: `${element.dividerHeight || '1px'} ${element.dividerStyle || 'solid'} ${element.dividerColor || '#e5e7eb'}`,\n width: element.dividerWidth || '100%',\n }}\n />\n );\n\n case 'spacer':\n return (\n <div\n key={element.id}\n className={element.customClass}\n style={{\n height: element.spacerHeight || '2rem',\n }}\n />\n );\n\n case 'code':\n return (\n <pre\n key={element.id}\n className={element.customClass}\n style={{\n ...commonStyle,\n backgroundColor: element.codeTheme === 'light' ? '#f3f4f6' : '#1e293b',\n color: element.codeTheme === 'light' ? '#1f2937' : '#e2e8f0',\n padding: '1rem',\n borderRadius: '6px',\n overflow: 'auto',\n fontSize: '0.875rem',\n fontFamily: 'monospace',\n }}\n >\n <code>{element.codeContent}</code>\n </pre>\n );\n\n case 'badge':\n return (\n <span\n key={element.id}\n className={element.customClass}\n style={{\n ...commonStyle,\n display: 'inline-block',\n padding: '0.25rem 0.75rem',\n backgroundColor: element.badgeBgColor || '#3b82f6',\n color: element.badgeColor || '#ffffff',\n borderRadius: '9999px',\n fontSize: '0.875rem',\n fontWeight: '500',\n }}\n >\n {element.badgeText}\n </span>\n );\n\n case 'alert': {\n const alertColors: Record<string, any> = {\n info: { bg: '#dbeafe', border: '#3b82f6', text: '#1e40af' },\n success: { bg: '#d1fae5', border: '#10b981', text: '#065f46' },\n warning: { bg: '#fef3c7', border: '#f59e0b', text: '#92400e' },\n error: { bg: '#fee2e2', border: '#ef4444', text: '#991b1b' },\n };\n const alertStyle = alertColors[element.alertType || 'info'];\n\n return (\n <div\n key={element.id}\n className={element.customClass}\n style={{\n ...commonStyle,\n backgroundColor: alertStyle.bg,\n borderLeft: `4px solid ${alertStyle.border}`,\n color: alertStyle.text,\n padding: '1rem',\n borderRadius: '6px',\n }}\n >\n {element.alertText}\n </div>\n );\n }\n\n default:\n return null;\n }\n };\n\n const responsiveCSS = `\n @media (max-width: ${mobileBreakpoint}) {\n .flexible-layout-container-${columnCount} {\n ${stackOnMobile ? 'flex-direction: column !important;' : ''}\n ${reverseOnMobile ? 'flex-direction: column-reverse !important;' : ''}\n }\n .flexible-layout-column-${columnCount} {\n ${stackOnMobile ? 'width: 100% !important; flex: none !important;' : ''}\n }\n }\n @media (max-width: ${tabletBreakpoint}) and (min-width: ${mobileBreakpoint}) {\n .flexible-layout-container-${columnCount} {\n ${stackOnTablet ? 'flex-direction: column !important;' : ''}\n }\n .flexible-layout-column-${columnCount} {\n ${stackOnTablet ? 'width: 100% !important; flex: none !important;' : ''}\n }\n }\n `;\n\n return (\n <div\n className={`flexible-layout w-full mx-auto overflow-hidden ${containerClass} ${className || ''}`}\n // style={{\n // maxWidth: containerMaxWidth,\n // marginTop: containerMarginTop,\n // marginBottom: containerMarginBottom,\n // padding: containerPadding,\n // backgroundColor: containerBackgroundColor,\n // borderRadius: containerBorderRadius,\n // }}\n >\n {customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}\n <style dangerouslySetInnerHTML={{ __html: responsiveCSS }} />\n\n <div\n className={`flexible-layout-container-${columnCount} flex w-full ${columnsWrapperClass}`}\n style={{\n gap: columnGap,\n alignItems: 'stretch',\n }}\n >\n {columns.slice(0, columnCount).map((column: Column, index: number) => (\n <div\n key={column.id}\n className={`flexible-layout-column-${columnCount}`}\n style={{\n flex: `0 0 ${ratios[index] || 'auto'}`,\n minWidth: 0,\n maxWidth: ratios[index] || 'auto',\n backgroundColor: column.backgroundColor,\n padding: column.padding,\n display: 'flex',\n flexDirection: 'column',\n justifyContent: column.alignment === 'center' ? 'center' : column.alignment === 'bottom' ? 'flex-end' : 'flex-start',\n boxSizing: 'border-box',\n overflow: 'hidden',\n }}\n >\n <div style={{ display: 'flex', flexDirection: 'column', gap: rowGap }}>\n {column.elements.map(renderElement)}\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { default as React } from 'react';
2
+ export type HeroBullet = {
3
+ icon?: string;
4
+ text: React.ReactNode;
5
+ };
6
+ export type HeroFeatureBannerProps = {
7
+ /** Background image url (served from /public or absolute). */
8
+ bgImageSrc: string;
9
+ /** Alt text for decorative bg (optional). */
10
+ bgAlt?: string;
11
+ /** Main heading (can be JSX for line breaks). */
12
+ heading: React.ReactNode;
13
+ /** Bullets with optional icon. */
14
+ bullets?: HeroBullet[];
15
+ /** CTA button config. If omitted, button is hidden. */
16
+ cta?: {
17
+ label: string;
18
+ href?: string;
19
+ onClick?: () => void;
20
+ icon?: string;
21
+ };
22
+ /** CTA position: 'left' (with content), 'center', 'top-left', 'top-right', 'bottom-left', 'bottom-right' */
23
+ ctaPosition?: 'left' | 'center' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
24
+ /** Height of the hero (px). */
25
+ height?: number;
26
+ /** Corner radius utility class from PrimeFlex. */
27
+ rounded?: string;
28
+ /** If true, apply a subtle left-side gradient for contrast. */
29
+ leftTint?: boolean;
30
+ /** Content max width (px) */
31
+ contentMaxWidth?: number;
32
+ /** Extra classes */
33
+ className?: string;
34
+ };
35
+ declare const HeroFeatureBanner: React.FC<HeroFeatureBannerProps>;
36
+ export default HeroFeatureBanner;
@@ -0,0 +1,88 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { Button } from "primereact/button";
3
+ import Image from "next/image";
4
+ const HeroFeatureBanner = ({
5
+ bgImageSrc,
6
+ bgAlt,
7
+ heading,
8
+ bullets = [],
9
+ cta,
10
+ ctaPosition = "left",
11
+ height = 520,
12
+ rounded = "",
13
+ leftTint = true,
14
+ contentMaxWidth = 720,
15
+ className = ""
16
+ }) => {
17
+ return /* @__PURE__ */ jsxs(
18
+ "section",
19
+ {
20
+ className: `relative w-full ${rounded} overflow-hidden ${className}`,
21
+ "aria-label": "Hero feature banner",
22
+ style: { minHeight: height },
23
+ children: [
24
+ /* @__PURE__ */ jsx("style", { children: `
25
+ .hfb-tint { position: absolute; inset: 0; pointer-events: none; z-index: 1; }
26
+ .hfb-content { position: relative; z-index: 2; }
27
+ .hfb-bullet i { color: var(--primary-color); font-size: 1.1rem; }
28
+ ` }),
29
+ /* @__PURE__ */ jsx(
30
+ Image,
31
+ {
32
+ src: bgImageSrc,
33
+ alt: bgAlt || "",
34
+ fill: true,
35
+ priority: true,
36
+ quality: 90,
37
+ sizes: "100vw",
38
+ style: {
39
+ objectFit: "cover",
40
+ objectPosition: "center right"
41
+ }
42
+ }
43
+ ),
44
+ leftTint && /* @__PURE__ */ jsx(
45
+ "div",
46
+ {
47
+ className: "hfb-tint"
48
+ }
49
+ ),
50
+ /* @__PURE__ */ jsxs("div", { className: "hfb-content w-full h-full container", style: { position: "relative" }, children: [
51
+ /* @__PURE__ */ jsx("div", { className: "p-4 p-md-5", style: { height: "100%", display: "flex", flexDirection: "column", justifyContent: ctaPosition === "center" ? "center" : "flex-start" }, children: /* @__PURE__ */ jsxs("div", { style: { maxWidth: contentMaxWidth }, children: [
52
+ /* @__PURE__ */ jsx("h1", { className: "m-0 text-900", style: { fontSize: 56, lineHeight: 1.05, fontWeight: 800 }, children: heading }),
53
+ bullets?.length > 0 && /* @__PURE__ */ jsx("ul", { className: "list-none m-0 p-0 mt-4", children: bullets.map((b, i) => /* @__PURE__ */ jsxs("li", { className: "flex align-items-center gap-3 mb-3 hfb-bullet", children: [
54
+ /* @__PURE__ */ jsx("span", { className: "flex align-items-center justify-content-center", style: { width: 34, height: 34, background: "rgba(255,100,50,.12)" }, children: /* @__PURE__ */ jsx("i", { className: `pi ${b.icon ?? "pi-check-circle"}` }) }),
55
+ /* @__PURE__ */ jsx("span", { className: "text-800", style: { fontSize: 18 }, children: b.text })
56
+ ] }, i)) }),
57
+ cta && ctaPosition === "left" && /* @__PURE__ */ jsx("div", { className: "mt-5", children: cta.href ? /* @__PURE__ */ jsxs("a", { href: cta.href, className: "p-button p-component p-button-rounded p-button-lg", style: { textDecoration: "none" }, children: [
58
+ /* @__PURE__ */ jsx("span", { className: "p-button-icon p-button-icon-left pi pi-arrow-right" }),
59
+ /* @__PURE__ */ jsx("span", { className: "p-button-label", children: cta.label })
60
+ ] }) : /* @__PURE__ */ jsx(Button, { rounded: true, size: "large", label: cta.label, icon: cta.icon ?? "pi pi-arrow-right", onClick: cta.onClick }) })
61
+ ] }) }),
62
+ cta && ctaPosition !== "left" && /* @__PURE__ */ jsx(
63
+ "div",
64
+ {
65
+ style: {
66
+ position: "absolute",
67
+ zIndex: 3,
68
+ ...ctaPosition === "center" && { top: "50%", left: "50%", transform: "translate(-50%, -50%)" },
69
+ ...ctaPosition === "top-left" && { top: "2rem", left: "2rem" },
70
+ ...ctaPosition === "top-right" && { top: "2rem", right: "2rem" },
71
+ ...ctaPosition === "bottom-left" && { bottom: "2rem", left: "2rem" },
72
+ ...ctaPosition === "bottom-right" && { bottom: "2rem", right: "2rem" }
73
+ },
74
+ children: cta.href ? /* @__PURE__ */ jsxs("a", { href: cta.href, className: "p-button p-component p-button-rounded p-button-lg", style: { textDecoration: "none" }, children: [
75
+ /* @__PURE__ */ jsx("span", { className: "p-button-icon p-button-icon-left pi pi-arrow-right" }),
76
+ /* @__PURE__ */ jsx("span", { className: "p-button-label", children: cta.label })
77
+ ] }) : /* @__PURE__ */ jsx(Button, { rounded: true, size: "large", label: cta.label, icon: cta.icon ?? "pi pi-arrow-right", onClick: cta.onClick })
78
+ }
79
+ )
80
+ ] })
81
+ ]
82
+ }
83
+ );
84
+ };
85
+ export {
86
+ HeroFeatureBanner as default
87
+ };
88
+ //# sourceMappingURL=HeroFeatureBanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HeroFeatureBanner.js","sources":["../../../src/components/landing/HeroFeatureBanner.tsx"],"sourcesContent":["import React from 'react';\nimport { Button } from 'primereact/button';\nimport Image from 'next/image';\n\nexport type HeroBullet = {\n icon?: string; // PrimeIcons name (e.g., 'pi-pencil'), defaults to check-circle\n text: React.ReactNode;\n};\n\nexport type HeroFeatureBannerProps = {\n /** Background image url (served from /public or absolute). */\n bgImageSrc: string;\n /** Alt text for decorative bg (optional). */\n bgAlt?: string;\n /** Main heading (can be JSX for line breaks). */\n heading: React.ReactNode;\n /** Bullets with optional icon. */\n bullets?: HeroBullet[];\n /** CTA button config. If omitted, button is hidden. */\n cta?: {\n label: string;\n href?: string;\n onClick?: () => void; // in case used client-side\n icon?: string; // PrimeIcons name\n };\n /** CTA position: 'left' (with content), 'center', 'top-left', 'top-right', 'bottom-left', 'bottom-right' */\n ctaPosition?: 'left' | 'center' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n /** Height of the hero (px). */\n height?: number; // default 520\n /** Corner radius utility class from PrimeFlex. */\n rounded?: string; // default 'border-round-2xl'\n /** If true, apply a subtle left-side gradient for contrast. */\n leftTint?: boolean;\n /** Content max width (px) */\n contentMaxWidth?: number; // default 680\n /** Extra classes */\n className?: string;\n};\n\n// RAFCE (SSR-friendly)\nconst HeroFeatureBanner: React.FC<HeroFeatureBannerProps> = ({\n bgImageSrc,\n bgAlt,\n heading,\n bullets = [],\n cta,\n ctaPosition = 'left',\n height = 520,\n rounded = '',\n leftTint = true,\n contentMaxWidth = 720,\n className = '',\n}) => {\n return (\n <section\n className={`relative w-full ${rounded} overflow-hidden ${className}`}\n aria-label=\"Hero feature banner\"\n style={{ minHeight: height }}\n >\n <style>{`\n .hfb-tint { position: absolute; inset: 0; pointer-events: none; z-index: 1; }\n .hfb-content { position: relative; z-index: 2; }\n .hfb-bullet i { color: var(--primary-color); font-size: 1.1rem; }\n `}</style>\n\n {/* Full-bleed background using Next.js Image */}\n <Image\n src={bgImageSrc}\n alt={bgAlt || ''}\n fill\n priority\n quality={90}\n sizes=\"100vw\"\n style={{\n objectFit: 'cover',\n objectPosition: 'center right',\n }}\n />\n\n {/* Optional readability tint on the left */}\n {leftTint && (\n <div\n className=\"hfb-tint\"\n // style={{\n // background:\n // 'linear-gradient(90deg, rgba(255,255,255,0.96) 0%, rgba(255,255,255,0.9) 32%, rgba(255,255,255,0.55) 55%, rgba(255,255,255,0.12) 75%, rgba(255,255,255,0) 100%)',\n // }}\n />\n )}\n\n {/* Content */}\n <div className=\"hfb-content w-full h-full container\" style={{ position: 'relative' }}>\n <div className=\"p-4 p-md-5\" style={{ height: '100%', display: 'flex', flexDirection: 'column', justifyContent: ctaPosition === 'center' ? 'center' : 'flex-start' }}>\n <div style={{ maxWidth: contentMaxWidth }}>\n <h1 className=\"m-0 text-900\" style={{ fontSize: 56, lineHeight: 1.05, fontWeight: 800 }}>\n {heading}\n </h1>\n\n {bullets?.length > 0 && (\n <ul className=\"list-none m-0 p-0 mt-4\">\n {bullets.map((b, i) => (\n <li key={i} className=\"flex align-items-center gap-3 mb-3 hfb-bullet\">\n <span className=\"flex align-items-center justify-content-center\" style={{ width: 34, height: 34, background: 'rgba(255,100,50,.12)' }}>\n <i className={`pi ${b.icon ?? 'pi-check-circle'}`} />\n </span>\n <span className=\"text-800\" style={{ fontSize: 18 }}>{b.text}</span>\n </li>\n ))}\n </ul>\n )}\n\n {cta && ctaPosition === 'left' && (\n <div className=\"mt-5\">\n {cta.href ? (\n <a href={cta.href} className=\"p-button p-component p-button-rounded p-button-lg\" style={{ textDecoration: 'none' }}>\n <span className=\"p-button-icon p-button-icon-left pi pi-arrow-right\" />\n <span className=\"p-button-label\">{cta.label}</span>\n </a>\n ) : (\n <Button rounded size=\"large\" label={cta.label} icon={cta.icon ?? 'pi pi-arrow-right'} onClick={cta.onClick} />\n )}\n </div>\n )}\n </div>\n </div>\n \n {/* Positioned CTA button */}\n {cta && ctaPosition !== 'left' && (\n <div \n style={{\n position: 'absolute',\n zIndex: 3,\n ...(ctaPosition === 'center' && { top: '50%', left: '50%', transform: 'translate(-50%, -50%)' }),\n ...(ctaPosition === 'top-left' && { top: '2rem', left: '2rem' }),\n ...(ctaPosition === 'top-right' && { top: '2rem', right: '2rem' }),\n ...(ctaPosition === 'bottom-left' && { bottom: '2rem', left: '2rem' }),\n ...(ctaPosition === 'bottom-right' && { bottom: '2rem', right: '2rem' }),\n }}\n >\n {cta.href ? (\n <a href={cta.href} className=\"p-button p-component p-button-rounded p-button-lg\" style={{ textDecoration: 'none' }}>\n <span className=\"p-button-icon p-button-icon-left pi pi-arrow-right\" />\n <span className=\"p-button-label\">{cta.label}</span>\n </a>\n ) : (\n <Button rounded size=\"large\" label={cta.label} icon={cta.icon ?? 'pi pi-arrow-right'} onClick={cta.onClick} />\n )}\n </div>\n )}\n </div>\n </section>\n );\n};\n\nexport default HeroFeatureBanner;\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { default as React } from 'react';
2
+ export declare const HeroFeatureBannerComponent: React.FC<{
3
+ props: Record<string, any>;
4
+ }>;
@@ -0,0 +1,100 @@
1
+ "use client";
2
+ import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
+ import React from "react";
4
+ import Link from "next/link";
5
+ import Image from "next/image";
6
+ const HeroFeatureBannerComponent = ({ props }) => {
7
+ const bullets = Array.isArray(props.bullets) ? props.bullets : [];
8
+ let headingNode = props.heading || "";
9
+ if (typeof headingNode === "string" && headingNode.includes("\n")) {
10
+ const parts = headingNode.split("\n");
11
+ headingNode = /* @__PURE__ */ jsx(Fragment, { children: parts.map((part, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
12
+ i > 0 && /* @__PURE__ */ jsx("br", {}),
13
+ part
14
+ ] }, i)) });
15
+ }
16
+ return /* @__PURE__ */ jsx("div", { className: `hero-feature-banner ${props.wrapperClassName || ""}`, children: /* @__PURE__ */ jsxs("div", { className: props.sectionBgClassName || "", children: [
17
+ /* @__PURE__ */ jsx("style", { children: `
18
+ .hfb-tint { position: absolute; inset: 0; pointer-events: none; z-index: 1; }
19
+ .hfb-content { position: relative; z-index: 2; }
20
+ .hfb-bullet i { color: ${props.bulletIconColor || "var(--primary-color, #f97316)"}; font-size: 1.1rem; }
21
+ ` }),
22
+ props.customCSS && /* @__PURE__ */ jsx("style", { children: props.customCSS }),
23
+ /* @__PURE__ */ jsxs(
24
+ "section",
25
+ {
26
+ className: `relative w-full ${props.rounded || ""} overflow-hidden ${props.className || ""}`,
27
+ style: { minHeight: props.height || 560 },
28
+ children: [
29
+ /* @__PURE__ */ jsx(
30
+ Image,
31
+ {
32
+ src: props.bgImageSrc,
33
+ alt: props.bgAlt || "",
34
+ fill: true,
35
+ priority: true,
36
+ quality: 90,
37
+ sizes: "100vw",
38
+ style: {
39
+ objectFit: "cover",
40
+ objectPosition: "center right"
41
+ }
42
+ }
43
+ ),
44
+ props.leftTint && /* @__PURE__ */ jsx("div", { className: "hfb-tint" }),
45
+ /* @__PURE__ */ jsxs("div", { className: "hfb-content w-full h-full container", style: { position: "relative" }, children: [
46
+ /* @__PURE__ */ jsx("div", { className: "p-4 p-md-5", style: { height: "100%", display: "flex", flexDirection: "column", justifyContent: props.ctaPosition === "center" ? "center" : "flex-start" }, children: /* @__PURE__ */ jsxs("div", { style: { maxWidth: props.contentMaxWidth || 720 }, children: [
47
+ /* @__PURE__ */ jsx("h1", { className: props.headingClassName || "m-0 text-900", style: { fontSize: props.headingFontSize || 56, lineHeight: 1.05, fontWeight: 800, color: props.headingColor || void 0 }, children: headingNode }),
48
+ bullets.length > 0 && /* @__PURE__ */ jsx("ul", { className: "list-none m-0 p-0 mt-4", children: bullets.map((b, i) => /* @__PURE__ */ jsxs("li", { className: "flex align-items-center gap-3 mb-3 hfb-bullet", children: [
49
+ /* @__PURE__ */ jsx("span", { className: "flex align-items-center justify-content-center", style: { width: 34, height: 34, background: props.bulletIconBgColor || "rgba(255,100,50,.12)" }, children: /* @__PURE__ */ jsx("i", { className: `pi ${b.icon || "pi-check-circle"}` }) }),
50
+ /* @__PURE__ */ jsx("span", { className: props.bulletTextClassName || "text-800", style: { fontSize: 18, color: props.bulletTextColor || void 0 }, children: b.text })
51
+ ] }, i)) }),
52
+ props.ctaLabel && (!props.ctaPosition || props.ctaPosition === "left") && /* @__PURE__ */ jsx("div", { className: "mt-5", children: /* @__PURE__ */ jsxs(
53
+ Link,
54
+ {
55
+ href: props.ctaHref || "#",
56
+ className: props.ctaClassName || "no-underline inline-flex align-items-center gap-2 bg-primary text-white px-4 py-3 border-round-lg font-semibold",
57
+ style: { fontSize: 16, textDecoration: "none", color: props.ctaColor || void 0, backgroundColor: props.ctaBgColor || void 0 },
58
+ children: [
59
+ props.ctaIcon && /* @__PURE__ */ jsx("i", { className: props.ctaIcon }),
60
+ /* @__PURE__ */ jsx("span", { children: props.ctaLabel })
61
+ ]
62
+ }
63
+ ) })
64
+ ] }) }),
65
+ props.ctaLabel && props.ctaPosition && props.ctaPosition !== "left" && /* @__PURE__ */ jsx(
66
+ "div",
67
+ {
68
+ style: {
69
+ position: "absolute",
70
+ zIndex: 3,
71
+ ...props.ctaPosition === "center" && { top: "50%", left: "50%", transform: "translate(-50%, -50%)" },
72
+ ...props.ctaPosition === "top-left" && { top: "2rem", left: "2rem" },
73
+ ...props.ctaPosition === "top-right" && { top: "2rem", right: "2rem" },
74
+ ...props.ctaPosition === "bottom-left" && { bottom: "2rem", left: "2rem" },
75
+ ...props.ctaPosition === "bottom-right" && { bottom: "2rem", right: "2rem" }
76
+ },
77
+ children: /* @__PURE__ */ jsxs(
78
+ Link,
79
+ {
80
+ href: props.ctaHref || "#",
81
+ className: props.ctaClassName || "no-underline inline-flex align-items-center gap-2 bg-primary text-white px-4 py-3 border-round-lg font-semibold",
82
+ style: { fontSize: 16, textDecoration: "none", color: props.ctaColor || void 0, backgroundColor: props.ctaBgColor || void 0 },
83
+ children: [
84
+ props.ctaIcon && /* @__PURE__ */ jsx("i", { className: props.ctaIcon }),
85
+ /* @__PURE__ */ jsx("span", { children: props.ctaLabel })
86
+ ]
87
+ }
88
+ )
89
+ }
90
+ )
91
+ ] })
92
+ ]
93
+ }
94
+ )
95
+ ] }) });
96
+ };
97
+ export {
98
+ HeroFeatureBannerComponent
99
+ };
100
+ //# sourceMappingURL=HeroFeatureBannerComponent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HeroFeatureBannerComponent.js","sources":["../../../src/components/landing/HeroFeatureBannerComponent.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\nimport Link from 'next/link';\nimport Image from 'next/image';\n\nexport const HeroFeatureBannerComponent: React.FC<{ props: Record<string, any> }> = ({ props }) => {\n const bullets: any[] = Array.isArray(props.bullets) ? props.bullets : [];\n\n // Transform heading line breaks\n let headingNode: React.ReactNode = props.heading || '';\n if (typeof headingNode === 'string' && headingNode.includes('\\n')) {\n const parts = (headingNode as string).split('\\n');\n headingNode = (\n <>\n {parts.map((part: string, i: number) => (\n <React.Fragment key={i}>\n {i > 0 && <br />}\n {part}\n </React.Fragment>\n ))}\n </>\n );\n }\n\n return (\n <div className={`hero-feature-banner ${props.wrapperClassName || ''}`}>\n <div className={props.sectionBgClassName || ''}>\n <style>{`\n .hfb-tint { position: absolute; inset: 0; pointer-events: none; z-index: 1; }\n .hfb-content { position: relative; z-index: 2; }\n .hfb-bullet i { color: ${props.bulletIconColor || 'var(--primary-color, #f97316)'}; font-size: 1.1rem; }\n `}</style>\n {props.customCSS && <style>{props.customCSS}</style>}\n <section\n className={`relative w-full ${props.rounded || ''} overflow-hidden ${props.className || ''}`}\n style={{ minHeight: props.height || 560 }}\n >\n {/* Background Image using Next.js Image */}\n <Image\n src={props.bgImageSrc}\n alt={props.bgAlt || ''}\n fill\n priority\n quality={90}\n sizes=\"100vw\"\n style={{\n objectFit: 'cover',\n objectPosition: 'center right',\n }}\n />\n\n {props.leftTint && <div className=\"hfb-tint\" />}\n\n <div className=\"hfb-content w-full h-full container\" style={{ position: 'relative' }}>\n <div className=\"p-4 p-md-5\" style={{ height: '100%', display: 'flex', flexDirection: 'column', justifyContent: props.ctaPosition === 'center' ? 'center' : 'flex-start' }}>\n <div style={{ maxWidth: props.contentMaxWidth || 720 }}>\n <h1 className={props.headingClassName || 'm-0 text-900'} style={{ fontSize: props.headingFontSize || 56, lineHeight: 1.05, fontWeight: 800, color: props.headingColor || undefined }}>\n {headingNode}\n </h1>\n\n {bullets.length > 0 && (\n <ul className=\"list-none m-0 p-0 mt-4\">\n {bullets.map((b: any, i: number) => (\n <li key={i} className=\"flex align-items-center gap-3 mb-3 hfb-bullet\">\n <span className=\"flex align-items-center justify-content-center\" style={{ width: 34, height: 34, background: props.bulletIconBgColor || 'rgba(255,100,50,.12)' }}>\n <i className={`pi ${b.icon || 'pi-check-circle'}`} />\n </span>\n <span className={props.bulletTextClassName || 'text-800'} style={{ fontSize: 18, color: props.bulletTextColor || undefined }}>{b.text}</span>\n </li>\n ))}\n </ul>\n )}\n\n {props.ctaLabel && (!props.ctaPosition || props.ctaPosition === 'left') && (\n <div className=\"mt-5\">\n <Link\n href={props.ctaHref || '#'}\n className={props.ctaClassName || 'no-underline inline-flex align-items-center gap-2 bg-primary text-white px-4 py-3 border-round-lg font-semibold'}\n style={{ fontSize: 16, textDecoration: 'none', color: props.ctaColor || undefined, backgroundColor: props.ctaBgColor || undefined }}\n >\n {props.ctaIcon && <i className={props.ctaIcon} />}\n <span>{props.ctaLabel}</span>\n </Link>\n </div>\n )}\n </div>\n </div>\n \n {/* Positioned CTA button */}\n {props.ctaLabel && props.ctaPosition && props.ctaPosition !== 'left' && (\n <div \n style={{\n position: 'absolute',\n zIndex: 3,\n ...(props.ctaPosition === 'center' && { top: '50%', left: '50%', transform: 'translate(-50%, -50%)' }),\n ...(props.ctaPosition === 'top-left' && { top: '2rem', left: '2rem' }),\n ...(props.ctaPosition === 'top-right' && { top: '2rem', right: '2rem' }),\n ...(props.ctaPosition === 'bottom-left' && { bottom: '2rem', left: '2rem' }),\n ...(props.ctaPosition === 'bottom-right' && { bottom: '2rem', right: '2rem' }),\n }}\n >\n <Link\n href={props.ctaHref || '#'}\n className={props.ctaClassName || 'no-underline inline-flex align-items-center gap-2 bg-primary text-white px-4 py-3 border-round-lg font-semibold'}\n style={{ fontSize: 16, textDecoration: 'none', color: props.ctaColor || undefined, backgroundColor: props.ctaBgColor || undefined }}\n >\n {props.ctaIcon && <i className={props.ctaIcon} />}\n <span>{props.ctaLabel}</span>\n </Link>\n </div>\n )}\n </div>\n </section>\n </div>\n </div>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { default as React } from 'react';
2
+ export type HeroBullet = {
3
+ icon?: string;
4
+ text: React.ReactNode;
5
+ };
6
+ export type HeroFeatureBannerVideoProps = {
7
+ bgVideoSrc?: string;
8
+ bgPosterSrc?: string;
9
+ bgPosterAlt?: string;
10
+ videoAutoplay?: boolean;
11
+ videoMuted?: boolean;
12
+ videoLoop?: boolean;
13
+ videoLazyLoad?: boolean;
14
+ /** Prioritize fetch/decode for above-the-fold hero usage */
15
+ videoPriority?: boolean;
16
+ heading: React.ReactNode;
17
+ bullets?: HeroBullet[];
18
+ cta?: {
19
+ label: string;
20
+ href?: string;
21
+ onClick?: () => void;
22
+ icon?: string;
23
+ backgroundColor?: string;
24
+ className?: string;
25
+ };
26
+ ctaPosition?: 'left' | 'center' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
27
+ height?: number;
28
+ rounded?: string;
29
+ leftTint?: boolean;
30
+ contentMaxWidth?: number;
31
+ className?: string;
32
+ };
33
+ declare const HeroFeatureBannerVideo: React.FC<HeroFeatureBannerVideoProps>;
34
+ export default HeroFeatureBannerVideo;
@@ -0,0 +1,261 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ import { useRef, useState, useEffect } from "react";
4
+ function configureMobileVideo(video, muted) {
5
+ video.muted = muted;
6
+ video.defaultMuted = muted;
7
+ video.playsInline = true;
8
+ video.setAttribute("playsinline", "");
9
+ video.setAttribute("webkit-playsinline", "");
10
+ }
11
+ const HeroBackgroundVideo = ({ src, autoplay, muted, loop, lazyLoad, priority }) => {
12
+ const containerRef = useRef(null);
13
+ const videoRef = useRef(null);
14
+ const [shouldLoad, setShouldLoad] = useState(!lazyLoad);
15
+ const [isReady, setIsReady] = useState(false);
16
+ const [reduceMotion, setReduceMotion] = useState(false);
17
+ useEffect(() => {
18
+ const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
19
+ const update = () => setReduceMotion(mq.matches);
20
+ update();
21
+ mq.addEventListener("change", update);
22
+ return () => mq.removeEventListener("change", update);
23
+ }, []);
24
+ useEffect(() => {
25
+ if (!lazyLoad || shouldLoad || reduceMotion) return;
26
+ const node = containerRef.current;
27
+ if (!node || typeof IntersectionObserver === "undefined") {
28
+ setShouldLoad(true);
29
+ return;
30
+ }
31
+ const observer = new IntersectionObserver(
32
+ (entries) => {
33
+ if (entries.some((entry) => entry.isIntersecting)) {
34
+ setShouldLoad(true);
35
+ observer.disconnect();
36
+ }
37
+ },
38
+ { rootMargin: "200px 0px", threshold: 0.01 }
39
+ );
40
+ observer.observe(node);
41
+ return () => observer.disconnect();
42
+ }, [lazyLoad, shouldLoad, reduceMotion]);
43
+ useEffect(() => {
44
+ setIsReady(false);
45
+ }, [src]);
46
+ useEffect(() => {
47
+ const video = videoRef.current;
48
+ if (!video || !shouldLoad || reduceMotion) return;
49
+ configureMobileVideo(video, muted);
50
+ const tryPlay = () => {
51
+ setIsReady(true);
52
+ if (!autoplay) return;
53
+ configureMobileVideo(video, muted);
54
+ void video.play().catch(() => {
55
+ });
56
+ };
57
+ const onLoadedData = () => tryPlay();
58
+ const onCanPlay = () => tryPlay();
59
+ const onVisibilityChange = () => {
60
+ if (!document.hidden && autoplay && video.paused) {
61
+ configureMobileVideo(video, muted);
62
+ void video.play().catch(() => {
63
+ });
64
+ }
65
+ };
66
+ const hardFallback = window.setTimeout(tryPlay, 2e3);
67
+ if (video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) {
68
+ tryPlay();
69
+ }
70
+ video.addEventListener("loadeddata", onLoadedData);
71
+ video.addEventListener("canplay", onCanPlay);
72
+ document.addEventListener("visibilitychange", onVisibilityChange);
73
+ return () => {
74
+ window.clearTimeout(hardFallback);
75
+ video.removeEventListener("loadeddata", onLoadedData);
76
+ video.removeEventListener("canplay", onCanPlay);
77
+ document.removeEventListener("visibilitychange", onVisibilityChange);
78
+ };
79
+ }, [shouldLoad, autoplay, muted, reduceMotion, src]);
80
+ const setVideoRef = (node) => {
81
+ videoRef.current = node;
82
+ if (node) {
83
+ configureMobileVideo(node, muted);
84
+ }
85
+ };
86
+ if (reduceMotion || !src) {
87
+ return /* @__PURE__ */ jsx("div", { ref: containerRef, className: "hfbv-media-layer", "aria-hidden": "true" });
88
+ }
89
+ return /* @__PURE__ */ jsx("div", { ref: containerRef, className: "hfbv-media-layer", "aria-hidden": "true", children: shouldLoad && /* @__PURE__ */ jsx(
90
+ "video",
91
+ {
92
+ ref: setVideoRef,
93
+ className: `hfbv-video${isReady ? " hfbv-video--ready" : ""}`,
94
+ src,
95
+ muted,
96
+ loop,
97
+ autoPlay: autoplay,
98
+ playsInline: true,
99
+ preload: priority ? "auto" : "metadata",
100
+ fetchPriority: priority ? "high" : "auto",
101
+ disablePictureInPicture: true,
102
+ disableRemotePlayback: true,
103
+ tabIndex: -1
104
+ }
105
+ ) });
106
+ };
107
+ const HeroFeatureBannerVideo = ({
108
+ bgVideoSrc,
109
+ videoAutoplay = true,
110
+ videoMuted = true,
111
+ videoLoop = true,
112
+ videoLazyLoad = false,
113
+ videoPriority = true,
114
+ heading,
115
+ bullets = [],
116
+ cta,
117
+ ctaPosition = "left",
118
+ height = 560,
119
+ rounded = "",
120
+ leftTint = true,
121
+ contentMaxWidth = 720,
122
+ className = ""
123
+ }) => {
124
+ return /* @__PURE__ */ jsxs(
125
+ "section",
126
+ {
127
+ className: `relative w-full ${rounded} overflow-hidden ${className}`,
128
+ "aria-label": "Hero feature banner",
129
+ style: { minHeight: height },
130
+ children: [
131
+ /* @__PURE__ */ jsx("style", { children: `
132
+ .hfbv-media-stack { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
133
+ .hfbv-media-layer { position: absolute; inset: 0; width: 100%; height: 100%; }
134
+ .hfbv-video {
135
+ position: absolute;
136
+ inset: 0;
137
+ width: 100%;
138
+ height: 100%;
139
+ object-fit: cover;
140
+ object-position: center right;
141
+ opacity: 0;
142
+ transition: opacity 0.35s ease;
143
+ transform: translate3d(0, 0, 0);
144
+ backface-visibility: hidden;
145
+ -webkit-backface-visibility: hidden;
146
+ }
147
+ .hfbv-video--ready { opacity: 1; }
148
+ .hfbv-tint { position: absolute; inset: 0; pointer-events: none; z-index: 1; }
149
+ .hfbv-content { position: relative; z-index: 2; }
150
+ .hfbv-bullet i { color: var(--primary-color); font-size: 1.1rem; }
151
+ ` }),
152
+ /* @__PURE__ */ jsx("div", { className: "hfbv-media-stack", children: bgVideoSrc && /* @__PURE__ */ jsx(
153
+ HeroBackgroundVideo,
154
+ {
155
+ src: bgVideoSrc,
156
+ autoplay: videoAutoplay,
157
+ muted: videoMuted,
158
+ loop: videoLoop,
159
+ lazyLoad: videoLazyLoad,
160
+ priority: videoPriority
161
+ }
162
+ ) }),
163
+ leftTint && /* @__PURE__ */ jsx("div", { className: "hfbv-tint" }),
164
+ /* @__PURE__ */ jsxs("div", { className: "hfbv-content w-full h-full container", style: { position: "relative" }, children: [
165
+ /* @__PURE__ */ jsx(
166
+ "div",
167
+ {
168
+ className: "p-4 p-md-5",
169
+ style: {
170
+ height: "100%",
171
+ display: "flex",
172
+ flexDirection: "column",
173
+ justifyContent: ctaPosition === "center" ? "center" : "flex-start"
174
+ },
175
+ children: /* @__PURE__ */ jsxs("div", { style: { maxWidth: contentMaxWidth }, children: [
176
+ /* @__PURE__ */ jsx("h1", { className: "m-0 text-900", style: { fontSize: 56, lineHeight: 1.05, fontWeight: 800 }, children: heading }),
177
+ bullets.length > 0 && /* @__PURE__ */ jsx("ul", { className: "list-none m-0 p-0 mt-4", children: bullets.map((b, i) => /* @__PURE__ */ jsxs("li", { className: "flex align-items-center gap-3 mb-3 hfbv-bullet", children: [
178
+ /* @__PURE__ */ jsx(
179
+ "span",
180
+ {
181
+ className: "flex align-items-center justify-content-center",
182
+ style: { width: 34, height: 34, background: "rgba(255,100,50,.12)" },
183
+ children: /* @__PURE__ */ jsx("i", { className: `pi ${b.icon ?? "pi-check-circle"}` })
184
+ }
185
+ ),
186
+ /* @__PURE__ */ jsx("span", { className: "text-800", style: { fontSize: 18 }, children: b.text })
187
+ ] }, i)) }),
188
+ cta && ctaPosition === "left" && /* @__PURE__ */ jsx("div", { className: "mt-5", children: cta.href ? /* @__PURE__ */ jsxs(
189
+ "a",
190
+ {
191
+ href: cta.href,
192
+ className: `p-button p-component p-button-rounded p-button-lg ${cta.className || ""}`,
193
+ style: { textDecoration: "none", backgroundColor: cta.backgroundColor },
194
+ children: [
195
+ /* @__PURE__ */ jsx("span", { className: "p-button-icon p-button-icon-left pi pi-arrow-right" }),
196
+ /* @__PURE__ */ jsx("span", { className: "p-button-label", children: cta.label })
197
+ ]
198
+ }
199
+ ) : /* @__PURE__ */ jsxs(
200
+ "button",
201
+ {
202
+ type: "button",
203
+ className: `p-button p-component p-button-rounded p-button-lg ${cta.className || ""}`,
204
+ onClick: cta.onClick,
205
+ style: { backgroundColor: cta.backgroundColor },
206
+ children: [
207
+ /* @__PURE__ */ jsx("span", { className: "p-button-icon p-button-icon-left pi pi-arrow-right" }),
208
+ /* @__PURE__ */ jsx("span", { className: "p-button-label", children: cta.label })
209
+ ]
210
+ }
211
+ ) })
212
+ ] })
213
+ }
214
+ ),
215
+ cta && ctaPosition !== "left" && /* @__PURE__ */ jsx(
216
+ "div",
217
+ {
218
+ style: {
219
+ position: "absolute",
220
+ zIndex: 3,
221
+ ...ctaPosition === "center" && { top: "50%", left: "50%", transform: "translate(-50%, -50%)" },
222
+ ...ctaPosition === "top-left" && { top: "2rem", left: "2rem" },
223
+ ...ctaPosition === "top-right" && { top: "2rem", right: "2rem" },
224
+ ...ctaPosition === "bottom-left" && { bottom: "2rem", left: "2rem" },
225
+ ...ctaPosition === "bottom-right" && { bottom: "2rem", right: "2rem" }
226
+ },
227
+ children: cta.href ? /* @__PURE__ */ jsxs(
228
+ "a",
229
+ {
230
+ href: cta.href,
231
+ className: `p-button p-component p-button-rounded p-button-lg ${cta.className || ""}`,
232
+ style: { textDecoration: "none", backgroundColor: cta.backgroundColor },
233
+ children: [
234
+ /* @__PURE__ */ jsx("span", { className: "p-button-icon p-button-icon-left pi pi-arrow-right" }),
235
+ /* @__PURE__ */ jsx("span", { className: "p-button-label", children: cta.label })
236
+ ]
237
+ }
238
+ ) : /* @__PURE__ */ jsxs(
239
+ "button",
240
+ {
241
+ type: "button",
242
+ className: `p-button p-component p-button-rounded p-button-lg ${cta.className || ""}`,
243
+ onClick: cta.onClick,
244
+ style: { backgroundColor: cta.backgroundColor },
245
+ children: [
246
+ /* @__PURE__ */ jsx("span", { className: "p-button-icon p-button-icon-left pi pi-arrow-right" }),
247
+ /* @__PURE__ */ jsx("span", { className: "p-button-label", children: cta.label })
248
+ ]
249
+ }
250
+ )
251
+ }
252
+ )
253
+ ] })
254
+ ]
255
+ }
256
+ );
257
+ };
258
+ export {
259
+ HeroFeatureBannerVideo as default
260
+ };
261
+ //# sourceMappingURL=HeroFeatureBannerVideo.js.map