Monorepo for Tangled

appview: highlight active file in PR filetree on scroll

When reviewing a pull request with multiple files, the currently visible
file is now highlighted (bolded) in the filetree sidebar. This makes it
easier to track your position when scrolling through large diffs and
lose track of the header of the file you're looking at.

The highlight updates on scroll and also responds to clicks on filetree
links.

Signed-off-by: Jes Olson <j3s@c3f.net>

authored by

Jes Olson and committed by tangled.org d0acfc93 a1e6f903

+47 -1
+46
appview/pages/templates/repo/fragments/diff.html
··· 11 11 {{ template "diffTopbar" . }} 12 12 {{ block "diffLayout" . }} {{ end }} 13 13 {{ template "fragments/resizable" }} 14 + {{ template "activeFileHighlight" }} 14 15 {{ end }} 15 16 16 17 {{ define "diffTopbar" }} ··· 229 230 }); 230 231 </script> 231 232 {{ end }} 233 + 234 + {{ define "activeFileHighlight" }} 235 + <script> 236 + document.addEventListener('DOMContentLoaded', function() { 237 + const diffFiles = document.querySelectorAll('details[id^="file-"]'); 238 + const filetreeLinks = document.querySelectorAll('.filetree-link'); 239 + if (diffFiles.length === 0 || filetreeLinks.length === 0) return; 240 + 241 + const linkMap = new Map(); 242 + filetreeLinks.forEach(link => { 243 + const path = link.getAttribute('data-path'); 244 + if (path) linkMap.set('file-' + path, link); 245 + }); 246 + 247 + let currentActive = null; 248 + function setActive(link) { 249 + if (link && link !== currentActive) { 250 + if (currentActive) currentActive.classList.remove('font-bold'); 251 + link.classList.add('font-bold'); 252 + currentActive = link; 253 + } 254 + } 255 + 256 + filetreeLinks.forEach(link => { 257 + link.addEventListener('click', () => setActive(link)); 258 + }); 259 + 260 + const topbar = document.querySelector('.sticky.top-0.z-30'); 261 + const headerHeight = topbar ? topbar.offsetHeight : 0; 262 + 263 + function updateActiveFile() { 264 + for (const file of diffFiles) { 265 + const rect = file.getBoundingClientRect(); 266 + if (rect.top <= headerHeight && rect.bottom > headerHeight) { 267 + setActive(linkMap.get(file.id)); 268 + return; 269 + } 270 + } 271 + } 272 + 273 + document.addEventListener('scroll', updateActiveFile); 274 + updateActiveFile(); 275 + }); 276 + </script> 277 + {{ end }}
+1 -1
appview/pages/templates/repo/fragments/fileTree.html
··· 16 16 {{ else if .Name }} 17 17 <div class="tree-file flex items-center gap-2 pt-1"> 18 18 {{ i "file" "flex-shrink-0 size-4" }} 19 - <a href="#file-{{ .Path }}" class="filename truncate text-black dark:text-white no-underline hover:underline">{{ .Name }}</a> 19 + <a href="#file-{{ .Path }}" data-path="{{ .Path }}" class="filetree-link filename truncate text-black dark:text-white no-underline hover:underline">{{ .Name }}</a> 20 20 </div> 21 21 {{ else }} 22 22 {{ range $child := .Children }}