All files / src/components/marketing CodeBlock.tsx

10.34% Statements 3/29
0% Branches 0/19
0% Functions 0/8
11.53% Lines 3/26

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123                  1x                                                                                                               1x                                                         1x                                                        
import React from 'react';
import { Check, Copy } from 'lucide-react';
 
interface CodeBlockProps {
    code: string;
    language?: string;
    filename?: string;
}
 
const CodeBlock: React.FC<CodeBlockProps> = ({ code, language = 'python', filename }) => {
    const [copied, setCopied] = React.useState(false);
 
    const handleCopy = () => {
        navigator.clipboard.writeText(code);
        setCopied(true);
        setTimeout(() => setCopied(false), 2000);
    };
 
    return (
        <div className="rounded-xl overflow-hidden bg-gray-900 border border-gray-800 shadow-2xl">
            {/* Header */}
            <div className="flex items-center justify-between px-4 py-2 bg-gray-800/50 border-b border-gray-800">
                <div className="flex items-center gap-2">
                    <div className="flex gap-1.5">
                        <div className="w-3 h-3 rounded-full bg-red-500/20 border border-red-500/50" />
                        <div className="w-3 h-3 rounded-full bg-yellow-500/20 border border-yellow-500/50" />
                        <div className="w-3 h-3 rounded-full bg-green-500/20 border border-green-500/50" />
                    </div>
                    {filename && (
                        <span className="ml-2 text-xs font-medium text-gray-400 font-mono">
                            {filename}
                        </span>
                    )}
                </div>
                <button
                    onClick={handleCopy}
                    className="p-1.5 rounded-lg text-gray-400 hover:text-white hover:bg-gray-700/50 transition-colors"
                    title="Copy code"
                >
                    {copied ? <Check className="w-4 h-4 text-green-400" /> : <Copy className="w-4 h-4" />}
                </button>
            </div>
 
            {/* Code */}
            <div className="p-4 overflow-x-auto">
                <pre className="font-mono text-sm leading-relaxed">
                    <code className={`language-${language}`}>
                        {code.split('\n').map((line, i) => (
                            <div key={i} className="table-row">
                                <span className="table-cell text-right pr-4 select-none text-gray-700 w-8">
                                    {i + 1}
                                </span>
                                <span className="table-cell text-gray-300 whitespace-pre">
                                    {highlightSyntax(line)}
                                </span>
                            </div>
                        ))}
                    </code>
                </pre>
            </div>
        </div>
    );
};
 
// Simple syntax highlighting for Python/JSON
const highlightSyntax = (line: string) => {
    // Comments
    if (line.trim().startsWith('#') || line.trim().startsWith('//')) {
        return <span className="text-gray-500">{line}</span>;
    }
 
    // Strings
    const stringRegex = /(['"])(.*?)\1/g;
    const parts = line.split(stringRegex);
 
    if (parts.length > 1) {
        return (
            <>
                {parts.map((part, i) => {
                    // Every 3rd part is the quote, then content, then quote again
                    // This is a very naive implementation but works for simple marketing snippets
                    if (i % 3 === 1) return <span key={i} className="text-green-400">"{part}"</span>; // Content
                    if (i % 3 === 2) return null; // Closing quote (handled by regex split logic usually, but here we just color content)
 
                    // Keywords
                    return <React.Fragment key={i}>{highlightKeywords(part)}</React.Fragment>;
                })}
            </>
        );
    }
 
    return highlightKeywords(line);
};
 
const highlightKeywords = (text: string) => {
    const keywords = ['def', 'class', 'return', 'import', 'from', 'if', 'else', 'for', 'in', 'True', 'False', 'None'];
    const words = text.split(' ');
 
    return (
        <>
            {words.map((word, i) => {
                const isKeyword = keywords.includes(word.trim());
                const isFunction = word.includes('(');
 
                return (
                    <React.Fragment key={i}>
                        {isKeyword ? (
                            <span className="text-purple-400">{word}</span>
                        ) : isFunction ? (
                            <span className="text-blue-400">{word}</span>
                        ) : (
                            word
                        )}
                        {' '}
                    </React.Fragment>
                );
            })}
        </>
    );
};
 
export default CodeBlock;