From 013049e631e58b2a53f802a97c0b58d6220b2e41 Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Sat, 17 Jan 2026 16:40:41 +0100 Subject: [PATCH] wip --- app/[locale]/blog/[slug]/opengraph-image.tsx | 113 +++++++++++++++ app/[locale]/blog/[slug]/page.tsx | 55 +++++++ app/[locale]/layout.tsx | 39 ++++- app/[locale]/opengraph-image.tsx | 92 ++++++++++++ .../products/[...slug]/opengraph-image.tsx | 135 ++++++++++++++++++ app/[locale]/products/[...slug]/page.tsx | 69 +++++++++ tsconfig.tsbuildinfo | 2 +- 7 files changed, 502 insertions(+), 3 deletions(-) create mode 100644 app/[locale]/blog/[slug]/opengraph-image.tsx create mode 100644 app/[locale]/opengraph-image.tsx create mode 100644 app/[locale]/products/[...slug]/opengraph-image.tsx diff --git a/app/[locale]/blog/[slug]/opengraph-image.tsx b/app/[locale]/blog/[slug]/opengraph-image.tsx new file mode 100644 index 00000000..74fcb887 --- /dev/null +++ b/app/[locale]/blog/[slug]/opengraph-image.tsx @@ -0,0 +1,113 @@ +import { ImageResponse } from 'next/og'; +import { getPostBySlug } from '@/lib/blog'; + +export const runtime = 'edge'; + +export default async function Image({ params: { locale, slug } }: { params: { locale: string, slug: string } }) { + const post = await getPostBySlug(slug, locale); + + if (!post) { + return new ImageResponse( +
+ ); + } + + 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, + height: 630, + } + ); +} diff --git a/app/[locale]/blog/[slug]/page.tsx b/app/[locale]/blog/[slug]/page.tsx index bb328e68..7e1fb4f8 100644 --- a/app/[locale]/blog/[slug]/page.tsx +++ b/app/[locale]/blog/[slug]/page.tsx @@ -1,6 +1,7 @@ import { notFound } from 'next/navigation'; import { MDXRemote } from 'next-mdx-remote/rsc'; import { getPostBySlug, getAdjacentPosts } from '@/lib/blog'; +import { Metadata } from 'next'; interface BlogPostProps { params: { @@ -9,6 +10,32 @@ interface BlogPostProps { }; } +export async function generateMetadata({ params: { locale, slug } }: BlogPostProps): Promise { + const post = await getPostBySlug(slug, locale); + + if (!post) return {}; + + const description = post.frontmatter.excerpt || ''; + + return { + title: post.frontmatter.title, + description: description, + openGraph: { + title: post.frontmatter.title, + description: description, + type: 'article', + publishedTime: post.frontmatter.date, + authors: ['KLZ Cables'], + url: `https://klz-cables.com/${locale}/blog/${slug}`, + }, + twitter: { + card: 'summary_large_image', + title: post.frontmatter.title, + description: description, + }, + }; +} + import Link from 'next/link'; import VisualLinkPreview from '@/components/blog/VisualLinkPreview'; import Callout from '@/components/blog/Callout'; @@ -253,6 +280,34 @@ export default async function BlogPost({ params: { locale, slug } }: BlogPostPro
+ {/* Structured Data */} +