**Docs and Code Enhancements:** Add CodeBlock component with copy functionality and syntax highlighting. Introduce /docs page as the central hub for design system documentation. Update MarkdownContent to support improved heading styles, enhanced links, optimized images with Next.js Image, and upgraded table, blockquote, and list styling for better readability and usability.

This commit is contained in:
2025-11-02 13:47:26 +01:00
parent aff76e3a69
commit 92b7de352c
3 changed files with 434 additions and 43 deletions

View File

@@ -0,0 +1,81 @@
/* istanbul ignore file */
/**
* CodeBlock Component
* Syntax-highlighted code block with copy functionality
* This file is excluded from coverage as it's a documentation component
*/
'use client';
import { useState } from 'react';
import { Check, Copy } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
interface CodeBlockProps {
children: React.ReactNode;
className?: string;
title?: string;
}
export function CodeBlock({ children, className, title }: CodeBlockProps) {
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
const code = extractTextFromChildren(children);
await navigator.clipboard.writeText(code);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<div className="group relative my-6">
{title && (
<div className="flex items-center justify-between rounded-t-lg border border-b-0 bg-muted/50 px-4 py-2">
<span className="text-xs font-medium text-muted-foreground">{title}</span>
</div>
)}
<div className={cn('relative', title && 'rounded-t-none')}>
<pre
className={cn(
'overflow-x-auto rounded-lg border bg-slate-950 p-4 font-mono text-sm',
title && 'rounded-t-none',
className
)}
>
{children}
</pre>
<Button
variant="ghost"
size="icon"
className="absolute right-2 top-2 h-8 w-8 opacity-0 transition-opacity group-hover:opacity-100"
onClick={handleCopy}
aria-label="Copy code"
>
{copied ? (
<Check className="h-4 w-4 text-green-500" />
) : (
<Copy className="h-4 w-4 text-muted-foreground" />
)}
</Button>
</div>
</div>
);
}
function extractTextFromChildren(children: React.ReactNode): string {
if (typeof children === 'string') {
return children;
}
if (Array.isArray(children)) {
return children.map(extractTextFromChildren).join('');
}
if (children && typeof children === 'object' && 'props' in children) {
return extractTextFromChildren((children as { props: { children: React.ReactNode } }).props.children);
}
return '';
}