web: the add/delete tint spans the whole diff row !86

merged merged by cmc on 2026-08-26 22:48 UTC · krz/gitbay:diff-row-tint into main

3 files changed, +16 −9

Layout: unified · split

e2e/diffweb_test.go +6 −1
@@ -83,9 +83,14 @@ func TestDiffRendering(t *testing.T) {
83 t.Error("diff content is not syntax highlighted") 83 t.Error("diff content is not syntax highlighted")
84 } 84 }
85 // The +/- markers are CSS, so a copied selection is real source. 85 // The +/- markers are CSS, so a copied selection is real source.
86 if strings.Contains(body, `<td class="code">+`) { 86 if strings.Contains(body, `<td class="src">+`) {
87 t.Error("diff markers are in the markup, not the stylesheet") 87 t.Error("diff markers are in the markup, not the stylesheet")
88 } 88 }
89 // The cell must not use .code: that class carries its own background,
90 // which would paint over the add/delete row tint.
91 if strings.Contains(body, `<td class="code">`) {
92 t.Error("diff cells use the blob code class, whose background hides the row tint")
93 }
89} 94}
90 95
91// jsonField pulls the first "name":"value" string out of a JSON blob. 96// jsonField pulls the first "name":"value" string out of a JSON blob.
internal/web/static/style.css +7 −5
@@ -945,16 +945,18 @@ table.difftable td.ln {
945 border-right: 1px solid var(--line); 945 border-right: 1px solid var(--line);
946 white-space: nowrap; 946 white-space: nowrap;
947} 947}
948table.difftable td.code { 948/* not .code: that class is the blob/code-block style and carries its own
949 background, which painted over every row tint */
950table.difftable td.src {
949 padding: 0 var(--sp-3); 951 padding: 0 var(--sp-3);
950 white-space: pre-wrap; 952 white-space: pre-wrap;
951 overflow-wrap: anywhere; 953 overflow-wrap: anywhere;
952} 954}
953/* the marker is decoration, so it lives in CSS and stays out of a copied 955/* the marker is decoration, so it lives in CSS and stays out of a copied
954 selection */ 956 selection */
955table.difftable tr.add td.code::before { content: "+"; color: var(--ok); } 957table.difftable tr.add td.src::before { content: "+"; color: var(--ok); }
956table.difftable tr.del td.code::before { content: "\2212"; color: var(--bad); } 958table.difftable tr.del td.src::before { content: "\2212"; color: var(--bad); }
957table.difftable tr.ctx td.code::before { content: " "; } 959table.difftable tr.ctx td.src::before { content: " "; }
958table.difftable tr.add { background: var(--diff-add); } 960table.difftable tr.add { background: var(--diff-add); }
959table.difftable tr.del { background: var(--diff-del); } 961table.difftable tr.del { background: var(--diff-del); }
960table.difftable tr.hunk td, table.difftable tr.dmeta td { 962table.difftable tr.hunk td, table.difftable tr.dmeta td {
@@ -964,7 +966,7 @@ table.difftable tr.hunk td, table.difftable tr.dmeta td {
964 border-top: 1px solid var(--line); 966 border-top: 1px solid var(--line);
965 border-bottom: 1px solid var(--line); 967 border-bottom: 1px solid var(--line);
966} 968}
967table.difftable tr.hunk td.code { color: var(--accent); } 969table.difftable tr.hunk td.src { color: var(--accent); }
968table.difftable tr.threadrow td { padding: var(--sp-2) var(--sp-3); background: var(--bg); } 970table.difftable tr.threadrow td { padding: var(--sp-2) var(--sp-3); background: var(--bg); }
969 971
970/* badges: signature and check states. Semantic colors stay distinct: 972/* badges: signature and check states. Semantic colors stay distinct:
internal/web/templates/layout.html +3 −3
@@ -126,9 +126,9 @@
126 </summary> 126 </summary>
127 {{if .Binary}}<p class="none">Binary file not shown.</p> 127 {{if .Binary}}<p class="none">Binary file not shown.</p>
128 {{else}}<div class="tablewrap"><table class="difftable"> 128 {{else}}<div class="tablewrap"><table class="difftable">
129 {{range .Lines}}{{if eq .Class "hunk"}}<tr class="hunk"><td class="ln" colspan="2"></td><td class="code">{{.Text}}</td></tr> 129 {{range .Lines}}{{if eq .Class "hunk"}}<tr class="hunk"><td class="ln" colspan="2"></td><td class="src">{{.Text}}</td></tr>
130 {{else if eq .Class "meta"}}<tr class="dmeta"><td class="ln" colspan="2"></td><td class="code">{{.Text}}</td></tr> 130 {{else if eq .Class "meta"}}<tr class="dmeta"><td class="ln" colspan="2"></td><td class="src">{{.Text}}</td></tr>
131 {{else}}<tr class="{{.Class}}"><td class="ln">{{if .OldLine}}{{.OldLine}}{{end}}</td><td class="ln">{{if .NewLine}}{{.NewLine}}{{end}}</td><td class="code">{{if .Code}}{{.Code}}{{else}}{{.Content}}{{end}}</td></tr> 131 {{else}}<tr class="{{.Class}}"><td class="ln">{{if .OldLine}}{{.OldLine}}{{end}}</td><td class="ln">{{if .NewLine}}{{.NewLine}}{{end}}</td><td class="src">{{if .Code}}{{.Code}}{{else}}{{.Content}}{{end}}</td></tr>
132 {{end}}{{range .Threads}}<tr class="threadrow"><td colspan="3"><div class="thread{{if .Resolved}} resolved{{end}}">{{if .Resolved}}<p class="threadstate">resolved by {{.Resolved}}</p>{{end}}{{range .Comments}}<p class="commenthead"><strong>{{.Author}}</strong> <span class="when">{{when .CreatedAt}}</span></p><div class="rendered">{{.BodyHTML}}</div>{{end}}{{template "threadact" dict "ID" .ID "Resolved" .Resolved "Base" $base "Can" $can}}</div></td></tr> 132 {{end}}{{range .Threads}}<tr class="threadrow"><td colspan="3"><div class="thread{{if .Resolved}} resolved{{end}}">{{if .Resolved}}<p class="threadstate">resolved by {{.Resolved}}</p>{{end}}{{range .Comments}}<p class="commenthead"><strong>{{.Author}}</strong> <span class="when">{{when .CreatedAt}}</span></p><div class="rendered">{{.BodyHTML}}</div>{{end}}{{template "threadact" dict "ID" .ID "Resolved" .Resolved "Base" $base "Can" $can}}</div></td></tr>
133 {{end}}{{end}} 133 {{end}}{{end}}
134 </table></div>{{end}} 134 </table></div>{{end}}