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 }}