e434c439c9
- Rename all component files to PascalCase matching exported names - Move components into feature directories (git/, session/, project/, terminal/, workspace/, ui/, layout/) - Rename all page files to PascalCase with Page suffix - Rename all API files to kebab-case - Update all imports across codebase with corrected relative depths - Preserve git history via git mv Quality gates: tsc (pass), eslint (pass), 66/74 tests pass (8 pre-existing failures) Refs: repo-restructure Task 4.4
78 lines
1.9 KiB
TypeScript
78 lines
1.9 KiB
TypeScript
import React, { useEffect, useState } from "react";
|
|
|
|
import { Icon } from "../../ui/Icon";
|
|
import { highlightCode, loadLanguage } from "../../../utils/language";
|
|
|
|
interface SyntaxHighlighterProps {
|
|
code: string;
|
|
language: string;
|
|
showLineNumbers?: boolean;
|
|
}
|
|
|
|
export const SyntaxHighlighter: React.FC<SyntaxHighlighterProps> = ({
|
|
code,
|
|
language,
|
|
showLineNumbers = true,
|
|
}) => {
|
|
const [highlighted, setHighlighted] = useState(">");
|
|
const [copied, setCopied] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const highlight = async () => {
|
|
await loadLanguage(language);
|
|
setHighlighted(highlightCode(code, language));
|
|
};
|
|
void highlight();
|
|
}, [code, language]);
|
|
|
|
const handleCopy = async () => {
|
|
await navigator.clipboard.writeText(code);
|
|
setCopied(true);
|
|
setTimeout(() => setCopied(false), 2000);
|
|
};
|
|
|
|
const lines = code.split("\n");
|
|
|
|
return (
|
|
<div className="syntax-highlighter">
|
|
<div className="highlighter-toolbar">
|
|
<span className="language-badge">{language}</span>
|
|
<button
|
|
className="copy-button"
|
|
onClick={handleCopy}
|
|
type="button"
|
|
>
|
|
{copied ? (
|
|
<>
|
|
<Icon name="success" size="sm" />
|
|
Copied!
|
|
</>
|
|
) : (
|
|
<>
|
|
<Icon name="copy" size="sm" />
|
|
Copy
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
<div className="code-container">
|
|
{showLineNumbers && (
|
|
<div className="line-numbers">
|
|
{lines.map((_, i) => (
|
|
<div key={i} className="line-number">
|
|
{i + 1}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
<pre className="code-block">
|
|
<code
|
|
className={`language-${language}`}
|
|
dangerouslySetInnerHTML={{ __html: highlighted }}
|
|
/>
|
|
</pre>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|