feat: migrate Payload CMS to MDX and harden static infrastructure

This commit is contained in:
2026-05-04 14:48:04 +02:00
parent d51e220802
commit d3141187ee
165 changed files with 7654 additions and 16136 deletions

View File

@@ -16,7 +16,7 @@ import Image from 'next/image';
import Link from 'next/link';
import { notFound, redirect } from 'next/navigation';
import ProductEngagementTracker from '@/components/analytics/ProductEngagementTracker';
import PayloadRichText from '@/components/PayloadRichText';
import MDXContent from '@/components/MDXContent';
interface ProductPageProps {
params: Promise<{
@@ -266,15 +266,17 @@ export default async function ProductPage({ params }: ProductPageProps) {
notFound();
}
// Extract technical data natively from the Lexical AST for Schema.org
let technicalItems = [];
if (product.content?.root?.children) {
const productTabsBlock = product.content.root.children.find(
(node: any) => node.type === 'block' && node.fields?.blockType === 'productTabs',
);
if (productTabsBlock && productTabsBlock.fields?.technicalItems) {
technicalItems = productTabsBlock.fields.technicalItems;
try {
const tabMatch =
typeof product.content === 'string' &&
product.content.match(/<Block type="productTabs" data={({.*?})}\s*\/>/s);
if (tabMatch && tabMatch[1]) {
const data = JSON.parse(tabMatch[1]);
technicalItems = data.technicalItems || [];
}
} catch (e) {
// Ignore JSON parse errors for AST
}
const datasheetPath = getDatasheetPath(productSlug, locale);
@@ -288,56 +290,17 @@ export default async function ProductPage({ params }: ProductPageProps) {
? t(`categories.${categoryKey}.title`)
: categoryFileSlug;
// Split content into Description and Technical Data
const rootChildren = product.content?.root?.children || [];
const technicalBlocks = rootChildren.filter(
(node: any) =>
node.type === 'block' &&
(node.fields?.blockType === 'productTabs' ||
node.fields?.blockType === 'productTechnicalData'),
);
let descriptionChildren = rootChildren.filter(
(node: any) =>
!(
node.type === 'block' &&
(node.fields?.blockType === 'productTabs' ||
node.fields?.blockType === 'productTechnicalData')
),
);
let descriptionContent = typeof product.content === 'string' ? product.content : '';
let technicalContent = '';
// If no standalone description nodes, extract from the productTabs block's embedded content
if (descriptionChildren.length === 0) {
const tabsBlock = rootChildren.find(
(node: any) => node.type === 'block' && node.fields?.blockType === 'productTabs',
);
if (tabsBlock?.fields?.content?.root?.children) {
descriptionChildren = tabsBlock.fields.content.root.children.filter((node: any) => {
// Filter out MDX parsing artifacts like `}>`
if (node.type === 'paragraph' && node.children?.length === 1) {
const text = node.children[0]?.text?.trim();
return text !== '}>' && text !== '{' && text !== '}';
}
return true;
});
if (typeof product.content === 'string') {
const tabBlockMatch = product.content.match(/<Block type="productTabs".*?\/>/s);
if (tabBlockMatch) {
descriptionContent = product.content.replace(tabBlockMatch[0], '');
technicalContent = tabBlockMatch[0];
}
}
console.log(`[DEBUG PAGE] Slug: ${productSlug}, children count: ${descriptionChildren.length}`);
const descriptionContent = {
root: {
...product.content.root,
children: descriptionChildren,
},
};
const technicalContent = {
root: {
...product.content.root,
children: technicalBlocks,
},
};
const sidebar = (
<ProductSidebar
productName={product.frontmatter.title}
@@ -461,17 +424,19 @@ export default async function ProductPage({ params }: ProductPageProps) {
{/* Description Area Next to Sidebar */}
<div className="lg:col-span-8">
<div className="max-w-none prose prose-primary prose-base md:prose-lg xl:prose-xl mb-8 md:mb-16 pb-8 md:pb-16 border-b border-neutral-dark/5">
{descriptionChildren.length > 0 ? (
<PayloadRichText data={descriptionContent} />
{descriptionContent ? (
<MDXContent data={descriptionContent} />
) : product.frontmatter.description ? (
<p className="text-lg md:text-xl text-text-secondary leading-relaxed">
{product.frontmatter.description}
</p>
) : null}
{product.application?.root?.children?.length > 0 && (
{product.application && (
<div className="mt-12">
<PayloadRichText data={product.application} />
<MDXContent
data={typeof product.application === 'string' ? product.application : ''}
/>
</div>
)}
</div>
@@ -484,7 +449,7 @@ export default async function ProductPage({ params }: ProductPageProps) {
{/* Full-width Technical Data Below */}
<div className="mt-8 md:mt-16 pt-8 md:pt-16 border-t-0">
<div className="max-w-none prose prose-primary prose-lg md:prose-xl">
<PayloadRichText data={technicalContent} />
<MDXContent data={technicalContent} />
</div>
{/* Datasheet Download Section */}