forked from
tangled.org/core
Monorepo for Tangled — https://tangled.org
1{{ define "title" }}{{ or .UserHandle .UserDid }}{{ end }}
2
3{{ define "content" }}
4<div class="grid grid-cols-1 md:grid-cols-8 gap-6">
5 <div class="md:col-span-2 order-1 md:order-1">
6 {{ block "profileCard" . }}{{ end }}
7 </div>
8 <div id="all-repos" class="md:col-span-3 order-2 md:order-2">
9 {{ block "ownRepos" . }}{{ end }}
10 {{ block "collaboratingRepos" . }}{{ end }}
11 </div>
12 <div class="md:col-span-3 order-3 md:order-3">
13 {{ block "profileTimeline" . }}{{ end }}
14 </div>
15</div>
16{{ end }}
17
18{{ define "profileTimeline" }}
19 <p class="text-sm font-bold p-2 dark:text-white">ACTIVITY</p>
20 <div class="flex flex-col gap-6 relative">
21 {{ with .ProfileTimeline }}
22 {{ range $idx, $byMonth := .ByMonth }}
23 {{ with $byMonth }}
24 <div class="bg-white dark:bg-gray-800 px-6 py-4 rounded drop-shadow-sm">
25 {{ if eq $idx 0 }}
26
27 {{ else }}
28 {{ $s := "s" }}
29 {{ if eq $idx 1 }}
30 {{ $s = "" }}
31 {{ end }}
32 <p class="text-sm font-bold dark:text-white mb-2">{{$idx}} month{{$s}} ago</p>
33 {{ end }}
34
35 {{ if .IsEmpty }}
36 <div class="text-gray-500 dark:text-gray-400">
37 No activity for this month
38 </div>
39 {{ else }}
40 <div class="flex flex-col gap-1">
41 {{ block "repoEvents" (list .RepoEvents $.DidHandleMap) }} {{ end }}
42 {{ block "issueEvents" (list .IssueEvents $.DidHandleMap) }} {{ end }}
43 {{ block "pullEvents" (list .PullEvents $.DidHandleMap) }} {{ end }}
44 </div>
45 {{ end }}
46 </div>
47
48 {{ end }}
49 {{ else }}
50 <p class="dark:text-white">This user does not have any activity yet.</p>
51 {{ end }}
52 {{ end }}
53 </div>
54{{ end }}
55
56{{ define "repoEvents" }}
57 {{ $items := index . 0 }}
58 {{ $handleMap := index . 1 }}
59
60 {{ if gt (len $items) 0 }}
61 <details>
62 <summary class="list-none cursor-pointer hover:text-gray-500 hover:dark:text-gray-400">
63 <div class="flex flex-wrap items-center gap-2">
64 {{ i "book-plus" "w-4 h-4" }}
65 created {{ len $items }} {{if eq (len $items) 1 }}repository{{else}}repositories{{end}}
66 </div>
67 </summary>
68 <div class="py-2 text-sm flex flex-col gap-3 mb-2">
69 {{ range $items }}
70 <div class="flex flex-wrap items-center gap-2">
71 <span class="text-gray-500 dark:text-gray-400">
72 {{ if .Source }}
73 {{ i "git-fork" "w-4 h-4" }}
74 {{ else }}
75 {{ i "book-plus" "w-4 h-4" }}
76 {{ end }}
77 </span>
78 <a href="/{{ index $handleMap .Repo.Did }}/{{ .Repo.Name }}" class="no-underline hover:underline">
79 {{- .Repo.Name -}}
80 </a>
81 </div>
82 {{ end }}
83 </div>
84 </details>
85 {{ end }}
86{{ end }}
87
88{{ define "issueEvents" }}
89 {{ $i := index . 0 }}
90 {{ $items := $i.Items }}
91 {{ $stats := $i.Stats }}
92 {{ $handleMap := index . 1 }}
93
94 {{ if gt (len $items) 0 }}
95 <details>
96 <summary class="list-none cursor-pointer hover:text-gray-500 hover:dark:text-gray-400">
97 <div class="flex flex-wrap items-center gap-2">
98 {{ i "circle-dot" "w-4 h-4" }}
99
100 <div>
101 created {{ len $items }} {{if eq (len $items) 1 }}issue{{else}}issues{{end}}
102 </div>
103
104 {{ if gt $stats.Open 0 }}
105 <span class="px-2 py-1/2 text-sm rounded text-white bg-green-600 dark:bg-green-700">
106 {{$stats.Open}} open
107 </span>
108 {{ end }}
109
110 {{ if gt $stats.Closed 0 }}
111 <span class="px-2 py-1/2 text-sm rounded text-white bg-gray-800 dark:bg-gray-700">
112 {{$stats.Closed}} closed
113 </span>
114 {{ end }}
115
116 </div>
117 </summary>
118 <div class="py-2 text-sm flex flex-col gap-3 mb-2">
119 {{ range $items }}
120 {{ $repoOwner := index $handleMap .Metadata.Repo.Did }}
121 {{ $repoName := .Metadata.Repo.Name }}
122 {{ $repoUrl := printf "%s/%s" $repoOwner $repoName }}
123
124 <div class="flex gap-2 text-gray-600 dark:text-gray-300">
125 {{ if .Open }}
126 <span class="text-green-600 dark:text-green-500">
127 {{ i "circle-dot" "w-4 h-4" }}
128 </span>
129 {{ else }}
130 <span class="text-gray-500 dark:text-gray-400">
131 {{ i "ban" "w-4 h-4" }}
132 </span>
133 {{ end }}
134 <div class="flex-none min-w-8 text-right">
135 <span class="text-gray-500 dark:text-gray-400">#{{ .IssueId }}</span>
136 </div>
137 <div class="break-words max-w-full">
138 <a href="/{{$repoUrl}}/issues/{{ .IssueId }}" class="no-underline hover:underline">
139 {{ .Title -}}
140 </a>
141 on
142 <a href="/{{$repoUrl}}" class="no-underline hover:underline whitespace-nowrap">
143 {{$repoUrl}}
144 </a>
145 </div>
146 </div>
147 {{ end }}
148 </div>
149 </details>
150 {{ end }}
151{{ end }}
152
153{{ define "pullEvents" }}
154 {{ $i := index . 0 }}
155 {{ $items := $i.Items }}
156 {{ $stats := $i.Stats }}
157 {{ $handleMap := index . 1 }}
158 {{ if gt (len $items) 0 }}
159 <details>
160 <summary class="list-none cursor-pointer hover:text-gray-500 hover:dark:text-gray-400">
161 <div class="flex flex-wrap items-center gap-2">
162 {{ i "git-pull-request" "w-4 h-4" }}
163
164 <div>
165 created {{ len $items }} {{if eq (len $items) 1 }}pull request{{else}}pull requests{{end}}
166 </div>
167
168 {{ if gt $stats.Open 0 }}
169 <span class="px-2 py-1/2 text-sm rounded text-white bg-green-600 dark:bg-green-700">
170 {{$stats.Open}} open
171 </span>
172 {{ end }}
173
174 {{ if gt $stats.Merged 0 }}
175 <span class="px-2 py-1/2 text-sm rounded text-white bg-purple-600 dark:bg-purple-700">
176 {{$stats.Merged}} merged
177 </span>
178 {{ end }}
179
180
181 {{ if gt $stats.Closed 0 }}
182 <span class="px-2 py-1/2 text-sm rounded text-white bg-gray-800 dark:bg-gray-700">
183 {{$stats.Closed}} closed
184 </span>
185 {{ end }}
186
187 </div>
188 </summary>
189 <div class="py-2 text-sm flex flex-col gap-3 mb-2">
190 {{ range $items }}
191 {{ $repoOwner := index $handleMap .Repo.Did }}
192 {{ $repoName := .Repo.Name }}
193 {{ $repoUrl := printf "%s/%s" $repoOwner $repoName }}
194
195 <div class="flex gap-2 text-gray-600 dark:text-gray-300">
196 {{ if .State.IsOpen }}
197 <span class="text-green-600 dark:text-green-500">
198 {{ i "git-pull-request" "w-4 h-4" }}
199 </span>
200 {{ else if .State.IsMerged }}
201 <span class="text-purple-600 dark:text-purple-500">
202 {{ i "git-merge" "w-4 h-4" }}
203 </span>
204 {{ else }}
205 <span class="text-gray-600 dark:text-gray-300">
206 {{ i "git-pull-request-closed" "w-4 h-4" }}
207 </span>
208 {{ end }}
209 <div class="flex-none min-w-8 text-right">
210 <span class="text-gray-500 dark:text-gray-400">#{{ .PullId }}</span>
211 </div>
212 <div class="break-words max-w-full">
213 <a href="/{{$repoUrl}}/pulls/{{ .PullId }}" class="no-underline hover:underline">
214 {{ .Title -}}
215 </a>
216 on
217 <a href="/{{$repoUrl}}" class="no-underline hover:underline whitespace-nowrap">
218 {{$repoUrl}}
219 </a>
220 </div>
221 </div>
222 {{ end }}
223 </div>
224 </details>
225 {{ end }}
226{{ end }}
227
228{{ define "profileCard" }}
229 <div class="bg-white dark:bg-gray-800 px-6 py-4 rounded drop-shadow-sm max-h-fit">
230 <div class="grid grid-cols-3 md:grid-cols-1 gap-1 items-center">
231 <div id="avatar" class="col-span-1 flex justify-center items-center">
232 {{ if .AvatarUri }}
233 <img class="w-3/4 rounded-full p-2" src="{{ .AvatarUri }}" />
234 {{ end }}
235 </div>
236 <div class="col-span-2">
237 <p title="{{ didOrHandle .UserDid .UserHandle }}"
238 class="text-lg font-bold dark:text-white overflow-hidden text-ellipsis whitespace-nowrap max-w-full">
239 {{ didOrHandle .UserDid .UserHandle }}
240 </p>
241
242 <div class="md:hidden">
243 {{ block "followerFollowing" .ProfileStats }} {{ end }}
244 </div>
245 </div>
246 <div class="col-span-3 md:col-span-full">
247 <div id="profile-bio" class="text-sm">
248 {{ $profile := .Profile }}
249 {{ with .Profile }}
250
251 {{ if .Description }}
252 <p class="text-base pb-4 md:pb-2">{{ .Description }}</p>
253 {{ end }}
254
255 <div class="hidden md:block">
256 {{ block "followerFollowing" $.ProfileStats }} {{ end }}
257 </div>
258
259 <div class="flex flex-col gap-2 mb-2 overflow-hidden text-ellipsis whitespace-nowrap max-w-full">
260 {{ if .Location }}
261 <div class="flex items-center gap-2">
262 <span class="flex-shrink-0">{{ i "map-pin" "size-4" }}</span>
263 <span>{{ .Location }}</span>
264 </div>
265 {{ end }}
266 {{ if .IncludeBluesky }}
267 <div class="flex items-center gap-2">
268 <span class="flex-shrink-0">{{ i "link" "size-4" }}</span>
269 <a id="bluesky-link" href="https://bsky.app/profile/{{ $.UserDid }}">
270 bluesky/{{ didOrHandle $.UserDid $.UserHandle }}
271 </a>
272 </div>
273 {{ end }}
274 {{ range $link := .Links }}
275 {{ if $link }}
276 <div class="flex items-center gap-2">
277 <span class="flex-shrink-0">{{ i "link" "size-4" }}</span>
278 <a href="{{ $link }}">{{ $link }}</a>
279 </div>
280 {{ end }}
281 {{ end }}
282 {{ if not $profile.IsStatsEmpty }}
283 <div class="flex items-center justify-evenly gap-2 py-2">
284 {{ range $stat := .Stats }}
285 {{ if $stat.Kind }}
286 <div class="flex flex-col items-center gap-2">
287 <span class="text-xl font-bold">{{ $stat.Value }}</span>
288 <span>{{ $stat.Kind.String }}</span>
289 </div>
290 {{ end }}
291 {{ end }}
292 </div>
293 {{ end }}
294 </div>
295 {{ end }}
296 {{ if ne .FollowStatus.String "IsSelf" }}
297 {{ template "user/fragments/follow" . }}
298 {{ else }}
299 <button id="editBtn"
300 class="btn mt-2 w-full flex items-center gap-2"
301 hx-target="#profile-bio"
302 hx-get="/{{ $.UserDid }}/profile/edit-bio"
303 hx-swap="innerHTML">
304 {{ i "pencil" "w-4 h-4" }}
305 edit
306 </button>
307 {{ end }}
308 </div>
309 <div id="update-profile" class="text-red-400 dark:text-red-500"></div>
310 </div>
311 </div>
312 </div>
313{{ end }}
314
315{{ define "followerFollowing" }}
316 <div class="flex items-center gap-2 my-2 overflow-hidden text-ellipsis whitespace-nowrap max-w-full text-sm">
317 <span class="flex-shrink-0">{{ i "users" "size-4" }}</span>
318 <span id="followers">{{ .Followers }} followers</span>
319 <span class="select-none after:content-['·']"></span>
320 <span id="following">{{ .Following }} following</span>
321 </div>
322{{ end }}
323
324{{ define "ownRepos" }}
325 <div class="text-sm font-bold p-2 pr-0 dark:text-white flex items-center justify-between gap-2">
326 <span>PINNED REPOS</span>
327 {{ if and .LoggedInUser (eq .LoggedInUser.Did .UserDid) }}
328 <button hx-get="/{{ $.UserDid }}/profile/edit-pins" hx-target="#all-repos" class="btn font-normal text-sm flex gap-2 items-center">
329 {{ i "pencil" "w-3 h-3" }}
330 edit
331 </button>
332 {{ end }}
333 </div>
334 <div id="repos" class="grid grid-cols-1 gap-4 mb-6">
335 {{ range .Repos }}
336 <div
337 id="repo-card"
338 class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800">
339 <div id="repo-card-name" class="font-medium">
340 <a href="/@{{ or $.UserHandle $.UserDid }}/{{ .Name }}"
341 >{{ .Name }}</a
342 >
343 </div>
344 {{ if .Description }}
345 <div class="text-gray-600 dark:text-gray-300 text-sm">
346 {{ .Description }}
347 </div>
348 {{ end }}
349 <div class="text-gray-400 pt-1 text-sm font-mono inline-flex gap-4 mt-auto">
350 {{ if .RepoStats.StarCount }}
351 <div class="flex gap-1 items-center text-sm">
352 {{ i "star" "w-3 h-3 fill-current" }}
353 <span>{{ .RepoStats.StarCount }}</span>
354 </div>
355 {{ end }}
356 </div>
357 </div>
358 {{ else }}
359 <p class="px-6 dark:text-white">This user does not have any repos yet.</p>
360 {{ end }}
361 </div>
362{{ end }}
363
364{{ define "collaboratingRepos" }}
365 {{ if gt (len .CollaboratingRepos) 0 }}
366 <p class="text-sm font-bold p-2 dark:text-white">COLLABORATING ON</p>
367 <div id="collaborating" class="grid grid-cols-1 gap-4 mb-6">
368 {{ range .CollaboratingRepos }}
369 <div
370 id="repo-card"
371 class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800 flex flex-col">
372 <div id="repo-card-name" class="font-medium dark:text-white">
373 <a href="/{{ index $.DidHandleMap .Did }}/{{ .Name }}">
374 {{ index $.DidHandleMap .Did }}/{{ .Name }}
375 </a>
376 </div>
377 {{ if .Description }}
378 <div class="text-gray-600 dark:text-gray-300 text-sm">
379 {{ .Description }}
380 </div>
381 {{ end }}
382 <div class="text-gray-400 pt-1 text-sm font-mono inline-flex gap-4 mt-auto">
383
384 {{ if .RepoStats.StarCount }}
385 <div class="flex gap-1 items-center text-sm">
386 {{ i "star" "w-3 h-3 fill-current" }}
387 <span>{{ .RepoStats.StarCount }}</span>
388 </div>
389 {{ end }}
390 </div>
391 </div>
392 {{ else }}
393 <p class="px-6 dark:text-white">This user is not collaborating.</p>
394 {{ end }}
395 </div>
396 {{ end }}
397{{ end }}