95 lines
2.7 KiB
TypeScript
95 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import { useMemo } from "react";
|
|
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
|
import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism";
|
|
import { useVisualization } from "./visualization-context";
|
|
|
|
interface CodePaneProps {
|
|
code: string;
|
|
language?: string;
|
|
}
|
|
|
|
export function CodePane({ code, language = "python" }: CodePaneProps) {
|
|
const { currentStep } = useVisualization();
|
|
|
|
const highlightedLines = useMemo(() => {
|
|
if (!currentStep?.codeHighlight) return new Set<number>();
|
|
const { startLine, endLine } = currentStep.codeHighlight;
|
|
const lines = new Set<number>();
|
|
for (let i = startLine; i <= endLine; i++) {
|
|
lines.add(i);
|
|
}
|
|
return lines;
|
|
}, [currentStep]);
|
|
|
|
const languageMap: Record<string, string> = {
|
|
python: "python",
|
|
javascript: "javascript",
|
|
typescript: "typescript",
|
|
java: "java",
|
|
cpp: "cpp",
|
|
c: "c",
|
|
go: "go",
|
|
rust: "rust",
|
|
};
|
|
|
|
const prismLanguage = languageMap[language.toLowerCase()] || language;
|
|
|
|
const customStyle = useMemo(
|
|
() => ({
|
|
margin: 0,
|
|
padding: "0.75rem 0",
|
|
fontSize: "0.8125rem",
|
|
borderRadius: "0.5rem",
|
|
background: "var(--code-bg, #282c34)",
|
|
}),
|
|
[]
|
|
);
|
|
|
|
return (
|
|
<div className="rounded-lg overflow-hidden border border-border">
|
|
<div className="bg-muted/50 px-3 py-1.5 border-b border-border">
|
|
<span className="text-xs font-medium text-muted-foreground capitalize">
|
|
{language}
|
|
</span>
|
|
</div>
|
|
<SyntaxHighlighter
|
|
language={prismLanguage}
|
|
style={oneDark}
|
|
customStyle={customStyle}
|
|
showLineNumbers
|
|
wrapLines
|
|
lineNumberStyle={(lineNumber) => ({
|
|
minWidth: "2.5em",
|
|
paddingRight: "1em",
|
|
textAlign: "right",
|
|
userSelect: "none",
|
|
color: highlightedLines.has(lineNumber)
|
|
? "var(--primary)"
|
|
: "var(--muted-foreground)",
|
|
fontWeight: highlightedLines.has(lineNumber) ? 600 : 400,
|
|
})}
|
|
lineProps={(lineNumber) => {
|
|
const isHighlighted = highlightedLines.has(lineNumber);
|
|
return {
|
|
style: {
|
|
display: "block",
|
|
padding: "0 0.75rem",
|
|
backgroundColor: isHighlighted
|
|
? "rgba(var(--primary-rgb, 59, 130, 246), 0.15)"
|
|
: "transparent",
|
|
borderLeft: isHighlighted
|
|
? "3px solid var(--primary)"
|
|
: "3px solid transparent",
|
|
transition: "background-color 0.2s ease, border-color 0.2s ease",
|
|
},
|
|
};
|
|
}}
|
|
>
|
|
{code.trim()}
|
|
</SyntaxHighlighter>
|
|
</div>
|
|
);
|
|
}
|