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 / single.html
31 kB 652 lines
1{{ define "title" }} 2 {{ .Pull.Title }} &middot; Pull #{{ .Pull.PullId }} &middot; {{ .RepoInfo.FullName }} &middot; Tangled 3{{ end }} 4 5{{ define "mainLayout" }} 6{{ template "fragments/resizable" }} 7<input type="hidden" id="pull-id" value="{{ .Pull.PullId }}" /> 8<input type="hidden" id="pull-target-repo-did" value="{{ .Pull.RepoDid }}" /> 9<input type="hidden" id="pull-active-version-id" value="{{ .ActiveVersionId }}" /> 10<div class="flex px-1 group/pr-layout"> 11 <div class="flex-1 min-w-0"> 12 <div class="max-w-screen-lg mx-auto"> 13 <!-- repo header --> 14 <section id="repo-header" class="mb-2 py-2 px-4 dark:text-white"> 15 <div class="flex flex-col sm:flex-row items-start gap-4 justify-between mb-2"> 16 <div class="flex flex-col gap-2"> 17 {{ template "repoOwnerAndName" . }} 18 {{ template "repoForkInfo" . }} 19 </div> 20 <div class="hidden sm:block sm:flex-shrink-0"> 21 {{ template "repoActions" . }} 22 </div> 23 </div> 24 {{ template "repoMetadata" . }} 25 26 <div class="block sm:hidden mt-4"> 27 {{ template "repoActions" . }} 28 </div> 29 </section> 30 <!-- repo nav --> 31 <nav class="w-full pl-4 overflow-auto"> 32 <div class="flex z-60"> 33 {{ range $item := .RepoInfo.GetTabs }} 34 {{ $key := index $item 0 }} 35 {{ $value := index $item 1 }} 36 {{ $icon := index $item 2 }} 37 {{ $meta := index $.RepoInfo.TabMetadata $key }} 38 {{/* no hx-boost here because PR page can be super large */}} 39 <a 40 href="/{{ $.RepoInfo.FullName }}{{ $value }}" 41 class="relative -mr-px group" 42 > 43 <div 44 class='px-4 py-1 mr-1 text-black dark:text-white min-w-[80px] text-center relative rounded-t whitespace-nowrap 45 {{ if eq "pulls" $key }} 46 -mb-px bg-white dark:bg-gray-800 47 {{ else }} 48 group-hover:bg-gray-100/25 group-hover:dark:bg-gray-700/25 49 {{ end }} 50 ' 51 > 52 <span class="flex items-center justify-center"> 53 {{ i $icon "size-4 mr-2" }} 54 {{ $key | capitalize }} 55 {{ if $meta }} 56 <span class="bg-gray-200 dark:bg-gray-700 rounded py-1/2 px-1 text-sm ml-1">{{ scaleFmt $meta }}</span> 57 {{ end }} 58 </span> 59 </div> 60 </a> 61 {{ end }} 62 </div> 63 </nav> 64 <div class="grid grid-cols-1 lg:grid-cols-[4fr_1fr] gap-4 mb-4"> 65 <div class="min-w-0"> 66 <section class="bg-white dark:bg-gray-800 p-6 rounded"> 67 <!-- PR header --> 68 <header class="pb-2"> 69 <h1 class="text-2xl"> 70 {{ .Pull.Title | description }} 71 <span class="text-gray-500 dark:text-gray-400">#{{ .Pull.PullId }}</span> 72 </h1> 73 </header> 74 <div class="flex items-center gap-2"> 75 {{ template "repo/pulls/fragments/pullState" .Pull.State }} 76 <span class="text-gray-500 dark:text-gray-400 text-sm flex flex-wrap items-center gap-1"> 77 opened by 78 {{ template "user/fragments/picLink" (list .Pull.OwnerDid.String "size-6" (index .VouchRelationships .Pull.OwnerDid)) }} 79 <a href="/{{ resolve .Pull.OwnerDid.String }}">{{ resolve .Pull.OwnerDid.String }}</a> 80 <span class="select-none before:content-['\00B7']"></span> 81 {{ template "repo/fragments/time" .Pull.Created }} 82 <span class="select-none before:content-['\00B7']"></span> 83 targeting 84 <span class="text-xs rounded bg-gray-100 dark:bg-gray-700 text-black dark:text-white font-mono px-2 mx-1/2 inline-flex items-center"> 85 <a href="/{{ .RepoInfo.FullName }}/tree/{{ .Pull.TargetBranch }}">{{ .Pull.TargetBranch }}</a> 86 </span> 87 88 {{ if .Pull.SourceBranch }} 89 from 90 <span class="text-xs rounded bg-gray-100 dark:bg-gray-700 text-black dark:text-white font-mono px-2 mx-1/2 inline-flex items-center"> 91 {{ if not .Pull.IsForkBased }} 92 {{ $repoPath := .RepoInfo.FullName }} 93 <a href="/{{ $repoPath }}/tree/{{ pathEscape .Pull.SourceBranch }}">{{ .Pull.SourceBranch }}</a> 94 {{ else }} 95 <a href="/{{ .Pull.SourceRepo }}">fork</a>: 96 <a href="/{{ .Pull.SourceRepo }}/tree/{{ pathEscape .Pull.SourceBranch }}">{{ .Pull.SourceBranch }}</a> 97 {{ end }} 98 </span> 99 {{ end }} 100 </span> 101 </div> 102 <article class="mt-4 prose dark:prose-invert"> 103 {{ if .Pull.Body }} 104 {{ .Pull.Body | markdown }} 105 {{ else }} 106 <span class="italic">No description provided</span> 107 {{ end }} 108 </article> 109 <div class="mt-4"> 110 {{ $aturi := .Pull.AtUri }} 111 {{ template "repo/fragments/reactions" 112 (dict "Reactions" (index .Reactions $aturi) 113 "UserReacted" (index .UserReacted $aturi) 114 "ThreadAt" $aturi) }} 115 </div> 116 </section> 117 </div> 118 <div class="lg:row-start-1 lg:row-end-3 lg:col-start-2 min-w-0"> 119 {{ template "repo/fragments/labelPanel" 120 (dict "RepoInfo" $.RepoInfo 121 "Defs" $.LabelDefs 122 "Subject" $.Pull.AtUri 123 "State" $.Pull.Labels) }} 124 {{ template "repo/fragments/participants" $.Pull.Participants }} 125 {{ if $.LoggedInUser }} 126 {{ template "repo/pulls/fragments/subscribeButton" 127 (dict "RepoInfo" $.RepoInfo 128 "PullId" $.Pull.PullId 129 "IsSubscribed" $.IsSubscribed) }} 130 {{ end }} 131 {{ template "repo/fragments/backlinks" 132 (dict "RepoInfo" $.RepoInfo 133 "Backlinks" $.Backlinks) }} 134 {{ template "repo/fragments/externalLinkPanel" $.Pull.AtUri }} 135 </div> 136 <div class="lg:row-start-2 lg:col-start-1"> 137 <h2 id="commits">Commits</h2> 138 {{ if .ErrorMsg }} 139 <div class="flex items-center justify-center w-full min-h-32 p-4 rounded text-red-600 dark:text-red-300 bg-red-50 dark:bg-red-900/30 border border-red-300 dark:border-red-700"> 140 <span>{{ .ErrorMsg }}</span> 141 </div> 142 {{ else }} 143 <div class="grid grid-cols-1 bg-white dark:bg-gray-800 rounded shadow-sm border border-gray-200 dark:border-gray-700 divide-y divide-gray-200 dark:divide-gray-700"> 144 {{ $seeAll := false }} 145 {{ if .IsInterdiff }} 146 {{ $seeAll = not .ChangeId }} 147 {{ else }} 148 {{ $version := index .Pull.Versions .VersionId }} 149 {{ $seeAll = and .IsDiffBase .IsDiffHead }} 150 {{ end }} 151 <div class="text-sm px-2 {{ if $seeAll }}bg-gray-100/50 dark:bg-gray-700/50{{ end }}"> 152 <div class="relative"> 153 {{ if $seeAll }} 154 <div class="flex-shrink-0 absolute top-3 left-0"> 155 {{ i "arrow-right" "size-4" }} 156 </div> 157 {{ end }} 158 <div class="py-2 ml-6"> 159 {{ if .IsInterdiff }} 160 <a href="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/{{ .Version1 }}..{{ .Version2 }}/all">See all changes</a> 161 {{ else }} 162 <a href="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/{{ .VersionId }}">See all changes</a> 163 {{ end }} 164 </div> 165 </div> 166 </div> 167 {{ range .Commits }} 168 {{ $messageParts := splitN .Message "\n\n" 2 }} 169 {{ $active := and (not $seeAll) (eq (shortId $.ActiveCommitId) (shortId .Hash.String)) }} 170 {{ $toggleId := printf "commit-message-toggle-%s" .Hash }} 171 {{ $pipeline := index $.Pipelines .Hash.String }} 172 <div class="text-sm px-2 {{ if $active }}bg-gray-100/50 dark:bg-gray-700/50{{ end }}"> 173 <input id="{{ $toggleId }}" type="checkbox" class="peer hidden" /> 174 <div class="relative flex items-center justify-between"> 175 {{ if $active }} 176 <div class="flex-shrink-0 absolute left-0"> 177 {{ i "arrow-right" "size-4" }} 178 </div> 179 {{ end }} 180 <div class="py-2 ml-6"> 181 <code class="py-0.5 px-1">{{ shortId .Hash.String }}</code> 182 {{ if .ChangeId }} 183 <code class="py-0.5 px-1">{{ shortId .ChangeId }}</code> 184 {{ end }} 185 {{ if $.IsInterdiff }} 186 <a href="/{{ $.RepoInfo.FullName }}/pulls/{{ $.Pull.PullId }}/{{ $.Version1 }}..{{ $.Version2 }}/{{ .ChangeId }}">{{ index $messageParts 0 }}</a> 187 {{ else }} 188 <a href="/{{ $.RepoInfo.FullName }}/pulls/{{ $.Pull.PullId }}/{{ $.VersionId }}/{{ shortId .FirstParentHash.String }}..{{ shortId .Hash.String }}">{{ index $messageParts 0 }}</a> 189 {{ end }} 190 <label 191 for="{{ $toggleId }}" 192 class="cursor-pointer inline-flex py-0.5 px-1 bg-gray-200 hover:bg-gray-400 rounded dark:bg-gray-700 dark:hover:bg-gray-600" 193 > 194 {{ i "ellipsis" "size-3" }} 195 </label> 196 </div> 197 {{ if and $pipeline $pipeline.Id }} 198 <div> 199 {{ template "repo/pipelines/fragments/pipelineSymbol" (dict "Pipeline" $pipeline "ShortSummary" true) }} 200 </div> 201 {{ end }} 202 </div> 203 {{ if gt (len $messageParts) 1 }} 204 <pre class="ml-6 mt-1 mb-2 hidden peer-checked:block">{{ index $messageParts 1 }}</pre> 205 {{ end }} 206 </div> 207 {{ end }} 208 </div> 209 {{ end }} 210 </div> 211 </div> 212 </div> 213 <!-- diff --> 214 <div hx-include="this" class="min-h-[50vh] group/diff-layout"> 215 {{ $diffUrl := "" }} 216 {{ if not .IsInterdiff }} 217 {{ $diffUrl = (printf "/%s/pulls/%d/_/diff?view=unified" .Pull.RepoDid .Pull.PullId) }} 218 {{ $diff := .DiffParams }} 219 <input type="hidden" name="baseRepo" value="{{ .Pull.RepoDid }}"> 220 <input type="hidden" name="base" value="{{ $diff.Base }}"> 221 <input type="hidden" name="headRepo" value="{{ .Pull.SourceRepo }}"> 222 <input type="hidden" name="head" value="{{ $diff.Head }}"> 223 {{ else if .DiffParams.Diff }} 224 {{ $diffUrl = (printf "/%s/pulls/%d/_/diff?view=unified" .Pull.RepoDid .Pull.PullId) }} 225 {{ $diff := .DiffParams.Diff }} 226 <input type="hidden" name="baseRepo" value="{{ .Pull.SourceRepo }}"> 227 <input type="hidden" name="base" value="{{ $diff.Base }}"> 228 <input type="hidden" name="headRepo" value="{{ .Pull.SourceRepo }}"> 229 <input type="hidden" name="head" value="{{ $diff.Head }}"> 230 {{ else }} 231 {{ $diffUrl = (printf "/%s/pulls/%d/_/interdiff?view=unified" .Pull.RepoDid .Pull.PullId) }} 232 {{ $diff := .DiffParams.Interdiff }} 233 <input type="hidden" name="repo" value="{{ .Pull.SourceRepo }}"> 234 <input type="hidden" name="base1" value="{{ $diff.From.Base }}"> 235 <input type="hidden" name="head1" value="{{ $diff.From.Head }}"> 236 <input type="hidden" name="base2" value="{{ $diff.To.Base }}"> 237 <input type="hidden" name="head2" value="{{ $diff.To.Head }}"> 238 {{ end }} 239 <!-- diff header --> 240 <header class="bg-slate-100 dark:bg-gray-900 sticky px-1 top-0 z-20 flex flex-col md:flex-row md:justify-between"> 241 <!-- left --> 242 <div class="h-12 flex items-center gap-2"> 243 <div class="md:block hidden"> 244 <label for="diff-tree-toggle" title="Toggle filetree panel" class="btn-flat"> 245 <span class="group-has-[#diff-tree-toggle:checked]/diff-layout:hidden inline">{{ i "panel-left-open" "size-4" }}</span> 246 <span class="hidden group-has-[#diff-tree-toggle:checked]/diff-layout:inline">{{ i "panel-left-close" "size-4" }}</span> 247 </label> 248 </div> 249 <div id="diff-stats"> 250 <div class="flex items-center font-mono text-sm"> 251 <span class="rounded-l p-1 select-none bg-green-100 text-green-700 dark:bg-green-800/50 dark:text-green-400">+{{ i "loader-circle" "size-3 inline-flex animate-spin" }}</span> 252 <span class="rounded-r p-1 select-none bg-red-100 text-red-700 dark:bg-red-800/50 dark:text-red-400">-{{ i "loader-circle" "size-3 inline-flex animate-spin" }}</span> 253 </div> 254 </div> 255 {{ if .IsInterdiff }} 256 <span class="text-sm"> 257 Interdiff 258 <span class="ml-1 text-xs after:content-['|'] after:ml-1 after:text-gray-300 dark:after:text-gray-600"> 259 <code class="inline-block box-content min-h-[1lh] py-0.5 px-1 border border-gray-300 dark:border-gray-600">v{{ .Version1 }}</code> 260 {{ i "arrow-right" "size-3 inline-flex" }} 261 <code class="inline-block box-content min-h-[1lh] py-0.5 px-1 border border-gray-300 dark:border-gray-600">v{{ .Version2 }}</code> 262 </span> 263 <a href="#commits" class="btn-flat text-xs hover:bg-gray-50 dark:hover:bg-gray-800"> 264 {{ with .ChangeId }} 265 <code class="py-0.5 px-1 border border-gray-300 dark:border-gray-600">{{ shortId . }}</code> 266 {{ else }} 267 <span class="px-1">All changes</span> 268 {{ end }} 269 </a> 270 </span> 271 {{ else }} 272 <span class="text-sm"> 273 Diff 274 <span class="ml-1 text-xs after:content-['|'] after:ml-1 after:text-gray-300 dark:after:text-gray-600"> 275 <code class="py-0.5 px-1 border border-gray-300 dark:border-gray-600">v{{ .VersionId }}</code> 276 </span> 277 <a href="#commits" class="btn-flat text-xs hover:bg-gray-50 dark:hover:bg-gray-800"> 278 <code class="inline-block box-content min-h-[1lh] py-0.5 px-1 border border-gray-300 dark:border-gray-600">{{ .DisplayDiffBase }}</code> 279 {{ i "arrow-right" "size-3 inline-flex" }} 280 <code class="inline-block box-content min-h-[1lh] py-0.5 px-1 border border-gray-300 dark:border-gray-600">{{ .DisplayDiffHead }}</code> 281 </a> 282 </span> 283 {{ end }} 284 </div> 285 <!-- right --> 286 <div class="h-12 flex items-center gap-2"> 287 <label title="Expand/Collapse diffs" class="btn font-normal normal-case"> 288 <input type="checkbox" id="diff-collapse-toggle" class="peer/collapse hidden" checked/> 289 <span class="peer-checked/collapse:hidden inline-flex items-center gap-2"> 290 {{ i "unfold-vertical" "size-4" }} 291 <span class="hidden md:inline">Expand all</span> 292 </span> 293 <span class="peer-checked/collapse:inline-flex hidden items-center gap-2"> 294 {{ i "fold-vertical" "size-4" }} 295 <span class="hidden md:inline">Collapse all</span> 296 </span> 297 </label> 298 299 <div class="md:hidden flex-grow"></div> 300 301 <!-- diff settings --> 302 <div id="diff-settings"> 303 {{ template "repo/pulls/fragments/diffSettings" (dict "DiffUrl" $diffUrl "Unified" true) }} 304 </div> 305 306 {{ $isInterdiff := .IsInterdiff }} 307 {{ $canInterdiff := gt .ActiveVersionId 0 }} 308 <div class="btn-group"> 309 <button 310 type="button" 311 role="link" 312 onclick="window.location.href='/{{ .Pull.RepoDid }}/pulls/{{ .Pull.PullId }}/{{ .ActiveVersionId }}';" 313 class="btn-group-item {{ if not $isInterdiff }}active{{ end }}" 314 > 315 {{ i "diff" "size-4" }} 316 Diff 317 </button> 318 <button 319 type="button" 320 role="link" 321 onclick="window.location.href='/{{ .Pull.RepoDid }}/pulls/{{ .Pull.PullId }}/{{ sub .ActiveVersionId 1 }}..{{ .ActiveVersionId }}';" 322 class="btn-group-item {{ if $isInterdiff }}active{{ end }}" 323 {{ if not $canInterdiff }}disabled{{ end }} 324 > 325 {{ i "chevrons-left-right-ellipsis" "size-4 rotate-90" }} 326 Interdiff 327 </button> 328 </div> 329 <label 330 for="discussion-toggle" 331 title="Toggle discussion panel" 332 class="btn-flat hidden lg:inline-flex group-has-[#discussion-toggle:checked]/pr-layout:hidden" 333 > 334 {{ i "message-square-more" "size-4" }} 335 </label> 336 </div> 337 </header> 338 <div class="flex"> 339 <input type="checkbox" id="diff-tree-toggle" class="peer hidden" checked> 340 <aside id="diff-files" class="hidden peer-checked:md:block w-[20%] max-w-[40%]"> 341 <div class="sticky top-12 bg-white dark:bg-gray-800 rounded shadow-sm border border-gray-200 dark:border-gray-700"> 342 <div class=" 343 max-h-[calc(100vh-3rem-0.5rem)] pb-2 344 overflow-y-auto 345 "> 346 <section class="text-sm px-6 py-2 w-full"> 347 <div class="mb-8"> 348 <div id="diff-files-content"> 349 {{ i "loader-circle" "size-4 inline-flex animate-spin" }} loading... 350 </div> 351 </div> 352 </section> 353 </div> 354 </div> 355 </aside> 356 357 {{ template "resize-grip" (list "resize-diff-files" "diff-files" "before" "hidden peer-checked:md:flex") }} 358 359 <div id="diff-list-container" class="flex-1 min-w-0"> 360 <div 361 id="diff-list" 362 hx-get="{{ $diffUrl }}" 363 hx-swap="outerHTML" 364 hx-trigger="load" 365 > 366 {{ i "loader-circle" "size-4 inline-flex animate-spin" }} loading... 367 </div> 368 </div> 369 <script> 370 (() => { 371 const checkbox = document.getElementById('diff-collapse-toggle'); 372 const diffList = document.getElementById('diff-list-container'); 373 374 checkbox.addEventListener('change', () => { 375 console.debug("checked", checkbox.checked); 376 diffList.querySelectorAll('details[id^="file-"]').forEach(detail => { 377 detail.open = checkbox.checked; 378 }); 379 }); 380 381 if (window.__collapseToggleHandler) { 382 diffList.removeEventListener('toggle', window.__collapseToggleHandler, true); 383 } 384 385 const handler = (e) => { 386 if (!e.target.matches('details[id^="file-"]')) return; 387 const details = document.querySelectorAll('details[id^="file-"]'); 388 const allOpen = Array.from(details).every(d => d.open); 389 const allClosed = Array.from(details).every(d => !d.open); 390 391 if (allOpen) checkbox.checked = true; 392 else if (allClosed) checkbox.checked = false; 393 }; 394 395 window.__collapseToggleHandler = handler; 396 diffList.addEventListener('toggle', handler, true); 397 })(); 398 </script> 399 </div> 400 </div> 401 </div> 402 403 <div id="bottom-sheet-backdrop" class="fixed inset-0 bg-black/50 lg:hidden opacity-0 pointer-events-none transition-opacity duration-300 z-20"></div> 404 405 <input type="checkbox" id="discussion-toggle" class="peer hidden" checked> 406 {{ template "resize-grip" (list "resize-discussion" "discussion" "after" "hidden peer-checked:lg:flex") }} 407 408 <div id="discussion" class=" 409 fixed z-30 bottom-0 right-0 w-full max-h-[calc(100vh-10rem)] rounded-t-2xl 410 bg-slate-100 dark:bg-gray-900 411 lg:sticky lg:top-0 lg:hidden peer-checked:lg:block lg:w-[25vw] lg:max-w-[50vw] lg:max-h-screen 412 lg:bg-transparent 413 "> 414 <details open id="bottom-sheet" class=" 415 flex flex-col group/history 416 {{ if .Pull.State.IsOpen -}} *:border-green-600 *:dark:border-green-900 417 {{ else if .Pull.State.IsMerged -}} *:border-purple-600 *:dark:border-purple-900 418 {{ else if .Pull.State.IsAbandoned -}} *:border-red-600 *:dark:border-red-900 419 {{ else -}} *:border-gray-600 *:dark:border-gray-900 420 {{ end }} 421 "> 422 {{ $versions := len .Pull.Versions }} 423 {{ $comments := .Pull.TotalComments }} 424 <summary class=" 425 list-none z-20 flex items-center justify-between 426 pl-3 pr-4 py-2 rounded-t-2xl 427 relative 428 border-t-4 border-x-4 429 group-open/history:bg-transparent 430 lg:border-0 431 lg:h-12 lg:px-1 lg:pointer-events-none 432 lg:bg-transparent 433 "> 434 <div class="flex items-center gap-2"> 435 <span class="lg:hidden"> 436 {{ template "repo/pulls/fragments/pullState" .Pull.State }} 437 </span> 438 <h2>History</h2> 439 </div> 440 <div class="flex items-center gap-2 text-sm"> 441 <span> 442 {{ $versions }} version{{ if ne $versions 1 }}s{{ end }} 443 </span> 444 <span class="select-none before:content-['\00B7']"></span> 445 <span> 446 {{ $comments }} comment{{ if ne $comments 1 }}s{{ end }} 447 </span> 448 <label for="discussion-toggle" title="Toggle discussion panel" class="hidden lg:inline-flex btn-flat pointer-events-auto"> 449 {{ i "message-square" "size-4" }} 450 </label> 451 <span class="lg:hidden"> 452 <span class="group-open/history:hidden inline">{{ i "chevron-up" "size-4" }}</span> 453 <span class="group-open/history:inline hidden">{{ i "chevron-down" "size-4" }}</span> 454 </span> 455 </div> 456 </summary> 457 <div class=" 458 max-h-[calc(100vh-3rem-0.5rem)] pb-32 overflow-y-auto space-y-4 459 px-1 border-x-4 460 lg:px-0 lg:border-0 461 "> 462 {{ range .Pull.Versions }} 463 {{ $active := eq .ID $.ActiveVersionId }} 464 <div 465 id="version-{{ .ID }}" 466 class=" 467 {{ if $active }}active{{ end }} 468 w-full shadow-sm rounded overflow-clip bg-gray-50 dark:bg-gray-900 469 " 470 > 471 <!-- header --> 472 <header class="sticky top-0 z-20 bg-slate-100 dark:bg-gray-900"> 473 <div class="pt-2 pr-2 pb-4 pl-4 lg:pl-6 flex gap-2 474 rounded-t border-t border-x border-gray-200 dark:border-gray-700 475 {{ if $active }} 476 bg-blue-50 dark:bg-blue-950 477 {{ else }} 478 bg-white dark:bg-gray-800 479 {{ end }} 480 "> 481 <!-- left column: just profile picture --> 482 <div class="flex-shrink-0 pt-2"> 483 {{ template "user/fragments/picLink" (list $.Pull.OwnerDid.String "size-8" (index $.VouchRelationships $.Pull.OwnerDid)) }} 484 </div> 485 <!-- right column --> 486 <div class="flex-1 min-w-0 flex flex-col gap-1"> 487 <!-- submission info --> 488 {{ $handle := resolve $.Pull.OwnerDid.String }} 489 <div class="flex gap-2 items-center justify-between mb-1"> 490 <span class="inline-flex items-center gap-2 text-sm pt-2 491 {{ if $active }} 492 text-gray-600 dark:text-gray-300 493 {{ else }} 494 text-gray-500 dark:text-gray-400 495 {{ end }}" 496 > 497 <a href="/{{ $handle }}">{{ $handle }}</a> 498 submitted 499 <span class=" 500 px-2 py-0.5 rounded font-mono text-xs border 501 {{ if $active }} 502 text-blue-800 dark:text-white bg-blue-100 dark:bg-blue-600 border-blue-200 dark:border-blue-500 503 {{ else }} 504 text-black dark:text-white bg-gray-100 dark:bg-gray-700 border-gray-300 dark:border-gray-600 505 {{ end }} 506 ">#{{ .ID }}</span> 507 <span class="select-none before:content-['\00B7']"></span> 508 <a href="/{{ $.Pull.RepoDid }}/pulls/{{ $.Pull.PullId }}/{{ .ID }}">{{ template "repo/fragments/shortTime" .Created }}</a> 509 </span> 510 <a class="btn-flat flex items-center gap-2 no-underline hover:no-underline text-sm" 511 href="/{{ $.Pull.RepoDid }}/pulls/{{ $.Pull.PullId }}/{{ .ID }}"> 512 {{ i "diff" "size-4" }} 513 Diff 514 </a> 515 </div> 516 {{ if eq .ID $.Pull.LatestVersionNumber }} 517 <div id="mergecheck-banner"> 518 {{ if $.Pull.State.IsOpen }} 519 <div class="flex items-center gap-2 text-gray-500 dark:text-gray-400"> 520 {{ i "loader-circle" "size-4 animate-spin" }} 521 <span>Checking mergeability…</span> 522 </div> 523 {{ end }} 524 </div> 525 {{ end }} 526 </div> 527 </div> 528 </header> 529 <!-- comments --> 530 {{ $count := len .Comments }} 531 <details 532 class="relative pl-8 lg:pl-10 rounded-b border-x border-b border-gray-200 dark:border-gray-700 group/comments group/collapse" 533 {{ if or $active (eq $count 0) }}open{{ end }} 534 > 535 <summary class="cursor-pointer list-none"> 536 <div class="collapse-trigger hidden group-open/comments:block absolute left-2 top-0 bottom-0 w-12 lg:w-16 transition-colors flex items-center justify-center group/border z-4"> 537 <div class="absolute left-1/2 -translate-x-1/2 top-0 bottom-0 w-0.5 group-open/comments:bg-gray-200 dark:group-open/comments:bg-gray-700 group-has-[.collapse-trigger:hover]/collapse:bg-gray-400 dark:group-has-[.collapse-trigger:hover]/collapse:bg-gray-500 transition-colors"> </div> 538 </div> 539 <div class="group-open/comments:hidden block relative group/summary py-4"> 540 <div class="absolute -left-8 top-0 bottom-0 w-16 transition-colors flex items-center justify-center z-4"> 541 <div class="absolute left-1/2 -translate-x-1/2 h-1/3 top-0 bottom-0 w-0.5 bg-gray-200 dark:bg-gray-700 group-hover/summary:bg-gray-400 dark:group-hover/summary:bg-gray-500 transition-colors"></div> 542 </div> 543 <span class="text-gray-500 dark:text-gray-400 text-sm group-hover/summary:text-gray-600 dark:group-hover/summary:text-gray-300 transition-colors flex items-center gap-2 -ml-2 relative"> 544 {{ i "circle-plus" "size-4 z-5" }} 545 Expand {{ $count }} comment{{ if ne $count 1 }}s{{ end }} 546 </span> 547 </div> 548 </summary> 549 <div id="pull-comments-{{ .ID }}"> 550 {{ range .Comments }} 551 {{ template "fragments/comment/pullComment" 552 (dict "LoggedInUser" $.LoggedInUser 553 "Reactions" (index (asReactionMapMap $.Reactions) .FeedCommentAtUri) 554 "UserReacted" (index (asReactionStatusMapMap $.UserReacted) .FeedCommentAtUri) 555 "Comment" .) }} 556 {{ end }} 557 </div> 558 {{ if gt $count 0}} 559 <button 560 class="collapse-trigger flex items-center gap-2 -ml-2 relative cursor-pointer text-sm text-gray-500 dark:text-gray-400 group-has-[.collapse-trigger:hover]/collapse:text-gray-600 dark:group-has-[.collapse-trigger:hover]/collapse:text-gray-300 mt-4 pb-4 transition-colors" 561 hx-on:click="this.closest('details').open = false" 562 > 563 <span class="bg-gray-50 dark:bg-slate-900 dark:rounded-full">{{ i "circle-chevron-up" "size-4 z-5" }}</span> Collapse comment{{ if ne $count 1 }}s{{ end }} 564 </button> 565 {{ end }} 566 567 <div hx-include="this" class="relative -ml-8 lg:-ml-10 rounded-b bg-gray-50 dark:bg-gray-900"> 568 {{ if eq .ID $.Pull.LatestVersionNumber }} 569 {{ block "mergeStatus" $ }} {{ end }} 570 <div id="pull-action-error" class="error"></div> 571 {{ end }} 572 <input name="subject-uri" type="hidden" value="{{ $.Pull.AtUri }}"> 573 <input name="pull-round-idx" type="hidden" value="{{ .ID }}"> 574 {{ template "repo/pulls/fragments/pullActions" 575 (dict 576 "LoggedInUser" $.LoggedInUser 577 "Pull" $.Pull 578 "RepoInfo" $.RepoInfo 579 "RoundNumber" .ID 580 "MergeCheck" $.MergeCheck 581 "ResubmitCheck" $.ResubmitCheck 582 "BranchDeleteStatus" $.BranchDeleteStatus 583 "Loading" (eq .ID $.Pull.LatestVersionNumber)) }} 584 </div> 585 </details> 586 </div> 587 {{ end }} 588 </div> 589 <div class="hidden sticky bottom-0 h-12"> 590 <!-- TODO: bottom PR actions --> 591 </div> 592 </details> 593 </div> 594 <script> 595 (function() { 596 const details = document.getElementById('bottom-sheet'); 597 const backdrop = document.getElementById('bottom-sheet-backdrop'); 598 const isDesktop = () => window.matchMedia('(min-width: 1024px)').matches; 599 600 // function to update backdrop 601 const updateBackdrop = () => { 602 if (backdrop) { 603 if (details.open && !isDesktop()) { 604 backdrop.classList.remove('opacity-0', 'pointer-events-none'); 605 backdrop.classList.add('opacity-100', 'pointer-events-auto'); 606 document.body.style.overflow = 'hidden'; 607 } else { 608 backdrop.classList.remove('opacity-100', 'pointer-events-auto'); 609 backdrop.classList.add('opacity-0', 'pointer-events-none'); 610 document.body.style.overflow = ''; 611 } 612 } 613 }; 614 615 // close on mobile initially 616 if (!isDesktop()) { 617 details.open = false; 618 } 619 updateBackdrop(); // initialize backdrop 620 621 // prevent closing on desktop 622 details.addEventListener('toggle', function(e) { 623 if (isDesktop() && !this.open) { 624 this.open = true; 625 } 626 updateBackdrop(); 627 }); 628 629 const mediaQuery = window.matchMedia('(min-width: 1024px)'); 630 mediaQuery.addEventListener('change', function(e) { 631 if (e.matches) { 632 // switched to desktop - keep open 633 details.open = true; 634 } else { 635 // switched to mobile - close 636 details.open = false; 637 } 638 updateBackdrop(); 639 }); 640 641 // close when clicking backdrop 642 if (backdrop) { 643 backdrop.addEventListener('click', () => { 644 if (!isDesktop()) { 645 details.open = false; 646 } 647 }); 648 } 649 })(); 650 </script> 651</div> 652{{ end }}