Files
codetutor/frontend/src/components/visualization/code-pane.tsx

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>
);
}