forked from tangled.org/core
this repo has no description

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