"use client";
import { useEffect, useRef, useState } from "react";
import { parsePatchFiles } from "@pierre/diffs";
import type { FileDiff as FileDiffRenderer, FileDiffMetadata } from "@pierre/diffs";
export type CommitDiffViewProps = {
patch: string;
};
export function CommitDiffView({ patch }: CommitDiffViewProps) {
const [diffStyle, setDiffStyle] = useState<"split" | "unified">("split");
if (!patch) {
return
No changes in this commit.
;
}
const parsed = parsePatchFiles(patch);
const files = parsed.flatMap((p) => p.files);
return (
{files.length} file{files.length !== 1 ? "s" : ""} changed
{files.map((fileDiff) => (
))}
);
}
function DiffFileRenderer({ fileDiff, diffStyle }: { fileDiff: FileDiffMetadata; diffStyle: "split" | "unified" }) {
const containerRef = useRef(null);
const instanceRef = useRef(null);
useEffect(() => {
let mounted = true;
async function render() {
const { FileDiff } = await import("@pierre/diffs");
if (!mounted || !containerRef.current) return;
if (instanceRef.current) {
instanceRef.current.cleanUp();
}
const instance = new FileDiff({
theme: "pierre-dark",
diffStyle,
diffIndicators: "bars",
hunkSeparators: "line-info",
overflow: "scroll",
});
instance.render({
fileDiff,
containerWrapper: containerRef.current,
});
instanceRef.current = instance;
}
render();
return () => {
mounted = false;
if (instanceRef.current) {
instanceRef.current.cleanUp();
instanceRef.current = null;
}
};
}, [fileDiff, diffStyle]);
return (
);
}