forked from tangled.org/core
Monorepo for Tangled — https://tangled.org
1{{ define "title" }}{{ .Issue.Title }} &middot; issue #{{ .Issue.IssueId }} &middot; {{ .RepoInfo.FullName }}{{ end }} 2 3 4{{ define "extrameta" }} 5 {{ $title := printf "%s &middot; issue #%d &middot; %s" .Issue.Title .Issue.IssueId .RepoInfo.FullName }} 6 {{ $url := printf "https://tangled.sh/%s/issues/%d" .RepoInfo.FullName .Issue.IssueId }} 7 8 {{ template "repo/fragments/og" (dict "RepoInfo" .RepoInfo "Title" $title "Url" $url) }} 9{{ end }} 10 11{{ define "repoContent" }} 12 <header class="pb-4"> 13 <h1 class="text-2xl"> 14 {{ .Issue.Title }} 15 <span class="text-gray-500 dark:text-gray-400">#{{ .Issue.IssueId }}</span> 16 </h1> 17 </header> 18 19 {{ $bgColor := "bg-gray-800 dark:bg-gray-700" }} 20 {{ $icon := "ban" }} 21 {{ if eq .State "open" }} 22 {{ $bgColor = "bg-green-600 dark:bg-green-700" }} 23 {{ $icon = "circle-dot" }} 24 {{ end }} 25 26 <section class="mt-2"> 27 <div class="inline-flex items-center gap-2"> 28 <div id="state" 29 class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }}"> 30 {{ i $icon "w-4 h-4 mr-1.5 text-white" }} 31 <span class="text-white">{{ .State }}</span> 32 </div> 33 <span class="text-gray-500 dark:text-gray-400 text-sm"> 34 opened by 35 {{ $owner := didOrHandle .Issue.OwnerDid .IssueOwnerHandle }} 36 <a href="/{{ $owner }}" class="no-underline hover:underline" 37 >{{ $owner }}</a 38 > 39 <span class="px-1 select-none before:content-['\00B7']"></span> 40 <time title="{{ .Issue.Created | longTimeFmt }}"> 41 {{ .Issue.Created | timeFmt }} 42 </time> 43 </span> 44 </div> 45 46 {{ if .Issue.Body }} 47 <article id="body" class="mt-8 prose dark:prose-invert"> 48 {{ .Issue.Body | markdown }} 49 </article> 50 {{ end }} 51 </section> 52{{ end }} 53 54{{ define "repoAfter" }} 55 <section id="comments" class="my-2 mt-2 space-y-2 relative"> 56 {{ range $index, $comment := .Comments }} 57 <div 58 id="comment-{{ .CommentId }}" 59 class="bg-white dark:bg-gray-800 rounded drop-shadow-sm py-2 px-4 relative w-full md:max-w-3/5 md:w-fit"> 60 {{ if gt $index 0 }} 61 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300 dark:bg-gray-600"></div> 62 {{ end }} 63 {{ template "repo/issues/fragments/issueComment" (dict "RepoInfo" $.RepoInfo "LoggedInUser" $.LoggedInUser "DidHandleMap" $.DidHandleMap "Issue" $.Issue "Comment" .)}} 64 </div> 65 {{ end }} 66 </section> 67 68 {{ block "newComment" . }} {{ end }} 69 70{{ end }} 71 72{{ define "newComment" }} 73 {{ if .LoggedInUser }} 74 <form 75 id="comment-form" 76 hx-post="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/comment" 77 hx-on::after-request="if(event.detail.successful) this.reset()" 78 > 79 <div class="bg-white dark:bg-gray-800 rounded drop-shadow-sm py-4 px-4 relative w-full md:w-3/5"> 80 <div class="text-sm pb-2 text-gray-500 dark:text-gray-400"> 81 {{ didOrHandle .LoggedInUser.Did .LoggedInUser.Handle }} 82 </div> 83 <textarea 84 id="comment-textarea" 85 name="body" 86 class="w-full p-2 rounded border border-gray-200 dark:border-gray-700" 87 placeholder="Add to the discussion. Markdown is supported." 88 onkeyup="updateCommentForm()" 89 ></textarea> 90 <div id="issue-comment"></div> 91 <div id="issue-action" class="error"></div> 92 </div> 93 94 <div class="flex gap-2 mt-2"> 95 <button 96 id="comment-button" 97 hx-post="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/comment" 98 type="submit" 99 hx-disabled-elt="#comment-button" 100 class="btn p-2 flex items-center gap-2 no-underline hover:no-underline group" 101 disabled 102 > 103 {{ i "message-square-plus" "w-4 h-4" }} 104 comment 105 {{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }} 106 </button> 107 108 {{ $isIssueAuthor := and .LoggedInUser (eq .LoggedInUser.Did .Issue.OwnerDid) }} 109 {{ $isRepoCollaborator := .RepoInfo.Roles.IsCollaborator }} 110 {{ $isRepoOwner := .RepoInfo.Roles.IsOwner }} 111 {{ if and (or $isIssueAuthor $isRepoCollaborator $isRepoOwner) (eq .State "open") }} 112 <button 113 id="close-button" 114 type="button" 115 class="btn flex items-center gap-2" 116 hx-indicator="#close-spinner" 117 hx-trigger="click" 118 > 119 {{ i "ban" "w-4 h-4" }} 120 close 121 <span id="close-spinner" class="group"> 122 {{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }} 123 </span> 124 </button> 125 <div 126 id="close-with-comment" 127 hx-post="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/comment" 128 hx-trigger="click from:#close-button" 129 hx-disabled-elt="#close-with-comment" 130 hx-target="#issue-comment" 131 hx-indicator="#close-spinner" 132 hx-vals="js:{body: document.getElementById('comment-textarea').value.trim() !== '' ? document.getElementById('comment-textarea').value : ''}" 133 hx-swap="none" 134 > 135 </div> 136 <div 137 id="close-issue" 138 hx-disabled-elt="#close-issue" 139 hx-post="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/close" 140 hx-trigger="click from:#close-button" 141 hx-target="#issue-action" 142 hx-indicator="#close-spinner" 143 hx-swap="none" 144 > 145 </div> 146 <script> 147 document.addEventListener('htmx:configRequest', function(evt) { 148 if (evt.target.id === 'close-with-comment') { 149 const commentText = document.getElementById('comment-textarea').value.trim(); 150 if (commentText === '') { 151 evt.detail.parameters = {}; 152 evt.preventDefault(); 153 } 154 } 155 }); 156 </script> 157 {{ else if and (or $isIssueAuthor $isRepoCollaborator $isRepoOwner) (eq .State "closed") }} 158 <button 159 type="button" 160 class="btn flex items-center gap-2" 161 hx-post="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/reopen" 162 hx-indicator="#reopen-spinner" 163 hx-swap="none" 164 > 165 {{ i "refresh-ccw-dot" "w-4 h-4" }} 166 reopen 167 <span id="reopen-spinner" class="group"> 168 {{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }} 169 </span> 170 </button> 171 {{ end }} 172 173 <script> 174 function updateCommentForm() { 175 const textarea = document.getElementById('comment-textarea'); 176 const commentButton = document.getElementById('comment-button'); 177 const closeButton = document.getElementById('close-button'); 178 179 if (textarea.value.trim() !== '') { 180 commentButton.removeAttribute('disabled'); 181 } else { 182 commentButton.setAttribute('disabled', ''); 183 } 184 185 if (closeButton) { 186 if (textarea.value.trim() !== '') { 187 closeButton.innerHTML = ` 188{{ i "ban" "w-4 h-4" }} 189<span>close with comment</span> 190<span id="close-spinner" class="group"> 191 {{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }} 192</span>`; 193 } else { 194 closeButton.innerHTML = ` 195{{ i "ban" "w-4 h-4" }} 196<span>close</span> 197<span id="close-spinner" class="group"> 198 {{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }} 199</span>`; 200 } 201 } 202 } 203 204 document.addEventListener('DOMContentLoaded', function() { 205 updateCommentForm(); 206 }); 207 </script> 208 </div> 209 </form> 210 {{ else }} 211 <div class="bg-white dark:bg-gray-800 rounded drop-shadow-sm py-4 px-4 relative w-fit"> 212 <a href="/login" class="underline">login</a> to join the discussion 213 </div> 214 {{ end }} 215{{ end }}