forked from
tangled.org/core
Monorepo for Tangled
1{{ define "repo/fragments/diff" }}
2 <style>
3 #filesToggle:checked ~ div label[for="filesToggle"] .show-text { display: none; }
4 #filesToggle:checked ~ div label[for="filesToggle"] .hide-text { display: inline; }
5 #filesToggle:not(:checked) ~ div label[for="filesToggle"] .hide-text { display: none; }
6 #filesToggle:checked ~ div div#files { width: fit-content; max-width: 15vw; margin-right: 1rem; }
7 #filesToggle:not(:checked) ~ div div#files { width: 0; display: none; margin-right: 0; }
8 </style>
9
10 {{ template "diffTopbar" . }}
11 {{ block "diffLayout" . }} {{ end }}
12{{ end }}
13
14{{ define "diffTopbar" }}
15 {{ $diff := index . 0 }}
16 {{ $opts := index . 1 }}
17 {{ $root := "" }}
18 {{ if gt (len .) 2 }}
19 {{ $root = index . 2 }}
20 {{ end }}
21
22 {{ block "filesCheckbox" $ }} {{ end }}
23 {{ block "subsCheckbox" $ }} {{ end }}
24
25 <!-- top bar -->
26 <div class="sticky top-0 z-30 bg-slate-100 dark:bg-gray-900 flex items-center gap-2 col-span-full h-12 p-2 {{ if $root }}mt-4{{ end }}">
27 <!-- left panel toggle -->
28 {{ template "filesToggle" . }}
29
30 <!-- stats -->
31 {{ $stat := $diff.Stats }}
32 {{ $count := len $diff.ChangedFiles }}
33 {{ template "repo/fragments/diffStatPill" $stat }}
34 <span class="text-xs text-gray-600 dark:text-gray-400 hidden md:inline-flex">{{ $count }} changed file{{ if ne $count 1 }}s{{ end }}</span>
35
36 {{ if $root }}
37 {{ if $root.IsInterdiff }}
38 <!-- interdiff indicator -->
39 <div class="flex items-center gap-2 before:content-['|'] before:text-gray-300 dark:before:text-gray-600 before:mr-2">
40 <span class="text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wide">Interdiff</span>
41 <a
42 href="/{{ $root.RepoInfo.FullName }}/pulls/{{ $root.Pull.PullId }}/round/{{ sub $root.ActiveRound 1 }}"
43 class="px-2 py-0.5 bg-white dark:bg-gray-700 rounded font-mono text-xs hover:bg-gray-50 dark:hover:bg-gray-600 border border-gray-300 dark:border-gray-600"
44 >
45 #{{ sub $root.ActiveRound 1 }}
46 </a>
47 <span class="text-gray-400 text-xs">→</span>
48 <a
49 href="/{{ $root.RepoInfo.FullName }}/pulls/{{ $root.Pull.PullId }}/round/{{ $root.ActiveRound }}"
50 class="px-2 py-0.5 bg-white dark:bg-gray-700 rounded font-mono text-xs hover:bg-gray-50 dark:hover:bg-gray-600 border border-gray-300 dark:border-gray-600"
51 >
52 #{{ $root.ActiveRound }}
53 </a>
54 </div>
55 {{ else if ne $root.ActiveRound nil }}
56 <!-- diff round indicator -->
57 <div class="flex items-center gap-2 before:content-['|'] before:text-gray-300 dark:before:text-gray-600 before:mr-2">
58 <span class="text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wide">Diff</span>
59 <span class="px-2 py-0.5 bg-white dark:bg-gray-700 rounded font-mono text-xs border border-gray-300 dark:border-gray-600">
60 <span class="hidden md:inline">round </span>#{{ $root.ActiveRound }}
61 </span>
62 </div>
63 {{ end }}
64 {{ end }}
65
66 <!-- spacer -->
67 <div class="flex-grow"></div>
68
69 <!-- collapse diffs -->
70 {{ template "collapseToggle" }}
71
72 <!-- diff options -->
73 {{ template "repo/fragments/diffOpts" $opts }}
74
75 <!-- right panel toggle -->
76 {{ block "subsToggle" $ }} {{ end }}
77 </div>
78
79{{ end }}
80
81{{ define "diffLayout" }}
82 {{ $diff := index . 0 }}
83 {{ $opts := index . 1 }}
84
85 <div class="flex col-span-full flex-grow">
86 <!-- left panel -->
87 <div id="files" class="w-0 hidden md:block overflow-hidden sticky top-12 max-h-screen overflow-y-auto pb-12">
88 <section class="overflow-x-auto text-sm px-6 py-2 border border-gray-200 dark:border-gray-700 w-full mx-auto min-h-full rounded bg-white dark:bg-gray-800 drop-shadow-sm">
89 {{ template "repo/fragments/fileTree" $diff.FileTree }}
90 </section>
91 </div>
92
93 <!-- main content -->
94 <div class="flex-1 min-w-0 sticky top-12 pb-12">
95 {{ template "diffFiles" (list $diff $opts) }}
96 </div>
97
98 </div>
99{{ end }}
100
101{{ define "diffFiles" }}
102 {{ $diff := index . 0 }}
103 {{ $opts := index . 1 }}
104 {{ $files := $diff.ChangedFiles }}
105 {{ $isSplit := $opts.Split }}
106 <div class="flex flex-col gap-4">
107 {{ if eq (len $files) 0 }}
108 <div class="text-center text-gray-500 dark:text-gray-400 py-8">
109 <p>No differences found between the selected revisions.</p>
110 </div>
111 {{ else }}
112 {{ range $idx, $file := $files }}
113 {{ template "diffFile" (list $idx $file $isSplit) }}
114 {{ end }}
115 {{ end }}
116 </div>
117{{ end }}
118
119{{ define "diffFile" }}
120 {{ $idx := index . 0 }}
121 {{ $file := index . 1 }}
122 {{ $isSplit := index . 2 }}
123 {{ with $file }}
124 <details open id="file-{{ .Id }}" class="group border border-gray-200 dark:border-gray-700 w-full mx-auto rounded bg-white dark:bg-gray-800 drop-shadow-sm" tabindex="{{ add $idx 1 }}">
125 <summary class="list-none cursor-pointer sticky top-12 group-open:border-b border-gray-200 dark:border-gray-700">
126 <div id="diff-file-header" class="rounded cursor-pointer bg-white dark:bg-gray-800 flex justify-between">
127 <div id="left-side-items" class="p-2 flex gap-2 items-center overflow-x-auto">
128 <span class="group-open:hidden inline">{{ i "chevron-right" "w-4 h-4" }}</span>
129 <span class="hidden group-open:inline">{{ i "chevron-down" "w-4 h-4" }}</span>
130 {{ template "repo/fragments/diffStatPill" .Stats }}
131
132 <div class="flex gap-2 items-center overflow-x-auto">
133 {{ $n := .Names }}
134 {{ if and $n.New $n.Old (ne $n.New $n.Old)}}
135 {{ $n.Old }} {{ i "arrow-right" "w-4 h-4" }} {{ $n.New }}
136 {{ else if $n.New }}
137 {{ $n.New }}
138 {{ else }}
139 {{ $n.Old }}
140 {{ end }}
141 </div>
142 </div>
143 </div>
144 </summary>
145
146 <div class="transition-all duration-700 ease-in-out">
147 {{ $reason := .CanRender }}
148 {{ if $reason }}
149 <p class="text-center text-gray-400 dark:text-gray-500 p-4">{{ $reason }}</p>
150 {{ else }}
151 {{ if $isSplit }}
152 {{- template "repo/fragments/splitDiff" .Split -}}
153 {{ else }}
154 {{- template "repo/fragments/unifiedDiff" . -}}
155 {{ end }}
156 {{- end -}}
157 </div>
158 </details>
159 {{ end }}
160{{ end }}
161
162{{ define "filesCheckbox" }}
163 <input type="checkbox" id="filesToggle" class="peer/files hidden" checked/>
164{{ end }}
165
166{{ define "filesToggle" }}
167 <label title="Toggle filetree panel" for="filesToggle" class="hidden md:inline-flex items-center justify-center rounded cursor-pointer text-normal font-normal normalcase">
168 <span class="show-text">{{ i "panel-left-open" "size-4" }}</span>
169 <span class="hide-text">{{ i "panel-left-close" "size-4" }}</span>
170 </label>
171{{ end }}
172
173{{ define "collapseToggle" }}
174 <label
175 title="Expand/Collapse diffs"
176 for="collapseToggle"
177 class="btn font-normal normal-case p-2"
178 >
179 <input type="checkbox" id="collapseToggle" class="peer/collapse hidden" checked/>
180 <span class="peer-checked/collapse:hidden inline-flex items-center gap-2">
181 {{ i "fold-vertical" "w-4 h-4" }}
182 <span class="hidden md:inline">expand all</span>
183 </span>
184 <span class="peer-checked/collapse:inline-flex hidden flex items-center gap-2">
185 {{ i "unfold-vertical" "w-4 h-4" }}
186 <span class="hidden md:inline">collapse all</span>
187 </span>
188 </label>
189 <script>
190 document.addEventListener('DOMContentLoaded', function() {
191 const checkbox = document.getElementById('collapseToggle');
192 const details = document.querySelectorAll('details[id^="file-"]');
193
194 checkbox.addEventListener('change', function() {
195 details.forEach(detail => {
196 detail.open = checkbox.checked;
197 });
198 });
199
200 details.forEach(detail => {
201 detail.addEventListener('toggle', function() {
202 const allOpen = Array.from(details).every(d => d.open);
203 const allClosed = Array.from(details).every(d => !d.open);
204
205 if (allOpen) {
206 checkbox.checked = true;
207 } else if (allClosed) {
208 checkbox.checked = false;
209 }
210 });
211 });
212 });
213 </script>
214{{ end }}