feat(repos): show language, stars and forks
7 files changed, +18 −7
- static/style.css modified +4 −1
- store.go modified +3 −2
- templates/index.html modified +1 −1
- templates/meta.html modified +2 −1
- templates/repos.html modified +1 −1
- templates/stars.html modified +1 −1
- web.go modified +6 −0
static/style.css modified
| @@ -265,7 +265,10 @@ table.blame td.n{border-right:1px solid var(--bar)} | ||
| 265 | 265 | .event h4{display:flex;align-items:baseline;flex-wrap:wrap} |
| 266 | 266 | .event h4 .muted{margin-left:.4rem} |
| 267 | 267 | .event h4 .tag{margin-left:.4rem} |
| 268 | -.event h4 .starcount{margin-left:auto;color:var(--muted);font-size:.85rem;font-weight:400} | |
| 268 | +.event p.repometa{display:flex;gap:1.1rem;color:var(--muted);font-size:.85rem;margin:.3rem 0 0} | |
| 269 | +.repometa span{display:inline-flex;align-items:center} | |
| 270 | +.repometa .dot{width:10px;height:10px;border-radius:50%;margin-right:.35rem;border:1px solid rgba(0,0,0,.12)} | |
| 271 | +.repometa svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:1.3;margin-right:.25rem} | |
| 269 | 272 | .label{display:inline-block;color:#fff;font-size:.75rem;padding:0 .45rem;border-radius:.6rem;vertical-align:middle;line-height:1.4;font-weight:500;text-shadow:0 0 2px rgba(0,0,0,.3);margin-left:.35rem} |
| 270 | 273 | .labelbar .label,.metaform .label,table .label{margin-left:0} |
| 271 | 274 | a.label{opacity:.75}a.label.on,a.label:hover{opacity:1;text-decoration:none} |
store.go modified
| @@ -210,6 +210,7 @@ type Repo struct { | ||
| 210 | 210 | Parent int64 |
| 211 | 211 | Archived bool |
| 212 | 212 | Stars int |
| 213 | + Forks int | |
| 213 | 214 | Created time.Time |
| 214 | 215 | Updated time.Time |
| 215 | 216 | } |
| @@ -561,7 +562,7 @@ func scanRepos(rows *sql.Rows) ([]Repo, error) { | ||
| 561 | 562 | var private, archived int |
| 562 | 563 | var tags string |
| 563 | 564 | var created, ucreated int64 |
| 564 | - if err := rows.Scan(&r.ID, &r.Name, &r.Description, &private, &tags, &r.Parent, &archived, &r.Stars, &created, &r.Owner.ID, &r.Owner.Name, &ucreated); err != nil { | |
| 565 | + if err := rows.Scan(&r.ID, &r.Name, &r.Description, &private, &tags, &r.Parent, &archived, &r.Stars, &r.Forks, &created, &r.Owner.ID, &r.Owner.Name, &ucreated); err != nil { | |
| 565 | 566 | return nil, err |
| 566 | 567 | } |
| 567 | 568 | r.Archived = archived != 0 |
| @@ -575,7 +576,7 @@ func scanRepos(rows *sql.Rows) ([]Repo, error) { | ||
| 575 | 576 | return repos, rows.Err() |
| 576 | 577 | } |
| 577 | 578 | |
| 578 | -const repoColumns = `r.id, r.name, r.description, r.private, r.tags, r.parent, r.archived, (select count(*) from stars st where st.repo = r.id), r.created, u.id, u.name, u.created from repos r join users u on u.id = r.owner` | |
| 579 | +const repoColumns = `r.id, r.name, r.description, r.private, r.tags, r.parent, r.archived, (select count(*) from stars st where st.repo = r.id), (select count(*) from repos f where f.parent = r.id), r.created, u.id, u.name, u.created from repos r join users u on u.id = r.owner` | |
| 579 | 580 | |
| 580 | 581 | func (s *Store) Backup(path string) error { |
| 581 | 582 | _, err := s.db.Exec(`vacuum into ?`, path) |
templates/index.html modified
| @@ -18,5 +18,5 @@ | ||
| 18 | 18 | </div>{{end}} |
| 19 | 19 | {{end}} |
| 20 | 20 | {{define "repolist"}} |
| 21 | -{{if .}}<div class="events">{{range .}}<div class="event"><h4><a href="/{{.Path}}">{{.Path}}</a>{{if .Private}} <span class="tag">private</span>{{else if .Unlisted}} <span class="tag">unlisted</span>{{end}}{{if .Stars}}<span class="starcount" title="{{.Stars}} stars">☆ {{.Stars}}</span>{{end}}</h4>{{if .Description}}<p>{{.Description}}</p>{{end}}{{if .Tags}}<p class="tags">{{range .Tags}}<a href="/search?q=tag:{{.}}">#{{.}}</a> {{end}}</p>{{end}}</div>{{end}}</div>{{else}}<p class="muted">Nothing here yet.</p>{{end}} | |
| 21 | +{{if .}}<div class="events">{{range .}}<div class="event"><h4><a href="/{{.Path}}">{{.Path}}</a>{{if .Private}} <span class="tag">private</span>{{else if .Unlisted}} <span class="tag">unlisted</span>{{end}}</h4>{{if .Description}}<p>{{.Description}}</p>{{end}}{{if .Tags}}<p class="tags">{{range .Tags}}<a href="/search?q=tag:{{.}}">#{{.}}</a> {{end}}</p>{{end}}{{template "repometa" .}}</div>{{end}}</div>{{else}}<p class="muted">Nothing here yet.</p>{{end}} | |
| 22 | 22 | {{end}} |
templates/meta.html modified
| @@ -9,4 +9,5 @@ | ||
| 9 | 9 | </div> |
| 10 | 10 | {{end}} |
| 11 | 11 | {{define "who"}}{{with person .Email}}<a href="/~{{.}}">{{$.Author}}</a>{{else}}{{.Author}}{{end}}{{end}} |
| 12 | -{{define "repoitem"}}<div class="event"><h4><a href="/{{.Path}}">{{.Name}}</a>{{if .Private}} <span class="tag">private</span>{{else if .Unlisted}} <span class="tag">unlisted</span>{{end}}{{if .Stars}}<span class="starcount" title="{{.Stars}} stars">☆ {{.Stars}}</span>{{end}}</h4>{{if .Description}}<p>{{.Description}}</p>{{end}}{{if .Tags}}<p class="tags">{{range .Tags}}<a href="/search?q=tag:{{.}}">#{{.}}</a> {{end}}</p>{{end}}</div>{{end}} | |
| 12 | +{{define "repoitem"}}<div class="event"><h4><a href="/{{.Path}}">{{.Name}}</a>{{if .Private}} <span class="tag">private</span>{{else if .Unlisted}} <span class="tag">unlisted</span>{{end}}</h4>{{if .Description}}<p>{{.Description}}</p>{{end}}{{if .Tags}}<p class="tags">{{range .Tags}}<a href="/search?q=tag:{{.}}">#{{.}}</a> {{end}}</p>{{end}}{{template "repometa" .}}</div>{{end}} | |
| 13 | +{{define "repometa"}}{{$l := lang .}}<p class="repometa">{{with $l.Name}}<span><i class="dot" style="background:{{$l.Colour}}"></i>{{.}}</span>{{end}}<span title="{{.Stars}} star{{if ne .Stars 1}}s{{end}}"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 1.6l1.9 4 4.4.5-3.3 3 .9 4.3L8 11.2 4.1 13.4l.9-4.3-3.3-3 4.4-.5z"/></svg>{{.Stars}}</span>{{if .Forks}}<span title="{{.Forks}} fork{{if ne .Forks 1}}s{{end}}"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="4" cy="3" r="1.6"/><circle cx="12" cy="3" r="1.6"/><circle cx="8" cy="13" r="1.6"/><path d="M4 4.6v1.4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2V4.6M8 8v3.4"/></svg>{{.Forks}}</span>{{end}}</p>{{end}} | |
templates/repos.html modified
| @@ -5,5 +5,5 @@ | ||
| 5 | 5 | <nav class="tabs small"><a href="/~{{$d.Owner.Name}}">about</a><a class="active" href="/~{{$d.Owner.Name}}/repos">repos{{if $d.Repos}} <span class="count">{{len $d.Repos}}</span>{{end}}</a>{{if not $d.Org}}<a href="/~{{$d.Owner.Name}}/stars">stars{{if $d.Count}} <span class="count">{{$d.Count}}</span>{{end}}</a>{{end}}<a href="/~{{$d.Owner.Name}}/feed">feed</a></nav> |
| 6 | 6 | {{if $d.Member}}<a class="btn primary newrepo" href="/create{{if $d.Org}}?owner={{$d.Owner.Name}}{{end}}">New repository</a>{{end}} |
| 7 | 7 | </div> |
| 8 | -{{if $d.Repos}}<div class="events">{{range $d.Repos}}<div class="event"><h4><a href="/{{.Path}}">{{.Name}}</a>{{if .Private}} <span class="tag">private</span>{{else if .Unlisted}} <span class="tag">unlisted</span>{{end}}{{if .Stars}}<span class="starcount" title="{{.Stars}} stars">☆ {{.Stars}}</span>{{end}}</h4>{{if .Description}}<p>{{.Description}}</p>{{end}}{{if .Tags}}<p class="tags">{{range .Tags}}<a href="/search?q=tag:{{.}}">#{{.}}</a> {{end}}</p>{{end}}</div>{{end}}</div>{{else}}<p class="info">No repos yet.</p>{{end}} | |
| 8 | +{{if $d.Repos}}<div class="events">{{range $d.Repos}}<div class="event"><h4><a href="/{{.Path}}">{{.Name}}</a>{{if .Private}} <span class="tag">private</span>{{else if .Unlisted}} <span class="tag">unlisted</span>{{end}}</h4>{{if .Description}}<p>{{.Description}}</p>{{end}}{{if .Tags}}<p class="tags">{{range .Tags}}<a href="/search?q=tag:{{.}}">#{{.}}</a> {{end}}</p>{{end}}{{template "repometa" .}}</div>{{end}}</div>{{else}}<p class="info">No repos yet.</p>{{end}} | |
| 9 | 9 | {{end}} |
templates/stars.html modified
| @@ -3,5 +3,5 @@ | ||
| 3 | 3 | <h2>~{{.Data.Owner.Name}}</h2> |
| 4 | 4 | <nav class="tabs small"><a href="/~{{.Data.Owner.Name}}">about</a><a href="/~{{.Data.Owner.Name}}/repos">repos</a><a class="active" href="/~{{.Data.Owner.Name}}/stars">stars{{if .Data.Count}} <span class="count">{{.Data.Count}}</span>{{end}}</a></nav> |
| 5 | 5 | </div> |
| 6 | -{{if .Data.Starred}}<div class="events">{{range .Data.Starred}}<div class="event"><h4><a href="/~{{.Owner.Name}}">~{{.Owner.Name}}</a>/<a href="/{{.Path}}">{{.Name}}</a>{{if .Stars}}<span class="starcount" title="{{.Stars}} stars">☆ {{.Stars}}</span>{{end}}</h4>{{if .Description}}<p>{{.Description}}</p>{{end}}{{if .Tags}}<p class="tags">{{range .Tags}}<a href="/search?q=tag:{{.}}">#{{.}}</a> {{end}}</p>{{end}}</div>{{end}}</div>{{else}}<p class="info">~{{.Data.Owner.Name}} has not starred anything yet.</p>{{end}} | |
| 6 | +{{if .Data.Starred}}<div class="events">{{range .Data.Starred}}<div class="event"><h4><a href="/~{{.Owner.Name}}">~{{.Owner.Name}}</a>/<a href="/{{.Path}}">{{.Name}}</a></h4>{{if .Description}}<p>{{.Description}}</p>{{end}}{{if .Tags}}<p class="tags">{{range .Tags}}<a href="/search?q=tag:{{.}}">#{{.}}</a> {{end}}</p>{{end}}{{template "repometa" .}}</div>{{end}}</div>{{else}}<p class="info">~{{.Data.Owner.Name}} has not starred anything yet.</p>{{end}} | |
| 7 | 7 | {{end}} |
web.go modified
| @@ -92,6 +92,12 @@ func newServer(store *Store, root, host, name string, sshUser string) *Server { | ||
| 92 | 92 | "inc": func(i int) int { return i + 1 }, |
| 93 | 93 | "perm": perm, |
| 94 | 94 | "signer": s.signer, |
| 95 | + "lang": func(r Repo) language { | |
| 96 | + if l := s.repoLanguages(r); len(l) > 0 { | |
| 97 | + return l[0] | |
| 98 | + } | |
| 99 | + return language{} | |
| 100 | + }, | |
| 95 | 101 | "bare": func(u string) string { |
| 96 | 102 | return strings.TrimSuffix(strings.TrimPrefix(strings.TrimPrefix(u, "https://"), "http://"), "/") |
| 97 | 103 | }, |