Spaces:
Running
Running
File size: 4,353 Bytes
7fa7b12 d08bef8 d6ab07d 7fa7b12 88d4eb1 7fa7b12 88d4eb1 7fa7b12 88d4eb1 7fa7b12 88d4eb1 7fa7b12 88d4eb1 7fa7b12 88d4eb1 7fa7b12 d6ab07d 7fa7b12 88d4eb1 7fa7b12 88d4eb1 d790df7 7fa7b12 d08bef8 7fa7b12 d08bef8 7fa7b12 88d4eb1 7fa7b12 88d4eb1 | 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 | import React, { useEffect, useRef } from 'react';
import { Check, Copy } from 'lucide-react';
import { logger } from '../utils/secureLogger';
interface CodeHighlightProps {
children: string;
language?: string;
className?: string;
}
export function CodeHighlight({ children, language = 'text', className = '' }: CodeHighlightProps) {
const codeRef = useRef<HTMLElement>(null);
const [copied, setCopied] = React.useState(false);
useEffect(() => {
if (codeRef.current && typeof window !== 'undefined') {
// Simple syntax highlighting for common languages
const code = codeRef.current;
const text = code.textContent || '';
if (language === 'javascript' || language === 'js') {
// Basic JS highlighting - adapted for light theme text contrast
code.innerHTML = text
.replace(/\b(const|let|var|function|return|if|else|for|while|class|import|export|from|default)\b/g, '<span class="text-[#5E6AD2] font-semibold">$1</span>')
.replace(/\b(true|false|null|undefined)\b/g, '<span class="text-amber-600 font-semibold">$1</span>')
.replace(/\b(console|log|error|warn)\b/g, '<span class="text-blue-600 font-semibold">$1</span>')
.replace(/"([^"]*)"/g, '<span class="text-emerald-600">"$1"</span>')
.replace(/'([^']*)'/g, '<span class="text-emerald-600">\'$1\'</span>')
.replace(/\b(\d+)\b/g, '<span class="text-teal-600">$1</span>');
} else if (language === 'python' || language === 'py') {
// Basic Python highlighting - adapted for light theme text contrast
code.innerHTML = text
.replace(/\b(def|class|import|from|return|if|else|elif|for|while|try|except|finally|with|as|in|is|None|True|False)\b/g, '<span class="text-[#5E6AD2] font-semibold">$1</span>')
.replace(/\b(print|len|str|int|float|list|dict|set)\b/g, '<span class="text-blue-600 font-semibold">$1</span>')
.replace(/"([^"]*)"/g, '<span class="text-emerald-600">"$1"</span>')
.replace(/'([^']*)'/g, '<span class="text-emerald-600">\'$1\'</span>')
.replace(/\b(\d+)\b/g, '<span class="text-teal-600">$1</span>');
} else if (language === 'html') {
// Basic HTML highlighting
code.innerHTML = text
.replace(/(<[^&]*>)/g, '<span class="text-blue-600">$1</span>')
.replace(/(<\/[^&]*>)/g, '<span class="text-blue-600">$1</span>')
.replace(/(\w+)=/g, '<span class="text-[#5E6AD2]">$1</span>=');
} else if (language === 'css') {
// Basic CSS highlighting
code.innerHTML = text
.replace(/([^{}]+)\s*{/g, '<span class="text-blue-600">$1</span> {')
.replace(/(\w+):/g, '<span class="text-[#5E6AD2]">$1</span>:')
.replace(/(#[0-9a-fA-F]{3,6})/g, '<span class="text-emerald-600">$1</span>');
}
}
}, [children, language]);
const copyToClipboard = async () => {
try {
await navigator.clipboard.writeText(children);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch (err) {
logger.error('Failed to copy text: ', err);
}
};
return (
<div className={`relative bg-slate-50 border border-slate-200 rounded overflow-hidden font-mono text-[11px] ${className}`}>
{/* Header */}
<div className="flex items-center justify-between px-4 py-2 bg-slate-100 border-b border-slate-200">
<span className="text-[10px] text-slate-400 uppercase font-bold tracking-widest">{language}</span>
<button
onClick={copyToClipboard}
className="inline-flex items-center gap-1 px-2 py-0.5 text-[10px] font-bold text-slate-500 hover:text-slate-900 transition-colors uppercase tracking-widest cursor-pointer"
title="Copy code"
>
{copied ? (
<>
<Check className="w-3 h-3 text-emerald-600" />
<span>Copied</span>
</>
) : (
<>
<Copy className="w-3 h-3" />
<span>Copy</span>
</>
)}
</button>
</div>
{/* Code */}
<pre className="p-4 m-0 overflow-x-auto">
<code
ref={codeRef}
className="text-slate-800 font-mono leading-relaxed"
>
{children}
</code>
</pre>
</div>
);
} |