diff --git a/app/[locale]/[slug]/opengraph-image.tsx b/app/[locale]/[slug]/opengraph-image.tsx
new file mode 100644
index 00000000..bf7b6cfc
--- /dev/null
+++ b/app/[locale]/[slug]/opengraph-image.tsx
@@ -0,0 +1,29 @@
+import { ImageResponse } from 'next/og';
+import { getPageBySlug } from '@/lib/pages';
+import { OGImageTemplate } from '@/components/OGImageTemplate';
+
+export const runtime = 'nodejs';
+
+export default async function Image({ params: { locale, slug } }: { params: { locale: string, slug: string } }) {
+ const pageData = await getPageBySlug(slug, locale);
+
+ if (!pageData) {
+ return new ImageResponse(
+
+ );
+ }
+
+ return new ImageResponse(
+ (
+
+ ),
+ {
+ width: 1200,
+ height: 630,
+ }
+ );
+}
diff --git a/app/[locale]/blog/[slug]/opengraph-image.tsx b/app/[locale]/blog/[slug]/opengraph-image.tsx
index 13ee2e7c..a12d7f26 100644
--- a/app/[locale]/blog/[slug]/opengraph-image.tsx
+++ b/app/[locale]/blog/[slug]/opengraph-image.tsx
@@ -1,5 +1,6 @@
import { ImageResponse } from 'next/og';
import { getPostBySlug } from '@/lib/blog';
+import { OGImageTemplate } from '@/components/OGImageTemplate';
export const runtime = 'nodejs';
@@ -12,98 +13,20 @@ export default async function Image({ params: { locale, slug } }: { params: { lo
);
}
+ const featuredImage = post.frontmatter.featuredImage
+ ? (post.frontmatter.featuredImage.startsWith('http')
+ ? post.frontmatter.featuredImage
+ : `https://klz-cables.com${post.frontmatter.featuredImage}`)
+ : undefined;
+
return new ImageResponse(
(
-
- {/* Background Image Overlay if available */}
- {post.frontmatter.featuredImage && (
-
)
- )}
-
- {/* Gradient Overlay */}
-
-
-
- {post.frontmatter.category && (
-
- {post.frontmatter.category}
-
- )}
-
- {post.frontmatter.title}
-
-
-
- KLZ Cables Blog
-
-
-
- {new Date(post.frontmatter.date).toLocaleDateString(locale, { year: 'numeric', month: 'long', day: 'numeric' })}
-
-
-
-
+
),
{
width: 1200,
diff --git a/app/[locale]/contact/opengraph-image.tsx b/app/[locale]/contact/opengraph-image.tsx
new file mode 100644
index 00000000..d7a7d44f
--- /dev/null
+++ b/app/[locale]/contact/opengraph-image.tsx
@@ -0,0 +1,25 @@
+import { ImageResponse } from 'next/og';
+import { getTranslations } from 'next-intl/server';
+import { OGImageTemplate } from '@/components/OGImageTemplate';
+
+export const runtime = 'nodejs';
+
+export default async function Image({ params: { locale } }: { params: { locale: string } }) {
+ const t = await getTranslations({ locale, namespace: 'Contact' });
+ const title = t('meta.title') || t('title');
+ const description = t('meta.description') || t('subtitle');
+
+ return new ImageResponse(
+ (
+
+ ),
+ {
+ width: 1200,
+ height: 630,
+ }
+ );
+}
diff --git a/app/[locale]/opengraph-image.tsx b/app/[locale]/opengraph-image.tsx
index 5cd03e7f..8a405205 100644
--- a/app/[locale]/opengraph-image.tsx
+++ b/app/[locale]/opengraph-image.tsx
@@ -1,5 +1,6 @@
import { ImageResponse } from 'next/og';
import { getTranslations } from 'next-intl/server';
+import { OGImageTemplate } from '@/components/OGImageTemplate';
export const runtime = 'edge';
@@ -8,81 +9,11 @@ export default async function Image({ params: { locale } }: { params: { locale:
return new ImageResponse(
(
-
- {/* Background Pattern / Scribble placeholder */}
-
-
-
-
- KLZ Cables
-
-
- {t('title')}
-
-
- {t('description')}
-
-
-
- {/* Bottom Accent Line */}
-
-
+
),
{
width: 1200,
diff --git a/app/[locale]/products/[...slug]/opengraph-image.tsx b/app/[locale]/products/[...slug]/opengraph-image.tsx
new file mode 100644
index 00000000..54812d1a
--- /dev/null
+++ b/app/[locale]/products/[...slug]/opengraph-image.tsx
@@ -0,0 +1,62 @@
+import { ImageResponse } from 'next/og';
+import { getProductBySlug } from '@/lib/mdx';
+import { getTranslations } from 'next-intl/server';
+import { OGImageTemplate } from '@/components/OGImageTemplate';
+
+export const runtime = 'nodejs';
+
+export default async function Image({ params: { locale, slug } }: { params: { locale: string, slug: string[] } }) {
+ const productSlug = slug[slug.length - 1];
+ const t = await getTranslations('Products');
+
+ // Check if it's a category page
+ const categories = ['low-voltage-cables', 'medium-voltage-cables', 'high-voltage-cables', 'solar-cables'];
+ if (categories.includes(productSlug)) {
+ const categoryKey = productSlug.replace(/-cables$/, '').replace(/-([a-z])/g, (g) => g[1].toUpperCase());
+ const categoryTitle = t.has(`categories.${categoryKey}.title`) ? t(`categories.${categoryKey}.title`) : productSlug;
+ const categoryDesc = t.has(`categories.${categoryKey}.description`) ? t(`categories.${categoryKey}.description`) : '';
+
+ return new ImageResponse(
+ (
+
+ ),
+ {
+ width: 1200,
+ height: 630,
+ }
+ );
+ }
+
+ const product = await getProductBySlug(productSlug, locale);
+
+ if (!product) {
+ return new ImageResponse(
+
+ );
+ }
+
+ const featuredImage = product.frontmatter.images?.[0]
+ ? (product.frontmatter.images[0].startsWith('http')
+ ? product.frontmatter.images[0]
+ : `https://klz-cables.com${product.frontmatter.images[0]}`)
+ : undefined;
+
+ return new ImageResponse(
+ (
+
+ ),
+ {
+ width: 1200,
+ height: 630,
+ }
+ );
+}
diff --git a/app/[locale]/products/opengraph-image.tsx b/app/[locale]/products/opengraph-image.tsx
new file mode 100644
index 00000000..1db211fc
--- /dev/null
+++ b/app/[locale]/products/opengraph-image.tsx
@@ -0,0 +1,25 @@
+import { ImageResponse } from 'next/og';
+import { getTranslations } from 'next-intl/server';
+import { OGImageTemplate } from '@/components/OGImageTemplate';
+
+export const runtime = 'nodejs';
+
+export default async function Image({ params: { locale } }: { params: { locale: string } }) {
+ const t = await getTranslations({ locale, namespace: 'Products' });
+ const title = t('meta.title') || t('title');
+ const description = t('meta.description') || t('subtitle');
+
+ return new ImageResponse(
+ (
+
+ ),
+ {
+ width: 1200,
+ height: 630,
+ }
+ );
+}
diff --git a/app/[locale]/team/opengraph-image.tsx b/app/[locale]/team/opengraph-image.tsx
new file mode 100644
index 00000000..a9decaad
--- /dev/null
+++ b/app/[locale]/team/opengraph-image.tsx
@@ -0,0 +1,26 @@
+import { ImageResponse } from 'next/og';
+import { getTranslations } from 'next-intl/server';
+import { OGImageTemplate } from '@/components/OGImageTemplate';
+
+export const runtime = 'nodejs';
+
+export default async function Image({ params: { locale } }: { params: { locale: string } }) {
+ const t = await getTranslations({ locale, namespace: 'Team' });
+ const title = t('meta.title') || t('hero.subtitle');
+ const description = t('meta.description') || t('hero.title');
+
+ return new ImageResponse(
+ (
+
+ ),
+ {
+ width: 1200,
+ height: 630,
+ }
+ );
+}
diff --git a/components/OGImageTemplate.tsx b/components/OGImageTemplate.tsx
new file mode 100644
index 00000000..4ea8eb6a
--- /dev/null
+++ b/components/OGImageTemplate.tsx
@@ -0,0 +1,173 @@
+import React from 'react';
+
+interface OGImageTemplateProps {
+ title: string;
+ description?: string;
+ label?: string;
+ image?: string;
+ mode?: 'dark' | 'light' | 'image';
+}
+
+export function OGImageTemplate({
+ title,
+ description,
+ label,
+ image,
+ mode = 'dark',
+}: OGImageTemplateProps) {
+ const primaryBlue = '#001a4d';
+ const accentGreen = '#82ed20';
+ const saturatedBlue = '#011dff';
+
+ const containerStyle: React.CSSProperties = {
+ height: '100%',
+ width: '100%',
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'flex-start',
+ justifyContent: 'center',
+ backgroundColor: mode === 'light' ? '#ffffff' : primaryBlue,
+ padding: '80px',
+ position: 'relative',
+ fontFamily: 'Inter, sans-serif',
+ };
+
+ return (
+
+ {/* Background Image with Overlay */}
+ {image && (
+
+

+
+
+ )}
+
+ {/* Decorative Scribble Circle (Simplified for Satori) */}
+
+
+
+ {/* Label / Category */}
+ {label && (
+
+ {label}
+
+ )}
+
+ {/* Title */}
+
+ {title}
+
+
+ {/* Description */}
+ {description && (
+
+ {description}
+
+ )}
+
+
+ {/* Brand Footer */}
+
+
+ {/* Saturated Blue Accent */}
+
+
+ );
+}