| 1 | <%# locals: diff (raw unified-diff text) %> |
| 2 | <% |
| 3 | file_diffs = [] |
| 4 | current = nil |
| 5 | |
| 6 | diff.to_s.each_line do |line| |
| 7 | if line.start_with?("diff --git ") |
| 8 | file_diffs << current if current |
| 9 | current = { header: line, lines: [] } |
| 10 | elsif current |
| 11 | current[:lines] << line |
| 12 | end |
| 13 | end |
| 14 | file_diffs << current if current |
| 15 | %> |
| 16 | |
| 17 | <% if file_diffs.empty? %> |
| 18 | <p class="text-sm text-gray-400">No changes.</p> |
| 19 | <% else %> |
| 20 | <% |
| 21 | total_additions = 0 |
| 22 | total_deletions = 0 |
| 23 | file_diffs.each do |fd| |
| 24 | total_additions += fd[:lines].count { |l| l.start_with?("+") && !l.start_with?("+++") } |
| 25 | total_deletions += fd[:lines].count { |l| l.start_with?("-") && !l.start_with?("---") } |
| 26 | end |
| 27 | %> |
| 28 | |
| 29 | <div class="text-xs text-gray-400 mb-4"> |
| 30 | <span class="text-gray-300 font-medium"><%= file_diffs.size %> <%= "file".pluralize(file_diffs.size) %> changed</span> |
| 31 | <% if total_additions > 0 %> |
| 32 | <span class="text-green-400 ml-2">+<%= total_additions %></span> |
| 33 | <% end %> |
| 34 | <% if total_deletions > 0 %> |
| 35 | <span class="text-red-400 ml-1">-<%= total_deletions %></span> |
| 36 | <% end %> |
| 37 | </div> |
| 38 | |
| 39 | <div class="space-y-3"> |
| 40 | <% file_diffs.each do |fd| %> |
| 41 | <% |
| 42 | m = fd[:header].match(/diff --git a\/(.*) b\/(.*)/) |
| 43 | filename = m ? m[2].chomp : fd[:header].chomp |
| 44 | additions = fd[:lines].count { |l| l.start_with?("+") && !l.start_with?("+++") } |
| 45 | deletions = fd[:lines].count { |l| l.start_with?("-") && !l.start_with?("---") } |
| 46 | %> |
| 47 | |
| 48 | <details class="card overflow-hidden group" open> |
| 49 | <summary class="flex items-center justify-between px-4 py-2.5 border-b border-surface-600 bg-surface-700 cursor-pointer list-none hover:bg-surface-600 transition-colors"> |
| 50 | <div class="flex items-center gap-2 min-w-0"> |
| 51 | <svg class="w-3.5 h-3.5 text-gray-500 shrink-0 transition-transform group-open:rotate-90" viewBox="0 0 16 16" fill="currentColor"> |
| 52 | <path d="M6.22 3.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L9.94 8 6.22 4.28a.75.75 0 0 1 0-1.06Z"/> |
| 53 | </svg> |
| 54 | <span class="font-mono text-xs text-gray-200 truncate"><%= filename %></span> |
| 55 | </div> |
| 56 | <div class="flex items-center gap-2 shrink-0 ml-4 font-mono text-xs"> |
| 57 | <% if additions > 0 %> |
| 58 | <span class="text-green-400">+<%= additions %></span> |
| 59 | <% end %> |
| 60 | <% if deletions > 0 %> |
| 61 | <span class="text-red-400">-<%= deletions %></span> |
| 62 | <% end %> |
| 63 | </div> |
| 64 | </summary> |
| 65 | |
| 66 | <div class="font-mono text-xs leading-5 overflow-x-auto"> |
| 67 | <% fd[:lines].each do |line| %> |
| 68 | <% css = if line.start_with?("+") && !line.start_with?("+++") |
| 69 | "diff-add block px-4" |
| 70 | elsif line.start_with?("-") && !line.start_with?("---") |
| 71 | "diff-remove block px-4" |
| 72 | elsif line.start_with?("@@") |
| 73 | "diff-header block px-4" |
| 74 | else |
| 75 | "block px-4 text-gray-500" |
| 76 | end %> |
| 77 | <span class="<%= css %>"><%= line.chomp %></span> |
| 78 | <% end %> |
| 79 | </div> |
| 80 | </details> |
| 81 | <% end %> |
| 82 | </div> |
| 83 | <% end %> |