|
|
|
|
@@ -12,7 +12,7 @@ import { mapFileSlugToTranslated, mapSlugToFileSlug } from '@/lib/slugs';
|
|
|
|
|
import { Metadata } from 'next';
|
|
|
|
|
import { getTranslations, setRequestLocale } from 'next-intl/server';
|
|
|
|
|
import { getProductOGImageMetadata } from '@/lib/metadata';
|
|
|
|
|
import { MDXRemote } from 'next-mdx-remote/rsc';
|
|
|
|
|
|
|
|
|
|
import Image from 'next/image';
|
|
|
|
|
import Link from 'next/link';
|
|
|
|
|
import { notFound } from 'next/navigation';
|
|
|
|
|
@@ -103,70 +103,70 @@ export async function generateMetadata({ params }: ProductPageProps): Promise<Me
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const components = {
|
|
|
|
|
ProductTechnicalData,
|
|
|
|
|
ProductTabs,
|
|
|
|
|
p: (props: any) => (
|
|
|
|
|
<p
|
|
|
|
|
{...props}
|
|
|
|
|
className="text-lg md:text-xl text-text-secondary leading-relaxed mb-8 font-medium"
|
|
|
|
|
/>
|
|
|
|
|
),
|
|
|
|
|
h2: (props: any) => (
|
|
|
|
|
<div className="relative mb-16">
|
|
|
|
|
<h2
|
|
|
|
|
{...props}
|
|
|
|
|
className="text-3xl md:text-4xl font-black text-primary tracking-tighter uppercase mb-6"
|
|
|
|
|
/>
|
|
|
|
|
<div className="w-20 h-1.5 bg-accent rounded-full" />
|
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
h3: (props: any) => (
|
|
|
|
|
<h3
|
|
|
|
|
{...props}
|
|
|
|
|
className="text-2xl md:text-3xl font-black text-primary mb-10 tracking-tight uppercase"
|
|
|
|
|
/>
|
|
|
|
|
),
|
|
|
|
|
ul: (props: any) => <ul {...props} className="list-none pl-0 mb-10" />,
|
|
|
|
|
section: (props: any) => <div {...props} className="block" />,
|
|
|
|
|
li: (props: any) => (
|
|
|
|
|
<li className="flex items-start gap-4 group mb-4 last:mb-0">
|
|
|
|
|
<div className="mt-2.5 w-2 h-2 rounded-full bg-accent flex-shrink-0 group-hover:scale-125 transition-transform" />
|
|
|
|
|
<span
|
|
|
|
|
{...props}
|
|
|
|
|
className="text-lg md:text-xl text-text-secondary leading-relaxed font-medium"
|
|
|
|
|
/>
|
|
|
|
|
</li>
|
|
|
|
|
),
|
|
|
|
|
strong: (props: any) => <strong {...props} className="font-black text-primary" />,
|
|
|
|
|
table: (props: any) => (
|
|
|
|
|
<div className="overflow-x-auto my-20 rounded-[32px] border border-neutral-dark/10 shadow-xl bg-white p-1">
|
|
|
|
|
<table {...props} className="min-w-full divide-y divide-neutral-dark/10" />
|
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
th: (props: any) => (
|
|
|
|
|
<th
|
|
|
|
|
{...props}
|
|
|
|
|
className="px-8 py-6 bg-neutral-light/50 text-left text-[10px] font-black uppercase tracking-[0.25em] text-primary/60"
|
|
|
|
|
/>
|
|
|
|
|
),
|
|
|
|
|
td: (props: any) => (
|
|
|
|
|
<td
|
|
|
|
|
{...props}
|
|
|
|
|
className="px-8 py-6 text-text-secondary border-t border-neutral-dark/5 text-lg md:text-xl font-medium"
|
|
|
|
|
/>
|
|
|
|
|
),
|
|
|
|
|
hr: () => <hr className="my-24 border-t-2 border-neutral-dark/5" />,
|
|
|
|
|
blockquote: (props: any) => (
|
|
|
|
|
<div className="my-20 p-10 md:p-16 bg-primary-dark rounded-[40px] relative overflow-hidden group">
|
|
|
|
|
<div className="absolute top-0 right-0 w-64 h-64 bg-accent/10 rounded-full -translate-y-1/2 translate-x-1/2 blur-3xl group-hover:bg-accent/20 transition-colors duration-700" />
|
|
|
|
|
<div
|
|
|
|
|
className="relative z-10 italic text-2xl md:text-3xl text-white/90 leading-relaxed font-black tracking-tight"
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
};
|
|
|
|
|
// const components = {
|
|
|
|
|
// ProductTechnicalData,
|
|
|
|
|
// ProductTabs,
|
|
|
|
|
// p: (props: any) => (
|
|
|
|
|
// <p
|
|
|
|
|
// {...props}
|
|
|
|
|
// className="text-lg md:text-xl text-text-secondary leading-relaxed mb-8 font-medium"
|
|
|
|
|
// />
|
|
|
|
|
// ),
|
|
|
|
|
// h2: (props: any) => (
|
|
|
|
|
// <div className="relative mb-16">
|
|
|
|
|
// <h2
|
|
|
|
|
// {...props}
|
|
|
|
|
// className="text-3xl md:text-4xl font-black text-primary tracking-tighter uppercase mb-6"
|
|
|
|
|
// />
|
|
|
|
|
// <div className="w-20 h-1.5 bg-accent rounded-full" />
|
|
|
|
|
// </div>
|
|
|
|
|
// ),
|
|
|
|
|
// h3: (props: any) => (
|
|
|
|
|
// <h3
|
|
|
|
|
// {...props}
|
|
|
|
|
// className="text-2xl md:text-3xl font-black text-primary mb-10 tracking-tight uppercase"
|
|
|
|
|
// />
|
|
|
|
|
// ),
|
|
|
|
|
// ul: (props: any) => <ul {...props} className="list-none pl-0 mb-10" />,
|
|
|
|
|
// section: (props: any) => <div {...props} className="block" />,
|
|
|
|
|
// li: (props: any) => (
|
|
|
|
|
// <li className="flex items-start gap-4 group mb-4 last:mb-0">
|
|
|
|
|
// <div className="mt-2.5 w-2 h-2 rounded-full bg-accent flex-shrink-0 group-hover:scale-125 transition-transform" />
|
|
|
|
|
// <span
|
|
|
|
|
// {...props}
|
|
|
|
|
// className="text-lg md:text-xl text-text-secondary leading-relaxed font-medium"
|
|
|
|
|
// />
|
|
|
|
|
// </li>
|
|
|
|
|
// ),
|
|
|
|
|
// strong: (props: any) => <strong {...props} className="font-black text-primary" />,
|
|
|
|
|
// table: (props: any) => (
|
|
|
|
|
// <div className="overflow-x-auto my-20 rounded-[32px] border border-neutral-dark/10 shadow-xl bg-white p-1">
|
|
|
|
|
// <table {...props} className="min-w-full divide-y divide-neutral-dark/10" />
|
|
|
|
|
// </div>
|
|
|
|
|
// ),
|
|
|
|
|
// th: (props: any) => (
|
|
|
|
|
// <th
|
|
|
|
|
// {...props}
|
|
|
|
|
// className="px-8 py-6 bg-neutral-light/50 text-left text-[10px] font-black uppercase tracking-[0.25em] text-primary/60"
|
|
|
|
|
// />
|
|
|
|
|
// ),
|
|
|
|
|
// td: (props: any) => (
|
|
|
|
|
// <td
|
|
|
|
|
// {...props}
|
|
|
|
|
// className="px-8 py-6 text-text-secondary border-t border-neutral-dark/5 text-lg md:text-xl font-medium"
|
|
|
|
|
// />
|
|
|
|
|
// ),
|
|
|
|
|
// hr: () => <hr className="my-24 border-t-2 border-neutral-dark/5" />,
|
|
|
|
|
// blockquote: (props: any) => (
|
|
|
|
|
// <div className="my-20 p-10 md:p-16 bg-primary-dark rounded-[40px] relative overflow-hidden group">
|
|
|
|
|
// <div className="absolute top-0 right-0 w-64 h-64 bg-accent/10 rounded-full -translate-y-1/2 translate-x-1/2 blur-3xl group-hover:bg-accent/20 transition-colors duration-700" />
|
|
|
|
|
// <div
|
|
|
|
|
// className="relative z-10 italic text-2xl md:text-3xl text-white/90 leading-relaxed font-black tracking-tight"
|
|
|
|
|
// {...props}
|
|
|
|
|
// />
|
|
|
|
|
// </div>
|
|
|
|
|
// ),
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
export default async function ProductPage({ params }: ProductPageProps) {
|
|
|
|
|
const { locale, slug } = await params;
|
|
|
|
|
@@ -307,20 +307,25 @@ export default async function ProductPage({ params }: ProductPageProps) {
|
|
|
|
|
notFound();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Extract technical data for schema
|
|
|
|
|
// Extract technical data from MDX content (bypass MDXRemote which crashes on complex JSX-in-MDX)
|
|
|
|
|
const technicalDataMatch = product.content.match(
|
|
|
|
|
/technicalData=\{<ProductTechnicalData data=\{(.*?)\}\s*\/>\}/s,
|
|
|
|
|
);
|
|
|
|
|
let technicalItems = [];
|
|
|
|
|
let technicalData: any = null;
|
|
|
|
|
let technicalItems: any[] = [];
|
|
|
|
|
if (technicalDataMatch) {
|
|
|
|
|
try {
|
|
|
|
|
const data = JSON.parse(technicalDataMatch[1]);
|
|
|
|
|
technicalItems = data.technicalItems || [];
|
|
|
|
|
technicalData = JSON.parse(technicalDataMatch[1]);
|
|
|
|
|
technicalItems = technicalData.technicalItems || [];
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('Failed to parse technical data for schema', e);
|
|
|
|
|
console.error('Failed to parse technical data', e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Extract section HTML content
|
|
|
|
|
const sectionMatch = product.content.match(/<section>([\s\S]*?)<\/section>/);
|
|
|
|
|
const sectionHtml = sectionMatch ? sectionMatch[1] : '';
|
|
|
|
|
|
|
|
|
|
const datasheetPath = getDatasheetPath(productSlug, locale);
|
|
|
|
|
const isFallback = (product.frontmatter as any).isFallback;
|
|
|
|
|
const categorySlug = slug[0];
|
|
|
|
|
@@ -340,22 +345,6 @@ export default async function ProductPage({ params }: ProductPageProps) {
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const productComponents = {
|
|
|
|
|
...components,
|
|
|
|
|
ProductTabs: (props: any) => <ProductTabs {...props} sidebar={sidebar} />,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Pre-process content to convert raw HTML tags to Markdown so they use our custom components
|
|
|
|
|
const processedContent = product.content
|
|
|
|
|
.replace(/<h2[^>]*>(.*?)<\/h2>/g, '\n## $1\n')
|
|
|
|
|
.replace(/<h3[^>]*>(.*?)<\/h3>/g, '\n### $1\n')
|
|
|
|
|
.replace(/<p[^>]*>(.*?)<\/p>/g, '\n$1\n')
|
|
|
|
|
.replace(/<ul[^>]*>(.*?)<\/ul>/gs, '\n$1\n')
|
|
|
|
|
.replace(/<li[^>]*>(.*?)<\/li>/g, '\n- $1\n')
|
|
|
|
|
.replace(/<strong[^>]*>(.*?)<\/strong>/g, '**$1**')
|
|
|
|
|
.replace(/<section[^>]*>/g, '')
|
|
|
|
|
.replace(/<\/section>/g, '');
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex flex-col min-h-screen bg-white relative">
|
|
|
|
|
{/* Product Hero */}
|
|
|
|
|
@@ -465,9 +454,25 @@ export default async function ProductPage({ params }: ProductPageProps) {
|
|
|
|
|
|
|
|
|
|
<div className="relative">
|
|
|
|
|
<div className="w-full">
|
|
|
|
|
{/* Main Content Area */}
|
|
|
|
|
{/* Main Content Area - Direct rendering (bypasses MDXRemote crash) */}
|
|
|
|
|
<div className="max-w-none">
|
|
|
|
|
<MDXRemote source={processedContent} components={productComponents} />
|
|
|
|
|
<ProductTabs
|
|
|
|
|
technicalData={
|
|
|
|
|
technicalData ? <ProductTechnicalData data={technicalData} /> : null
|
|
|
|
|
}
|
|
|
|
|
sidebar={sidebar}
|
|
|
|
|
>
|
|
|
|
|
{sectionHtml && (
|
|
|
|
|
<div
|
|
|
|
|
className="prose prose-lg max-w-none
|
|
|
|
|
[&_h2]:text-3xl [&_h2]:md:text-4xl [&_h2]:font-black [&_h2]:text-primary [&_h2]:tracking-tighter [&_h2]:uppercase [&_h2]:mb-6
|
|
|
|
|
[&_h3]:text-2xl [&_h3]:md:text-3xl [&_h3]:font-black [&_h3]:text-primary [&_h3]:mb-10 [&_h3]:tracking-tight [&_h3]:uppercase
|
|
|
|
|
[&_p]:text-lg [&_p]:md:text-xl [&_p]:text-text-secondary [&_p]:leading-relaxed [&_p]:mb-8 [&_p]:font-medium
|
|
|
|
|
[&_strong]:font-black [&_strong]:text-primary"
|
|
|
|
|
dangerouslySetInnerHTML={{ __html: sectionHtml }}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</ProductTabs>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Datasheet Download Section - Only for Medium Voltage for now */}
|
|
|
|
|
|