forked from tangled.org/core
Monorepo for Tangled

show stars in profile; styles for issue comments

Changed files
+116 -26
appview
db
pages
templates
fragments
repo
user
+75 -4
appview/db/repos.go
··· 13 13 Created time.Time 14 14 AtUri string 15 15 Description string 16 + 17 + // optionally, populate this when querying for reverse mappings 18 + RepoStats *RepoStats 16 19 } 17 20 18 21 func GetAllRepos(e Execer, limit int) ([]Repo, error) { ··· 52 55 func GetAllReposByDid(e Execer, did string) ([]Repo, error) { 53 56 var repos []Repo 54 57 55 - rows, err := e.Query(`select did, name, knot, rkey, description, created from repos where did = ?`, did) 58 + rows, err := e.Query( 59 + `select 60 + r.did, 61 + r.name, 62 + r.knot, 63 + r.rkey, 64 + r.description, 65 + r.created, 66 + count(s.id) as star_count 67 + from 68 + repos r 69 + left join 70 + stars s on r.at_uri = s.repo_at 71 + where 72 + r.did = ? 73 + group by 74 + r.at_uri`, did) 56 75 if err != nil { 57 76 return nil, err 58 77 } ··· 60 79 61 80 for rows.Next() { 62 81 var repo Repo 63 - err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Description, &repo.Created) 82 + var repoStats RepoStats 83 + var createdAt string 84 + var nullableDescription sql.NullString 85 + 86 + err := rows.Scan(&repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &nullableDescription, &createdAt, &repoStats.StarCount) 64 87 if err != nil { 65 88 return nil, err 66 89 } 90 + 91 + if nullableDescription.Valid { 92 + repo.Description = nullableDescription.String 93 + } else { 94 + repo.Description = "" 95 + } 96 + 97 + createdAtTime, err := time.Parse(time.RFC3339, createdAt) 98 + if err != nil { 99 + repo.Created = time.Now() 100 + } else { 101 + repo.Created = createdAtTime 102 + } 103 + 104 + repo.RepoStats = &repoStats 105 + 67 106 repos = append(repos, repo) 68 107 } 69 108 ··· 150 189 func CollaboratingIn(e Execer, collaborator string) ([]Repo, error) { 151 190 var repos []Repo 152 191 153 - rows, err := e.Query(`select r.did, r.name, r.knot, r.rkey, r.description, r.created from repos r join collaborators c on r.id = c.repo where c.did = ?;`, collaborator) 192 + rows, err := e.Query( 193 + `select 194 + r.did, r.name, r.knot, r.rkey, r.description, r.created, count(s.id) as star_count 195 + from 196 + repos r 197 + join 198 + collaborators c on r.id = c.repo 199 + left join 200 + stars s on r.at_uri = s.repo_at 201 + where 202 + c.did = ? 203 + group by 204 + r.id;`, collaborator) 154 205 if err != nil { 155 206 return nil, err 156 207 } ··· 158 209 159 210 for rows.Next() { 160 211 var repo Repo 161 - err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Description, &repo.Created) 212 + var repoStats RepoStats 213 + var createdAt string 214 + var nullableDescription sql.NullString 215 + 216 + err := rows.Scan(&repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &nullableDescription, &createdAt, &repoStats.StarCount) 162 217 if err != nil { 163 218 return nil, err 164 219 } 220 + 221 + if nullableDescription.Valid { 222 + repo.Description = nullableDescription.String 223 + } else { 224 + repo.Description = "" 225 + } 226 + 227 + createdAtTime, err := time.Parse(time.RFC3339, createdAt) 228 + if err != nil { 229 + repo.Created = time.Now() 230 + } else { 231 + repo.Created = createdAtTime 232 + } 233 + 234 + repo.RepoStats = &repoStats 235 + 165 236 repos = append(repos, repo) 166 237 } 167 238
+3 -1
appview/db/star.go
··· 10 10 type Star struct { 11 11 StarredByDid string 12 12 RepoAt syntax.ATURI 13 - Repo *Repo 14 13 Created time.Time 15 14 Rkey string 15 + 16 + // optionally, populate this when querying for reverse mappings 17 + Repo *Repo 16 18 } 17 19 18 20 func (star *Star) ResolveRepo(e Execer) error {
+6 -1
appview/pages/pages.go
··· 523 523 524 524 func Cache(h http.Handler) http.Handler { 525 525 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 526 - w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") 526 + if strings.HasSuffix(r.URL.Path, ".css") { 527 + // on day for css files 528 + w.Header().Set("Cache-Control", "public, max-age=86400") 529 + } else { 530 + w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") 531 + } 527 532 h.ServeHTTP(w, r) 528 533 }) 529 534 }
-3
appview/pages/templates/fragments/star.html
··· 22 22 <span> 23 23 {{ .Stats.StarCount }} 24 24 </span> 25 - <span id="starSpinner" class="hidden"> 26 - loading 27 - </span> 28 25 </div> 29 26 </button> 30 27 <script>
+11 -8
appview/pages/templates/repo/issues/issue.html
··· 4 4 {{ end }} 5 5 6 6 {{ define "repoContent" }} 7 - <h1> 7 + <header> 8 + <p class="text-2xl font-bold"> 8 9 {{ .Issue.Title }} 9 - <span class="text-gray-400">#{{ .Issue.IssueId }}</span> 10 - </h1> 10 + <span class="text-gray-500">#{{ .Issue.IssueId }}</span> 11 + </p> 12 + </header> 11 13 12 14 {{ $bgColor := "bg-gray-800" }} 13 15 {{ $icon := "ban" }} ··· 23 25 <i data-lucide="{{ $icon }}" class="w-4 h-4 mr-1.5 text-white" ></i> 24 26 <span class="text-white">{{ .State }}</span> 25 27 </div> 26 - <span class="text-gray-400 text-sm"> 28 + <span class="text-gray-500 text-sm"> 27 29 opened by 28 30 {{ $owner := didOrHandle .Issue.OwnerDid .IssueOwnerHandle }} 29 31 <a href="/{{ $owner }}" class="no-underline hover:underline" ··· 35 37 </div> 36 38 37 39 {{ if .Issue.Body }} 38 - <article id="body" class="mt-8 prose"> 40 + <article id="body" class="mt-4 prose"> 39 41 {{ .Issue.Body | markdown }} 40 42 </article> 41 43 {{ end }} ··· 47 49 {{ range $index, $comment := .Comments }} 48 50 <div 49 51 id="comment-{{ .CommentId }}" 50 - class="rounded bg-white p-4 relative" 52 + class="rounded bg-white px-6 py-4 relative" 51 53 > 52 54 {{ if eq $index 0 }} 53 55 <div ··· 58 60 class="absolute left-8 -top-4 w-px h-4 bg-gray-300" 59 61 ></div> 60 62 {{ end }} 61 - <div class="flex items-center gap-2 mb-2 text-gray-400"> 63 + <div class="flex items-center gap-2 mb-2 text-gray-500"> 62 64 {{ $owner := index $.DidHandleMap .OwnerDid }} 63 65 <span class="text-sm"> 64 66 <a ··· 67 69 >{{ $owner }}</a 68 70 > 69 71 </span> 70 - <span class="px-1 select-none before:content-['\00B7']"></span> 72 + 73 + <span class="before:content-['·']"></span> 71 74 <a 72 75 href="#{{ .CommentId }}" 73 76 class="text-gray-500 text-sm hover:text-gray-500 hover:underline no-underline"
+4 -4
appview/pages/templates/repo/issues/issues.html
··· 4 4 <div class="flex justify-between items-center"> 5 5 <p> 6 6 filtering 7 - <select class="font-bold border border-gray-200 rounded" onchange="window.location.href = '/{{ .RepoInfo.FullName }}/issues?state=' + this.value"> 7 + <select class="border px-1 bg-white border-gray-200" onchange="window.location.href = '/{{ .RepoInfo.FullName }}/issues?state=' + this.value"> 8 8 <option value="open" {{ if .FilteringByOpen }}selected{{ end }}>open</option> 9 9 <option value="closed" {{ if not .FilteringByOpen }}selected{{ end }}>closed</option> 10 10 </select> ··· 30 30 class="no-underline hover:underline" 31 31 > 32 32 {{ .Title }} 33 - <span class="text-gray-400">#{{ .IssueId }}</span> 33 + <span class="text-gray-500">#{{ .IssueId }}</span> 34 34 </a> 35 35 </div> 36 - <p class="text-sm text-gray-400"> 36 + <p class="text-sm text-gray-500"> 37 37 {{ $bgColor := "bg-gray-800" }} 38 38 {{ $icon := "ban" }} 39 39 {{ $state := "closed" }} ··· 64 64 {{ if eq .Metadata.CommentCount 1 }} 65 65 {{ $s = "" }} 66 66 {{ end }} 67 - <a href="/{{ $.RepoInfo.FullName }}/issues/{{ .IssueId }}" class="text-gray-400">{{ .Metadata.CommentCount }} comment{{$s}}</a> 67 + <a href="/{{ $.RepoInfo.FullName }}/issues/{{ .IssueId }}" class="text-gray-500">{{ .Metadata.CommentCount }} comment{{$s}}</a> 68 68 </span> 69 69 </p> 70 70 </div>
+17 -5
appview/pages/templates/user/profile.html
··· 44 44 class="py-4 px-6 drop-shadow-sm rounded bg-white" 45 45 > 46 46 <div id="repo-card-name" class="font-medium"> 47 - <a href="/@{{ or $.UserHandle $.UserDid }}/{{ .Name }}" 48 - >{{ .Name }}</a 49 - > 47 + <a href="/@{{ or $.UserHandle $.UserDid }}/{{ .Name }}">{{ .Name }}</a> 50 48 </div> 51 49 {{ if .Description }} 52 50 <div class="text-gray-600 text-sm"> 53 51 {{ .Description }} 54 52 </div> 55 53 {{ end }} 56 - <div class="text-gray-600 text-sm font-mono"> 54 + <div class="text-gray-600 text-sm font-mono inline-flex gap-4"> 57 55 {{ .Knot }} 56 + 57 + {{ if .RepoStats.StarCount }} 58 + <div class="flex gap-1 items-center text-sm"> 59 + <span class="w-2 h-2 fill-current" data-lucide="star"></span> 60 + <span>{{ .RepoStats.StarCount }}</span> 61 + </div> 62 + {{ end }} 58 63 </div> 59 64 </div> 60 65 {{ else }} ··· 81 86 {{ .Description }} 82 87 </div> 83 88 {{ end }} 84 - <div class="text-gray-600 text-sm font-mono"> 89 + <div class="text-gray-600 text-sm font-mono inline-flex gap-4"> 85 90 {{ .Knot }} 91 + 92 + {{ if .RepoStats.StarCount }} 93 + <div class="flex gap-1 items-center text-sm"> 94 + <span class="w-2 h-2 fill-current" data-lucide="star"></span> 95 + <span>{{ .RepoStats.StarCount }}</span> 96 + </div> 97 + {{ end }} 86 98 </div> 87 99 </div> 88 100 {{ else }}