Commit: 1732d66
Parent: 2be9313

Commit diffs

Mårten Åsberg committed on 2025-11-09 at 20:26
GitBrowser/Components/Pages/Commit.razor +105 -0
diff --git a/GitBrowser/Components/Pages/Commit.razor b/GitBrowser/Components/Pages/Commit.razor
index d726c68..4851364 100644
@@ -64,6 +64,40 @@ else if (commit != null)
</a>
</div>
</div>
@if (fileDiffs.Any())
{
<div class="diffs-container">
@foreach (var fileDiff in fileDiffs)
{
<div class="file-diff">
<div class="file-diff-header">
<span class="file-path">@fileDiff.Path</span>
<span class="file-stats">
<span class="stats-added">+@fileDiff.LinesAdded</span>
<span class="stats-deleted">-@fileDiff.LinesDeleted</span>
</span>
</div>
@if (fileDiff.IsLarge)
{
<div class="large-diff-warning">
Large diff (@(fileDiff.LinesAdded + fileDiff.LinesDeleted) lines changed) - not displayed
</div>
}
else
{
<div class="diff-content">
@foreach (var line in fileDiff.Lines)
{
<div class="diff-line diff-line-@line.Type">@line.Content</div>
}
</div>
}
</div>
}
</div>
}
</div>
}
@@ -77,6 +111,22 @@ else if (commit != null)
private bool notFound = false;
private string commitTitle = "";
private string commitBody = "";
private List<FileDiff> fileDiffs = new();
private class FileDiff
{
public string Path { get; set; } = "";
public int LinesAdded { get; set; }
public int LinesDeleted { get; set; }
public bool IsLarge { get; set; }
public List<DiffLine> Lines { get; set; } = new();
}
private class DiffLine
{
public string Type { get; set; } = ""; // "add", "del", "context", "hunk"
public string Content { get; set; } = "";
}
protected override void OnInitialized()
{
@@ -134,6 +184,29 @@ else if (commit != null)
{
// If we can't find a child, just continue
}
// Load diffs (including initial commit with no parents)
var parentTree = commit.Parents.Any() ? commit.Parents.First().Tree : null;
var patch = repo.Diff.Compare<Patch>(parentTree, commit.Tree);
foreach (var fileChange in patch)
{
var totalLines = fileChange.LinesAdded + fileChange.LinesDeleted;
var fileDiff = new FileDiff
{
Path = fileChange.Path,
LinesAdded = fileChange.LinesAdded,
LinesDeleted = fileChange.LinesDeleted,
IsLarge = totalLines > 1000
};
if (!fileDiff.IsLarge)
{
fileDiff.Lines = ParseDiff(fileChange.Patch);
}
fileDiffs.Add(fileDiff);
}
}
catch
{
@@ -141,6 +214,38 @@ else if (commit != null)
}
}
private List<DiffLine> ParseDiff(string patch)
{
var lines = new List<DiffLine>();
foreach (var line in patch.Split('\n'))
{
if (string.IsNullOrEmpty(line))
continue;
if (line.StartsWith("@@"))
{
lines.Add(new DiffLine { Type = "hunk", Content = line });
}
else if (line.StartsWith("+") && !line.StartsWith("+++"))
{
lines.Add(new DiffLine { Type = "add", Content = line.Substring(1) });
}
else if (line.StartsWith("-") && !line.StartsWith("---"))
{
lines.Add(new DiffLine { Type = "del", Content = line.Substring(1) });
}
else if (!line.StartsWith("+++") && !line.StartsWith("---"))
{
// Context line or other content
var content = line.StartsWith(" ") ? line.Substring(1) : line;
lines.Add(new DiffLine { Type = "context", Content = content });
}
}
return lines;
}
private void SetNotFound()
{
notFound = true;
GitBrowser/Components/Pages/Commit.razor.css +104 -0
diff --git a/GitBrowser/Components/Pages/Commit.razor.css b/GitBrowser/Components/Pages/Commit.razor.css
index f127a1e..23f33f9 100644
@@ -124,3 +124,107 @@ code {
.browse-button:hover {
background: #0860ca;
}
.diffs-container {
margin-top: 1.5rem;
}
.file-diff {
margin-bottom: 1.5rem;
border: 1px solid #d0d7de;
border-radius: 6px;
overflow: hidden;
}
.file-diff-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.75rem 1rem;
background: #f6f8fa;
border-bottom: 1px solid #d0d7de;
}
.file-path {
font-family: "Consolas", "Monaco", "Courier New", monospace;
font-size: 0.875rem;
font-weight: 600;
color: #24292f;
}
.file-stats {
display: flex;
gap: 0.75rem;
font-size: 0.875rem;
font-weight: 600;
}
.stats-added {
color: #1a7f37;
}
.stats-deleted {
color: #cf222e;
}
.large-diff-warning {
padding: 2rem;
text-align: center;
background: #fff8c5;
color: #7d4e00;
font-weight: 500;
border-top: 1px solid #d4a72c;
}
.diff-content {
background: white;
overflow-x: auto;
}
.diff-line {
font-family: "Consolas", "Monaco", "Courier New", monospace;
font-size: 0.875rem;
line-height: 1.5;
padding: 0 1rem;
white-space: pre;
}
.diff-line-add {
background: #e6ffec;
color: #24292f;
}
.diff-line-add::before {
content: "+";
color: #1a7f37;
padding-right: 1rem;
}
.diff-line-del {
background: #ffebe9;
color: #24292f;
}
.diff-line-del::before {
content: "-";
color: #cf222e;
padding-right: 1rem;
}
.diff-line-context {
color: #57606a;
}
.diff-line-context::before {
content: " ";
padding-right: 1rem;
}
.diff-line-hunk {
background: #f6f8fa;
color: #57606a;
padding: 0.25rem 1rem;
font-weight: 600;
border-top: 1px solid #d0d7de;
border-bottom: 1px solid #d0d7de;
}