| // src/components/multimodal/CodeBlock.tsx | |
| import { useState, type ComponentType } from "react"; | |
| import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; | |
| import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism"; | |
| import { Copy, Check } from "lucide-react"; | |
| interface CodeBlockProps { | |
| code: string; | |
| language: string; | |
| maxLines?: number; | |
| } | |
| export function CodeBlock({ code, language, maxLines = 30 }: CodeBlockProps) { | |
| const [copied, setCopied] = useState(false); | |
| const [expanded, setExpanded] = useState(false); | |
| const Highlighter = SyntaxHighlighter as unknown as ComponentType<any>; | |
| const lines = code.split("\n"); | |
| const truncated = !expanded && lines.length > maxLines; | |
| const displayCode = truncated | |
| ? lines.slice(0, maxLines).join("\n") + `\n// ... ${lines.length - maxLines} more lines` | |
| : code; | |
| const handleCopy = async () => { | |
| await navigator.clipboard.writeText(code); | |
| setCopied(true); | |
| setTimeout(() => setCopied(false), 2000); | |
| }; | |
| return ( | |
| <div className="rounded-xl overflow-hidden border border-gray-200 dark:border-gray-700"> | |
| {/* Header */} | |
| <div className="flex items-center justify-between px-4 py-1.5 bg-gray-800 dark:bg-gray-900 text-gray-300 text-xs"> | |
| <span className="font-mono">{language}</span> | |
| <button | |
| onClick={handleCopy} | |
| className="flex items-center gap-1 hover:text-white transition" | |
| > | |
| {copied ? ( | |
| <> | |
| <Check className="w-3.5 h-3.5 text-green-400" /> Copied | |
| </> | |
| ) : ( | |
| <> | |
| <Copy className="w-3.5 h-3.5" /> Copy | |
| </> | |
| )} | |
| </button> | |
| </div> | |
| {/* Code */} | |
| <Highlighter | |
| language={language} | |
| style={oneDark} | |
| customStyle={{ | |
| margin: 0, | |
| padding: "1rem", | |
| fontSize: "0.8rem", | |
| borderRadius: "0 0 0.75rem 0.75rem", | |
| maxHeight: "400px", | |
| }} | |
| showLineNumbers={lines.length > 5} | |
| > | |
| {displayCode} | |
| </Highlighter> | |
| {/* Expand button */} | |
| {truncated && ( | |
| <button | |
| onClick={() => setExpanded(true)} | |
| className="w-full py-1.5 text-xs text-primary hover:bg-primary/5 transition" | |
| > | |
| Show all {lines.length} lines | |
| </button> | |
| )} | |
| </div> | |
| ); | |
| } | |
Xet Storage Details
- Size:
- 2.37 kB
- Xet hash:
- c6a3139bfa6b4fbd663c91e013b721dd3a0c17d5a1bd503b2e1a2dd3076693e3
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.