import { useMemo } from 'react'; import { diffLines } from 'diff'; import type { FileChangeSummary, SnippetDiff } from '@shared/types/review'; interface ReviewDiffContentProps { file: FileChangeSummary; } const SnippetDiffView = ({ snippet, index }: { snippet: SnippetDiff; index: number }) => { const diffResult = useMemo(() => { if (snippet.type === 'write-new') { // Весь файл — новый return diffLines('', snippet.newString); } if (snippet.type === 'write-update') { // Полная перезапись return diffLines('', snippet.newString); } return diffLines(snippet.oldString, snippet.newString); }, [snippet]); const toolLabel = snippet.type === 'write-new' ? 'New file' : snippet.type === 'write-update' ? 'Full rewrite' : snippet.type === 'multi-edit' ? 'Multi-edit' : 'Edit'; return (
{/* Заголовок snippet */}
#{index + 1} {toolLabel} {snippet.timestamp ? new Date(snippet.timestamp).toLocaleTimeString() : ''}
{/* Строки диффа */}
{diffResult.map((part, i) => { const lines = part.value.replace(/\n$/, '').split('\n'); return lines.map((line, j) => { let bgClass = ''; let prefix = ' '; let textClass = 'text-text-secondary'; if (part.added) { bgClass = 'bg-[var(--diff-added-bg,rgba(46,160,67,0.15))]'; prefix = '+'; textClass = 'text-[var(--diff-added-text,#3fb950)]'; } else if (part.removed) { bgClass = 'bg-[var(--diff-removed-bg,rgba(248,81,73,0.15))]'; prefix = '-'; textClass = 'text-[var(--diff-removed-text,#f85149)]'; } return (
{prefix} {line}
); }); })}
); }; export const ReviewDiffContent = ({ file }: ReviewDiffContentProps) => { const nonErrorSnippets = useMemo(() => file.snippets.filter((s) => !s.isError), [file.snippets]); return (
{/* Snippets */} {nonErrorSnippets.map((snippet, index) => ( ))} {nonErrorSnippets.length === 0 && (
No changes to display
)}
); };