feat(FN-683): add diff syntax highlighting with background colors

- Add highlightDiff utility React component for diff rendering
- Add CSS styles for diff-add (green), diff-del (red), diff-hunk (blue) line highlighting
- Integrate highlightDiff in TaskChangesTab for inline diffs
- Integrate highlightDiff in ChangedFilesModal for file diffs
- Add unit tests for highlightDiff utility
This commit is contained in:
gsxdsm
2026-04-02 09:58:04 -07:00
parent 0d71541a4d
commit fa096cf518
5 changed files with 217 additions and 2 deletions

View File

@@ -0,0 +1,42 @@
import React from "react";
/**
* Highlights diff output by wrapping each line in a <span> with appropriate CSS classes.
*
* - Lines starting with `+` (but not `+++`) → class `diff-add`
* - Lines starting with `-` (but not `---`) → class `diff-del`
* - Lines starting with `@@` → class `diff-hunk`
* - Context lines and other diff headers → no special class
*
* @param diff - The raw diff string to highlight
* @returns An array of React nodes with appropriate span wrappers
*/
export function highlightDiff(diff: string): React.ReactNode[] {
const lines = diff.split("\n");
return lines.map((line, index) => {
// Determine the class for this line based on its prefix
let className = "";
if (line.startsWith("+") && !line.startsWith("+++")) {
className = "diff-add";
} else if (line.startsWith("-") && !line.startsWith("---")) {
className = "diff-del";
} else if (line.startsWith("@@")) {
className = "diff-hunk";
}
// Wrap in a span if we have a class, otherwise return the line as-is
if (className) {
return (
<span key={index} className={className}>
{`${line}\n`}
</span>
);
}
// For lines without special classes, we still need to add the newline
// We use a fragment to avoid unnecessary wrapper elements
return <React.Fragment key={index}>{`${line}\n`}</React.Fragment>;
});
}