shreyask's picture
Upload folder using huggingface_hub
7ac2545 verified
import type React from "react";
import { useState, useRef, useEffect } from "react";
import { Copy, Check } from "lucide-react";
import hljs from "highlight.js";
import "highlight.js/styles/github-dark.css";
interface CodeBlockProps {
language: string;
code: string;
}
const CodeBlock: React.FC<CodeBlockProps> = ({ language, code }) => {
const [copied, setCopied] = useState(false);
const codeRef = useRef<HTMLElement>(null);
useEffect(() => {
if (codeRef.current) {
codeRef.current.removeAttribute("data-highlighted");
hljs.highlightElement(codeRef.current);
}
}, [code, language]);
const handleCopy = async () => {
await navigator.clipboard.writeText(code);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<div className="rounded-xl overflow-hidden border border-white/10 bg-[#0d1117] my-3">
<div className="flex items-center justify-between px-4 py-2 bg-white/5 border-b border-white/10">
<span className="text-xs font-mono text-gray-400">
{language || "code"}
</span>
<button
onClick={handleCopy}
className="flex items-center gap-1.5 text-xs text-gray-400 hover:text-white transition-colors"
>
{copied ? <Check size={14} /> : <Copy size={14} />}
{copied ? "Copied" : "Copy"}
</button>
</div>
<pre className="p-4 overflow-x-auto text-sm leading-relaxed !bg-[#0d1117]">
<code ref={codeRef} className={language ? `language-${language}` : ""}>
{code}
</code>
</pre>
</div>
);
};
function looksLikeCode(text: string): boolean {
const result = hljs.highlightAuto(text);
return result.relevance > 5;
}
function parseContent(text: string): React.ReactNode[] {
const parts: React.ReactNode[] = [];
const codeBlockRegex = /```(\w*)\n([\s\S]*?)```/g;
let lastIndex = 0;
let match;
while ((match = codeBlockRegex.exec(text)) !== null) {
if (match.index > lastIndex) {
const textBefore = text.slice(lastIndex, match.index);
parts.push(
<span key={`text-${lastIndex}`} className="whitespace-pre-wrap">
{textBefore}
</span>,
);
}
parts.push(
<CodeBlock
key={`code-${match.index}`}
language={match[1]}
code={match[2].trimEnd()}
/>,
);
lastIndex = match.index + match[0].length;
}
if (lastIndex < text.length) {
const remaining = text.slice(lastIndex);
// If no code fences were found and the content looks like code, render as code block
if (lastIndex === 0 && remaining.trim().length > 0 && looksLikeCode(remaining)) {
const detected = hljs.highlightAuto(remaining);
parts.push(
<CodeBlock
key="code-auto"
language={detected.language || ""}
code={remaining.trimEnd()}
/>,
);
} else {
parts.push(
<span key={`text-${lastIndex}`} className="whitespace-pre-wrap">
{remaining}
</span>,
);
}
}
return parts;
}
export const ChatMessage: React.FC<{
role: "user" | "assistant";
content: string;
}> = ({ role, content }) => {
if (role === "user") {
return (
<div className="flex justify-end">
<div className="px-4 py-3 rounded-2xl max-w-lg bg-emerald-600/20 border border-emerald-500/30">
<p className="text-white whitespace-pre-wrap">{content}</p>
</div>
</div>
);
}
return (
<div className="flex justify-start">
<div className="px-4 py-3 rounded-2xl max-w-2xl bg-white/5 border border-white/10">
<div className="text-gray-200">{parseContent(content)}</div>
</div>
</div>
);
};