Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 14s
Build & Deploy / 🧪 QA (push) Has started running
Build & Deploy / 🏗️ Build (push) Has been cancelled
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
Fixes an issue where TOC links wouldn't scroll due to ID generation mismatches on MDX headers containing formatted text or German umlauts.
191 lines
6.2 KiB
TypeScript
191 lines
6.2 KiB
TypeScript
import Link from 'next/link';
|
|
import VisualLinkPreview from '@/components/blog/VisualLinkPreview';
|
|
import { Callout } from '@/components/ui';
|
|
import HighlightBox from '@/components/blog/HighlightBox';
|
|
import Stats from '@/components/blog/Stats';
|
|
import AnimatedImage from '@/components/blog/AnimatedImage';
|
|
import ChatBubble from '@/components/blog/ChatBubble';
|
|
import SplitHeading from '@/components/blog/SplitHeading';
|
|
import PowerCTA from '@/components/blog/PowerCTA';
|
|
import StickyNarrative from '@/components/blog/StickyNarrative';
|
|
import TechnicalGrid from '@/components/blog/TechnicalGrid';
|
|
import ComparisonGrid from '@/components/blog/ComparisonGrid';
|
|
import { generateHeadingId, getTextContent } from '@/lib/blog';
|
|
|
|
export const mdxComponents = {
|
|
VisualLinkPreview,
|
|
Callout,
|
|
HighlightBox,
|
|
Stats,
|
|
AnimatedImage,
|
|
ChatBubble,
|
|
PowerCTA,
|
|
SplitHeading,
|
|
StickyNarrative,
|
|
TechnicalGrid,
|
|
ComparisonGrid,
|
|
h1: () => null,
|
|
a: ({ href, children, ...props }: any) => {
|
|
// Special handling for PDF downloads to make them prominent
|
|
if (href?.endsWith('.pdf')) {
|
|
return (
|
|
<a
|
|
href={href}
|
|
{...props}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="inline-flex items-center gap-3 px-6 py-3 bg-primary text-white font-bold rounded-xl hover:bg-accent hover:text-primary-dark transition-all duration-300 no-underline my-8 group shadow-lg hover:shadow-xl hover:-translate-y-1"
|
|
>
|
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
|
/>
|
|
</svg>
|
|
<span>{children}</span>
|
|
<span className="text-xs opacity-50 font-normal group-hover:opacity-100 transition-opacity">
|
|
(PDF)
|
|
</span>
|
|
</a>
|
|
);
|
|
}
|
|
|
|
if (href?.startsWith('/')) {
|
|
return (
|
|
<Link
|
|
href={href}
|
|
{...props}
|
|
className="text-primary font-medium hover:underline decoration-2 underline-offset-2 transition-all"
|
|
>
|
|
{children}
|
|
</Link>
|
|
);
|
|
}
|
|
return (
|
|
<a
|
|
href={href}
|
|
{...props}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="text-primary font-medium hover:underline decoration-2 underline-offset-2 transition-all inline-flex items-center gap-1"
|
|
>
|
|
{children}
|
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
|
|
/>
|
|
</svg>
|
|
</a>
|
|
);
|
|
},
|
|
img: (props: any) => <AnimatedImage src={props.src} alt={props.alt} />,
|
|
h2: ({ children, ...props }: any) => {
|
|
const id = props.id || generateHeadingId(getTextContent(children));
|
|
return (
|
|
<SplitHeading {...props} id={id} className="mt-16 mb-6 pb-3 border-b-2 border-primary/20">
|
|
{children}
|
|
</SplitHeading>
|
|
);
|
|
},
|
|
h3: ({ children, ...props }: any) => {
|
|
const id = props.id || generateHeadingId(getTextContent(children));
|
|
return (
|
|
<h3 {...props} id={id} className="text-2xl font-bold text-text-primary mt-12 mb-4">
|
|
{children}
|
|
</h3>
|
|
);
|
|
},
|
|
p: ({ children, ...props }: any) => (
|
|
<p {...props} className="text-lg text-text-secondary leading-relaxed mb-6">
|
|
{children}
|
|
</p>
|
|
),
|
|
ul: ({ children, ...props }: any) => (
|
|
<ul {...props} className="my-8 space-y-3">
|
|
{children}
|
|
</ul>
|
|
),
|
|
ol: ({ children, ...props }: any) => (
|
|
<ol {...props} className="my-8 space-y-3 list-decimal list-inside">
|
|
{children}
|
|
</ol>
|
|
),
|
|
li: ({ children, ...props }: any) => (
|
|
<li {...props} className="text-lg text-text-secondary flex items-start gap-3">
|
|
<span className="text-primary mt-1.5 flex-shrink-0">
|
|
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
|
<path
|
|
fillRule="evenodd"
|
|
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
|
|
clipRule="evenodd"
|
|
/>
|
|
</svg>
|
|
</span>
|
|
<span className="flex-1">{children}</span>
|
|
</li>
|
|
),
|
|
blockquote: ({ children, ...props }: any) => (
|
|
<blockquote
|
|
{...props}
|
|
className="my-8 pl-6 border-l-4 border-primary bg-neutral-light/30 py-4 pr-6 rounded-r-lg"
|
|
>
|
|
<div className="text-lg text-text-primary italic">{children}</div>
|
|
</blockquote>
|
|
),
|
|
strong: ({ children, ...props }: any) => (
|
|
<strong {...props} className="font-bold text-primary">
|
|
{children}
|
|
</strong>
|
|
),
|
|
code: ({ children, ...props }: any) => (
|
|
<code {...props} className="px-2 py-1 bg-neutral-light text-primary rounded font-mono text-sm">
|
|
{children}
|
|
</code>
|
|
),
|
|
pre: ({ children, ...props }: any) => (
|
|
<pre {...props} className="my-8 p-6 bg-neutral-dark/5 rounded-xl overflow-x-auto">
|
|
{children}
|
|
</pre>
|
|
),
|
|
table: ({ children, ...props }: any) => (
|
|
<div className="my-8 overflow-x-auto rounded-lg border border-neutral-200 shadow-sm">
|
|
<table {...props} className="w-full text-left text-sm text-text-secondary">
|
|
{children}
|
|
</table>
|
|
</div>
|
|
),
|
|
thead: ({ children, ...props }: any) => (
|
|
<thead
|
|
{...props}
|
|
className="bg-neutral-50 text-text-primary font-semibold border-b border-neutral-200"
|
|
>
|
|
{children}
|
|
</thead>
|
|
),
|
|
tbody: ({ children, ...props }: any) => (
|
|
<tbody {...props} className="divide-y divide-neutral-200 bg-white">
|
|
{children}
|
|
</tbody>
|
|
),
|
|
tr: ({ children, ...props }: any) => (
|
|
<tr {...props} className="hover:bg-neutral-50/50 transition-colors">
|
|
{children}
|
|
</tr>
|
|
),
|
|
th: ({ children, ...props }: any) => (
|
|
<th {...props} className="px-6 py-4 whitespace-nowrap">
|
|
{children}
|
|
</th>
|
|
),
|
|
td: ({ children, ...props }: any) => (
|
|
<td {...props} className="px-6 py-4">
|
|
{children}
|
|
</td>
|
|
),
|
|
};
|