@gosalesdeal/blog 0.1.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 (50) hide show
  1. package/README.md +265 -34
  2. package/dist/client/blogClient.js +79 -13
  3. package/dist/client/blogClient.js.map +1 -1
  4. package/dist/components/BlogPost.d.ts +12 -1
  5. package/dist/components/BlogPost.js +27 -16
  6. package/dist/components/BlogPost.js.map +1 -1
  7. package/dist/components/BlogPostHeader.d.ts +15 -0
  8. package/dist/components/BlogPostHeader.js +41 -0
  9. package/dist/components/BlogPostHeader.js.map +1 -0
  10. package/dist/components/landing/BlogLayoutComponents.d.ts +14 -0
  11. package/dist/components/landing/BlogLayoutComponents.js +198 -0
  12. package/dist/components/landing/BlogLayoutComponents.js.map +1 -0
  13. package/dist/components/landing/FlexibleLayoutComponent.d.ts +40 -0
  14. package/dist/components/landing/FlexibleLayoutComponent.js +352 -0
  15. package/dist/components/landing/FlexibleLayoutComponent.js.map +1 -0
  16. package/dist/components/landing/HeroFeatureBanner.d.ts +36 -0
  17. package/dist/components/landing/HeroFeatureBanner.js +88 -0
  18. package/dist/components/landing/HeroFeatureBanner.js.map +1 -0
  19. package/dist/components/landing/HeroFeatureBannerComponent.d.ts +4 -0
  20. package/dist/components/landing/HeroFeatureBannerComponent.js +100 -0
  21. package/dist/components/landing/HeroFeatureBannerComponent.js.map +1 -0
  22. package/dist/components/landing/HeroFeatureBannerVideo.d.ts +34 -0
  23. package/dist/components/landing/HeroFeatureBannerVideo.js +261 -0
  24. package/dist/components/landing/HeroFeatureBannerVideo.js.map +1 -0
  25. package/dist/components/landing/HeroFeatureBannerVideoComponent.d.ts +5 -0
  26. package/dist/components/landing/HeroFeatureBannerVideoComponent.js +69 -0
  27. package/dist/components/landing/HeroFeatureBannerVideoComponent.js.map +1 -0
  28. package/dist/components/landing/VarietyReviewslistComponent.d.ts +4 -0
  29. package/dist/components/landing/VarietyReviewslistComponent.js +172 -0
  30. package/dist/components/landing/VarietyReviewslistComponent.js.map +1 -0
  31. package/dist/index.d.ts +13 -0
  32. package/dist/index.js +25 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/lib/postUtils.d.ts +3 -0
  35. package/dist/lib/postUtils.js +8 -0
  36. package/dist/lib/postUtils.js.map +1 -0
  37. package/dist/lib/resolveMediaSrc.d.ts +2 -0
  38. package/dist/lib/resolveMediaSrc.js +21 -0
  39. package/dist/lib/resolveMediaSrc.js.map +1 -0
  40. package/dist/render/BlockRenderer.js +5 -0
  41. package/dist/render/BlockRenderer.js.map +1 -1
  42. package/dist/render/LandingPageRenderer.d.ts +5 -0
  43. package/dist/render/LandingPageRenderer.js +50 -0
  44. package/dist/render/LandingPageRenderer.js.map +1 -0
  45. package/dist/render/landingPageHtml.d.ts +28 -0
  46. package/dist/render/landingPageHtml.js +205 -0
  47. package/dist/render/landingPageHtml.js.map +1 -0
  48. package/dist/styles.css +27 -0
  49. package/dist/types/blog.d.ts +8 -2
  50. package/package.json +13 -3
@@ -0,0 +1,352 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ const FlexibleLayoutComponent = ({ props }) => {
3
+ const {
4
+ columnCount = 2,
5
+ columns = [],
6
+ columnRatio = "50-50",
7
+ containerMaxWidth = "1200px",
8
+ containerPadding = "0rem",
9
+ containerMarginTop = "0rem",
10
+ containerMarginBottom = "0rem",
11
+ containerBackgroundColor = "transparent",
12
+ containerBorderRadius = "0px",
13
+ columnGap = "2rem",
14
+ rowGap = "1rem",
15
+ stackOnMobile = true,
16
+ stackOnTablet = false,
17
+ reverseOnMobile = false,
18
+ mobileBreakpoint = "768px",
19
+ tabletBreakpoint = "1024px",
20
+ customCSS = "",
21
+ className = "",
22
+ containerClass = "",
23
+ columnsWrapperClass = ""
24
+ } = props;
25
+ let ratios = columnRatio.split("-").map((r) => `${r}%`);
26
+ if (ratios.length !== columnCount) {
27
+ const equalRatio = `${Math.floor(100 / columnCount)}%`;
28
+ ratios = Array(columnCount).fill(equalRatio);
29
+ }
30
+ const renderElement = (element) => {
31
+ const commonStyle = {
32
+ marginTop: element.marginTop || "0",
33
+ marginBottom: element.marginBottom || "0"
34
+ };
35
+ switch (element.type) {
36
+ case "heading": {
37
+ const level = element.headingLevel || "h2";
38
+ const headingProps = {
39
+ key: element.id,
40
+ className: element.customClass,
41
+ style: {
42
+ ...commonStyle,
43
+ color: element.headingColor,
44
+ fontSize: element.headingSize,
45
+ fontWeight: element.headingWeight,
46
+ textAlign: element.headingAlign
47
+ }
48
+ };
49
+ switch (level) {
50
+ case "h1":
51
+ return /* @__PURE__ */ jsx("h1", { ...headingProps, children: element.headingText });
52
+ case "h2":
53
+ return /* @__PURE__ */ jsx("h2", { ...headingProps, children: element.headingText });
54
+ case "h3":
55
+ return /* @__PURE__ */ jsx("h3", { ...headingProps, children: element.headingText });
56
+ case "h4":
57
+ return /* @__PURE__ */ jsx("h4", { ...headingProps, children: element.headingText });
58
+ case "h5":
59
+ return /* @__PURE__ */ jsx("h5", { ...headingProps, children: element.headingText });
60
+ case "h6":
61
+ return /* @__PURE__ */ jsx("h6", { ...headingProps, children: element.headingText });
62
+ default:
63
+ return /* @__PURE__ */ jsx("h2", { ...headingProps, children: element.headingText });
64
+ }
65
+ }
66
+ case "paragraph":
67
+ return /* @__PURE__ */ jsx(
68
+ "p",
69
+ {
70
+ className: element.customClass,
71
+ style: {
72
+ ...commonStyle,
73
+ color: element.paragraphColor,
74
+ fontSize: element.paragraphSize,
75
+ textAlign: element.paragraphAlign,
76
+ lineHeight: element.paragraphLineHeight
77
+ },
78
+ children: element.paragraphText
79
+ },
80
+ element.id
81
+ );
82
+ case "image":
83
+ return /* @__PURE__ */ jsxs("div", { className: element.customClass, style: commonStyle, children: [
84
+ /* @__PURE__ */ jsx(
85
+ "img",
86
+ {
87
+ src: element.imageUrl || "https://via.placeholder.com/400x300",
88
+ alt: element.imageAlt || "Image",
89
+ style: {
90
+ width: element.imageWidth || "100%",
91
+ height: element.imageHeight || "auto",
92
+ objectFit: element.imageObjectFit,
93
+ borderRadius: element.imageBorderRadius,
94
+ display: "block"
95
+ }
96
+ }
97
+ ),
98
+ element.imageCaption && /* @__PURE__ */ jsx("p", { style: { fontSize: "0.875rem", color: "#6b7280", marginTop: "0.5rem", textAlign: "center" }, children: element.imageCaption })
99
+ ] }, element.id);
100
+ case "video": {
101
+ const getVideoEmbedUrl = (url, type) => {
102
+ if (type === "youtube") {
103
+ const videoId = url.includes("v=") ? url.split("v=")[1]?.split("&")[0] : url.split("/").pop();
104
+ return `https://www.youtube.com/embed/${videoId}`;
105
+ } else if (type === "vimeo") {
106
+ const videoId = url.split("/").pop();
107
+ return `https://player.vimeo.com/video/${videoId}`;
108
+ }
109
+ return url;
110
+ };
111
+ return /* @__PURE__ */ jsx("div", { className: element.customClass, style: commonStyle, children: element.videoType === "direct" ? /* @__PURE__ */ jsx(
112
+ "video",
113
+ {
114
+ src: element.videoUrl,
115
+ controls: element.videoControls,
116
+ autoPlay: element.videoAutoplay,
117
+ style: {
118
+ width: element.videoWidth || "100%",
119
+ height: element.videoHeight || "auto",
120
+ borderRadius: "8px"
121
+ }
122
+ }
123
+ ) : /* @__PURE__ */ jsx(
124
+ "iframe",
125
+ {
126
+ src: getVideoEmbedUrl(element.videoUrl || "", element.videoType || "youtube"),
127
+ style: {
128
+ width: element.videoWidth || "100%",
129
+ height: element.videoHeight || "400px",
130
+ border: "none",
131
+ borderRadius: "8px"
132
+ },
133
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
134
+ allowFullScreen: true
135
+ }
136
+ ) }, element.id);
137
+ }
138
+ case "button":
139
+ return /* @__PURE__ */ jsx(
140
+ "a",
141
+ {
142
+ href: element.buttonUrl || "#",
143
+ target: element.buttonTarget,
144
+ className: element.customClass,
145
+ style: {
146
+ ...commonStyle,
147
+ display: element.buttonFullWidth ? "block" : "inline-block",
148
+ padding: element.buttonSize === "small" ? "0.5rem 1rem" : element.buttonSize === "large" ? "1rem 2rem" : "0.75rem 1.5rem",
149
+ backgroundColor: element.buttonBgColor || "#3b82f6",
150
+ color: element.buttonTextColor || "#ffffff",
151
+ textDecoration: "none",
152
+ borderRadius: "6px",
153
+ fontWeight: "500",
154
+ textAlign: "center",
155
+ border: element.buttonStyle === "outline" ? "2px solid currentColor" : "none",
156
+ background: element.buttonStyle === "outline" || element.buttonStyle === "text" ? "transparent" : element.buttonBgColor
157
+ },
158
+ children: element.buttonText
159
+ },
160
+ element.id
161
+ );
162
+ case "list": {
163
+ const listProps = {
164
+ key: element.id,
165
+ className: element.customClass,
166
+ style: {
167
+ ...commonStyle,
168
+ listStyle: element.listStyle === "default" ? void 0 : "none",
169
+ paddingLeft: element.listStyle === "default" ? "1.5rem" : "0"
170
+ }
171
+ };
172
+ const items = (element.listItems || []).map((item, idx) => /* @__PURE__ */ jsx("li", { style: { marginBottom: "0.5rem" }, children: item }, idx));
173
+ return element.listType === "ordered" ? /* @__PURE__ */ jsx("ol", { ...listProps, children: items }) : /* @__PURE__ */ jsx("ul", { ...listProps, children: items });
174
+ }
175
+ case "quote":
176
+ return /* @__PURE__ */ jsxs(
177
+ "blockquote",
178
+ {
179
+ className: element.customClass,
180
+ style: {
181
+ ...commonStyle,
182
+ borderLeft: `4px solid ${element.quoteBorderColor || "#3b82f6"}`,
183
+ paddingLeft: "1.5rem",
184
+ fontStyle: "italic",
185
+ color: "#374151"
186
+ },
187
+ children: [
188
+ /* @__PURE__ */ jsx("p", { style: { marginBottom: "0.5rem" }, children: element.quoteText }),
189
+ element.quoteAuthor && /* @__PURE__ */ jsxs("footer", { style: { fontSize: "0.875rem", color: "#6b7280" }, children: [
190
+ "— ",
191
+ element.quoteAuthor
192
+ ] })
193
+ ]
194
+ },
195
+ element.id
196
+ );
197
+ case "divider":
198
+ return /* @__PURE__ */ jsx(
199
+ "hr",
200
+ {
201
+ className: element.customClass,
202
+ style: {
203
+ ...commonStyle,
204
+ border: "none",
205
+ borderTop: `${element.dividerHeight || "1px"} ${element.dividerStyle || "solid"} ${element.dividerColor || "#e5e7eb"}`,
206
+ width: element.dividerWidth || "100%"
207
+ }
208
+ },
209
+ element.id
210
+ );
211
+ case "spacer":
212
+ return /* @__PURE__ */ jsx(
213
+ "div",
214
+ {
215
+ className: element.customClass,
216
+ style: {
217
+ height: element.spacerHeight || "2rem"
218
+ }
219
+ },
220
+ element.id
221
+ );
222
+ case "code":
223
+ return /* @__PURE__ */ jsx(
224
+ "pre",
225
+ {
226
+ className: element.customClass,
227
+ style: {
228
+ ...commonStyle,
229
+ backgroundColor: element.codeTheme === "light" ? "#f3f4f6" : "#1e293b",
230
+ color: element.codeTheme === "light" ? "#1f2937" : "#e2e8f0",
231
+ padding: "1rem",
232
+ borderRadius: "6px",
233
+ overflow: "auto",
234
+ fontSize: "0.875rem",
235
+ fontFamily: "monospace"
236
+ },
237
+ children: /* @__PURE__ */ jsx("code", { children: element.codeContent })
238
+ },
239
+ element.id
240
+ );
241
+ case "badge":
242
+ return /* @__PURE__ */ jsx(
243
+ "span",
244
+ {
245
+ className: element.customClass,
246
+ style: {
247
+ ...commonStyle,
248
+ display: "inline-block",
249
+ padding: "0.25rem 0.75rem",
250
+ backgroundColor: element.badgeBgColor || "#3b82f6",
251
+ color: element.badgeColor || "#ffffff",
252
+ borderRadius: "9999px",
253
+ fontSize: "0.875rem",
254
+ fontWeight: "500"
255
+ },
256
+ children: element.badgeText
257
+ },
258
+ element.id
259
+ );
260
+ case "alert": {
261
+ const alertColors = {
262
+ info: { bg: "#dbeafe", border: "#3b82f6", text: "#1e40af" },
263
+ success: { bg: "#d1fae5", border: "#10b981", text: "#065f46" },
264
+ warning: { bg: "#fef3c7", border: "#f59e0b", text: "#92400e" },
265
+ error: { bg: "#fee2e2", border: "#ef4444", text: "#991b1b" }
266
+ };
267
+ const alertStyle = alertColors[element.alertType || "info"];
268
+ return /* @__PURE__ */ jsx(
269
+ "div",
270
+ {
271
+ className: element.customClass,
272
+ style: {
273
+ ...commonStyle,
274
+ backgroundColor: alertStyle.bg,
275
+ borderLeft: `4px solid ${alertStyle.border}`,
276
+ color: alertStyle.text,
277
+ padding: "1rem",
278
+ borderRadius: "6px"
279
+ },
280
+ children: element.alertText
281
+ },
282
+ element.id
283
+ );
284
+ }
285
+ default:
286
+ return null;
287
+ }
288
+ };
289
+ const responsiveCSS = `
290
+ @media (max-width: ${mobileBreakpoint}) {
291
+ .flexible-layout-container-${columnCount} {
292
+ ${stackOnMobile ? "flex-direction: column !important;" : ""}
293
+ ${reverseOnMobile ? "flex-direction: column-reverse !important;" : ""}
294
+ }
295
+ .flexible-layout-column-${columnCount} {
296
+ ${stackOnMobile ? "width: 100% !important; flex: none !important;" : ""}
297
+ }
298
+ }
299
+ @media (max-width: ${tabletBreakpoint}) and (min-width: ${mobileBreakpoint}) {
300
+ .flexible-layout-container-${columnCount} {
301
+ ${stackOnTablet ? "flex-direction: column !important;" : ""}
302
+ }
303
+ .flexible-layout-column-${columnCount} {
304
+ ${stackOnTablet ? "width: 100% !important; flex: none !important;" : ""}
305
+ }
306
+ }
307
+ `;
308
+ return /* @__PURE__ */ jsxs(
309
+ "div",
310
+ {
311
+ className: `flexible-layout w-full mx-auto overflow-hidden ${containerClass} ${className || ""}`,
312
+ children: [
313
+ customCSS && /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: customCSS } }),
314
+ /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: responsiveCSS } }),
315
+ /* @__PURE__ */ jsx(
316
+ "div",
317
+ {
318
+ className: `flexible-layout-container-${columnCount} flex w-full ${columnsWrapperClass}`,
319
+ style: {
320
+ gap: columnGap,
321
+ alignItems: "stretch"
322
+ },
323
+ children: columns.slice(0, columnCount).map((column, index) => /* @__PURE__ */ jsx(
324
+ "div",
325
+ {
326
+ className: `flexible-layout-column-${columnCount}`,
327
+ style: {
328
+ flex: `0 0 ${ratios[index] || "auto"}`,
329
+ minWidth: 0,
330
+ maxWidth: ratios[index] || "auto",
331
+ backgroundColor: column.backgroundColor,
332
+ padding: column.padding,
333
+ display: "flex",
334
+ flexDirection: "column",
335
+ justifyContent: column.alignment === "center" ? "center" : column.alignment === "bottom" ? "flex-end" : "flex-start",
336
+ boxSizing: "border-box",
337
+ overflow: "hidden"
338
+ },
339
+ children: /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: rowGap }, children: column.elements.map(renderElement) })
340
+ },
341
+ column.id
342
+ ))
343
+ }
344
+ )
345
+ ]
346
+ }
347
+ );
348
+ };
349
+ export {
350
+ FlexibleLayoutComponent
351
+ };
352
+ //# sourceMappingURL=FlexibleLayoutComponent.js.map
@@ -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
+ }>;