+59
-16
appview/pages/templates/fragments/diff.html
+59
-16
appview/pages/templates/fragments/diff.html
···
8
{{ $this := $commit.This }}
9
{{ $parent := $commit.Parent }}
10
11
{{ $last := sub (len $diff) 1 }}
12
{{ range $idx, $hunk := $diff }}
13
{{ with $hunk }}
···
32
{{ else }}
33
<span class="bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300 {{ $markerstyle }}">MODIFIED</span>
34
{{ end }}
35
36
{{ if .IsDelete }}
37
<a class="dark:text-white whitespace-nowrap overflow-x-auto" {{if $this }}href="/{{ $repo }}/blob/{{ $this }}/{{ .Name.Old }}"{{end}}>
···
72
73
<div class="transition-all duration-700 ease-in-out">
74
{{ if .IsDelete }}
75
-
<p class="text-center text-gray-400 dark:text-gray-500 p-4">
76
-
This file has been deleted in this commit.
77
-
</p>
78
{{ else }}
79
-
{{ if .IsBinary }}
80
-
<p class="text-center text-gray-400 dark:text-gray-500 p-4">
81
-
This is a binary file and will not be displayed.
82
-
</p>
83
-
{{ else }}
84
<pre class="overflow-x-auto"><div class="overflow-x-auto"><div class="min-w-full inline-block">{{- range .TextFragments -}}<div class="bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400 select-none text-center">···</div>
85
{{- $oldStart := .OldPosition -}}
86
{{- $newStart := .NewPosition -}}
87
-
{{- $lineNrStyle := "min-w-[3rem] flex-shrink-0 select-none text-right" -}}
88
-
{{- $lineNrSepStyle1 := "text-gray-400 dark:text-gray-500 bg-white dark:bg-gray-800" -}}
89
-
{{- $lineNrSepStyle2 := "text-gray-400 dark:text-gray-500 bg-white dark:bg-gray-800 pr-2" -}}
90
{{- range .Lines -}}
91
{{- if eq .Op.String "+" -}}
92
<div class="bg-green-100 dark:bg-green-800/30 text-green-700 dark:text-green-400 flex min-w-full items-center">
93
<div class="{{$lineNrStyle}} {{$lineNrSepStyle1}}"><span aria-hidden="true" class="invisible">{{$newStart}}</span></div>
94
-
<div class="{{$lineNrStyle}} {{$lineNrSepStyle2}}">{{ $newStart }}</div>
95
<div class="w-5 flex-shrink-0 select-none text-center">{{ .Op.String }}</div>
96
<div class="px-2">{{ .Line }}</div>
97
</div>
···
99
{{- end -}}
100
{{- if eq .Op.String "-" -}}
101
<div class="bg-red-100 dark:bg-red-800/30 text-red-700 dark:text-red-400 flex min-w-full items-center">
102
-
<div class="{{$lineNrStyle}} {{$lineNrSepStyle1}}">{{ $oldStart }}</div>
103
<div class="{{$lineNrStyle}} {{$lineNrSepStyle2}}"><span aria-hidden="true" class="invisible">{{$oldStart}}</span></div>
104
<div class="w-5 flex-shrink-0 select-none text-center">{{ .Op.String }}</div>
105
<div class="px-2">{{ .Line }}</div>
···
108
{{- end -}}
109
{{- if eq .Op.String " " -}}
110
<div class="bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400 flex min-w-full items-center">
111
-
<div class="{{$lineNrStyle}} {{$lineNrSepStyle1}}">{{ $oldStart }}</div>
112
-
<div class="{{$lineNrStyle}} {{$lineNrSepStyle2}}">{{ $newStart }}</div>
113
<div class="w-5 flex-shrink-0 select-none text-center">{{ .Op.String }}</div>
114
<div class="px-2">{{ .Line }}</div>
115
</div>
···
119
{{- end -}}
120
{{- end -}}</div></div></pre>
121
{{- end -}}
122
-
{{ end }}
123
</div>
124
125
</details>
···
130
{{ end }}
131
{{ end }}
132
{{ end }}
···
8
{{ $this := $commit.This }}
9
{{ $parent := $commit.Parent }}
10
11
+
<section class="mt-6 p-6 border border-gray-200 dark:border-gray-700 w-full mx-auto rounded bg-white dark:bg-gray-800 drop-shadow-sm">
12
+
<div class="diff-stat">
13
+
<div class="flex gap-2 items-center">
14
+
<strong class="text-sm uppercase dark:text-gray-200">Changed files</strong>
15
+
{{ block "statPill" $stat }} {{ end }}
16
+
</div>
17
+
<div class="overflow-x-auto">
18
+
{{ range $diff }}
19
+
<ul class="dark:text-gray-200">
20
+
{{ if .IsDelete }}
21
+
<li><a href="#file-{{ .Name.Old }}" class="dark:hover:text-gray-300">{{ .Name.Old }}</a></li>
22
+
{{ else }}
23
+
<li><a href="#file-{{ .Name.New }}" class="dark:hover:text-gray-300">{{ .Name.New }}</a></li>
24
+
{{ end }}
25
+
</ul>
26
+
{{ end }}
27
+
</div>
28
+
</div>
29
+
</section>
30
+
31
{{ $last := sub (len $diff) 1 }}
32
{{ range $idx, $hunk := $diff }}
33
{{ with $hunk }}
···
52
{{ else }}
53
<span class="bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300 {{ $markerstyle }}">MODIFIED</span>
54
{{ end }}
55
+
56
+
{{ block "statPill" .Stats }} {{ end }}
57
58
{{ if .IsDelete }}
59
<a class="dark:text-white whitespace-nowrap overflow-x-auto" {{if $this }}href="/{{ $repo }}/blob/{{ $this }}/{{ .Name.Old }}"{{end}}>
···
94
95
<div class="transition-all duration-700 ease-in-out">
96
{{ if .IsDelete }}
97
+
<p class="text-center text-gray-400 dark:text-gray-500 p-4">
98
+
This file has been deleted.
99
+
</p>
100
+
{{ else if .IsCopy }}
101
+
<p class="text-center text-gray-400 dark:text-gray-500 p-4">
102
+
This file has been copied.
103
+
</p>
104
+
{{ else if .IsRename }}
105
+
<p class="text-center text-gray-400 dark:text-gray-500 p-4">
106
+
This file has been renamed.
107
+
</p>
108
+
{{ else if .IsBinary }}
109
+
<p class="text-center text-gray-400 dark:text-gray-500 p-4">
110
+
This is a binary file and will not be displayed.
111
+
</p>
112
{{ else }}
113
+
{{ $name := .Name.New }}
114
<pre class="overflow-x-auto"><div class="overflow-x-auto"><div class="min-w-full inline-block">{{- range .TextFragments -}}<div class="bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400 select-none text-center">···</div>
115
{{- $oldStart := .OldPosition -}}
116
{{- $newStart := .NewPosition -}}
117
+
{{- $lineNrStyle := "min-w-[3.5rem] flex-shrink-0 select-none text-right bg-white dark:bg-gray-800 scroll-mt-10 target:border target:border-amber-500 target:rounded " -}}
118
+
{{- $linkStyle := "text-gray-400 dark:text-gray-500 hover:underline" -}}
119
+
{{- $lineNrSepStyle1 := "" -}}
120
+
{{- $lineNrSepStyle2 := "pr-2" -}}
121
{{- range .Lines -}}
122
{{- if eq .Op.String "+" -}}
123
<div class="bg-green-100 dark:bg-green-800/30 text-green-700 dark:text-green-400 flex min-w-full items-center">
124
<div class="{{$lineNrStyle}} {{$lineNrSepStyle1}}"><span aria-hidden="true" class="invisible">{{$newStart}}</span></div>
125
+
<div class="{{$lineNrStyle}} {{$lineNrSepStyle2}}" id="{{$name}}-N{{$newStart}}"><a class="{{$linkStyle}}" href="#{{$name}}-N{{$newStart}}">{{ $newStart }}</a></div>
126
<div class="w-5 flex-shrink-0 select-none text-center">{{ .Op.String }}</div>
127
<div class="px-2">{{ .Line }}</div>
128
</div>
···
130
{{- end -}}
131
{{- if eq .Op.String "-" -}}
132
<div class="bg-red-100 dark:bg-red-800/30 text-red-700 dark:text-red-400 flex min-w-full items-center">
133
+
<div class="{{$lineNrStyle}} {{$lineNrSepStyle1}}" id="{{$name}}-O{{$oldStart}}"><a class="{{$linkStyle}}" href="#{{$name}}-O{{$oldStart}}">{{ $oldStart }}</a></div>
134
<div class="{{$lineNrStyle}} {{$lineNrSepStyle2}}"><span aria-hidden="true" class="invisible">{{$oldStart}}</span></div>
135
<div class="w-5 flex-shrink-0 select-none text-center">{{ .Op.String }}</div>
136
<div class="px-2">{{ .Line }}</div>
···
139
{{- end -}}
140
{{- if eq .Op.String " " -}}
141
<div class="bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400 flex min-w-full items-center">
142
+
<div class="{{$lineNrStyle}} {{$lineNrSepStyle1}}" id="{{$name}}-O{{$oldStart}}"><a class="{{$linkStyle}}" href="#{{$name}}-O{{$oldStart}}">{{ $oldStart }}</a></div>
143
+
<div class="{{$lineNrStyle}} {{$lineNrSepStyle2}}" id="{{$name}}-N{{$newStart}}"><a class="{{$linkStyle}}" href="#{{$name}}-N{{$newStart}}">{{ $newStart }}</a></div>
144
<div class="w-5 flex-shrink-0 select-none text-center">{{ .Op.String }}</div>
145
<div class="px-2">{{ .Line }}</div>
146
</div>
···
150
{{- end -}}
151
{{- end -}}</div></div></pre>
152
{{- end -}}
153
</div>
154
155
</details>
···
160
{{ end }}
161
{{ end }}
162
{{ end }}
163
+
164
+
{{ define "statPill" }}
165
+
<div class="flex items-center font-mono text-sm">
166
+
{{ if and .Insertions .Deletions }}
167
+
<span class="rounded-l p-1 select-none bg-green-100 text-green-700 dark:bg-green-800/50 dark:text-green-400">+{{ .Insertions }}</span>
168
+
<span class="rounded-r p-1 select-none bg-red-100 text-red-700 dark:bg-red-800/50 dark:text-red-400">-{{ .Deletions }}</span>
169
+
{{ else if .Insertions }}
170
+
<span class="rounded p-1 select-none bg-green-100 text-green-700 dark:bg-green-800/50 dark:text-green-400">+{{ .Insertions }}</span>
171
+
{{ else if .Deletions }}
172
+
<span class="rounded p-1 select-none bg-red-100 text-red-700 dark:bg-red-800/50 dark:text-red-400">-{{ .Deletions }}</span>
173
+
{{ end }}
174
+
</div>
175
+
{{ end }}
+1
-20
appview/pages/templates/repo/commit.html
+1
-20
appview/pages/templates/repo/commit.html
···
4
5
{{ $repo := .RepoInfo.FullName }}
6
{{ $commit := .Diff.Commit }}
7
-
{{ $stat := .Diff.Stat }}
8
-
{{ $diff := .Diff.Diff }}
9
10
<section class="commit dark:text-white">
11
<div id="commit-message">
···
13
<div>
14
<p class="pb-2">{{ index $messageParts 0 }}</p>
15
{{ if gt (len $messageParts) 1 }}
16
-
<p class="mt-1 cursor-text pb-2 text-sm">{{ nl2br (unwrapText (index $messageParts 1)) }}</p>
17
{{ end }}
18
</div>
19
</div>
···
29
{{ end }}
30
<span class="px-1 select-none before:content-['\00B7']"></span>
31
{{ timeFmt $commit.Author.When }}
32
-
<span class="px-1 select-none before:content-['\00B7']"></span>
33
-
<span>{{ $stat.FilesChanged }}</span> files <span class="font-mono">(+{{ $stat.Insertions }}, -{{ $stat.Deletions }})</span>
34
<span class="px-1 select-none before:content-['\00B7']"></span>
35
</p>
36
···
43
</p>
44
</div>
45
46
-
<div class="diff-stat">
47
-
<br>
48
-
<strong class="text-sm uppercase mb-4 dark:text-gray-200">Changed files</strong>
49
-
<div class="overflow-x-auto">
50
-
{{ range $diff }}
51
-
<ul class="dark:text-gray-200">
52
-
{{ if .IsDelete }}
53
-
<li><a href="#file-{{ .Name.Old }}" class="dark:hover:text-gray-300">{{ .Name.Old }}</a></li>
54
-
{{ else }}
55
-
<li><a href="#file-{{ .Name.New }}" class="dark:hover:text-gray-300">{{ .Name.New }}</a></li>
56
-
{{ end }}
57
-
</ul>
58
-
{{ end }}
59
-
</div>
60
-
</div>
61
</section>
62
63
{{end}}
···
4
5
{{ $repo := .RepoInfo.FullName }}
6
{{ $commit := .Diff.Commit }}
7
8
<section class="commit dark:text-white">
9
<div id="commit-message">
···
11
<div>
12
<p class="pb-2">{{ index $messageParts 0 }}</p>
13
{{ if gt (len $messageParts) 1 }}
14
+
<p class="mt-1 cursor-text pb-2 text-sm">{{ nl2br (index $messageParts 1) }}</p>
15
{{ end }}
16
</div>
17
</div>
···
27
{{ end }}
28
<span class="px-1 select-none before:content-['\00B7']"></span>
29
{{ timeFmt $commit.Author.When }}
30
<span class="px-1 select-none before:content-['\00B7']"></span>
31
</p>
32
···
39
</p>
40
</div>
41
42
</section>
43
44
{{end}}
+1
-1
appview/pages/templates/repo/index.html
+1
-1
appview/pages/templates/repo/index.html
+1
-1
appview/pages/templates/repo/issues/issues.html
+1
-1
appview/pages/templates/repo/issues/issues.html
···
4
<div class="flex justify-between items-center">
5
<p>
6
filtering
7
-
<select class="border px-1 bg-white border-gray-200 dark:bg-gray-800 dark:border-gray-700" onchange="window.location.href = '/{{ .RepoInfo.FullName }}/issues?state=' + this.value">
8
<option value="open" {{ if .FilteringByOpen }}selected{{ end }}>open ({{ .RepoInfo.Stats.IssueCount.Open }})</option>
9
<option value="closed" {{ if not .FilteringByOpen }}selected{{ end }}>closed ({{ .RepoInfo.Stats.IssueCount.Closed }})</option>
10
</select>
···
4
<div class="flex justify-between items-center">
5
<p>
6
filtering
7
+
<select class="border p-1 bg-white border-gray-200 dark:bg-gray-800 dark:border-gray-700" onchange="window.location.href = '/{{ .RepoInfo.FullName }}/issues?state=' + this.value">
8
<option value="open" {{ if .FilteringByOpen }}selected{{ end }}>open ({{ .RepoInfo.Stats.IssueCount.Open }})</option>
9
<option value="closed" {{ if not .FilteringByOpen }}selected{{ end }}>closed ({{ .RepoInfo.Stats.IssueCount.Closed }})</option>
10
</select>
+1
-1
appview/pages/templates/repo/log.html
+1
-1
appview/pages/templates/repo/log.html
-13
appview/pages/templates/repo/pulls/patch.html
-13
appview/pages/templates/repo/pulls/patch.html
···
69
{{ end }}
70
</section>
71
72
-
<div id="diff-stat">
73
-
<br>
74
-
<strong class="text-sm uppercase mb-4">Changed files</strong>
75
-
{{ range .Diff.Diff }}
76
-
<ul>
77
-
{{ if .IsDelete }}
78
-
<li><a href="#file-{{ .Name.Old }}">{{ .Name.Old }}</a></li>
79
-
{{ else }}
80
-
<li><a href="#file-{{ .Name.New }}">{{ .Name.New }}</a></li>
81
-
{{ end }}
82
-
</ul>
83
-
{{ end }}
84
-
</div>
85
</div>
86
87
<section>
+1
-1
appview/pages/templates/repo/pulls/pull.html
+1
-1
appview/pages/templates/repo/pulls/pull.html
+1
-1
appview/pages/templates/repo/pulls/pulls.html
+1
-1
appview/pages/templates/repo/pulls/pulls.html
···
5
<p class="dark:text-white">
6
filtering
7
<select
8
-
class="border px-1 bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-600 dark:text-white"
9
onchange="window.location.href = '/{{ .RepoInfo.FullName }}/pulls?state=' + this.value"
10
>
11
<option value="open" {{ if .FilteringBy.IsOpen }}selected{{ end }}>
···
5
<p class="dark:text-white">
6
filtering
7
<select
8
+
class="border p-1 bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-600 dark:text-white"
9
onchange="window.location.href = '/{{ .RepoInfo.FullName }}/pulls?state=' + this.value"
10
>
11
<option value="open" {{ if .FilteringBy.IsOpen }}selected{{ end }}>
+4
-3
appview/pages/templates/repo/tree.html
+4
-3
appview/pages/templates/repo/tree.html
···
28
{{ $stats := .TreeStats }}
29
30
<span>at <a href="/{{ $.RepoInfo.FullName }}/tree/{{ $.Ref }}">{{ $.Ref }}</a></span>
31
-
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
32
{{ if eq $stats.NumFolders 1 }}
33
-
<span>{{ $stats.NumFolders }} folder</span>
34
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
35
{{ else if gt $stats.NumFolders 1 }}
36
<span>{{ $stats.NumFolders }} folders</span>
37
-
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
38
{{ end }}
39
40
{{ if eq $stats.NumFiles 1 }}
41
<span>{{ $stats.NumFiles }} file</span>
42
{{ else if gt $stats.NumFiles 1 }}
43
<span>{{ $stats.NumFiles }} files</span>
44
{{ end }}
45
···
28
{{ $stats := .TreeStats }}
29
30
<span>at <a href="/{{ $.RepoInfo.FullName }}/tree/{{ $.Ref }}">{{ $.Ref }}</a></span>
31
{{ if eq $stats.NumFolders 1 }}
32
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
33
+
<span>{{ $stats.NumFolders }} folder</span>
34
{{ else if gt $stats.NumFolders 1 }}
35
+
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
36
<span>{{ $stats.NumFolders }} folders</span>
37
{{ end }}
38
39
{{ if eq $stats.NumFiles 1 }}
40
+
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
41
<span>{{ $stats.NumFiles }} file</span>
42
{{ else if gt $stats.NumFiles 1 }}
43
+
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
44
<span>{{ $stats.NumFiles }} files</span>
45
{{ end }}
46
+14
types/diff.go
+14
types/diff.go
···
23
IsRename bool `json:"is_rename"`
24
}
25
26
+
type DiffStat struct {
27
+
Insertions int64
28
+
Deletions int64
29
+
}
30
+
31
+
func (d *Diff) Stats() DiffStat {
32
+
var stats DiffStat
33
+
for _, f := range d.TextFragments {
34
+
stats.Insertions += f.LinesAdded
35
+
stats.Deletions += f.LinesDeleted
36
+
}
37
+
return stats
38
+
}
39
+
40
// A nicer git diff representation.
41
type NiceDiff struct {
42
Commit struct {