@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
@@ -1,9 +1,12 @@
1
1
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
2
2
  import { getPostBySlug, incrementView } from "../client/blogClient.js";
3
3
  import { renderBlocks } from "../render/BlockRenderer.js";
4
- import { formatDate } from "../lib/format.js";
5
4
  import { generateBlogPostJsonLd, generateBlogBreadcrumbJsonLd } from "../seo/index.js";
6
5
  import { JsonLd } from "./JsonLd.js";
6
+ import { BlogPostHeader } from "./BlogPostHeader.js";
7
+ import { getLandingPageSchema } from "../render/landingPageHtml.js";
8
+ import { LandingPageRenderer } from "../render/LandingPageRenderer.js";
9
+ import { RichText } from "../render/RichText.js";
7
10
  function mergeConfig(config, apiBaseUrl, tenantId) {
8
11
  return {
9
12
  ...config,
@@ -13,6 +16,7 @@ function mergeConfig(config, apiBaseUrl, tenantId) {
13
16
  }
14
17
  async function BlogPost({
15
18
  slug,
19
+ post: initialPost,
16
20
  apiBaseUrl,
17
21
  tenantId,
18
22
  config,
@@ -20,31 +24,38 @@ async function BlogPost({
20
24
  renderJsonLd = true,
21
25
  seo,
22
26
  locale = "en-US",
27
+ showTitle = true,
28
+ showFeatured = true,
29
+ showMeta = true,
30
+ showExcerpt = true,
23
31
  fallback = null
24
32
  }) {
25
33
  const cfg = mergeConfig(config, apiBaseUrl, tenantId);
26
- const post = await getPostBySlug(slug, cfg);
34
+ const post = initialPost ?? await getPostBySlug(slug, cfg);
27
35
  if (!post) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
28
36
  if (trackView) await incrementView(post.post_id, cfg);
37
+ const landingSchema = post.content_blocks.length === 0 ? getLandingPageSchema(post) : null;
38
+ const landingPageHtml = post.content_blocks.length === 0 && !landingSchema && post.landing_page_html ? { html: post.landing_page_html, css: post.landing_page_css ?? "" } : null;
29
39
  return /* @__PURE__ */ jsxs("article", { className: "ggblog-post", children: [
30
40
  renderJsonLd ? /* @__PURE__ */ jsxs(Fragment, { children: [
31
41
  /* @__PURE__ */ jsx(JsonLd, { id: "ggblog-post-jsonld", data: generateBlogPostJsonLd(post, seo) }),
32
42
  /* @__PURE__ */ jsx(JsonLd, { id: "ggblog-breadcrumb-jsonld", data: generateBlogBreadcrumbJsonLd(post, seo) })
33
43
  ] }) : null,
34
- /* @__PURE__ */ jsxs("header", { className: "ggblog-post-header", children: [
35
- /* @__PURE__ */ jsx("h1", { className: "ggblog-post-title", children: post.title }),
36
- /* @__PURE__ */ jsxs("div", { className: "ggblog-post-meta", children: [
37
- post.author_name ? /* @__PURE__ */ jsx("span", { className: "ggblog-post-author", children: post.author_name }) : null,
38
- post.published_at ? /* @__PURE__ */ jsx("time", { dateTime: post.published_at, children: formatDate(post.published_at, locale) }) : null,
39
- post.reading_time ? /* @__PURE__ */ jsxs("span", { className: "ggblog-post-readtime", children: [
40
- post.reading_time,
41
- " min read"
42
- ] }) : null
43
- ] }),
44
- post.excerpt ? /* @__PURE__ */ jsx("p", { className: "ggblog-post-excerpt", children: post.excerpt }) : null,
45
- post.featured_image ? /* @__PURE__ */ jsx("figure", { className: "ggblog-post-cover", children: /* @__PURE__ */ jsx("img", { src: post.featured_image, alt: post.featured_image_alt ?? post.title }) }) : null
46
- ] }),
47
- /* @__PURE__ */ jsx("div", { className: "ggblog-post-body", children: renderBlocks(post.content_blocks) })
44
+ /* @__PURE__ */ jsx(
45
+ BlogPostHeader,
46
+ {
47
+ post,
48
+ locale,
49
+ showTitle,
50
+ showFeatured,
51
+ showMeta,
52
+ showExcerpt
53
+ }
54
+ ),
55
+ /* @__PURE__ */ jsx("div", { className: "ggblog-post-body", children: post.content_blocks.length > 0 ? renderBlocks(post.content_blocks) : landingSchema ? /* @__PURE__ */ jsx(LandingPageRenderer, { schema: landingSchema }) : landingPageHtml?.html ? /* @__PURE__ */ jsxs(Fragment, { children: [
56
+ landingPageHtml.css ? /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: landingPageHtml.css } }) : null,
57
+ /* @__PURE__ */ jsx(RichText, { html: landingPageHtml.html, className: "ggblog-landing-page" })
58
+ ] }) : null })
48
59
  ] });
49
60
  }
50
61
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"BlogPost.js","sources":["../../src/components/BlogPost.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { BlogConfig } from '../config';\nimport { getPostBySlug, incrementView } from '../client/blogClient';\nimport { renderBlocks } from '../render/BlockRenderer';\nimport { formatDate } from '../lib/format';\nimport { generateBlogPostJsonLd, generateBlogBreadcrumbJsonLd, type SeoOptions } from '../seo';\nimport { JsonLd } from './JsonLd';\n\nexport interface BlogPostProps {\n /** Slug of the post to render. */\n slug: string;\n /** API base URL (overrides configured/env default). */\n apiBaseUrl?: string;\n /** Tenant id sent as `X-Tenant`. */\n tenantId?: string;\n /** Full config override (takes precedence over apiBaseUrl/tenantId props). */\n config?: Partial<BlogConfig>;\n /** Fire a best-effort view increment. Default true. */\n trackView?: boolean;\n /** Emit BlogPosting + breadcrumb JSON-LD. Default true. */\n renderJsonLd?: boolean;\n /** SEO context (site origin/name) used for JSON-LD canonical URLs. */\n seo?: SeoOptions;\n /** Locale for date formatting. Default 'en-US'. */\n locale?: string;\n /** Rendered when the post is not found (consumer typically calls notFound()). */\n fallback?: ReactNode;\n}\n\nfunction mergeConfig(\n config?: Partial<BlogConfig>,\n apiBaseUrl?: string,\n tenantId?: string,\n): Partial<BlogConfig> {\n return {\n ...config,\n ...(apiBaseUrl ? { apiBaseUrl } : {}),\n ...(tenantId ? { tenantId } : {}),\n };\n}\n\n/** Async server component: fetches a post by slug and renders it. */\nexport async function BlogPost({\n slug,\n apiBaseUrl,\n tenantId,\n config,\n trackView = true,\n renderJsonLd = true,\n seo,\n locale = 'en-US',\n fallback = null,\n}: BlogPostProps) {\n const cfg = mergeConfig(config, apiBaseUrl, tenantId);\n const post = await getPostBySlug(slug, cfg);\n if (!post) return <>{fallback}</>;\n\n if (trackView) await incrementView(post.post_id, cfg);\n\n return (\n <article className=\"ggblog-post\">\n {renderJsonLd ? (\n <>\n <JsonLd id=\"ggblog-post-jsonld\" data={generateBlogPostJsonLd(post, seo)} />\n <JsonLd id=\"ggblog-breadcrumb-jsonld\" data={generateBlogBreadcrumbJsonLd(post, seo)} />\n </>\n ) : null}\n\n <header className=\"ggblog-post-header\">\n <h1 className=\"ggblog-post-title\">{post.title}</h1>\n <div className=\"ggblog-post-meta\">\n {post.author_name ? <span className=\"ggblog-post-author\">{post.author_name}</span> : null}\n {post.published_at ? (\n <time dateTime={post.published_at}>{formatDate(post.published_at, locale)}</time>\n ) : null}\n {post.reading_time ? (\n <span className=\"ggblog-post-readtime\">{post.reading_time} min read</span>\n ) : null}\n </div>\n {post.excerpt ? <p className=\"ggblog-post-excerpt\">{post.excerpt}</p> : null}\n {post.featured_image ? (\n <figure className=\"ggblog-post-cover\">\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img src={post.featured_image} alt={post.featured_image_alt ?? post.title} />\n </figure>\n ) : null}\n </header>\n\n <div className=\"ggblog-post-body\">{renderBlocks(post.content_blocks)}</div>\n </article>\n );\n}\n"],"names":[],"mappings":";;;;;;AA6BA,SAAS,YACP,QACA,YACA,UACqB;AACrB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAI,aAAa,EAAE,WAAA,IAAe,CAAA;AAAA,IAClC,GAAI,WAAW,EAAE,aAAa,CAAA;AAAA,EAAC;AAEnC;AAGA,eAAsB,SAAS;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,eAAe;AAAA,EACf;AAAA,EACA,SAAS;AAAA,EACT,WAAW;AACb,GAAkB;AAChB,QAAM,MAAM,YAAY,QAAQ,YAAY,QAAQ;AACpD,QAAM,OAAO,MAAM,cAAc,MAAM,GAAG;AAC1C,MAAI,CAAC,KAAM,QAAO,oBAAA,UAAA,EAAG,UAAA,UAAS;AAE9B,MAAI,UAAW,OAAM,cAAc,KAAK,SAAS,GAAG;AAEpD,SACE,qBAAC,WAAA,EAAQ,WAAU,eAChB,UAAA;AAAA,IAAA,eACC,qBAAA,UAAA,EACE,UAAA;AAAA,MAAA,oBAAC,UAAO,IAAG,sBAAqB,MAAM,uBAAuB,MAAM,GAAG,GAAG;AAAA,MACzE,oBAAC,UAAO,IAAG,4BAA2B,MAAM,6BAA6B,MAAM,GAAG,EAAA,CAAG;AAAA,IAAA,EAAA,CACvF,IACE;AAAA,IAEJ,qBAAC,UAAA,EAAO,WAAU,sBAChB,UAAA;AAAA,MAAA,oBAAC,MAAA,EAAG,WAAU,qBAAqB,UAAA,KAAK,OAAM;AAAA,MAC9C,qBAAC,OAAA,EAAI,WAAU,oBACZ,UAAA;AAAA,QAAA,KAAK,cAAc,oBAAC,QAAA,EAAK,WAAU,sBAAsB,UAAA,KAAK,aAAY,IAAU;AAAA,QACpF,KAAK,eACJ,oBAAC,QAAA,EAAK,UAAU,KAAK,cAAe,UAAA,WAAW,KAAK,cAAc,MAAM,EAAA,CAAE,IACxE;AAAA,QACH,KAAK,eACJ,qBAAC,QAAA,EAAK,WAAU,wBAAwB,UAAA;AAAA,UAAA,KAAK;AAAA,UAAa;AAAA,QAAA,EAAA,CAAS,IACjE;AAAA,MAAA,GACN;AAAA,MACC,KAAK,UAAU,oBAAC,KAAA,EAAE,WAAU,uBAAuB,UAAA,KAAK,SAAQ,IAAO;AAAA,MACvE,KAAK,iBACJ,oBAAC,UAAA,EAAO,WAAU,qBAEhB,UAAA,oBAAC,OAAA,EAAI,KAAK,KAAK,gBAAgB,KAAK,KAAK,sBAAsB,KAAK,OAAO,GAC7E,IACE;AAAA,IAAA,GACN;AAAA,wBAEC,OAAA,EAAI,WAAU,oBAAoB,UAAA,aAAa,KAAK,cAAc,EAAA,CAAE;AAAA,EAAA,GACvE;AAEJ;"}
1
+ {"version":3,"file":"BlogPost.js","sources":["../../src/components/BlogPost.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { BlogConfig } from '../config';\nimport { getPostBySlug, incrementView } from '../client/blogClient';\nimport { renderBlocks } from '../render/BlockRenderer';\nimport { generateBlogPostJsonLd, generateBlogBreadcrumbJsonLd, type SeoOptions } from '../seo';\nimport { JsonLd } from './JsonLd';\nimport { BlogPostHeader } from './BlogPostHeader';\nimport type { BlogPost as BlogPostData } from '../types/blog';\nimport { getLandingPageSchema, type LandingPageSchema } from '../render/landingPageHtml';\nimport { LandingPageRenderer } from '../render/LandingPageRenderer';\nimport { RichText } from '../render/RichText';\n\ntype BlogPostWithLanding = BlogPostData & {\n landingPage?: {\n publishedVersion?: {\n schema_json?: LandingPageSchema;\n };\n };\n};\n\nexport interface BlogPostProps {\n /** Slug of the post to render. */\n slug: string;\n /** Pre-fetched post (skips the slug API call when provided). */\n post?: BlogPostData;\n /** API base URL (overrides configured/env default). */\n apiBaseUrl?: string;\n /** Tenant id sent as `X-Tenant`. */\n tenantId?: string;\n /** Full config override (takes precedence over apiBaseUrl/tenantId props). */\n config?: Partial<BlogConfig>;\n /** Fire a best-effort view increment. Default true. */\n trackView?: boolean;\n /** Emit BlogPosting + breadcrumb JSON-LD. Default true. */\n renderJsonLd?: boolean;\n /** SEO context (site origin/name) used for JSON-LD canonical URLs. */\n seo?: SeoOptions;\n /** Locale for date formatting. Default 'en-US'. */\n locale?: string;\n /** Show the post title in the header. Default true. */\n showTitle?: boolean;\n /** Show the featured image when available. Default true. */\n showFeatured?: boolean;\n /** Show author, date, and reading time. Default true. */\n showMeta?: boolean;\n /** Show the excerpt. Default true. */\n showExcerpt?: boolean;\n /** Rendered when the post is not found (consumer typically calls notFound()). */\n fallback?: ReactNode;\n}\n\nfunction mergeConfig(\n config?: Partial<BlogConfig>,\n apiBaseUrl?: string,\n tenantId?: string,\n): Partial<BlogConfig> {\n return {\n ...config,\n ...(apiBaseUrl ? { apiBaseUrl } : {}),\n ...(tenantId ? { tenantId } : {}),\n };\n}\n\n/** Async server component: fetches a post by slug and renders it. */\nexport async function BlogPost({\n slug,\n post: initialPost,\n apiBaseUrl,\n tenantId,\n config,\n trackView = true,\n renderJsonLd = true,\n seo,\n locale = 'en-US',\n showTitle = true,\n showFeatured = true,\n showMeta = true,\n showExcerpt = true,\n fallback = null,\n}: BlogPostProps) {\n const cfg = mergeConfig(config, apiBaseUrl, tenantId);\n const post = initialPost ?? (await getPostBySlug(slug, cfg));\n if (!post) return <>{fallback}</>;\n\n if (trackView) await incrementView(post.post_id, cfg);\n\n const landingSchema =\n post.content_blocks.length === 0\n ? getLandingPageSchema(post as BlogPostWithLanding)\n : null;\n\n const landingPageHtml =\n post.content_blocks.length === 0 && !landingSchema && post.landing_page_html\n ? { html: post.landing_page_html, css: post.landing_page_css ?? '' }\n : null;\n\n return (\n <article className=\"ggblog-post\">\n {renderJsonLd ? (\n <>\n <JsonLd id=\"ggblog-post-jsonld\" data={generateBlogPostJsonLd(post, seo)} />\n <JsonLd id=\"ggblog-breadcrumb-jsonld\" data={generateBlogBreadcrumbJsonLd(post, seo)} />\n </>\n ) : null}\n\n <BlogPostHeader\n post={post}\n locale={locale}\n showTitle={showTitle}\n showFeatured={showFeatured}\n showMeta={showMeta}\n showExcerpt={showExcerpt}\n />\n\n <div className=\"ggblog-post-body\">\n {post.content_blocks.length > 0 ? (\n renderBlocks(post.content_blocks)\n ) : landingSchema ? (\n <LandingPageRenderer schema={landingSchema} />\n ) : landingPageHtml?.html ? (\n <>\n {landingPageHtml.css ? (\n <style dangerouslySetInnerHTML={{ __html: landingPageHtml.css }} />\n ) : null}\n <RichText html={landingPageHtml.html} className=\"ggblog-landing-page\" />\n </>\n ) : null}\n </div>\n </article>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AAmDA,SAAS,YACP,QACA,YACA,UACqB;AACrB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAI,aAAa,EAAE,WAAA,IAAe,CAAA;AAAA,IAClC,GAAI,WAAW,EAAE,aAAa,CAAA;AAAA,EAAC;AAEnC;AAGA,eAAsB,SAAS;AAAA,EAC7B;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,eAAe;AAAA,EACf;AAAA,EACA,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AACb,GAAkB;AAChB,QAAM,MAAM,YAAY,QAAQ,YAAY,QAAQ;AACpD,QAAM,OAAO,eAAgB,MAAM,cAAc,MAAM,GAAG;AAC1D,MAAI,CAAC,KAAM,QAAO,oBAAA,UAAA,EAAG,UAAA,UAAS;AAE9B,MAAI,UAAW,OAAM,cAAc,KAAK,SAAS,GAAG;AAEpD,QAAM,gBACJ,KAAK,eAAe,WAAW,IAC3B,qBAAqB,IAA2B,IAChD;AAEN,QAAM,kBACJ,KAAK,eAAe,WAAW,KAAK,CAAC,iBAAiB,KAAK,oBACvD,EAAE,MAAM,KAAK,mBAAmB,KAAK,KAAK,oBAAoB,OAC9D;AAEN,SACE,qBAAC,WAAA,EAAQ,WAAU,eAChB,UAAA;AAAA,IAAA,eACC,qBAAA,UAAA,EACE,UAAA;AAAA,MAAA,oBAAC,UAAO,IAAG,sBAAqB,MAAM,uBAAuB,MAAM,GAAG,GAAG;AAAA,MACzE,oBAAC,UAAO,IAAG,4BAA2B,MAAM,6BAA6B,MAAM,GAAG,EAAA,CAAG;AAAA,IAAA,EAAA,CACvF,IACE;AAAA,IAEJ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,IAAA;AAAA,IAGF,oBAAC,SAAI,WAAU,oBACZ,eAAK,eAAe,SAAS,IAC5B,aAAa,KAAK,cAAc,IAC9B,oCACD,qBAAA,EAAoB,QAAQ,eAAe,IAC1C,iBAAiB,OACnB,qBAAA,UAAA,EACG,UAAA;AAAA,MAAA,gBAAgB,0BACd,SAAA,EAAM,yBAAyB,EAAE,QAAQ,gBAAgB,IAAA,EAAI,CAAG,IAC/D;AAAA,0BACH,UAAA,EAAS,MAAM,gBAAgB,MAAM,WAAU,sBAAA,CAAsB;AAAA,IAAA,EAAA,CACxE,IACE,KAAA,CACN;AAAA,EAAA,GACF;AAEJ;"}
@@ -0,0 +1,15 @@
1
+ import { BlogPost } from '../types/blog';
2
+ export interface BlogPostHeaderProps {
3
+ post: Pick<BlogPost, 'title' | 'featured_image' | 'featured_image_alt' | 'excerpt' | 'author_name' | 'published_at' | 'reading_time'>;
4
+ /** Show the post title. Default true. */
5
+ showTitle?: boolean;
6
+ /** Show the featured image when `post.featured_image` is set. Default true. */
7
+ showFeatured?: boolean;
8
+ /** Show author, date, and reading time. Default true. */
9
+ showMeta?: boolean;
10
+ /** Show the excerpt paragraph. Default true. */
11
+ showExcerpt?: boolean;
12
+ locale?: string;
13
+ }
14
+ /** Optional post header: title, meta, excerpt, and featured image. */
15
+ export declare function BlogPostHeader({ post, showTitle, showFeatured, showMeta, showExcerpt, locale, }: BlogPostHeaderProps): import("react").JSX.Element | null;
@@ -0,0 +1,41 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { formatDate } from "../lib/format.js";
3
+ function BlogPostHeader({
4
+ post,
5
+ showTitle = true,
6
+ showFeatured = true,
7
+ showMeta = true,
8
+ showExcerpt = true,
9
+ locale = "en-US"
10
+ }) {
11
+ const hasTitle = showTitle && Boolean(post.title);
12
+ const hasFeatured = showFeatured && Boolean(post.featured_image);
13
+ const hasMeta = showMeta && Boolean(post.author_name || post.published_at || post.reading_time);
14
+ const hasExcerpt = showExcerpt && Boolean(post.excerpt);
15
+ if (!hasTitle && !hasFeatured && !hasMeta && !hasExcerpt) {
16
+ return null;
17
+ }
18
+ return /* @__PURE__ */ jsxs("header", { className: "ggblog-post-header", children: [
19
+ hasTitle ? /* @__PURE__ */ jsx("h1", { className: "ggblog-post-title", children: post.title }) : null,
20
+ hasMeta ? /* @__PURE__ */ jsxs("div", { className: "ggblog-post-meta", children: [
21
+ post.author_name ? /* @__PURE__ */ jsx("span", { className: "ggblog-post-author", children: post.author_name }) : null,
22
+ post.published_at ? /* @__PURE__ */ jsx("time", { dateTime: post.published_at, children: formatDate(post.published_at, locale) }) : null,
23
+ post.reading_time ? /* @__PURE__ */ jsxs("span", { className: "ggblog-post-readtime", children: [
24
+ post.reading_time,
25
+ " min read"
26
+ ] }) : null
27
+ ] }) : null,
28
+ hasExcerpt ? /* @__PURE__ */ jsx("p", { className: "ggblog-post-excerpt", children: post.excerpt }) : null,
29
+ hasFeatured ? /* @__PURE__ */ jsx("figure", { className: "ggblog-post-cover", children: /* @__PURE__ */ jsx(
30
+ "img",
31
+ {
32
+ src: post.featured_image,
33
+ alt: post.featured_image_alt ?? post.title
34
+ }
35
+ ) }) : null
36
+ ] });
37
+ }
38
+ export {
39
+ BlogPostHeader
40
+ };
41
+ //# sourceMappingURL=BlogPostHeader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BlogPostHeader.js","sources":["../../src/components/BlogPostHeader.tsx"],"sourcesContent":["import type { BlogPost } from '../types/blog';\nimport { formatDate } from '../lib/format';\n\nexport interface BlogPostHeaderProps {\n post: Pick<\n BlogPost,\n | 'title'\n | 'featured_image'\n | 'featured_image_alt'\n | 'excerpt'\n | 'author_name'\n | 'published_at'\n | 'reading_time'\n >;\n /** Show the post title. Default true. */\n showTitle?: boolean;\n /** Show the featured image when `post.featured_image` is set. Default true. */\n showFeatured?: boolean;\n /** Show author, date, and reading time. Default true. */\n showMeta?: boolean;\n /** Show the excerpt paragraph. Default true. */\n showExcerpt?: boolean;\n locale?: string;\n}\n\n/** Optional post header: title, meta, excerpt, and featured image. */\nexport function BlogPostHeader({\n post,\n showTitle = true,\n showFeatured = true,\n showMeta = true,\n showExcerpt = true,\n locale = 'en-US',\n}: BlogPostHeaderProps) {\n const hasTitle = showTitle && Boolean(post.title);\n const hasFeatured = showFeatured && Boolean(post.featured_image);\n const hasMeta =\n showMeta &&\n Boolean(post.author_name || post.published_at || post.reading_time);\n const hasExcerpt = showExcerpt && Boolean(post.excerpt);\n\n if (!hasTitle && !hasFeatured && !hasMeta && !hasExcerpt) {\n return null;\n }\n\n return (\n <header className=\"ggblog-post-header\">\n {hasTitle ? <h1 className=\"ggblog-post-title\">{post.title}</h1> : null}\n {hasMeta ? (\n <div className=\"ggblog-post-meta\">\n {post.author_name ? (\n <span className=\"ggblog-post-author\">{post.author_name}</span>\n ) : null}\n {post.published_at ? (\n <time dateTime={post.published_at}>{formatDate(post.published_at, locale)}</time>\n ) : null}\n {post.reading_time ? (\n <span className=\"ggblog-post-readtime\">{post.reading_time} min read</span>\n ) : null}\n </div>\n ) : null}\n {hasExcerpt ? <p className=\"ggblog-post-excerpt\">{post.excerpt}</p> : null}\n {hasFeatured ? (\n <figure className=\"ggblog-post-cover\">\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img\n src={post.featured_image}\n alt={post.featured_image_alt ?? post.title}\n />\n </figure>\n ) : null}\n </header>\n );\n}\n"],"names":[],"mappings":";;AA0BO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,WAAW;AAAA,EACX,cAAc;AAAA,EACd,SAAS;AACX,GAAwB;AACtB,QAAM,WAAW,aAAa,QAAQ,KAAK,KAAK;AAChD,QAAM,cAAc,gBAAgB,QAAQ,KAAK,cAAc;AAC/D,QAAM,UACJ,YACA,QAAQ,KAAK,eAAe,KAAK,gBAAgB,KAAK,YAAY;AACpE,QAAM,aAAa,eAAe,QAAQ,KAAK,OAAO;AAEtD,MAAI,CAAC,YAAY,CAAC,eAAe,CAAC,WAAW,CAAC,YAAY;AACxD,WAAO;AAAA,EACT;AAEA,SACE,qBAAC,UAAA,EAAO,WAAU,sBACf,UAAA;AAAA,IAAA,+BAAY,MAAA,EAAG,WAAU,qBAAqB,UAAA,KAAK,OAAM,IAAQ;AAAA,IACjE,UACC,qBAAC,OAAA,EAAI,WAAU,oBACZ,UAAA;AAAA,MAAA,KAAK,cACJ,oBAAC,QAAA,EAAK,WAAU,sBAAsB,UAAA,KAAK,aAAY,IACrD;AAAA,MACH,KAAK,eACJ,oBAAC,QAAA,EAAK,UAAU,KAAK,cAAe,UAAA,WAAW,KAAK,cAAc,MAAM,EAAA,CAAE,IACxE;AAAA,MACH,KAAK,eACJ,qBAAC,QAAA,EAAK,WAAU,wBAAwB,UAAA;AAAA,QAAA,KAAK;AAAA,QAAa;AAAA,MAAA,EAAA,CAAS,IACjE;AAAA,IAAA,EAAA,CACN,IACE;AAAA,IACH,aAAa,oBAAC,KAAA,EAAE,WAAU,uBAAuB,UAAA,KAAK,SAAQ,IAAO;AAAA,IACrE,cACC,oBAAC,UAAA,EAAO,WAAU,qBAEhB,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK,KAAK;AAAA,QACV,KAAK,KAAK,sBAAsB,KAAK;AAAA,MAAA;AAAA,IAAA,GAEzC,IACE;AAAA,EAAA,GACN;AAEJ;"}
@@ -0,0 +1,14 @@
1
+ import { default as React } from 'react';
2
+ /**
3
+ * Blog Layout Components
4
+ * Flexible layout components for arranging blog content in columns
5
+ */
6
+ export declare const BlogTwoColumnComponent: React.FC<{
7
+ props: Record<string, any>;
8
+ }>;
9
+ export declare const BlogThreeColumnComponent: React.FC<{
10
+ props: Record<string, any>;
11
+ }>;
12
+ export declare const BlogContainerComponent: React.FC<{
13
+ props: Record<string, any>;
14
+ }>;
@@ -0,0 +1,198 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ const BlogTwoColumnComponent = ({ props }) => {
4
+ const ratios = {
5
+ "50-50": { left: "50%", right: "50%" },
6
+ "60-40": { left: "60%", right: "40%" },
7
+ "40-60": { left: "40%", right: "60%" },
8
+ "70-30": { left: "70%", right: "30%" },
9
+ "30-70": { left: "30%", right: "70%" },
10
+ "66-33": { left: "66.66%", right: "33.33%" },
11
+ "33-66": { left: "33.33%", right: "66.66%" }
12
+ };
13
+ const ratio = ratios[props.columnRatio] || ratios["50-50"];
14
+ const containerStyle = {
15
+ backgroundColor: props.backgroundColor || "transparent",
16
+ marginTop: props.marginTop || "2rem",
17
+ marginBottom: props.marginBottom || "2rem"
18
+ };
19
+ const innerContainerStyle = {
20
+ maxWidth: props.containerMaxWidth || "1200px",
21
+ margin: "0 auto",
22
+ padding: props.containerPadding || "2rem"
23
+ };
24
+ const rowStyle = {
25
+ display: "flex",
26
+ gap: props.gap || "2rem",
27
+ alignItems: props.verticalAlign || "center"
28
+ };
29
+ const leftColStyle = {
30
+ flex: `0 0 ${ratio.left}`,
31
+ backgroundColor: props.leftBgColor || "transparent",
32
+ padding: props.leftPadding || "0"
33
+ };
34
+ const rightColStyle = {
35
+ flex: `0 0 ${ratio.right}`,
36
+ backgroundColor: props.rightBgColor || "transparent",
37
+ padding: props.rightPadding || "0"
38
+ };
39
+ const responsiveCSS = `
40
+ @media (max-width: 768px) {
41
+ .blog-two-column-row${props.stackOnMobile ? "-stack-mobile" : ""} {
42
+ ${props.stackOnMobile ? "flex-direction: column;" : ""}
43
+ ${props.stackOnMobile && props.reverseOnMobile ? "flex-direction: column-reverse;" : ""}
44
+ }
45
+ .blog-two-column-row${props.stackOnMobile ? "-stack-mobile" : ""} > div {
46
+ ${props.stackOnMobile ? "flex: 0 0 100% !important;" : ""}
47
+ }
48
+ }
49
+ @media (min-width: 769px) and (max-width: 1024px) {
50
+ .blog-two-column-row${props.stackOnTablet ? "-stack-tablet" : ""} {
51
+ ${props.stackOnTablet ? "flex-direction: column;" : ""}
52
+ }
53
+ .blog-two-column-row${props.stackOnTablet ? "-stack-tablet" : ""} > div {
54
+ ${props.stackOnTablet ? "flex: 0 0 100% !important;" : ""}
55
+ }
56
+ }
57
+ `;
58
+ return /* @__PURE__ */ jsxs("div", { className: `blog-two-column ${props.className || ""}`, style: containerStyle, children: [
59
+ props.customCSS && /* @__PURE__ */ jsx("style", { children: props.customCSS }),
60
+ /* @__PURE__ */ jsx("style", { children: responsiveCSS }),
61
+ /* @__PURE__ */ jsx("div", { style: innerContainerStyle, children: /* @__PURE__ */ jsxs(
62
+ "div",
63
+ {
64
+ className: `blog-two-column-row${props.stackOnMobile ? "-stack-mobile" : ""}${props.stackOnTablet ? "-stack-tablet" : ""}`,
65
+ style: rowStyle,
66
+ children: [
67
+ /* @__PURE__ */ jsx("div", { className: props.leftClassName || "", style: leftColStyle, children: /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: props.leftContent || "Left column content" } }) }),
68
+ /* @__PURE__ */ jsx("div", { className: props.rightClassName || "", style: rightColStyle, children: /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: props.rightContent || "Right column content" } }) })
69
+ ]
70
+ }
71
+ ) })
72
+ ] });
73
+ };
74
+ const BlogThreeColumnComponent = ({ props }) => {
75
+ const ratios = {
76
+ "33-33-33": { col1: "33.33%", col2: "33.33%", col3: "33.33%" },
77
+ "50-25-25": { col1: "50%", col2: "25%", col3: "25%" },
78
+ "25-50-25": { col1: "25%", col2: "50%", col3: "25%" },
79
+ "25-25-50": { col1: "25%", col2: "25%", col3: "50%" },
80
+ "40-30-30": { col1: "40%", col2: "30%", col3: "30%" },
81
+ "30-40-30": { col1: "30%", col2: "40%", col3: "30%" },
82
+ "30-30-40": { col1: "30%", col2: "30%", col3: "40%" }
83
+ };
84
+ const ratio = ratios[props.columnRatio] || ratios["33-33-33"];
85
+ const containerStyle = {
86
+ backgroundColor: props.backgroundColor || "transparent",
87
+ marginTop: props.marginTop || "2rem",
88
+ marginBottom: props.marginBottom || "2rem"
89
+ };
90
+ const innerContainerStyle = {
91
+ maxWidth: props.containerMaxWidth || "1200px",
92
+ margin: "0 auto",
93
+ padding: props.containerPadding || "2rem"
94
+ };
95
+ const rowStyle = {
96
+ display: "flex",
97
+ gap: props.gap || "1.5rem",
98
+ alignItems: props.verticalAlign || "flex-start"
99
+ };
100
+ const responsiveCSS = `
101
+ @media (max-width: 768px) {
102
+ .blog-three-column-row${props.stackOnMobile ? "-stack-mobile" : ""} {
103
+ ${props.stackOnMobile ? "flex-direction: column;" : ""}
104
+ }
105
+ .blog-three-column-row${props.stackOnMobile ? "-stack-mobile" : ""} > div {
106
+ ${props.stackOnMobile ? "flex: 0 0 100% !important;" : ""}
107
+ }
108
+ }
109
+ @media (min-width: 769px) and (max-width: 1024px) {
110
+ .blog-three-column-row${props.stackOnTablet ? "-stack-tablet" : ""} {
111
+ ${props.stackOnTablet ? "flex-direction: column;" : ""}
112
+ }
113
+ .blog-three-column-row${props.stackOnTablet ? "-stack-tablet" : ""} > div {
114
+ ${props.stackOnTablet ? "flex: 0 0 100% !important;" : ""}
115
+ }
116
+ }
117
+ `;
118
+ return /* @__PURE__ */ jsxs("div", { className: `blog-three-column ${props.className || ""}`, style: containerStyle, children: [
119
+ props.customCSS && /* @__PURE__ */ jsx("style", { children: props.customCSS }),
120
+ /* @__PURE__ */ jsx("style", { children: responsiveCSS }),
121
+ /* @__PURE__ */ jsx("div", { style: innerContainerStyle, children: /* @__PURE__ */ jsxs(
122
+ "div",
123
+ {
124
+ className: `blog-three-column-row${props.stackOnMobile ? "-stack-mobile" : ""}${props.stackOnTablet ? "-stack-tablet" : ""}`,
125
+ style: rowStyle,
126
+ children: [
127
+ /* @__PURE__ */ jsx(
128
+ "div",
129
+ {
130
+ className: props.column1ClassName || "",
131
+ style: {
132
+ flex: `0 0 ${ratio.col1}`,
133
+ backgroundColor: props.column1BgColor || "transparent",
134
+ padding: props.column1Padding || "0"
135
+ },
136
+ children: /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: props.column1Content || "Column 1" } })
137
+ }
138
+ ),
139
+ /* @__PURE__ */ jsx(
140
+ "div",
141
+ {
142
+ className: props.column2ClassName || "",
143
+ style: {
144
+ flex: `0 0 ${ratio.col2}`,
145
+ backgroundColor: props.column2BgColor || "transparent",
146
+ padding: props.column2Padding || "0"
147
+ },
148
+ children: /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: props.column2Content || "Column 2" } })
149
+ }
150
+ ),
151
+ /* @__PURE__ */ jsx(
152
+ "div",
153
+ {
154
+ className: props.column3ClassName || "",
155
+ style: {
156
+ flex: `0 0 ${ratio.col3}`,
157
+ backgroundColor: props.column3BgColor || "transparent",
158
+ padding: props.column3Padding || "0"
159
+ },
160
+ children: /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: props.column3Content || "Column 3" } })
161
+ }
162
+ )
163
+ ]
164
+ }
165
+ ) })
166
+ ] });
167
+ };
168
+ const BlogContainerComponent = ({ props }) => {
169
+ const wrapperStyle = {
170
+ display: "flex",
171
+ justifyContent: props.contentAlign || "center",
172
+ marginTop: props.marginTop || "2rem",
173
+ marginBottom: props.marginBottom || "2rem"
174
+ };
175
+ const containerStyle = {
176
+ width: props.width || "100%",
177
+ maxWidth: props.maxWidth || "800px",
178
+ backgroundColor: props.backgroundColor || "transparent",
179
+ backgroundImage: props.backgroundImage ? `url(${props.backgroundImage})` : "none",
180
+ backgroundSize: props.backgroundSize || "cover",
181
+ backgroundPosition: props.backgroundPosition || "center",
182
+ backgroundRepeat: "no-repeat",
183
+ padding: props.paddingTop || props.paddingBottom || props.paddingLeft || props.paddingRight ? `${props.paddingTop || props.padding || "2rem"} ${props.paddingRight || props.padding || "2rem"} ${props.paddingBottom || props.padding || "2rem"} ${props.paddingLeft || props.padding || "2rem"}` : props.padding || "2rem",
184
+ border: props.border ? `${props.borderWidth || "1px"} ${props.borderStyle || "solid"} ${props.borderColor || "#e5e7eb"}` : "none",
185
+ borderRadius: props.borderRadius || "8px",
186
+ textAlign: props.textAlign || "left"
187
+ };
188
+ return /* @__PURE__ */ jsx("div", { style: wrapperStyle, children: /* @__PURE__ */ jsxs("div", { className: `blog-container ${props.shadow || ""} ${props.className || ""}`, style: containerStyle, children: [
189
+ props.customCSS && /* @__PURE__ */ jsx("style", { children: props.customCSS }),
190
+ /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: props.content || "Container content" } })
191
+ ] }) });
192
+ };
193
+ export {
194
+ BlogContainerComponent,
195
+ BlogThreeColumnComponent,
196
+ BlogTwoColumnComponent
197
+ };
198
+ //# sourceMappingURL=BlogLayoutComponents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BlogLayoutComponents.js","sources":["../../../src/components/landing/BlogLayoutComponents.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\n/**\n * Blog Layout Components\n * Flexible layout components for arranging blog content in columns\n */\n\n// Blog Two Column Layout Component\nexport const BlogTwoColumnComponent: React.FC<{ props: Record<string, any> }> = ({ props }) => {\n const ratios: Record<string, { left: string; right: string }> = {\n '50-50': { left: '50%', right: '50%' },\n '60-40': { left: '60%', right: '40%' },\n '40-60': { left: '40%', right: '60%' },\n '70-30': { left: '70%', right: '30%' },\n '30-70': { left: '30%', right: '70%' },\n '66-33': { left: '66.66%', right: '33.33%' },\n '33-66': { left: '33.33%', right: '66.66%' },\n };\n\n const ratio = ratios[props.columnRatio] || ratios['50-50'];\n\n const containerStyle: any = {\n backgroundColor: props.backgroundColor || 'transparent',\n marginTop: props.marginTop || '2rem',\n marginBottom: props.marginBottom || '2rem',\n };\n\n const innerContainerStyle: any = {\n maxWidth: props.containerMaxWidth || '1200px',\n margin: '0 auto',\n padding: props.containerPadding || '2rem',\n };\n\n const rowStyle: any = {\n display: 'flex',\n gap: props.gap || '2rem',\n alignItems: props.verticalAlign || 'center',\n };\n\n const leftColStyle: any = {\n flex: `0 0 ${ratio.left}`,\n backgroundColor: props.leftBgColor || 'transparent',\n padding: props.leftPadding || '0',\n };\n\n const rightColStyle: any = {\n flex: `0 0 ${ratio.right}`,\n backgroundColor: props.rightBgColor || 'transparent',\n padding: props.rightPadding || '0',\n };\n\n const responsiveCSS = `\n @media (max-width: 768px) {\n .blog-two-column-row${props.stackOnMobile ? '-stack-mobile' : ''} {\n ${props.stackOnMobile ? 'flex-direction: column;' : ''}\n ${props.stackOnMobile && props.reverseOnMobile ? 'flex-direction: column-reverse;' : ''}\n }\n .blog-two-column-row${props.stackOnMobile ? '-stack-mobile' : ''} > div {\n ${props.stackOnMobile ? 'flex: 0 0 100% !important;' : ''}\n }\n }\n @media (min-width: 769px) and (max-width: 1024px) {\n .blog-two-column-row${props.stackOnTablet ? '-stack-tablet' : ''} {\n ${props.stackOnTablet ? 'flex-direction: column;' : ''}\n }\n .blog-two-column-row${props.stackOnTablet ? '-stack-tablet' : ''} > div {\n ${props.stackOnTablet ? 'flex: 0 0 100% !important;' : ''}\n }\n }\n `;\n\n return (\n <div className={`blog-two-column ${props.className || ''}`} style={containerStyle}>\n {props.customCSS && <style>{props.customCSS}</style>}\n <style>{responsiveCSS}</style>\n <div style={innerContainerStyle}>\n <div \n className={`blog-two-column-row${props.stackOnMobile ? '-stack-mobile' : ''}${props.stackOnTablet ? '-stack-tablet' : ''}`}\n style={rowStyle}\n >\n <div className={props.leftClassName || ''} style={leftColStyle}>\n <div dangerouslySetInnerHTML={{ __html: props.leftContent || 'Left column content' }} />\n </div>\n <div className={props.rightClassName || ''} style={rightColStyle}>\n <div dangerouslySetInnerHTML={{ __html: props.rightContent || 'Right column content' }} />\n </div>\n </div>\n </div>\n </div>\n );\n};\n\n// Blog Three Column Layout Component\nexport const BlogThreeColumnComponent: React.FC<{ props: Record<string, any> }> = ({ props }) => {\n const ratios: Record<string, { col1: string; col2: string; col3: string }> = {\n '33-33-33': { col1: '33.33%', col2: '33.33%', col3: '33.33%' },\n '50-25-25': { col1: '50%', col2: '25%', col3: '25%' },\n '25-50-25': { col1: '25%', col2: '50%', col3: '25%' },\n '25-25-50': { col1: '25%', col2: '25%', col3: '50%' },\n '40-30-30': { col1: '40%', col2: '30%', col3: '30%' },\n '30-40-30': { col1: '30%', col2: '40%', col3: '30%' },\n '30-30-40': { col1: '30%', col2: '30%', col3: '40%' },\n };\n\n const ratio = ratios[props.columnRatio] || ratios['33-33-33'];\n\n const containerStyle: any = {\n backgroundColor: props.backgroundColor || 'transparent',\n marginTop: props.marginTop || '2rem',\n marginBottom: props.marginBottom || '2rem',\n };\n\n const innerContainerStyle: any = {\n maxWidth: props.containerMaxWidth || '1200px',\n margin: '0 auto',\n padding: props.containerPadding || '2rem',\n };\n\n const rowStyle: any = {\n display: 'flex',\n gap: props.gap || '1.5rem',\n alignItems: props.verticalAlign || 'flex-start',\n };\n\n const responsiveCSS = `\n @media (max-width: 768px) {\n .blog-three-column-row${props.stackOnMobile ? '-stack-mobile' : ''} {\n ${props.stackOnMobile ? 'flex-direction: column;' : ''}\n }\n .blog-three-column-row${props.stackOnMobile ? '-stack-mobile' : ''} > div {\n ${props.stackOnMobile ? 'flex: 0 0 100% !important;' : ''}\n }\n }\n @media (min-width: 769px) and (max-width: 1024px) {\n .blog-three-column-row${props.stackOnTablet ? '-stack-tablet' : ''} {\n ${props.stackOnTablet ? 'flex-direction: column;' : ''}\n }\n .blog-three-column-row${props.stackOnTablet ? '-stack-tablet' : ''} > div {\n ${props.stackOnTablet ? 'flex: 0 0 100% !important;' : ''}\n }\n }\n `;\n\n return (\n <div className={`blog-three-column ${props.className || ''}`} style={containerStyle}>\n {props.customCSS && <style>{props.customCSS}</style>}\n <style>{responsiveCSS}</style>\n <div style={innerContainerStyle}>\n <div \n className={`blog-three-column-row${props.stackOnMobile ? '-stack-mobile' : ''}${props.stackOnTablet ? '-stack-tablet' : ''}`}\n style={rowStyle}\n >\n <div \n className={props.column1ClassName || ''} \n style={{\n flex: `0 0 ${ratio.col1}`,\n backgroundColor: props.column1BgColor || 'transparent',\n padding: props.column1Padding || '0',\n }}\n >\n <div dangerouslySetInnerHTML={{ __html: props.column1Content || 'Column 1' }} />\n </div>\n <div \n className={props.column2ClassName || ''} \n style={{\n flex: `0 0 ${ratio.col2}`,\n backgroundColor: props.column2BgColor || 'transparent',\n padding: props.column2Padding || '0',\n }}\n >\n <div dangerouslySetInnerHTML={{ __html: props.column2Content || 'Column 2' }} />\n </div>\n <div \n className={props.column3ClassName || ''} \n style={{\n flex: `0 0 ${ratio.col3}`,\n backgroundColor: props.column3BgColor || 'transparent',\n padding: props.column3Padding || '0',\n }}\n >\n <div dangerouslySetInnerHTML={{ __html: props.column3Content || 'Column 3' }} />\n </div>\n </div>\n </div>\n </div>\n );\n};\n\n// Blog Container/Section Component\nexport const BlogContainerComponent: React.FC<{ props: Record<string, any> }> = ({ props }) => {\n const wrapperStyle: any = {\n display: 'flex',\n justifyContent: props.contentAlign || 'center',\n marginTop: props.marginTop || '2rem',\n marginBottom: props.marginBottom || '2rem',\n };\n\n const containerStyle: any = {\n width: props.width || '100%',\n maxWidth: props.maxWidth || '800px',\n backgroundColor: props.backgroundColor || 'transparent',\n backgroundImage: props.backgroundImage ? `url(${props.backgroundImage})` : 'none',\n backgroundSize: props.backgroundSize || 'cover',\n backgroundPosition: props.backgroundPosition || 'center',\n backgroundRepeat: 'no-repeat',\n padding: props.paddingTop || props.paddingBottom || props.paddingLeft || props.paddingRight \n ? `${props.paddingTop || props.padding || '2rem'} ${props.paddingRight || props.padding || '2rem'} ${props.paddingBottom || props.padding || '2rem'} ${props.paddingLeft || props.padding || '2rem'}`\n : (props.padding || '2rem'),\n border: props.border ? `${props.borderWidth || '1px'} ${props.borderStyle || 'solid'} ${props.borderColor || '#e5e7eb'}` : 'none',\n borderRadius: props.borderRadius || '8px',\n textAlign: props.textAlign || 'left',\n };\n\n return (\n <div style={wrapperStyle}>\n <div className={`blog-container ${props.shadow || ''} ${props.className || ''}`} style={containerStyle}>\n {props.customCSS && <style>{props.customCSS}</style>}\n <div dangerouslySetInnerHTML={{ __html: props.content || 'Container content' }} />\n </div>\n </div>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { default as React } from 'react';
2
+ interface ColumnElement {
3
+ id: string;
4
+ type: string;
5
+ [key: string]: any;
6
+ }
7
+ interface Column {
8
+ id: string;
9
+ elements: ColumnElement[];
10
+ width?: string;
11
+ backgroundColor?: string;
12
+ padding?: string;
13
+ alignment?: 'top' | 'center' | 'bottom';
14
+ }
15
+ interface FlexibleLayoutProps {
16
+ props: {
17
+ columnCount?: number;
18
+ columns?: Column[];
19
+ columnRatio?: string;
20
+ containerMaxWidth?: string;
21
+ containerPadding?: string;
22
+ containerMarginTop?: string;
23
+ containerMarginBottom?: string;
24
+ containerBackgroundColor?: string;
25
+ containerBorderRadius?: string;
26
+ columnGap?: string;
27
+ rowGap?: string;
28
+ stackOnMobile?: boolean;
29
+ stackOnTablet?: boolean;
30
+ reverseOnMobile?: boolean;
31
+ mobileBreakpoint?: string;
32
+ tabletBreakpoint?: string;
33
+ customCSS?: string;
34
+ className?: string;
35
+ containerClass?: string;
36
+ columnsWrapperClass?: string;
37
+ };
38
+ }
39
+ export declare const FlexibleLayoutComponent: React.FC<FlexibleLayoutProps>;
40
+ export {};