This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / appview / pages / templates / repo / fragments / diff.html
12 kB 307 lines
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; } 7 #filesToggle:not(:checked) ~ div div#files { width: 0; display: none; margin-right: 0; } 8 #filesToggle:not(:checked) ~ div div#resize-files { display: none; } 9 </style> 10 11 <div id="diff-area"> 12 {{ template "diffTopbar" . }} 13 {{ block "diffLayout" . }} {{ end }} 14 {{ template "fragments/resizable" }} 15 {{ template "activeFileHighlight" }} 16 {{ template "fragments/line-quote-button" }} 17 </div> 18{{ end }} 19 20{{ define "diffTopbar" }} 21 {{ $diff := index . 0 }} 22 {{ $opts := index . 1 }} 23 {{ $root := "" }} 24 {{ if gt (len .) 2 }} 25 {{ $root = index . 2 }} 26 {{ end }} 27 28 {{ block "filesCheckbox" $ }} {{ end }} 29 {{ block "subsCheckbox" $ }} {{ end }} 30 31 <!-- top bar --> 32 <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 }}"> 33 <!-- left panel toggle --> 34 {{ template "filesToggle" . }} 35 36 <!-- stats --> 37 {{ $stat := $diff.Stats }} 38 {{ $count := len $diff.ChangedFiles }} 39 {{ template "repo/fragments/diffStatPill" $stat }} 40 <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> 41 42 {{ if $root }} 43 {{ if $root.IsInterdiff }} 44 <!-- interdiff indicator --> 45 <div class="flex items-center gap-2 before:content-['|'] before:text-gray-300 dark:before:text-gray-600 before:mr-2"> 46 <span class="text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wide">Interdiff</span> 47 <a 48 href="/{{ $root.RepoInfo.FullName }}/pulls/{{ $root.Pull.PullId }}/round/{{ sub $root.ActiveRound 1 }}" 49 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" 50 > 51 #{{ sub $root.ActiveRound 1 }} 52 </a> 53 <span class="text-gray-400 text-xs"></span> 54 <a 55 href="/{{ $root.RepoInfo.FullName }}/pulls/{{ $root.Pull.PullId }}/round/{{ $root.ActiveRound }}" 56 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" 57 > 58 #{{ $root.ActiveRound }} 59 </a> 60 </div> 61 {{ else if ne $root.ActiveRound nil }} 62 <!-- diff round indicator --> 63 <div class="flex items-center gap-2 before:content-['|'] before:text-gray-300 dark:before:text-gray-600 before:mr-2"> 64 <span class="text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wide">Diff</span> 65 <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"> 66 <span class="hidden md:inline">round </span>#{{ $root.ActiveRound }} 67 </span> 68 </div> 69 {{ end }} 70 {{ end }} 71 72 <!-- spacer --> 73 <div class="flex-grow"></div> 74 75 <!-- collapse diffs --> 76 {{ template "collapseToggle" }} 77 78 <!-- diff options --> 79 {{ template "repo/fragments/diffOpts" $opts }} 80 81 <!-- right panel toggle --> 82 {{ block "subsToggle" $ }} {{ end }} 83 </div> 84 85{{ end }} 86 87{{ define "resize-grip" }} 88 {{ $id := index . 0 }} 89 {{ $target := index . 1 }} 90 {{ $direction := index . 2 }} 91 <div id="{{ $id }}" 92 data-resizer="vertical" 93 data-target="{{ $target }}" 94 data-direction="{{ $direction }}" 95 class="resizer-vertical hidden md:flex w-4 sticky top-12 max-h-screen flex-col items-center justify-center group"> 96 <div class="w-1 h-16 group-hover:h-24 group-[.resizing]:h-24 transition-all rounded-full bg-gray-400 dark:bg-gray-500 group-hover:bg-gray-500 group-hover:dark:bg-gray-400"></div> 97 </div> 98{{ end }} 99 100{{ define "diffLayout" }} 101 {{ $diff := index . 0 }} 102 {{ $opts := index . 1 }} 103 104 <div class="flex col-span-full flex-grow"> 105 <!-- left panel --> 106 <div id="files" class="w-0 hidden md:block overflow-hidden sticky top-12 max-h-screen overflow-y-auto pb-12"> 107 <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"> 108 {{ template "repo/fragments/fileTree" $diff.FileTree }} 109 </section> 110 </div> 111 112 {{ template "resize-grip" (list "resize-files" "files" "before") }} 113 114 <!-- main content --> 115 <div id="diff-files" class="flex-1 min-w-0 sticky top-12 pb-12"> 116 {{ template "diffFiles" (list $diff $opts) }} 117 </div> 118 119 </div> 120{{ end }} 121 122{{ define "diffFiles" }} 123 {{ $diff := index . 0 }} 124 {{ $opts := index . 1 }} 125 {{ $files := $diff.ChangedFiles }} 126 {{ $isSplit := $opts.Split }} 127 <div class="flex flex-col gap-4"> 128 {{ if eq (len $files) 0 }} 129 <div class="text-center text-gray-500 dark:text-gray-400 py-8"> 130 <p>No differences found between the selected revisions.</p> 131 </div> 132 {{ else }} 133 {{ range $idx, $file := $files }} 134 {{ template "diffFile" (list $idx $file $isSplit) }} 135 {{ end }} 136 {{ end }} 137 </div> 138{{ end }} 139 140{{ define "diffFile" }} 141 {{ $idx := index . 0 }} 142 {{ $file := index . 1 }} 143 {{ $isSplit := index . 2 }} 144 {{ $isGenerated := false }} 145 {{ $isDeleted := false }} 146 {{ with $file }} 147 {{ $n := .Names }} 148 {{ $isDeleted = and (eq $n.New "") (ne $n.Old "") }} 149 {{ if $n.New }} 150 {{ $isGenerated = isGenerated $n.New }} 151 {{ else if $n.Old }} 152 {{ $isGenerated = isGenerated $n.Old }} 153 {{ end }} 154 <details {{ if and (not $isGenerated) (not $isDeleted) }}open{{ end }} 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 }}"> 155 <summary class="list-none cursor-pointer sticky top-12 group-open:border-b border-gray-200 dark:border-gray-700"> 156 <div id="diff-file-header" class="rounded cursor-pointer bg-white dark:bg-gray-800 flex justify-between"> 157 <div id="left-side-items" class="p-2 flex gap-2 items-center overflow-x-auto"> 158 <span class="group-open:hidden inline">{{ i "chevron-right" "w-4 h-4" }}</span> 159 <span class="hidden group-open:inline">{{ i "chevron-down" "w-4 h-4" }}</span> 160 {{ template "repo/fragments/diffStatPill" .Stats }} 161 162 <div class="flex gap-2 items-center overflow-x-auto"> 163 {{ if and $n.New $n.Old (ne $n.New $n.Old)}} 164 {{ $n.Old }} {{ i "arrow-right" "w-4 h-4" }} {{ $n.New }} 165 {{ else if $n.New }} 166 {{ $n.New }} 167 {{ else }} 168 {{ $n.Old }} 169 {{ end }} 170 {{ if $isDeleted }} 171 <span class="text-gray-400 dark:text-gray-500" title="Deleted files are collapsed by default"> 172 {{ i "circle-question-mark" "size-4" }} 173 </span> 174 {{ else if $isGenerated }} 175 <span class="text-gray-400 dark:text-gray-500" title="Generated files are collapsed by default"> 176 {{ i "circle-question-mark" "size-4" }} 177 </span> 178 {{ end }} 179 </div> 180 </div> 181 </div> 182 </summary> 183 184 <div class="transition-all duration-700 ease-in-out"> 185 {{ $reason := .CanRender }} 186 {{ if $reason }} 187 <p class="text-center text-gray-400 dark:text-gray-500 p-4">{{ $reason }}</p> 188 {{ else }} 189 {{ if $isSplit }} 190 {{- template "repo/fragments/splitDiff" .Split -}} 191 {{ else }} 192 {{- template "repo/fragments/unifiedDiff" . -}} 193 {{ end }} 194 {{- end -}} 195 </div> 196 </details> 197 {{ end }} 198{{ end }} 199 200{{ define "filesCheckbox" }} 201 <input type="checkbox" id="filesToggle" class="peer/files hidden" checked/> 202{{ end }} 203 204{{ define "filesToggle" }} 205 <label title="Toggle filetree panel" for="filesToggle" class="hidden md:inline-flex items-center justify-center rounded cursor-pointer text-normal font-normal normalcase"> 206 <span class="show-text">{{ i "panel-left-open" "size-4" }}</span> 207 <span class="hide-text">{{ i "panel-left-close" "size-4" }}</span> 208 </label> 209{{ end }} 210 211{{ define "collapseToggle" }} 212 <label 213 title="Expand/Collapse diffs" 214 for="collapseToggle" 215 class="btn font-normal normal-case p-2" 216 > 217 <input type="checkbox" id="collapseToggle" class="peer/collapse hidden" checked/> 218 <span class="peer-checked/collapse:hidden inline-flex items-center gap-2"> 219 {{ i "fold-vertical" "w-4 h-4" }} 220 <span class="hidden md:inline">expand all</span> 221 </span> 222 <span class="peer-checked/collapse:inline-flex hidden flex items-center gap-2"> 223 {{ i "unfold-vertical" "w-4 h-4" }} 224 <span class="hidden md:inline">collapse all</span> 225 </span> 226 </label> 227 <script> 228 (() => { 229 const checkbox = document.getElementById('collapseToggle'); 230 const diffArea = document.getElementById('diff-area'); 231 232 checkbox.addEventListener('change', () => { 233 document.querySelectorAll('details[id^="file-"]').forEach(detail => { 234 detail.open = checkbox.checked; 235 }); 236 }); 237 238 if (window.__collapseToggleHandler) { 239 diffArea.removeEventListener('toggle', window.__collapseToggleHandler, true); 240 } 241 242 const handler = (e) => { 243 if (!e.target.matches('details[id^="file-"]')) return; 244 const details = document.querySelectorAll('details[id^="file-"]'); 245 const allOpen = Array.from(details).every(d => d.open); 246 const allClosed = Array.from(details).every(d => !d.open); 247 248 if (allOpen) checkbox.checked = true; 249 else if (allClosed) checkbox.checked = false; 250 }; 251 252 window.__collapseToggleHandler = handler; 253 diffArea.addEventListener('toggle', handler, true); 254 })(); 255 </script> 256{{ end }} 257 258{{ define "activeFileHighlight" }} 259 <script> 260 (() => { 261 if (window.__activeFileScrollHandler) { 262 document.removeEventListener('scroll', window.__activeFileScrollHandler); 263 } 264 265 const filetreeLinks = document.querySelectorAll('.filetree-link'); 266 if (filetreeLinks.length === 0) return; 267 268 const linkMap = new Map(); 269 filetreeLinks.forEach(link => { 270 const path = link.getAttribute('data-path'); 271 if (path) linkMap.set('file-' + path, link); 272 }); 273 274 let currentActive = null; 275 const setActive = (link) => { 276 if (link && link !== currentActive) { 277 if (currentActive) currentActive.classList.remove('font-bold'); 278 link.classList.add('font-bold'); 279 currentActive = link; 280 } 281 }; 282 283 filetreeLinks.forEach(link => { 284 link.addEventListener('click', () => setActive(link)); 285 }); 286 287 const topbar = document.querySelector('.sticky.top-0.z-30'); 288 const headerHeight = topbar ? topbar.offsetHeight : 0; 289 290 const updateActiveFile = () => { 291 const diffFiles = document.querySelectorAll('details[id^="file-"]'); 292 Array.from(diffFiles).some(file => { 293 const rect = file.getBoundingClientRect(); 294 if (rect.top <= headerHeight && rect.bottom > headerHeight) { 295 setActive(linkMap.get(file.id)); 296 return true; 297 } 298 return false; 299 }); 300 }; 301 302 window.__activeFileScrollHandler = updateActiveFile; 303 document.addEventListener('scroll', updateActiveFile); 304 updateActiveFile(); 305 })(); 306 </script> 307{{ end }}