fix: product texts, mobile nav background, mobile product page layout
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Successful in 2m20s
Build & Deploy / 🏗️ Build (push) Successful in 4m22s
Build & Deploy / 🚀 Deploy (push) Successful in 23s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 5m16s
Build & Deploy / 🔔 Notify (push) Successful in 1s

- Fix PayloadRichText: migrate custom JSX converters to Lexical v3 nodesToJSX API
  - paragraph, heading, list, listitem, quote, link converters now use nodesToJSX
  - Resolves missing product texts since PayloadCMS migration
- Fix mobile navigation: move overlay outside <header> to prevent fixed-position clipping
  - Header transform/backdrop-filter was containing the fixed overlay
  - Use bg-primary/95 backdrop-blur-3xl for premium blue background
- Fix product image mobile layout: use md:-mt-32 responsive prefix
  - Negative margin only applies on md+ to avoid overlap on mobile
- Improve mobile product page UX:
  - Breadcrumbs: flex-wrap, truncate, reduced separator spacing
  - Hero: reduced top padding pt-28 on mobile
  - Product image card: 4/3 aspect ratio and smaller padding on mobile
  - Section spacing: use responsive md: prefixes throughout
  - Data tables: 2-col grid on mobile, smaller card padding/radius
  - Tables: add right-edge scroll hint gradient on mobile
This commit is contained in:
2026-02-28 10:51:58 +01:00
parent ce719a1d70
commit aa4e3aab4f
10 changed files with 171 additions and 222 deletions

1
.env
View File

@@ -7,6 +7,7 @@ SENTRY_DSN=https://c10957d0182245b1a2a806ac2d34a197@errors.infra.mintel.me/1
LOG_LEVEL=info LOG_LEVEL=info
NEXT_PUBLIC_FEEDBACK_ENABLED=false NEXT_PUBLIC_FEEDBACK_ENABLED=false
NEXT_PUBLIC_RECORD_MODE_ENABLED=false NEXT_PUBLIC_RECORD_MODE_ENABLED=false
NPM_TOKEN=263e7f75d8ada27f3a2e71fd6bd9d95298d48a4d
# SMTP Configuration # SMTP Configuration
MAIL_HOST=smtp.eu.mailgun.org MAIL_HOST=smtp.eu.mailgun.org

View File

@@ -322,6 +322,8 @@ export default async function ProductPage({ params }: ProductPageProps) {
} }
} }
console.log(`[DEBUG PAGE] Slug: ${productSlug}, children count: ${descriptionChildren.length}`);
const descriptionContent = { const descriptionContent = {
root: { root: {
...product.content.root, ...product.content.root,
@@ -353,29 +355,31 @@ export default async function ProductPage({ params }: ProductPageProps) {
categories={product.frontmatter.categories} categories={product.frontmatter.categories}
sku={product.frontmatter.sku} sku={product.frontmatter.sku}
/> />
<section className="relative pt-40 pb-24 overflow-hidden bg-primary-dark"> <section className="relative pt-28 md:pt-40 pb-12 md:pb-24 overflow-hidden bg-primary-dark">
{/* Background Decorative Elements */} {/* Background Decorative Elements */}
<div className="absolute top-0 right-0 w-1/2 h-full bg-gradient-to-l from-accent/5 to-transparent pointer-events-none" /> <div className="absolute top-0 right-0 w-1/2 h-full bg-gradient-to-l from-accent/5 to-transparent pointer-events-none" />
<div className="absolute -top-24 -right-24 w-96 h-96 bg-accent/10 rounded-full blur-3xl pointer-events-none" /> <div className="absolute -top-24 -right-24 w-96 h-96 bg-accent/10 rounded-full blur-3xl pointer-events-none" />
<Container className="relative z-10"> <Container className="relative z-10">
<div className="max-w-4xl animate-slide-up"> <div className="max-w-4xl animate-slide-up">
<nav className="flex items-center mb-12 text-white/40 text-[10px] font-black uppercase tracking-[0.2em]"> <nav className="flex flex-wrap items-center gap-y-1 mb-6 md:mb-12 text-white/40 text-[10px] font-black uppercase tracking-[0.2em]">
<Link <Link
href={`/${locale}/${productsSlug}`} href={`/${locale}/${productsSlug}`}
className="hover:text-accent transition-colors" className="hover:text-accent transition-colors shrink-0"
> >
{t.has('breadcrumb') ? t('breadcrumb') : 'Products'} {t.has('breadcrumb') ? t('breadcrumb') : 'Products'}
</Link> </Link>
<span className="mx-4 opacity-20">/</span> <span className="mx-2 md:mx-4 opacity-20">/</span>
<Link <Link
href={`/${locale}/${productsSlug}/${categorySlug}`} href={`/${locale}/${productsSlug}/${categorySlug}`}
className="hover:text-accent transition-colors" className="hover:text-accent transition-colors shrink-0 max-w-[140px] truncate"
> >
{categoryTitle} {categoryTitle}
</Link> </Link>
<span className="mx-4 opacity-20">/</span> <span className="mx-2 md:mx-4 opacity-20">/</span>
<span className="text-white/90">{product.frontmatter.title}</span> <span className="text-white/90 truncate max-w-[140px] md:max-w-none">
{product.frontmatter.title}
</span>
</nav> </nav>
<div className="flex flex-col lg:flex-row lg:items-center justify-between gap-12"> <div className="flex flex-col lg:flex-row lg:items-center justify-between gap-12">
@@ -386,7 +390,7 @@ export default async function ProductPage({ params }: ProductPageProps) {
{t('englishVersion')} {t('englishVersion')}
</div> </div>
)} )}
<div className="flex flex-wrap gap-3 mb-8"> <div className="flex flex-wrap gap-2 mb-4 md:mb-8">
{product.frontmatter.categories.map((cat, idx) => ( {product.frontmatter.categories.map((cat, idx) => (
<Badge <Badge
key={idx} key={idx}
@@ -397,10 +401,10 @@ export default async function ProductPage({ params }: ProductPageProps) {
</Badge> </Badge>
))} ))}
</div> </div>
<Heading level={1} className="text-white mb-8 uppercase"> <Heading level={1} className="text-white mb-4 md:mb-8 uppercase">
{product.frontmatter.title} {product.frontmatter.title}
</Heading> </Heading>
<p className="text-xl md:text-2xl text-white/60 max-w-2xl leading-relaxed font-medium"> <p className="text-base md:text-xl lg:text-2xl text-white/60 max-w-2xl leading-relaxed font-medium">
{product.frontmatter.description} {product.frontmatter.description}
</p> </p>
</div> </div>
@@ -414,11 +418,11 @@ export default async function ProductPage({ params }: ProductPageProps) {
{/* Large Product Image Section */} {/* Large Product Image Section */}
{product.frontmatter.images && product.frontmatter.images.length > 0 && ( {product.frontmatter.images && product.frontmatter.images.length > 0 && (
<div <div
className="relative -mt-32 mb-32 animate-slide-up" className="relative md:-mt-32 mb-8 md:mb-32 animate-slide-up"
style={{ animationDelay: '200ms' }} style={{ animationDelay: '200ms' }}
> >
<div className="bg-white shadow-[0_32px_64px_-12px_rgba(0,0,0,0.1)] rounded-[48px] border border-neutral-dark/5 overflow-hidden p-12 md:p-20 lg:p-24"> <div className="bg-white shadow-[0_32px_64px_-12px_rgba(0,0,0,0.1)] rounded-[24px] md:rounded-[48px] border border-neutral-dark/5 overflow-hidden p-6 md:p-20 lg:p-24">
<div className="relative w-full aspect-[21/9]"> <div className="relative w-full aspect-[4/3] md:aspect-[21/9]">
<Image <Image
src={product.frontmatter.images[0]} src={product.frontmatter.images[0]}
alt={product.frontmatter.title} alt={product.frontmatter.title}
@@ -453,10 +457,10 @@ export default async function ProductPage({ params }: ProductPageProps) {
</div> </div>
)} )}
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-20"> <div className="grid grid-cols-1 lg:grid-cols-12 gap-8 lg:gap-20">
{/* Description Area Next to Sidebar */} {/* Description Area Next to Sidebar */}
<div className="lg:col-span-8"> <div className="lg:col-span-8">
<div className="max-w-none prose prose-primary prose-lg md:prose-xl mb-16 pb-16 border-b border-neutral-dark/5"> <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 ? ( {descriptionChildren.length > 0 ? (
<PayloadRichText data={descriptionContent} /> <PayloadRichText data={descriptionContent} />
) : product.frontmatter.description ? ( ) : product.frontmatter.description ? (
@@ -464,6 +468,12 @@ export default async function ProductPage({ params }: ProductPageProps) {
{product.frontmatter.description} {product.frontmatter.description}
</p> </p>
) : null} ) : null}
{product.application?.root?.children?.length > 0 && (
<div className="mt-12">
<PayloadRichText data={product.application} />
</div>
)}
</div> </div>
</div> </div>
@@ -472,7 +482,7 @@ export default async function ProductPage({ params }: ProductPageProps) {
</div> </div>
{/* Full-width Technical Data Below */} {/* Full-width Technical Data Below */}
<div className="mt-16 pt-16 border-t-0"> <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"> <div className="max-w-none prose prose-primary prose-lg md:prose-xl">
<PayloadRichText data={technicalContent} /> <PayloadRichText data={technicalContent} />
</div> </div>
@@ -530,7 +540,7 @@ export default async function ProductPage({ params }: ProductPageProps) {
</div> </div>
{/* Related Products Section */} {/* Related Products Section */}
<div className="mt-16 pt-16 border-t border-neutral-dark/5"> <div className="mt-10 md:mt-16 pt-10 md:pt-16 border-t border-neutral-dark/5">
<RelatedProducts <RelatedProducts
currentSlug={productSlug} currentSlug={productSlug}
categories={product.frontmatter.categories} categories={product.frontmatter.categories}

View File

@@ -141,7 +141,8 @@ export default function Header() {
{ {
'bg-primary/95 backdrop-blur-md md:bg-transparent py-3 md:py-8 shadow-2xl md:shadow-none': 'bg-primary/95 backdrop-blur-md md:bg-transparent py-3 md:py-8 shadow-2xl md:shadow-none':
isHomePage && !isScrolled && !isMobileMenuOpen, isHomePage && !isScrolled && !isMobileMenuOpen,
'bg-primary py-3 md:py-4 shadow-2xl': !isHomePage || isScrolled || isMobileMenuOpen, 'bg-primary/90 backdrop-blur-md py-3 md:py-4 shadow-2xl':
!isHomePage || isScrolled || isMobileMenuOpen,
}, },
); );
@@ -152,9 +153,7 @@ export default function Header() {
<> <>
<header className={headerClass} style={{ animationDuration: '800ms' }}> <header className={headerClass} style={{ animationDuration: '800ms' }}>
<div className="container mx-auto px-4 md:px-12 lg:px-16 max-w-7xl flex items-center justify-between"> <div className="container mx-auto px-4 md:px-12 lg:px-16 max-w-7xl flex items-center justify-between">
<div <div className="flex-shrink-0 group touch-target fill-mode-both">
className="flex-shrink-0 group touch-target fill-mode-both"
>
<Link <Link
href={`/${currentLocale}`} href={`/${currentLocale}`}
onClick={() => onClick={() =>
@@ -336,11 +335,12 @@ export default function Header() {
</button> </button>
</div> </div>
</div> </div>
</header>
{/* Mobile Menu Overlay */} {/* Mobile Menu Overlay */}
<div <div
className={cn( className={cn(
'fixed inset-0 bg-primary z-[60] lg:hidden transition-all duration-500 ease-in-out flex flex-col', 'fixed inset-0 bg-primary/95 backdrop-blur-3xl z-[60] lg:hidden transition-all duration-500 ease-in-out flex flex-col',
isMobileMenuOpen isMobileMenuOpen
? 'opacity-100 translate-y-0' ? 'opacity-100 translate-y-0'
: 'opacity-0 -translate-y-full pointer-events-none', : 'opacity-0 -translate-y-full pointer-events-none',
@@ -444,7 +444,6 @@ export default function Header() {
</div> </div>
</nav> </nav>
</div> </div>
</header>
</> </>
); );
} }

View File

@@ -39,95 +39,17 @@ import CTA from '@/components/home/CTA';
const jsxConverters: JSXConverters = { const jsxConverters: JSXConverters = {
...defaultJSXConverters, ...defaultJSXConverters,
// Let the default converters handle text nodes to preserve valid formatting // Let the default converters handle text nodes to preserve valid formatting
// If the text node contains raw HTML (from messy migrations), render it as HTML instead of escaping it
text: ({ node }: any) => {
const text = node.text;
// Handle markdown-style lists embedded in text nodes from Markdown migration
if (text && text.includes('\n- ')) {
const parts = text.split('\n- ').filter((p: string) => p.trim() !== '');
// If first part doesn't start with "- ", it's a prefix paragraph
const startsWithDash = text.trimStart().startsWith('- ');
const prefix = startsWithDash ? null : parts.shift();
return (
<div className="my-4">
{prefix && (
<div dangerouslySetInnerHTML={prefix.includes('<') ? { __html: prefix } : undefined}>
{!prefix.includes('<') ? prefix : undefined}
</div>
)}
<ul className="list-disc pl-6 my-4 space-y-2">
{parts.map((item: string, i: number) => {
const cleanItem = item.trim();
if (cleanItem.includes('<')) {
return <li key={i} dangerouslySetInnerHTML={{ __html: cleanItem }} />;
}
return <li key={i}>{cleanItem}</li>;
})}
</ul>
</div>
);
}
if (text && (text.includes('<') || text.includes('data-start'))) {
return <span dangerouslySetInnerHTML={{ __html: text }} />;
}
// Handle markdown-style links [text](url) from Markdown migration
if (text && /\[([^\]]+)\]\(([^)]+)\)/.test(text)) {
const parts: React.ReactNode[] = [];
const remaining = text;
let key = 0;
const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
let match;
let lastIndex = 0;
while ((match = linkRegex.exec(remaining)) !== null) {
if (match.index > lastIndex) {
parts.push(<span key={key++}>{remaining.slice(lastIndex, match.index)}</span>);
}
parts.push(
<a
key={key++}
href={match[2]}
target="_blank"
rel="noopener noreferrer"
className="text-primary underline decoration-primary/30 hover:decoration-primary transition-colors"
>
{match[1]}
</a>,
);
lastIndex = match.index + match[0].length;
}
if (lastIndex < remaining.length) {
parts.push(<span key={key++}>{remaining.slice(lastIndex)}</span>);
}
return <>{parts}</>;
}
// Handle newlines in text nodes — convert to <br> for proper line breaks
if (text && text.includes('\n')) {
const lines = text.split('\n');
return (
<>
{lines.map((line: string, i: number) => (
<span key={i}>
{line}
{i < lines.length - 1 && <br />}
</span>
))}
</>
);
}
if (node.format === 1) return <strong key="bold">{text}</strong>;
if (node.format === 2) return <em key="italic">{text}</em>;
return <span key="text">{text}</span>;
},
// Use div instead of p for paragraphs to allow nested block elements (like the lists above) // Use div instead of p for paragraphs to allow nested block elements (like the lists above)
paragraph: ({ children }: any) => ( paragraph: ({ node, nodesToJSX }: any) => {
<div className="mb-6 leading-relaxed text-text-secondary">{children}</div> return (
), <div className="mb-6 leading-relaxed text-text-secondary">
{nodesToJSX({ nodes: node.children })}
</div>
);
},
// Scale headings to prevent multiple H1s (H1 -> H2, etc) and style natively // Scale headings to prevent multiple H1s (H1 -> H2, etc) and style natively
heading: ({ node, children }: any) => { heading: ({ node, nodesToJSX }: any) => {
const children = nodesToJSX({ nodes: node.children });
const tag = node?.tag; const tag = node?.tag;
if (tag === 'h1') if (tag === 'h1')
return ( return (
@@ -151,7 +73,8 @@ const jsxConverters: JSXConverters = {
); );
return <h6 className="text-base font-bold mt-6 mb-4 text-text-primary">{children}</h6>; return <h6 className="text-base font-bold mt-6 mb-4 text-text-primary">{children}</h6>;
}, },
list: ({ node, children }: any) => { list: ({ node, nodesToJSX }: any) => {
const children = nodesToJSX({ nodes: node.children });
if (node?.listType === 'number') { if (node?.listType === 'number') {
return ( return (
<ol className="list-decimal pl-6 my-6 space-y-2 text-text-secondary marker:text-primary marker:font-bold"> <ol className="list-decimal pl-6 my-6 space-y-2 text-text-secondary marker:text-primary marker:font-bold">
@@ -168,7 +91,8 @@ const jsxConverters: JSXConverters = {
</ul> </ul>
); );
}, },
listitem: ({ node, children }: any) => { listitem: ({ node, nodesToJSX }: any) => {
const children = nodesToJSX({ nodes: node.children });
if (node?.checked != null) { if (node?.checked != null) {
return ( return (
<li className="flex items-center gap-3 mb-2 leading-relaxed"> <li className="flex items-center gap-3 mb-2 leading-relaxed">
@@ -184,12 +108,16 @@ const jsxConverters: JSXConverters = {
} }
return <li className="mb-2 leading-relaxed">{children}</li>; return <li className="mb-2 leading-relaxed">{children}</li>;
}, },
quote: ({ children }: any) => ( quote: ({ node, nodesToJSX }: any) => {
const children = nodesToJSX({ nodes: node.children });
return (
<blockquote className="border-l-4 border-primary bg-primary/5 rounded-r-2xl pl-6 py-4 my-8 italic text-text-secondary shadow-sm"> <blockquote className="border-l-4 border-primary bg-primary/5 rounded-r-2xl pl-6 py-4 my-8 italic text-text-secondary shadow-sm">
{children} {children}
</blockquote> </blockquote>
), );
link: ({ node, children }: any) => { },
link: ({ node, nodesToJSX }: any) => {
const children = nodesToJSX({ nodes: node.children });
// Handling Payload CMS link nodes // Handling Payload CMS link nodes
const href = node?.fields?.url || node?.url || '#'; const href = node?.fields?.url || node?.url || '#';
const newTab = node?.fields?.newTab || node?.newTab; const newTab = node?.fields?.newTab || node?.newTab;
@@ -1090,6 +1018,10 @@ export default function PayloadRichText({
if (!data) return null; if (!data) return null;
if (data.root?.children?.length > 0) {
console.log('[PayloadRichText DEBUG] received children', data.root.children.length);
}
const dynamicConverters: JSXConverters = { const dynamicConverters: JSXConverters = {
...jsxConverters, ...jsxConverters,
blocks: { blocks: {

View File

@@ -38,14 +38,14 @@ export default function ProductTechnicalData({ data }: ProductTechnicalDataProps
}; };
return ( return (
<div className="space-y-16"> <div className="space-y-8 md:space-y-16">
{technicalItems.length > 0 && ( {technicalItems.length > 0 && (
<div className="bg-white p-8 md:p-12 rounded-[32px] shadow-sm border border-neutral-dark/5"> <div className="bg-white p-5 md:p-12 rounded-[20px] md:rounded-[32px] shadow-sm border border-neutral-dark/5">
<h3 className="text-2xl font-bold text-primary mb-8 flex items-center gap-3"> <h3 className="text-2xl font-bold text-primary mb-8 flex items-center gap-3">
<div className="w-2 h-8 bg-accent rounded-full" /> <div className="w-2 h-8 bg-accent rounded-full" />
General Data General Data
</h3> </h3>
<dl className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-x-12 gap-y-8"> <dl className="grid grid-cols-2 sm:grid-cols-2 lg:grid-cols-3 gap-x-6 gap-y-6 md:gap-x-12 md:gap-y-8">
{technicalItems.map((item, idx) => ( {technicalItems.map((item, idx) => (
<div key={idx} className="flex flex-col group"> <div key={idx} className="flex flex-col group">
<dt className="text-sm font-bold uppercase tracking-widest text-primary/40 mb-2 group-hover:text-accent transition-colors"> <dt className="text-sm font-bold uppercase tracking-widest text-primary/40 mb-2 group-hover:text-accent transition-colors">
@@ -72,7 +72,7 @@ export default function ProductTechnicalData({ data }: ProductTechnicalDataProps
return ( return (
<div <div
key={idx} key={idx}
className="bg-white p-8 md:p-12 rounded-[32px] shadow-sm border border-neutral-dark/5 overflow-hidden" className="bg-white p-5 md:p-12 rounded-[20px] md:rounded-[32px] shadow-sm border border-neutral-dark/5 overflow-hidden"
> >
<h3 className="text-2xl font-bold text-primary mb-8 flex items-center gap-3"> <h3 className="text-2xl font-bold text-primary mb-8 flex items-center gap-3">
<div className="w-2 h-8 bg-accent rounded-full" /> <div className="w-2 h-8 bg-accent rounded-full" />
@@ -83,7 +83,7 @@ export default function ProductTechnicalData({ data }: ProductTechnicalDataProps
</h3> </h3>
{table.metaItems.length > 0 && ( {table.metaItems.length > 0 && (
<dl className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-8 mb-12 bg-neutral-light/50 p-8 rounded-2xl border border-neutral-dark/5"> <dl className="grid grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 md:gap-8 mb-6 md:mb-12 bg-neutral-light/50 p-4 md:p-8 rounded-xl md:rounded-2xl border border-neutral-dark/5">
{table.metaItems.map((item, mIdx) => ( {table.metaItems.map((item, mIdx) => (
<div key={mIdx}> <div key={mIdx}>
<dt className="text-[10px] font-black uppercase tracking-[0.2em] text-primary/40 mb-1"> <dt className="text-[10px] font-black uppercase tracking-[0.2em] text-primary/40 mb-1">
@@ -98,9 +98,11 @@ export default function ProductTechnicalData({ data }: ProductTechnicalDataProps
)} )}
<div className="relative"> <div className="relative">
{/* Scroll hint gradient on right edge for mobile */}
<div className="pointer-events-none absolute right-0 top-0 h-full w-8 bg-gradient-to-l from-white to-transparent z-20 md:hidden" />
<div <div
id={`voltage-table-${idx}`} id={`voltage-table-${idx}`}
className={`overflow-x-auto -mx-8 md:-mx-12 px-8 md:px-12 transition-all duration-500 ease-in-out ${ className={`overflow-x-auto -mx-5 md:-mx-12 px-5 md:px-12 transition-all duration-500 ease-in-out ${
!isExpanded && hasManyRows ? 'max-h-[400px] overflow-y-hidden' : 'max-h-[none]' !isExpanded && hasManyRows ? 'max-h-[400px] overflow-y-hidden' : 'max-h-[none]'
}`} }`}
> >

View File

@@ -29,7 +29,7 @@ services:
NEXT_TELEMETRY_DISABLED: "1" NEXT_TELEMETRY_DISABLED: "1"
POSTGRES_URI: postgres://${PAYLOAD_DB_USER:-payload}:${PAYLOAD_DB_PASSWORD:-120in09oenaoinsd9iaidon}@klz-db:5432/${PAYLOAD_DB_NAME:-payload} POSTGRES_URI: postgres://${PAYLOAD_DB_USER:-payload}:${PAYLOAD_DB_PASSWORD:-120in09oenaoinsd9iaidon}@klz-db:5432/${PAYLOAD_DB_NAME:-payload}
PAYLOAD_SECRET: ${PAYLOAD_SECRET:-fallback-secret-for-dev} PAYLOAD_SECRET: ${PAYLOAD_SECRET:-fallback-secret-for-dev}
NODE_OPTIONS: "--max-old-space-size=4096" NODE_OPTIONS: "--max-old-space-size=8192"
UV_THREADPOOL_SIZE: "4" UV_THREADPOOL_SIZE: "4"
NPM_TOKEN: ${NPM_TOKEN:-} NPM_TOKEN: ${NPM_TOKEN:-}
CI: "true" CI: "true"

View File

@@ -1,4 +1,5 @@
// Sentry initialization move to GlitchtipErrorReportingService to allow lazy-loading // Sentry initialization move to GlitchtipErrorReportingService to allow lazy-loading
// for PageSpeed 100 optimizations. This file is now empty to prevent the SDK // for PageSpeed 100 optimizations. This file is now empty to prevent the SDK
// from being included in the initial JS bundle. // from being included in the initial JS bundle.
export {}; import * as Sentry from '@sentry/nextjs';
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;

View File

@@ -18,6 +18,7 @@ export interface ProductData {
slug: string; slug: string;
frontmatter: ProductFrontmatter; frontmatter: ProductFrontmatter;
content: any; // Lexical AST from Payload content: any; // Lexical AST from Payload
application?: any; // Lexical AST for Application field
} }
export async function getProductMetadata( export async function getProductMetadata(
@@ -113,6 +114,7 @@ export async function getProductBySlug(slug: string, locale: string): Promise<Pr
: 50, : 50,
}, },
content: doc.content, content: doc.content,
application: doc.application,
}; };
} }
@@ -195,6 +197,7 @@ export async function getAllProducts(locale: string): Promise<ProductData[]> {
: 50, : 50,
}, },
content: null, content: null,
application: null,
}; };
}); });

2
next-env.d.ts vendored
View File

@@ -1,6 +1,6 @@
/// <reference types="next" /> /// <reference types="next" />
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts"; import "./.next/dev/types/routes.d.ts";
// NOTE: This file should not be edited // NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

View File

@@ -17,6 +17,7 @@ const nextConfig = {
workerThreads: false, workerThreads: false,
}, },
reactStrictMode: false, reactStrictMode: false,
swcMinify: true,
productionBrowserSourceMaps: false, productionBrowserSourceMaps: false,
logging: { logging: {
fetches: { fetches: {