forked from
tangled.org/core
Monorepo for Tangled — https://tangled.org
1{{ define "title" }}{{ .Issue.Title }} · issue #{{ .Issue.IssueId }} · {{ .RepoInfo.FullName }}{{ end }}
2
3
4{{ define "extrameta" }}
5 {{ $title := printf "%s · issue #%d · %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 }}