96 lines
2.6 KiB
TypeScript
96 lines
2.6 KiB
TypeScript
'use client';
|
|
|
|
import { useMemo } from 'react';
|
|
import * as Diff from 'diff';
|
|
|
|
interface DiffViewerProps {
|
|
oldContent: string;
|
|
newContent: string;
|
|
}
|
|
|
|
interface DiffLine {
|
|
type: 'added' | 'removed' | 'unchanged';
|
|
content: string;
|
|
oldLineNum?: number;
|
|
newLineNum?: number;
|
|
}
|
|
|
|
export function DiffViewer({ oldContent, newContent }: DiffViewerProps) {
|
|
const diffLines = useMemo(() => {
|
|
const changes = Diff.diffLines(oldContent, newContent);
|
|
const lines: DiffLine[] = [];
|
|
let oldLineNum = 1;
|
|
let newLineNum = 1;
|
|
|
|
for (const change of changes) {
|
|
const changeLines = change.value.split('\n');
|
|
// Remove empty last line from split
|
|
if (changeLines[changeLines.length - 1] === '') {
|
|
changeLines.pop();
|
|
}
|
|
|
|
for (const line of changeLines) {
|
|
if (change.added) {
|
|
lines.push({
|
|
type: 'added',
|
|
content: line,
|
|
newLineNum: newLineNum++,
|
|
});
|
|
} else if (change.removed) {
|
|
lines.push({
|
|
type: 'removed',
|
|
content: line,
|
|
oldLineNum: oldLineNum++,
|
|
});
|
|
} else {
|
|
lines.push({
|
|
type: 'unchanged',
|
|
content: line,
|
|
oldLineNum: oldLineNum++,
|
|
newLineNum: newLineNum++,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return lines;
|
|
}, [oldContent, newContent]);
|
|
|
|
// Split into old and new columns
|
|
const oldLines = diffLines.filter(l => l.type !== 'added');
|
|
const newLines = diffLines.filter(l => l.type !== 'removed');
|
|
|
|
return (
|
|
<div className="diff-viewer">
|
|
<div className="diff-header">
|
|
<div className="diff-column-header">Previous Version</div>
|
|
<div className="diff-column-header">New Version</div>
|
|
</div>
|
|
<div className="diff-content">
|
|
<div className="diff-column diff-old">
|
|
{oldLines.map((line, i) => (
|
|
<div
|
|
key={i}
|
|
className={`diff-line ${line.type === 'removed' ? 'diff-removed' : ''}`}
|
|
>
|
|
<span className="diff-line-num">{line.oldLineNum || ''}</span>
|
|
<span className="diff-line-content">{line.content || '\u00A0'}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div className="diff-column diff-new">
|
|
{newLines.map((line, i) => (
|
|
<div
|
|
key={i}
|
|
className={`diff-line ${line.type === 'added' ? 'diff-added' : ''}`}
|
|
>
|
|
<span className="diff-line-num">{line.newLineNum || ''}</span>
|
|
<span className="diff-line-content">{line.content || '\u00A0'}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|