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(/(&lt;[^&]*&gt;)/g, '<span class="text-blue-600">$1</span>')
          .replace(/(&lt;\/[^&]*&gt;)/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>
  );
}