mirror of
https://github.com/SamyRai/tercul-frontend.git
synced 2025-12-27 02:31:34 +00:00
Adds typography components (Heading, Paragraph, BlockQuote, CodeBlock, Prose) with variants and updates COMPONENT-IMPLEMENTATION-TRACKER.md. Replit-Commit-Author: Agent Replit-Commit-Session-Id: bddfbb2b-6d6b-457b-b18c-05792cdaa035 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/39b5c689-6e8a-4d5a-9792-69cc81a56534/d046f5ac-7f62-419b-8fdb-893187a139f2.jpg
157 lines
3.9 KiB
TypeScript
157 lines
3.9 KiB
TypeScript
import { forwardRef } from "react";
|
|
import { cn } from "@/lib/utils";
|
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
|
|
/**
|
|
* Code Block component for displaying code snippets and inline code
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* <CodeBlock>const greeting = "Hello, world!";</CodeBlock>
|
|
*
|
|
* <CodeBlock variant="inline">const x = 10;</CodeBlock>
|
|
*
|
|
* <CodeBlock language="python" showLineNumbers>
|
|
* def hello_world():
|
|
* print("Hello, world!")
|
|
* </CodeBlock>
|
|
* ```
|
|
*/
|
|
|
|
const codeBlockVariants = cva(
|
|
"font-mono text-sm rounded-md",
|
|
{
|
|
variants: {
|
|
variant: {
|
|
default: "bg-muted text-foreground p-4 overflow-x-auto",
|
|
inline: "bg-muted px-1.5 py-0.5 text-primary-foreground",
|
|
terminal: "bg-black text-white p-4",
|
|
},
|
|
language: {
|
|
none: "",
|
|
js: "",
|
|
ts: "",
|
|
jsx: "",
|
|
tsx: "",
|
|
html: "",
|
|
css: "",
|
|
python: "",
|
|
ruby: "",
|
|
java: "",
|
|
csharp: "",
|
|
go: "",
|
|
rust: "",
|
|
php: "",
|
|
swift: "",
|
|
shell: "",
|
|
sql: "",
|
|
markdown: "",
|
|
json: "",
|
|
yaml: "",
|
|
},
|
|
},
|
|
defaultVariants: {
|
|
variant: "default",
|
|
language: "none",
|
|
},
|
|
}
|
|
);
|
|
|
|
export interface CodeBlockProps
|
|
extends React.HTMLAttributes<HTMLPreElement>,
|
|
VariantProps<typeof codeBlockVariants> {
|
|
/**
|
|
* Whether to show line numbers
|
|
*/
|
|
showLineNumbers?: boolean;
|
|
/**
|
|
* Whether this is a single line of code (uses inline styling)
|
|
*/
|
|
inline?: boolean;
|
|
/**
|
|
* Optional title for the code block
|
|
*/
|
|
title?: string;
|
|
}
|
|
|
|
const CodeBlock = forwardRef<HTMLPreElement, CodeBlockProps>(
|
|
({
|
|
className,
|
|
variant = "default",
|
|
language,
|
|
showLineNumbers = false,
|
|
inline = false,
|
|
title,
|
|
children,
|
|
...props
|
|
}, ref) => {
|
|
// If inline is true, override variant to "inline"
|
|
const actualVariant = inline ? "inline" : variant;
|
|
|
|
// If inline, render as inline code element
|
|
if (inline) {
|
|
return (
|
|
<code
|
|
className={cn(codeBlockVariants({ variant: actualVariant, language, className }))}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</code>
|
|
);
|
|
}
|
|
|
|
// Process code content for line numbers if needed
|
|
let codeContent = children;
|
|
if (showLineNumbers && typeof children === 'string') {
|
|
const lines = children.toString().trim().split('\n');
|
|
const lineCount = lines.length;
|
|
const lineNumberWidth = lineCount.toString().length;
|
|
|
|
codeContent = (
|
|
<div className="flex">
|
|
<div className="flex-none pr-4 text-muted-foreground select-none border-r border-muted-foreground/20 mr-4">
|
|
{lines.map((_, idx) => (
|
|
<div key={idx} className="text-right">
|
|
{(idx + 1).toString().padStart(lineNumberWidth, ' ')}
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div className="flex-1">
|
|
{lines.map((line, idx) => (
|
|
<div key={idx}>{line || ' '}</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="relative my-6 rounded-md overflow-hidden">
|
|
{title && (
|
|
<div className="bg-muted-foreground/10 text-muted-foreground px-4 py-1.5 text-sm font-medium border-b border-border">
|
|
{title}
|
|
</div>
|
|
)}
|
|
<pre
|
|
className={cn(
|
|
codeBlockVariants({ variant: actualVariant, language, className }),
|
|
showLineNumbers && "pl-0"
|
|
)}
|
|
ref={ref}
|
|
{...props}
|
|
>
|
|
{language && (
|
|
<div className="absolute right-2 top-2 bg-muted-foreground/20 text-muted-foreground px-2 py-0.5 rounded text-xs uppercase">
|
|
{language}
|
|
</div>
|
|
)}
|
|
{codeContent}
|
|
</pre>
|
|
</div>
|
|
);
|
|
}
|
|
);
|
|
|
|
CodeBlock.displayName = "CodeBlock";
|
|
|
|
export { CodeBlock, codeBlockVariants }; |