appview/pages: unify diff & interdiff templates

any object that adheres to the DiffRenderer interface can now be
presented as html using the repo/fragments/diff template.

authored by oppi.li and committed by tangled.org d7c6aa99 d33579d7

+170 -194
+1 -18
appview/pages/templates/repo/commit.html
··· 116 116 {{ block "content" . }}{{ end }} 117 117 {{ end }} 118 118 119 - {{ block "contentAfterLayout" . }} 120 - <div class="flex-grow grid grid-cols-1 md:grid-cols-12 gap-4"> 121 - <div class="flex flex-col gap-4 col-span-1 md:col-span-2"> 122 - {{ block "contentAfterLeft" . }} {{ end }} 123 - </div> 124 - <main class="col-span-1 md:col-span-10"> 125 - {{ block "contentAfter" . }}{{ end }} 126 - </main> 127 - </div> 128 - {{ end }} 119 + {{ block "contentAfter" . }}{{ end }} 129 120 </div> 130 121 {{ end }} 131 122 ··· 139 130 {{ template "repo/fragments/diff" (list .Diff .DiffOpts) }} 140 131 {{end}} 141 132 142 - {{ define "contentAfterLeft" }} 143 - <div class="flex flex-col gap-4 col-span-1 md:col-span-2"> 144 - {{ template "repo/fragments/diffOpts" .DiffOpts }} 145 - </div> 146 - <div class="sticky top-0 flex-grow max-h-screen overflow-y-auto"> 147 - {{ template "repo/fragments/diffChangedFiles" .Diff }} 148 - </div> 149 - {{end}}
+1 -19
appview/pages/templates/repo/compare/compare.html
··· 22 22 {{ block "content" . }}{{ end }} 23 23 {{ end }} 24 24 25 - {{ block "contentAfterLayout" . }} 26 - <div class="flex-grow grid grid-cols-1 md:grid-cols-12 gap-4"> 27 - <div class="flex flex-col gap-4 col-span-1 md:col-span-2"> 28 - {{ block "contentAfterLeft" . }} {{ end }} 29 - </div> 30 - <main class="col-span-1 md:col-span-10"> 31 - {{ block "contentAfter" . }}{{ end }} 32 - </main> 33 - </div> 34 - {{ end }} 25 + {{ block "contentAfter" . }}{{ end }} 35 26 </div> 36 27 {{ end }} 37 28 ··· 44 35 {{ define "contentAfter" }} 45 36 {{ template "repo/fragments/diff" (list .Diff .DiffOpts) }} 46 37 {{end}} 47 - 48 - {{ define "contentAfterLeft" }} 49 - <div class="flex flex-col gap-4 col-span-1 md:col-span-2"> 50 - {{ template "repo/fragments/diffOpts" .DiffOpts }} 51 - </div> 52 - <div class="sticky top-0 flex-grow max-h-screen overflow-y-auto"> 53 - {{ template "repo/fragments/diffChangedFiles" .Diff }} 54 - </div> 55 - {{end}}
+164 -43
appview/pages/templates/repo/fragments/diff.html
··· 1 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: hidden; margin-right: 0; } 8 + </style> 9 + 10 + {{ template "diffTopbar" . }} 11 + {{ block "diffLayout" . }} {{ end }} 12 + {{ end }} 13 + 14 + {{ define "diffTopbar" }} 2 15 {{ $diff := index . 0 }} 3 16 {{ $opts := index . 1 }} 4 17 5 - {{ $commit := $diff.Commit }} 6 - {{ $diff := $diff.Diff }} 7 - {{ $isSplit := $opts.Split }} 8 - {{ $this := $commit.This }} 9 - {{ $parent := $commit.Parent }} 10 - {{ $last := sub (len $diff) 1 }} 18 + {{ block "filesCheckbox" $ }} {{ end }} 19 + {{ block "subsCheckbox" $ }} {{ end }} 20 + 21 + <!-- top bar --> 22 + <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"> 23 + <!-- left panel toggle --> 24 + {{ template "filesToggle" . }} 11 25 26 + <!-- stats --> 27 + {{ $stat := $diff.Stats }} 28 + {{ $count := len $diff.ChangedFiles }} 29 + {{ template "repo/fragments/diffStatPill" $stat }} 30 + {{ $count }} changed file{{ if ne $count 1 }}s{{ end }} 31 + 32 + <!-- spacer --> 33 + <div class="flex-grow"></div> 34 + 35 + <!-- collapse diffs --> 36 + {{ template "collapseToggle" }} 37 + 38 + <!-- diff options --> 39 + {{ template "repo/fragments/diffOpts" $opts }} 40 + 41 + <!-- right panel toggle --> 42 + {{ block "subsToggle" $ }} {{ end }} 43 + </div> 44 + 45 + {{ end }} 46 + 47 + {{ define "diffLayout" }} 48 + {{ $diff := index . 0 }} 49 + {{ $opts := index . 1 }} 50 + 51 + <div class="flex col-span-full flex-grow"> 52 + <!-- left panel --> 53 + <div id="files" class="w-0 hidden md:block overflow-hidden sticky top-12 max-h-screen overflow-y-auto pb-12"> 54 + <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"> 55 + {{ template "repo/fragments/fileTree" $diff.FileTree }} 56 + </section> 57 + </div> 58 + 59 + <!-- main content --> 60 + <div class="flex-1 min-w-0 sticky top-12 pb-12"> 61 + {{ template "diffFiles" (list $diff $opts) }} 62 + </div> 63 + 64 + </div> 65 + {{ end }} 66 + 67 + {{ define "diffFiles" }} 68 + {{ $diff := index . 0 }} 69 + {{ $opts := index . 1 }} 70 + {{ $files := $diff.ChangedFiles }} 71 + {{ $isSplit := $opts.Split }} 12 72 <div class="flex flex-col gap-4"> 13 - {{ if eq (len $diff) 0 }} 73 + {{ if eq (len $files) 0 }} 14 74 <div class="text-center text-gray-500 dark:text-gray-400 py-8"> 15 75 <p>No differences found between the selected revisions.</p> 16 76 </div> 17 77 {{ else }} 18 - {{ range $idx, $hunk := $diff }} 19 - {{ with $hunk }} 20 - <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 }}"> 21 - <summary class="list-none cursor-pointer sticky top-0"> 22 - <div id="diff-file-header" class="rounded cursor-pointer bg-white dark:bg-gray-800 flex justify-between"> 23 - <div id="left-side-items" class="p-2 flex gap-2 items-center overflow-x-auto"> 24 - <span class="group-open:hidden inline">{{ i "chevron-right" "w-4 h-4" }}</span> 25 - <span class="hidden group-open:inline">{{ i "chevron-down" "w-4 h-4" }}</span> 26 - {{ template "repo/fragments/diffStatPill" .Stats }} 78 + {{ range $idx, $file := $files }} 79 + {{ template "diffFile" (list $idx $file $isSplit) }} 80 + {{ end }} 81 + {{ end }} 82 + </div> 83 + {{ end }} 27 84 28 - <div class="flex gap-2 items-center overflow-x-auto"> 29 - {{ if .IsDelete }} 30 - {{ .Name.Old }} 31 - {{ else if (or .IsCopy .IsRename) }} 32 - {{ .Name.Old }} {{ i "arrow-right" "w-4 h-4" }} {{ .Name.New }} 33 - {{ else }} 34 - {{ .Name.New }} 35 - {{ end }} 36 - </div> 37 - </div> 38 - </div> 39 - </summary> 85 + {{ define "diffFile" }} 86 + {{ $idx := index . 0 }} 87 + {{ $file := index . 1 }} 88 + {{ $isSplit := index . 2 }} 89 + {{ with $file }} 90 + <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 }}"> 91 + <summary class="list-none cursor-pointer sticky top-12 group-open:border-b border-gray-200 dark:border-gray-700"> 92 + <div id="diff-file-header" class="rounded cursor-pointer bg-white dark:bg-gray-800 flex justify-between"> 93 + <div id="left-side-items" class="p-2 flex gap-2 items-center overflow-x-auto"> 94 + <span class="group-open:hidden inline">{{ i "chevron-right" "w-4 h-4" }}</span> 95 + <span class="hidden group-open:inline">{{ i "chevron-down" "w-4 h-4" }}</span> 96 + {{ template "repo/fragments/diffStatPill" .Stats }} 40 97 41 - <div class="transition-all duration-700 ease-in-out"> 42 - {{ if .IsBinary }} 43 - <p class="text-center text-gray-400 dark:text-gray-500 p-4"> 44 - This is a binary file and will not be displayed. 45 - </p> 46 - {{ else }} 47 - {{ if $isSplit }} 48 - {{- template "repo/fragments/splitDiff" .Split -}} 98 + <div class="flex gap-2 items-center overflow-x-auto"> 99 + {{ $n := .Names }} 100 + {{ if and $n.New $n.Old (ne $n.New $n.Old)}} 101 + {{ $n.Old }} {{ i "arrow-right" "w-4 h-4" }} {{ $n.New }} 102 + {{ else if $n.New }} 103 + {{ $n.New }} 49 104 {{ else }} 50 - {{- template "repo/fragments/unifiedDiff" . -}} 105 + {{ $n.Old }} 51 106 {{ end }} 52 - {{- end -}} 107 + </div> 53 108 </div> 54 - </details> 55 - {{ end }} 56 - {{ end }} 57 - {{ end }} 58 - </div> 109 + </div> 110 + </summary> 111 + 112 + <div class="transition-all duration-700 ease-in-out"> 113 + {{ $reason := .CanRender }} 114 + {{ if $reason }} 115 + <p class="text-center text-gray-400 dark:text-gray-500 p-4">{{ $reason }}</p> 116 + {{ else }} 117 + {{ if $isSplit }} 118 + {{- template "repo/fragments/splitDiff" .Split -}} 119 + {{ else }} 120 + {{- template "repo/fragments/unifiedDiff" . -}} 121 + {{ end }} 122 + {{- end -}} 123 + </div> 124 + </details> 125 + {{ end }} 126 + {{ end }} 127 + 128 + {{ define "filesCheckbox" }} 129 + <input type="checkbox" id="filesToggle" class="peer/files hidden" checked/> 130 + {{ end }} 131 + 132 + {{ define "filesToggle" }} 133 + <label title="Toggle filetree panel" for="filesToggle" class="hidden md:inline-flex items-center justify-center rounded cursor-pointer text-normal font-normal normalcase"> 134 + <span class="show-text">{{ i "panel-left-open" "size-4" }}</span> 135 + <span class="hide-text">{{ i "panel-left-close" "size-4" }}</span> 136 + </label> 137 + {{ end }} 138 + 139 + {{ define "collapseToggle" }} 140 + <label 141 + title="Expand/Collapse diffs" 142 + for="collapseToggle" 143 + class="btn font-normal normal-case p-2" 144 + > 145 + <input type="checkbox" id="collapseToggle" class="peer/collapse hidden" checked/> 146 + <span class="peer-checked/collapse:hidden inline-flex items-center gap-2"> 147 + {{ i "fold-vertical" "w-4 h-4" }} 148 + <span class="hidden md:inline">expand all</span> 149 + </span> 150 + <span class="peer-checked/collapse:inline-flex hidden flex items-center gap-2"> 151 + {{ i "unfold-vertical" "w-4 h-4" }} 152 + <span class="hidden md:inline">collapse all</span> 153 + </span> 154 + </label> 155 + <script> 156 + document.addEventListener('DOMContentLoaded', function() { 157 + const checkbox = document.getElementById('collapseToggle'); 158 + const details = document.querySelectorAll('details[id^="file-"]'); 159 + 160 + checkbox.addEventListener('change', function() { 161 + details.forEach(detail => { 162 + detail.open = checkbox.checked; 163 + }); 164 + }); 165 + 166 + details.forEach(detail => { 167 + detail.addEventListener('toggle', function() { 168 + const allOpen = Array.from(details).every(d => d.open); 169 + const allClosed = Array.from(details).every(d => !d.open); 170 + 171 + if (allOpen) { 172 + checkbox.checked = true; 173 + } else if (allClosed) { 174 + checkbox.checked = false; 175 + } 176 + }); 177 + }); 178 + }); 179 + </script> 59 180 {{ end }}
-13
appview/pages/templates/repo/fragments/diffChangedFiles.html
··· 1 - {{ define "repo/fragments/diffChangedFiles" }} 2 - {{ $stat := .Stat }} 3 - {{ $fileTree := fileTree .ChangedFiles }} 4 - <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"> 5 - <div class="diff-stat"> 6 - <div class="flex gap-2 items-center"> 7 - <strong class="text-sm uppercase dark:text-gray-200">Changed files</strong> 8 - {{ template "repo/fragments/diffStatPill" $stat }} 9 - </div> 10 - {{ template "repo/fragments/fileTree" $fileTree }} 11 - </div> 12 - </section> 13 - {{ end }}
-67
appview/pages/templates/repo/fragments/interdiff.html
··· 1 - {{ define "repo/fragments/interdiff" }} 2 - {{ $repo := index . 0 }} 3 - {{ $x := index . 1 }} 4 - {{ $opts := index . 2 }} 5 - {{ $fileTree := fileTree $x.AffectedFiles }} 6 - {{ $diff := $x.Files }} 7 - {{ $last := sub (len $diff) 1 }} 8 - {{ $isSplit := $opts.Split }} 9 - 10 - <div class="flex flex-col gap-4"> 11 - {{ range $idx, $hunk := $diff }} 12 - {{ with $hunk }} 13 - <details {{ if not (.Status.IsOnlyInOne) }}open{{end}} id="file-{{ .Name }}" class="border border-gray-200 dark:border-gray-700 w-full mx-auto rounded bg-white dark:bg-gray-800 drop-shadow-sm"> 14 - <summary class="list-none cursor-pointer sticky top-0"> 15 - <div id="diff-file-header" class="rounded cursor-pointer bg-white dark:bg-gray-800 flex justify-between"> 16 - <div id="left-side-items" class="p-2 flex gap-2 items-center overflow-x-auto"> 17 - <div class="flex gap-1 items-center" style="direction: ltr;"> 18 - {{ $markerstyle := "diff-type p-1 mr-1 font-mono text-sm rounded select-none" }} 19 - {{ if .Status.IsOk }} 20 - <span class="bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300 {{ $markerstyle }}">CHANGED</span> 21 - {{ else if .Status.IsUnchanged }} 22 - <span class="bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300 {{ $markerstyle }}">UNCHANGED</span> 23 - {{ else if .Status.IsOnlyInOne }} 24 - <span class="bg-red-100 text-red-700 dark:bg-red-800/50 dark:text-red-400 {{ $markerstyle }}">REVERTED</span> 25 - {{ else if .Status.IsOnlyInTwo }} 26 - <span class="bg-green-100 text-green-700 dark:bg-green-800/50 dark:text-green-400 {{ $markerstyle }}">NEW</span> 27 - {{ else if .Status.IsRebased }} 28 - <span class="bg-amber-100 text-amber-700 dark:bg-amber-800/50 dark:text-amber-400 {{ $markerstyle }}">REBASED</span> 29 - {{ else }} 30 - <span class="bg-red-100 text-red-700 dark:bg-red-800/50 dark:text-red-400 {{ $markerstyle }}">ERROR</span> 31 - {{ end }} 32 - </div> 33 - 34 - <div class="flex gap-2 items-center overflow-x-auto" style="direction: rtl;">{{ .Name }}</div> 35 - </div> 36 - 37 - </div> 38 - </summary> 39 - 40 - <div class="transition-all duration-700 ease-in-out"> 41 - {{ if .Status.IsUnchanged }} 42 - <p class="text-center text-gray-400 dark:text-gray-500 p-4"> 43 - This file has not been changed. 44 - </p> 45 - {{ else if .Status.IsRebased }} 46 - <p class="text-center text-gray-400 dark:text-gray-500 p-4"> 47 - This patch was likely rebased, as context lines do not match. 48 - </p> 49 - {{ else if .Status.IsError }} 50 - <p class="text-center text-gray-400 dark:text-gray-500 p-4"> 51 - Failed to calculate interdiff for this file. 52 - </p> 53 - {{ else }} 54 - {{ if $isSplit }} 55 - {{- template "repo/fragments/splitDiff" .Split -}} 56 - {{ else }} 57 - {{- template "repo/fragments/unifiedDiff" . -}} 58 - {{ end }} 59 - {{- end -}} 60 - </div> 61 - 62 - </details> 63 - {{ end }} 64 - {{ end }} 65 - </div> 66 - {{ end }} 67 -
-11
appview/pages/templates/repo/fragments/interdiffFiles.html
··· 1 - {{ define "repo/fragments/interdiffFiles" }} 2 - {{ $fileTree := fileTree .AffectedFiles }} 3 - <section class="px-6 py-2 border border-gray-200 dark:border-gray-700 w-full mx-auto rounded bg-white dark:bg-gray-800 drop-shadow-sm min-h-full text-sm"> 4 - <div class="diff-stat"> 5 - <div class="flex gap-2 items-center"> 6 - <strong class="text-sm uppercase dark:text-gray-200">files</strong> 7 - </div> 8 - {{ template "repo/fragments/fileTree" $fileTree }} 9 - </div> 10 - </section> 11 - {{ end }}
+1 -1
appview/pages/templates/repo/fragments/splitDiff.html
··· 3 3 {{- $lineNrStyle := "min-w-[3.5rem] flex-shrink-0 select-none text-right bg-white dark:bg-gray-800" -}} 4 4 {{- $linkStyle := "text-gray-400 dark:text-gray-500 hover:underline" -}} 5 5 {{- $lineNrSepStyle := "pr-2 border-r border-gray-200 dark:border-gray-700" -}} 6 - {{- $containerStyle := "inline-flex w-full items-center target:border target:rounded-sm target:border-yellow-200 target:dark:border-yellow-700 scroll-mt-20" -}} 6 + {{- $containerStyle := "inline-flex w-full items-center target:bg-yellow-200 target:dark:bg-yellow-700 scroll-mt-48" -}} 7 7 {{- $emptyStyle := "bg-gray-200/30 dark:bg-gray-700/30" -}} 8 8 {{- $addStyle := "bg-green-100 dark:bg-green-800/30 text-green-700 dark:text-green-400" -}} 9 9 {{- $delStyle := "bg-red-100 dark:bg-red-800/30 text-red-700 dark:text-red-400 " -}}
+1 -1
appview/pages/templates/repo/fragments/unifiedDiff.html
··· 7 7 {{- $linkStyle := "text-gray-400 dark:text-gray-500 hover:underline" -}} 8 8 {{- $lineNrSepStyle1 := "" -}} 9 9 {{- $lineNrSepStyle2 := "pr-2 border-r border-gray-200 dark:border-gray-700" -}} 10 - {{- $containerStyle := "inline-flex w-full items-center target:border target:rounded-sm target:border-yellow-200 target:dark:border-yellow-700 scroll-mt-20" -}} 10 + {{- $containerStyle := "inline-flex w-full items-center target:bg-yellow-200 target:dark:bg-yellow-700 scroll-mt-48" -}} 11 11 {{- $addStyle := "bg-green-100 dark:bg-green-800/30 text-green-700 dark:text-green-400 " -}} 12 12 {{- $delStyle := "bg-red-100 dark:bg-red-800/30 text-red-700 dark:text-red-400 " -}} 13 13 {{- $ctxStyle := "bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400" -}}
+2 -21
appview/pages/templates/repo/pulls/interdiff.html
··· 25 25 {{ template "repo/pulls/fragments/pullHeader" . }} 26 26 </header> 27 27 </section> 28 - 29 28 {{ end }} 30 29 31 30 {{ define "mainLayout" }} ··· 34 33 {{ block "content" . }}{{ end }} 35 34 {{ end }} 36 35 37 - {{ block "contentAfterLayout" . }} 38 - <div class="flex-grow grid grid-cols-1 md:grid-cols-12 gap-4"> 39 - <div class="flex flex-col gap-4 col-span-1 md:col-span-2"> 40 - {{ block "contentAfterLeft" . }} {{ end }} 41 - </div> 42 - <main class="col-span-1 md:col-span-10"> 43 - {{ block "contentAfter" . }}{{ end }} 44 - </main> 45 - </div> 46 - {{ end }} 36 + {{ block "contentAfter" . }}{{ end }} 47 37 </div> 48 38 {{ end }} 49 39 50 40 {{ define "contentAfter" }} 51 - {{ template "repo/fragments/interdiff" (list .RepoInfo.FullName .Interdiff .DiffOpts) }} 52 - {{end}} 53 - 54 - {{ define "contentAfterLeft" }} 55 - <div class="flex flex-col gap-4 col-span-1 md:col-span-2"> 56 - {{ template "repo/fragments/diffOpts" .DiffOpts }} 57 - </div> 58 - <div class="sticky top-0 flex-grow max-h-screen overflow-y-auto"> 59 - {{ template "repo/fragments/interdiffFiles" .Interdiff }} 60 - </div> 41 + {{ template "repo/fragments/diff" (list .Interdiff .DiffOpts) }} 61 42 {{end}}