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 / pulls / fragments / pullStepReview.html
28 kB 516 lines
1{{ define "repo/pulls/fragments/pullStepReview" }} 2 <section class="flex flex-col gap-3"> 3 {{ if not .Comparison }} 4 <div class="p-4 border border-gray-200 dark:border-gray-700 rounded bg-gray-50 dark:bg-gray-800/30 text-sm text-gray-600 dark:text-gray-400"> 5 {{ if eq .Source "patch" }} 6 Paste a patch above to see a comparison. 7 {{ else }} 8 Pick a source and target above to see a comparison. 9 {{ end }} 10 </div> 11 {{ else }} 12 {{ $commits := .Comparison.FormatPatch }} 13 {{ if $commits }} 14 <div class="flex flex-col gap-2"> 15 <div class="flex items-center justify-between gap-3 min-w-0 text-sm text-gray-500 dark:text-gray-400"> 16 {{ if .IsStacked }} 17 <span class="inline-flex items-center gap-2 flex-shrink-0 text-gray-900 dark:text-gray-100"> 18 {{ i "chevrons-down-up" "w-4 h-4" }} 19 <span>Stack</span> 20 <span class="text-gray-500 dark:text-gray-400">{{ len $commits }} pull request{{ if ne (len $commits) 1 }}s{{ end }}</span> 21 </span> 22 {{ else }} 23 <span class="flex-shrink-0">{{ len $commits }} commit{{ if ne (len $commits) 1 }}s{{ end }}</span> 24 {{ end }} 25 {{ if and .SourceBranch .TargetBranch }} 26 <span class="inline-flex items-center gap-2 font-mono text-gray-600 dark:text-gray-300 truncate"> 27 <span>{{ .TargetBranch }}</span> 28 {{ i "arrow-left-right" "w-4 h-4 flex-shrink-0" }} 29 <span>{{ .SourceBranch }}</span> 30 </span> 31 {{ end }} 32 </div> 33 {{ if .IsStacked }} 34 {{ template "pullReviewStackedCommits" . }} 35 {{ else }} 36 {{ template "pullReviewFlatCommits" . }} 37 {{ end }} 38 </div> 39 {{ else if ne .Source "patch" }} 40 <div class="p-4 border border-gray-200 dark:border-gray-700 rounded bg-gray-50 dark:bg-gray-800/30 text-sm text-gray-600 dark:text-gray-400"> 41 {{ if and .SourceBranch .TargetBranch (eq .SourceBranch .TargetBranch) }} 42 Source and target are the same branch, nothing to merge. 43 {{ else }} 44 No commits between target and source. Make sure your source branch has commits not on the target. 45 {{ end }} 46 </div> 47 {{ end }} 48 49 {{ if and .Diff (not .IsStacked) }} 50 {{ template "pullComposeFlatDiff" (list .Diff .DiffOpts) }} 51 {{ end }} 52 53 {{ if and .IsStacked $commits }} 54 {{ template "pullSubmitRow" . }} 55 {{ template "pullStackApplyAllScript" }} 56 {{ end }} 57 {{ end }} 58 </section> 59{{ end }} 60 61{{ define "pullStackApplyAllScript" }} 62 <script> 63 (() => { 64 const checkbox = document.getElementById('stack-apply-all'); 65 if (!checkbox || checkbox.dataset.applyAllWired === '1') return; 66 checkbox.dataset.applyAllWired = '1'; 67 68 const update = () => { 69 const panels = document.querySelectorAll('[data-stack-labels]'); 70 panels.forEach((panel, idx) => { 71 if (idx === 0) return; 72 panel.classList.toggle('hidden', checkbox.checked); 73 }); 74 }; 75 checkbox.addEventListener('change', update); 76 update(); 77 })(); 78 </script> 79{{ end }} 80 81{{ define "pullReviewFlatCommits" }} 82 {{ $commits := .Comparison.FormatPatch }} 83 <ul class="flex flex-col gap-2"> 84 {{ range $commits }} 85 <li class="border border-gray-200 dark:border-gray-700 rounded bg-white dark:bg-gray-800 px-3 py-2 flex items-center gap-3"> 86 <span class="text-gray-700 dark:text-gray-300 flex-shrink-0"> 87 {{ i "git-pull-request-create" "w-4 h-4" }} 88 </span> 89 <span class="flex-1 min-w-0 truncate text-sm dark:text-gray-200">{{ .Title }}</span> 90 {{ template "pullReviewCommitTimestamp" (dict "Patch" .) }} 91 <span class="-my-2 self-stretch w-px bg-gray-200 dark:bg-gray-700"></span> 92 {{ template "pullReviewCommitActions" (dict "Patch" . "RepoInfo" $.RepoInfo) }} 93 </li> 94 {{ end }} 95 </ul> 96{{ end }} 97 98{{ define "pullReviewStackedCommits" }} 99 {{ $root := . }} 100 {{ $commits := .Comparison.FormatPatch }} 101 {{ $hasSidePanel := and $root.LabelDefs $root.RepoInfo.Roles.IsPushAllowed }} 102 <ul class="flex flex-col gap-2"> 103 {{ range $idx, $p := $commits }} 104 {{ $cid := $p.ChangeIdOrEmpty }} 105 {{ $titleOverride := index $root.StackTitles $cid }} 106 {{ $bodyOverride := index $root.StackBodies $cid }} 107 {{ $displayTitle := $p.Title }} 108 {{ if $titleOverride }}{{ $displayTitle = $titleOverride }}{{ end }} 109 {{ $bodyValue := $p.Body }} 110 {{ if $bodyOverride }}{{ $bodyValue = $bodyOverride }}{{ end }} 111 {{ $perDiff := "" }} 112 {{ $perOpts := dict }} 113 {{ if lt $idx (len $root.StackedDiffs) }} 114 {{ $sd := index $root.StackedDiffs $idx }} 115 {{ $perDiff = $sd.Diff }} 116 {{ $perOpts = $sd.Opts }} 117 {{ end }} 118 <li> 119 <details class="group/stacked border border-gray-200 dark:border-gray-700 rounded bg-white dark:bg-gray-800"> 120 <summary class="p-3 cursor-pointer flex items-center gap-3 list-none"> 121 <span class="text-gray-700 dark:text-gray-300 flex-shrink-0"> 122 {{ i "chevron-right" "w-4 h-4 group-open/stacked:hidden inline" }} 123 {{ i "chevron-down" "w-4 h-4 hidden group-open/stacked:inline" }} 124 </span> 125 <span class="-my-3 self-stretch w-px bg-gray-200 dark:bg-gray-700"></span> 126 <span class="text-gray-700 dark:text-gray-300 flex-shrink-0"> 127 {{ i "git-pull-request-create" "w-4 h-4" }} 128 </span> 129 <span class="flex-1 min-w-0 truncate text-sm dark:text-gray-200">{{ $displayTitle }}</span> 130 {{ template "pullReviewCommitTimestamp" (dict "Patch" $p) }} 131 <span class="-my-3 self-stretch w-px bg-gray-200 dark:bg-gray-700"></span> 132 {{ template "pullReviewCommitActions" (dict "Patch" $p "RepoInfo" $root.RepoInfo) }} 133 </summary> 134 {{ if $cid }} 135 <div class="px-3 pb-3 pt-1 flex flex-col gap-3 border-t border-gray-100 dark:border-gray-700"> 136 {{ $titleName := printf "stackTitle[%s]" $cid }} 137 {{ $bodyName := printf "stackBody[%s]" $cid }} 138 {{ $blobName := printf "stackBlobs[%s]" $cid }} 139 <div class="flex flex-col md:flex-row gap-6"> 140 <div class="flex-1 min-w-0 flex flex-col gap-3"> 141 <div class="flex flex-col gap-1"> 142 <label class="text-xs tracking-wide text-gray-800 dark:text-gray-200">Title</label> 143 <input 144 type="text" 145 name="{{ $titleName }}" 146 value="{{ $displayTitle }}" 147 class="w-full dark:bg-gray-800 dark:text-white dark:border-gray-700" 148 placeholder="{{ $p.Title }}" 149 /> 150 </div> 151 {{ template "fragments/markdownEditor" (dict 152 "Name" $bodyName 153 "Value" $bodyValue 154 "BlobName" $blobName 155 "Rows" 4 156 "Placeholder" "Describe this pull request. Markdown is supported." 157 ) }} 158 </div> 159 {{ if $hasSidePanel }} 160 <aside data-stack-labels="{{ $cid }}" class="w-full md:w-72 md:flex-shrink-0 flex flex-col gap-4"> 161 {{ $labelState := $root.LabelState }} 162 {{ if $root.StackLabelStates }} 163 {{ $perCid := index $root.StackLabelStates $cid }} 164 {{ if $perCid }}{{ $labelState = $perCid }}{{ end }} 165 {{ end }} 166 {{ $labelCtx := dict "Defs" $root.LabelDefs "State" $labelState "RepoInfo" $root.RepoInfo "Subject" "" "LoggedInUser" $root.LoggedInUser "Prefix" (printf "stackLabel[%s]" $cid) }} 167 {{ template "editBasicLabels" $labelCtx }} 168 {{ template "editKvLabels" $labelCtx }} 169 {{ if eq $idx 0 }} 170 <label class="flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400 self-start"> 171 <input type="checkbox" id="stack-apply-all" name="applyLabelsToAll" autocomplete="off" /> 172 Apply labels and assignees to all PRs in stack 173 </label> 174 {{ end }} 175 </aside> 176 {{ end }} 177 </div> 178 {{ if $perDiff }} 179 <hr class="border-gray-200 dark:border-gray-700 my-1" /> 180 <div id="stack-diff-{{ $cid }}"> 181 <input type="hidden" name="stackSplit[{{ $cid }}]" value="{{ if $perOpts.Split }}split{{ else }}unified{{ end }}" /> 182 {{ template "pullStackedDiffArea" (dict "Diff" $perDiff "DiffOpts" $perOpts "Cid" $cid) }} 183 </div> 184 {{ end }} 185 </div> 186 {{ else }} 187 <div class="px-3 pb-3 pt-1 text-sm text-yellow-700 dark:text-yellow-300 border-t border-gray-100 dark:border-gray-700"> 188 This commit has no <span class="font-mono">Change-Id</span> header and can't be stacked. Set one on the commit and re-push. 189 </div> 190 {{ end }} 191 </details> 192 </li> 193 {{ end }} 194 </ul> 195{{ end }} 196 197{{ define "pullReviewCommitTimestamp" }} 198 {{ $p := .Patch }} 199 {{ if or (not $p.AuthorDate.IsZero) $p.SHA }} 200 <span class="flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400 flex-shrink-0"> 201 {{ if not $p.AuthorDate.IsZero }} 202 {{ template "repo/fragments/shortTimeAgo" $p.AuthorDate }} 203 {{ end }} 204 {{ if $p.SHA }} 205 <span class="font-mono bg-gray-100 dark:bg-gray-900 text-gray-700 dark:text-gray-300 px-2 py-0.5 rounded">{{ slice $p.SHA 0 8 }}</span> 206 {{ end }} 207 </span> 208 {{ end }} 209{{ end }} 210 211{{ define "pullReviewCommitActions" }} 212 {{ $p := .Patch }} 213 {{ $repoInfo := .RepoInfo }} 214 {{ if $p.SHA }} 215 <span class="flex items-center gap-1 text-gray-700 dark:text-gray-300 flex-shrink-0"> 216 <button type="button" 217 class="p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded text-gray-700 dark:text-gray-300" 218 title="Copy SHA" 219 onclick="event.preventDefault(); event.stopPropagation(); navigator.clipboard.writeText('{{ $p.SHA }}'); this.innerHTML=`{{ i "copy-check" "w-4 h-4" }}`; setTimeout(() => this.innerHTML=`{{ i "copy" "w-4 h-4" }}`, 1500)"> 220 {{ i "copy" "w-4 h-4" }} 221 </button> 222 <a href="/{{ $repoInfo.FullName }}/tree/{{ $p.SHA }}" 223 onclick="event.stopPropagation()" 224 class="p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded text-gray-700 dark:text-gray-300" 225 title="Browse repository at this commit"> 226 {{ i "folder-code" "w-4 h-4" }} 227 </a> 228 </span> 229 {{ end }} 230{{ end }} 231 232{{ define "pullStackedDiffArea" }} 233 {{ $diff := .Diff }} 234 {{ $opts := .DiffOpts }} 235 {{ $cid := .Cid }} 236 {{ $togId := printf "stack-%s-filesToggle" $cid }} 237 {{ $colId := printf "stack-%s-collapseToggle" $cid }} 238 {{ $filesId := printf "stack-%s-files" $cid }} 239 {{ $diffAreaId := printf "stack-%s-diff-area" $cid }} 240 {{ $filePrefix := printf "stack-%s-file-" $cid }} 241 {{ $stat := $diff.Stats }} 242 {{ $count := len $diff.ChangedFiles }} 243 244 <style> 245 #{{ $togId }}:checked ~ * label[for="{{ $togId }}"] .show-text { display: none; } 246 #{{ $togId }}:checked ~ * label[for="{{ $togId }}"] .hide-text { display: inline; } 247 #{{ $togId }}:not(:checked) ~ * label[for="{{ $togId }}"] .hide-text { display: none; } 248 #{{ $togId }}:checked ~ * div#{{ $filesId }} { width: fit-content; max-width: 15vw; } 249 #{{ $togId }}:not(:checked) ~ * div#{{ $filesId }} { width: 0; display: none; margin-right: 0; } 250 </style> 251 252 <input type="checkbox" id="{{ $togId }}" class="hidden"/> 253 254 <div id="{{ $diffAreaId }}"> 255 <div class="bg-slate-100 dark:bg-gray-700/50 flex items-center gap-2 h-12 p-2 rounded-t-md border border-b-0 border-gray-200 dark:border-gray-700"> 256 <label title="Toggle filetree panel" for="{{ $togId }}" class="hidden md:inline-flex items-center justify-center rounded cursor-pointer text-normal font-normal normal-case"> 257 <span class="show-text">{{ i "panel-left-open" "size-4" }}</span> 258 <span class="hide-text">{{ i "panel-left-close" "size-4" }}</span> 259 </label> 260 261 {{ template "repo/fragments/diffStatPill" $stat }} 262 <span class="text-xs text-gray-600 dark:text-gray-300 hidden md:inline-flex">{{ $count }} changed file{{ if ne $count 1 }}s{{ end }}</span> 263 264 <div class="flex-grow"></div> 265 266 <label title="Expand/Collapse diffs" for="{{ $colId }}" class="btn font-normal normal-case"> 267 <input type="checkbox" id="{{ $colId }}" class="peer/collapse hidden"/> 268 <span class="peer-checked/collapse:hidden inline-flex items-center gap-2"> 269 {{ i "unfold-vertical" "w-4 h-4" }} 270 <span class="hidden md:inline">Expand all</span> 271 </span> 272 <span class="peer-checked/collapse:inline-flex hidden flex items-center gap-2"> 273 {{ i "fold-vertical" "w-4 h-4" }} 274 <span class="hidden md:inline">Collapse all</span> 275 </span> 276 </label> 277 278 {{ template "repo/fragments/diffOpts" $opts }} 279 </div> 280 281 <div class="flex border border-gray-200 dark:border-gray-700 rounded-b-md"> 282 <div id="{{ $filesId }}" class="hidden md:block overflow-hidden max-h-[60vh] overflow-y-auto border-r border-gray-200 dark:border-gray-700"> 283 <section class="overflow-x-auto text-sm px-3 py-2 w-full mx-auto"> 284 {{ template "repo/fragments/fileTreePrefixed" (dict "Tree" $diff.FileTree "Prefix" $filePrefix) }} 285 </section> 286 </div> 287 288 <div class="flex-1 min-w-0 p-2"> 289 <div class="flex flex-col gap-2"> 290 {{ if eq $count 0 }} 291 <div class="text-center text-gray-500 dark:text-gray-400 py-8"> 292 <p>No differences found.</p> 293 </div> 294 {{ else if le $count 5 }} 295 {{ range $idx, $file := $diff.ChangedFiles }} 296 {{ template "stackedDiffFile" (dict "Idx" $idx "File" $file "IsSplit" $opts.Split "Prefix" $filePrefix) }} 297 {{ end }} 298 {{ else }} 299 {{ range $idx, $file := slice $diff.ChangedFiles 0 5 }} 300 {{ template "stackedDiffFile" (dict "Idx" $idx "File" $file "IsSplit" $opts.Split "Prefix" $filePrefix) }} 301 {{ end }} 302 {{ $remaining := sub $count 5 }} 303 <details class="group/showmore"> 304 <summary class="cursor-pointer text-sm text-gray-700 dark:text-gray-300 py-2 px-1 flex items-center gap-2 select-none hover:text-gray-900 dark:hover:text-gray-100 list-none"> 305 <span class="group-open/showmore:hidden inline-flex items-center gap-2"> 306 {{ i "chevron-right" "w-4 h-4" }} 307 Show {{ $remaining }} more file{{ if ne $remaining 1 }}s{{ end }} 308 </span> 309 <span class="hidden group-open/showmore:inline-flex items-center gap-2"> 310 {{ i "chevron-down" "w-4 h-4" }} 311 Hide {{ $remaining }} file{{ if ne $remaining 1 }}s{{ end }} 312 </span> 313 </summary> 314 <div class="flex flex-col gap-2 mt-2"> 315 {{ range $idx, $file := slice $diff.ChangedFiles 5 }} 316 {{ template "stackedDiffFile" (dict "Idx" (add $idx 5) "File" $file "IsSplit" $opts.Split "Prefix" $filePrefix) }} 317 {{ end }} 318 </div> 319 </details> 320 {{ end }} 321 </div> 322 </div> 323 </div> 324 </div> 325 326 <script> 327 (() => { 328 const cb = document.getElementById('{{ $colId }}'); 329 const area = document.getElementById('{{ $diffAreaId }}'); 330 if (!cb || !area) return; 331 const all = () => area.querySelectorAll('details[id^="{{ $filePrefix }}"]'); 332 cb.addEventListener('change', () => { 333 all().forEach(d => { d.open = cb.checked; }); 334 }); 335 area.addEventListener('toggle', (e) => { 336 if (!e.target.matches('details[id^="{{ $filePrefix }}"]')) return; 337 const dets = Array.from(all()); 338 const allOpen = dets.every(d => d.open); 339 const allClosed = dets.every(d => !d.open); 340 if (allOpen) cb.checked = true; 341 else if (allClosed) cb.checked = false; 342 }, true); 343 })(); 344 </script> 345{{ end }} 346 347{{ define "stackedDiffFile" }} 348 {{ $idx := .Idx }} 349 {{ $file := .File }} 350 {{ $isSplit := .IsSplit }} 351 {{ $prefix := .Prefix }} 352 {{ $isGenerated := false }} 353 {{ $isDeleted := false }} 354 {{ with $file }} 355 {{ $n := .Names }} 356 {{ $isDeleted = and (eq $n.New "") (ne $n.Old "") }} 357 {{ if $n.New }} 358 {{ $isGenerated = isGenerated $n.New }} 359 {{ else if $n.Old }} 360 {{ $isGenerated = isGenerated $n.Old }} 361 {{ end }} 362 <details id="{{ $prefix }}{{ .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 }}"> 363 <summary class="list-none cursor-pointer group-open:border-b border-gray-200 dark:border-gray-700"> 364 <div class="rounded cursor-pointer bg-white dark:bg-gray-800 flex justify-between"> 365 <div class="p-2 flex gap-2 items-center overflow-x-auto"> 366 <span class="group-open:hidden inline">{{ i "chevron-right" "w-4 h-4" }}</span> 367 <span class="hidden group-open:inline">{{ i "chevron-down" "w-4 h-4" }}</span> 368 {{ template "repo/fragments/diffStatPill" .Stats }} 369 <div class="flex gap-2 items-center overflow-x-auto"> 370 {{ if and $n.New $n.Old (ne $n.New $n.Old)}} 371 {{ $n.Old }} {{ i "arrow-right" "w-4 h-4" }} {{ $n.New }} 372 {{ else if $n.New }} 373 {{ $n.New }} 374 {{ else }} 375 {{ $n.Old }} 376 {{ end }} 377 {{ if $isDeleted }} 378 <span class="text-gray-400 dark:text-gray-500" title="Deleted files are collapsed by default"> 379 {{ i "circle-question-mark" "size-4" }} 380 </span> 381 {{ else if $isGenerated }} 382 <span class="text-gray-400 dark:text-gray-500" title="Generated files are collapsed by default"> 383 {{ i "circle-question-mark" "size-4" }} 384 </span> 385 {{ end }} 386 </div> 387 </div> 388 </div> 389 </summary> 390 391 <div class="transition-all duration-700 ease-in-out"> 392 {{ $reason := .CanRender }} 393 {{ if $reason }} 394 <p class="text-center text-gray-400 dark:text-gray-500 p-4">{{ $reason }}</p> 395 {{ else }} 396 {{ if $isSplit }} 397 {{- template "repo/fragments/splitDiff" .Split -}} 398 {{ else }} 399 {{- template "repo/fragments/unifiedDiff" . -}} 400 {{ end }} 401 {{- end -}} 402 </div> 403 </details> 404 {{ end }} 405{{ end }} 406 407{{ define "pullComposeFlatDiff" }} 408 {{ $diff := index . 0 }} 409 {{ $opts := index . 1 }} 410 {{ $files := $diff.ChangedFiles }} 411 {{ $isSplit := $opts.Split }} 412 {{ $count := len $files }} 413 {{ $stat := $diff.Stats }} 414 415 <style> 416 #composeFilesToggle:checked ~ * label[for="composeFilesToggle"] .show-text { display: none; } 417 #composeFilesToggle:checked ~ * label[for="composeFilesToggle"] .hide-text { display: inline; } 418 #composeFilesToggle:not(:checked) ~ * label[for="composeFilesToggle"] .hide-text { display: none; } 419 #composeFilesToggle:checked ~ * div#composeFiles { width: fit-content; max-width: 15vw; } 420 #composeFilesToggle:not(:checked) ~ * div#composeFiles { width: 0; display: none; margin-right: 0; } 421 </style> 422 423 <input type="checkbox" id="composeFilesToggle" class="hidden"/> 424 425 <div id="diff-area"> 426 <div class="bg-slate-100 dark:bg-gray-700/50 flex items-center gap-2 h-12 p-2 rounded-t-md border border-b-0 border-gray-200 dark:border-gray-700"> 427 <label title="Toggle filetree panel" for="composeFilesToggle" class="hidden md:inline-flex items-center justify-center rounded cursor-pointer text-normal font-normal normal-case"> 428 <span class="show-text">{{ i "panel-left-open" "size-4" }}</span> 429 <span class="hide-text">{{ i "panel-left-close" "size-4" }}</span> 430 </label> 431 432 {{ template "repo/fragments/diffStatPill" $stat }} 433 <span class="text-xs text-gray-600 dark:text-gray-300 hidden md:inline-flex">{{ $count }} changed file{{ if ne $count 1 }}s{{ end }}</span> 434 435 <div class="flex-grow"></div> 436 437 <label title="Expand/Collapse diffs" for="composeCollapseToggle" class="btn font-normal normal-case"> 438 <input type="checkbox" id="composeCollapseToggle" class="peer/collapse hidden"/> 439 <span class="peer-checked/collapse:hidden inline-flex items-center gap-2"> 440 {{ i "unfold-vertical" "w-4 h-4" }} 441 <span class="hidden md:inline">Expand all</span> 442 </span> 443 <span class="peer-checked/collapse:inline-flex hidden flex items-center gap-2"> 444 {{ i "fold-vertical" "w-4 h-4" }} 445 <span class="hidden md:inline">Collapse all</span> 446 </span> 447 </label> 448 449 {{ template "repo/fragments/diffOpts" $opts }} 450 </div> 451 452 <div class="flex border border-gray-200 dark:border-gray-700 rounded-b-md"> 453 <div id="composeFiles" class="hidden md:block overflow-hidden max-h-[60vh] overflow-y-auto border-r border-gray-200 dark:border-gray-700"> 454 <section class="overflow-x-auto text-sm px-3 py-2 w-full mx-auto"> 455 {{ template "repo/fragments/fileTree" $diff.FileTree }} 456 </section> 457 </div> 458 459 <div class="flex-1 min-w-0 p-2"> 460 <div class="flex flex-col gap-2"> 461 {{ if eq $count 0 }} 462 <div class="text-center text-gray-500 dark:text-gray-400 py-8"> 463 <p>No differences found.</p> 464 </div> 465 {{ else if le $count 5 }} 466 {{ range $idx, $file := $files }} 467 {{ template "diffFile" (list $idx $file $isSplit true) }} 468 {{ end }} 469 {{ else }} 470 {{ range $idx, $file := slice $files 0 5 }} 471 {{ template "diffFile" (list $idx $file $isSplit true) }} 472 {{ end }} 473 {{ $remaining := sub $count 5 }} 474 <details class="group/showmore"> 475 <summary class="cursor-pointer text-sm text-gray-700 dark:text-gray-300 py-2 px-1 flex items-center gap-2 select-none hover:text-gray-900 dark:hover:text-gray-100 list-none"> 476 <span class="group-open/showmore:hidden inline-flex items-center gap-2"> 477 {{ i "chevron-right" "w-4 h-4" }} 478 Show {{ $remaining }} more file{{ if ne $remaining 1 }}s{{ end }} 479 </span> 480 <span class="hidden group-open/showmore:inline-flex items-center gap-2"> 481 {{ i "chevron-down" "w-4 h-4" }} 482 Hide {{ $remaining }} file{{ if ne $remaining 1 }}s{{ end }} 483 </span> 484 </summary> 485 <div class="flex flex-col gap-2 mt-2"> 486 {{ range $idx, $file := slice $files 5 }} 487 {{ template "diffFile" (list (add $idx 5) $file $isSplit true) }} 488 {{ end }} 489 </div> 490 </details> 491 {{ end }} 492 </div> 493 </div> 494 </div> 495 </div> 496 497 <script> 498 (() => { 499 const checkbox = document.getElementById('composeCollapseToggle'); 500 const diffArea = document.getElementById('diff-area'); 501 if (!checkbox || !diffArea) return; 502 const all = () => diffArea.querySelectorAll('details[id^="file-"]'); 503 checkbox.addEventListener('change', () => { 504 all().forEach(d => { d.open = checkbox.checked; }); 505 }); 506 diffArea.addEventListener('toggle', (e) => { 507 if (!e.target.matches('details[id^="file-"]')) return; 508 const dets = Array.from(all()); 509 const allOpen = dets.every(d => d.open); 510 const allClosed = dets.every(d => !d.open); 511 if (allOpen) checkbox.checked = true; 512 else if (allClosed) checkbox.checked = false; 513 }, true); 514 })(); 515 </script> 516{{ end }}