import Image from 'next/image'; import Link from 'next/link'; import Balancer from 'react-wrap-balancer'; import { Callout } from '@/components/callout'; import { CodeBlock } from '@/components/code-block'; import { TableOfContents } from '@/components/table-of-contents'; import { Video } from '@/components/video'; import { cn } from '@/lib/utils'; /** * Use for internal links and for external links and anchors * and open external links in a new tab */ function a({ href, children }: React.HTMLProps) { if (href && href.startsWith('/')) { return {children}; } if (href && href.startsWith('#')) { return {children}; } return ( {children} ); } /** * Use div instead of p elements since p elements have restrictions on what * elements can be nested inside them */ function p(props: React.HTMLProps) { return
; } /** * Image component that uses next/image, with optional caption and width/height * Example usage: \!\[alt text {{ w: 600, h: 300, cap: "caption text" }}](/path/to/image) */ function img({ src, alt }: React.HTMLProps) { const _alt = (alt?.split('{')[0].trim() ?? alt) || ''; const props = alt?.split('{')[1]; const width = parseInt(props?.match(/w:\s*(\d+)/)?.[1] ?? '700'); const height = parseInt(props?.match(/h:\s*(\d+)/)?.[1] ?? '400'); const caption = props?.match(/cap:\s*"(.*?)"/)?.[1]; return (
{_alt} {caption && (
{caption}
)}
); } /** * Code block component with copy button */ function pre({ children }: React.HTMLProps) { return {children}; } export const MDXComponents = { a, p, img, pre, TableOfContents, Callout, Video };