@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.
- package/README.md +265 -34
- package/dist/client/blogClient.js +36 -7
- package/dist/client/blogClient.js.map +1 -1
- package/dist/components/BlogPost.js +7 -8
- package/dist/components/BlogPost.js.map +1 -1
- package/dist/components/landing/BlogLayoutComponents.d.ts +14 -0
- package/dist/components/landing/BlogLayoutComponents.js +198 -0
- package/dist/components/landing/BlogLayoutComponents.js.map +1 -0
- package/dist/components/landing/FlexibleLayoutComponent.d.ts +40 -0
- package/dist/components/landing/FlexibleLayoutComponent.js +352 -0
- package/dist/components/landing/FlexibleLayoutComponent.js.map +1 -0
- package/dist/components/landing/HeroFeatureBanner.d.ts +36 -0
- package/dist/components/landing/HeroFeatureBanner.js +88 -0
- package/dist/components/landing/HeroFeatureBanner.js.map +1 -0
- package/dist/components/landing/HeroFeatureBannerComponent.d.ts +4 -0
- package/dist/components/landing/HeroFeatureBannerComponent.js +100 -0
- package/dist/components/landing/HeroFeatureBannerComponent.js.map +1 -0
- package/dist/components/landing/HeroFeatureBannerVideo.d.ts +34 -0
- package/dist/components/landing/HeroFeatureBannerVideo.js +261 -0
- package/dist/components/landing/HeroFeatureBannerVideo.js.map +1 -0
- package/dist/components/landing/HeroFeatureBannerVideoComponent.d.ts +5 -0
- package/dist/components/landing/HeroFeatureBannerVideoComponent.js +69 -0
- package/dist/components/landing/HeroFeatureBannerVideoComponent.js.map +1 -0
- package/dist/components/landing/VarietyReviewslistComponent.d.ts +4 -0
- package/dist/components/landing/VarietyReviewslistComponent.js +172 -0
- package/dist/components/landing/VarietyReviewslistComponent.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +21 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/resolveMediaSrc.d.ts +2 -0
- package/dist/lib/resolveMediaSrc.js +21 -0
- package/dist/lib/resolveMediaSrc.js.map +1 -0
- package/dist/render/BlockRenderer.js +5 -0
- package/dist/render/BlockRenderer.js.map +1 -1
- package/dist/render/LandingPageRenderer.d.ts +5 -0
- package/dist/render/LandingPageRenderer.js +50 -0
- package/dist/render/LandingPageRenderer.js.map +1 -0
- package/dist/render/landingPageHtml.d.ts +3 -1
- package/dist/render/landingPageHtml.js +18 -2
- package/dist/render/landingPageHtml.js.map +1 -1
- package/dist/styles.css +13 -0
- package/dist/types/blog.d.ts +5 -2
- 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,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
|