import ReactDiffViewer, { DiffMethod } from 'react-diff-viewer-continued' import { Highlight, themes } from 'prism-react-renderer' import { CopyButton } from '../shared/CopyButton' type Props = { filePath: string oldString: string newString: string } function inferLanguage(filePath: string): string { const ext = filePath.split('.').pop()?.toLowerCase() const langMap: Record = { ts: 'typescript', tsx: 'tsx', js: 'javascript', jsx: 'jsx', py: 'python', rs: 'rust', go: 'go', rb: 'ruby', json: 'json', yaml: 'yaml', yml: 'yaml', toml: 'toml', md: 'markdown', css: 'css', html: 'markup', xml: 'markup', sql: 'sql', sh: 'bash', bash: 'bash', zsh: 'bash', } return langMap[ext ?? ''] || 'text' } function highlightSyntax(str: string, language: string) { return ( {({ tokens, getTokenProps }) => ( <> {tokens.map((line, i) => ( {line.map((token, key) => ( ))} ))} )} ) } const diffStyles = { variables: { light: { diffViewerBackground: '#ffffff', diffViewerColor: '#24292f', addedBackground: '#dafbe1', addedColor: '#24292f', removedBackground: '#ffebe9', removedColor: '#24292f', wordAddedBackground: '#abf2bc', wordRemovedBackground: '#ff818266', addedGutterBackground: '#ccffd8', removedGutterBackground: '#ffd7d5', gutterBackground: '#f6f8fa', gutterBackgroundDark: '#f0f1f3', highlightBackground: '#fffbdd', highlightGutterBackground: '#fff5b1', codeFoldGutterBackground: '#dbedff', codeFoldBackground: '#f1f8ff', emptyLineBackground: '#fafbfc', gutterColor: '#8b949e', addedGutterColor: '#1a7f37', removedGutterColor: '#cf222e', codeFoldContentColor: '#57606a', diffViewerTitleBackground: '#fafbfc', diffViewerTitleColor: '#57606a', diffViewerTitleBorderColor: '#d0d7de', }, }, diffContainer: { borderRadius: '0', fontSize: '12px', lineHeight: '1.3', fontFamily: 'var(--font-mono)', }, line: { padding: '1px 0', }, gutter: { padding: '1px 8px', minWidth: '40px', fontSize: '11px', }, wordDiff: { padding: '1px 2px', borderRadius: '2px', }, } export function DiffViewer({ filePath, oldString, newString }: Props) { const language = inferLanguage(filePath) const oldLines = oldString.split('\n') const newLines = newString.split('\n') const additions = newLines.filter((l, i) => l !== (oldLines[i] ?? null)).length const deletions = oldLines.filter((l, i) => l !== (newLines[i] ?? null)).length return (
{filePath}
+{additions} -{deletions}
highlightSyntax(str, language)} hideLineNumbers={false} styles={diffStyles} useDarkTheme={false} />
) }