~gitpocket/gitpocket

1

feat(ui): suggest repository names

commit
1773b7c386c0ea9d272c542f176cb60a6a6054b2 browse tree
parent
7d9c64e97dcd0a31a25f8c2e91ca1c411ca8b250
author
obscurejames <354576047+obscurejames@users.noreply.github.com>
signature
Verified ~james signed with a key registered by ~james
date
2026-10-28 21:21 UTC

12 files changed, +28 −15

static/style.css modified

@@ -440,3 +440,7 @@ input.rank{width:4rem}
440440 .introhead{font-family:var(--mono,monospace);font-size:.8rem;color:var(--muted);margin:0 0 .3rem}
441441 .introhead a{color:var(--muted)}
442442 .intro .readme>article>:last-child{margin-bottom:0}
443+.userhead .newrepo{margin:0 0 .3rem auto}
444+.orgtabs{display:inline-flex;margin-bottom:.8rem}
445+nav.site .me{display:flex;gap:1.1rem;align-items:center}
446+nav.site .me form{margin:0}

templates/blame.html modified

@@ -5,7 +5,7 @@
55 {{with .Data.Entry}}<span class="mode">{{perm .Mode}}</span><span class="muted">{{size .Size}}</span>{{end}}
66 <a href="/{{$p.Repo.Path}}/tree/{{$p.Ref}}/{{.Data.Path}}">View</a><a href="/{{$p.Repo.Path}}/log/{{$p.Ref}}?path={{.Data.Path}}">Log</a><a class="active" href="/{{$p.Repo.Path}}/blame/{{$p.Ref}}/{{.Data.Path}}">Blame</a><a href="/{{$p.Repo.Path}}/raw/{{$p.Ref}}/{{.Data.Path}}">View raw</a><a href="/{{$p.Repo.Path}}/blame/{{$p.Commit}}/{{.Data.Path}}">Permalink</a>
77 <span class="spacer"></span>
8-{{with .Data.LastCommit}}<span class="lastcommit"><a class="hash" href="/{{$p.Repo.Path}}/commit/{{.Hash}}">{{short .Hash}}</a> — {{.Subject}} <span class="muted">{{ago .Time}}</span></span>{{end}}
8+{{with .Data.LastCommit}}<span class="lastcommit"><a class="hash" href="/{{$p.Repo.Path}}/commit/{{.Hash}}">{{short .Hash}}</a> {{.Subject}} <span class="muted">{{ago .Time}}</span></span>{{end}}
99 </div>
1010 <div class="code"><table class="blame">{{range .Data.Lines}}<tr{{if .First}} class="first"{{end}}><td class="who">{{if .First}}<a class="hash" href="/{{$p.Repo.Path}}/commit/{{.Hash}}" title="{{.Subject}}">{{short .Hash}}</a> {{.Author}} <span class="muted">{{ago .Time}}</span>{{end}}</td><td class="n" id="L{{.Line}}"><a href="#L{{.Line}}">{{.Line}}</a></td><td class="l">{{.Text}}</td></tr>{{end}}</table></div>
1111 {{end}}

templates/blob.html modified

@@ -16,6 +16,6 @@
1616 {{with .Entry}}<span class="mode">{{perm .Mode}}</span>{{if eq .Type "blob"}}<span class="muted">{{size .Size}}</span>{{end}}{{end}}
1717 <a class="active" href="/{{$p.Repo.Path}}/tree/{{$p.Ref}}/{{.Path}}">View</a><a href="/{{$p.Repo.Path}}/log/{{$p.Ref}}?path={{.Path}}">Log</a><a href="/{{$p.Repo.Path}}/blame/{{$p.Ref}}/{{.Path}}">Blame</a><a href="/{{$p.Repo.Path}}/raw/{{$p.Ref}}/{{.Path}}">View raw</a><a href="/{{$p.Repo.Path}}/tree/{{$p.Commit}}/{{.Path}}">Permalink</a>{{if and $p.Owner (not $p.Repo.Archived)}}<a href="/{{$p.Repo.Path}}/edit/{{$p.Ref}}/{{.Path}}">Edit</a><form method="post" action="/{{$p.Repo.Path}}/remove/{{$p.Ref}}/{{.Path}}" class="inlineform"><button class="linkbutton">Delete</button></form>{{end}}
1818 <span class="spacer"></span>
19-{{with .LastCommit}}<span class="lastcommit"><a class="hash" href="/{{$p.Repo.Path}}/commit/{{.Hash}}">{{short .Hash}}</a> — {{.Subject}} <span class="muted">{{ago .Time}}</span></span>{{end}}
19+{{with .LastCommit}}<span class="lastcommit"><a class="hash" href="/{{$p.Repo.Path}}/commit/{{.Hash}}">{{short .Hash}}</a> {{.Subject}} <span class="muted">{{ago .Time}}</span></span>{{end}}
2020 </div>
2121 {{end}}

templates/create.html modified

@@ -3,9 +3,9 @@
33 <form method="post" action="/create" class="twocol">
44 <div>
55 {{with .Data.Orgs}}<label>Owner <select name="owner"><option value="{{$.User.Name}}">~{{$.User.Name}}</option>{{range .}}<option value="{{.Name}}"{{if eq .Name $.Data.Owner}} selected{{end}}>~{{.Name}}</option>{{end}}</select></label>{{end}}
6-<label>Repository name <input name="name" required autofocus pattern="[a-z0-9][a-z0-9_.-]{0,38}" placeholder="my-cool-project" value="{{.Data.Name}}"></label>
6+<label>Repository name <input name="name" required autofocus pattern="[a-z0-9][a-z0-9_.-]{0,38}" placeholder="{{.Data.Suggest}}" value="{{.Data.Name}}"></label>
77 <label>Description <input name="description" maxlength="200" placeholder="Short description, shown in lists" value="{{.Data.Description}}"></label>
8-<label>Tags <input name="tags" placeholder="Up to three comma-separated topics" value="{{.Data.Tags}}"></label>
8+<label>Tags <input name="tags" placeholder="Up to three comma separated topics" value="{{.Data.Tags}}"></label>
99 <div class="actions"><button class="btn primary">Create repository ▸</button></div>
1010 </div>
1111 <div>

templates/layout.html modified

@@ -21,7 +21,7 @@
2121 <a href="/search">explore</a>
2222 {{if not (and .Data (index .Data "Facets"))}}<form class="navsearch" method="get" action="/search" role="search"><input name="q" placeholder="Search repositories, people, languages" aria-label="Search"></form>{{end}}
2323 <span class="spacer"></span>
24-{{if .User}}<span>{{if .Admin}}<a href="/admin">admin</a> — {{end}}Logged in as <a href="/~{{.User.Name}}">~{{.User.Name}}</a> — <form method="post" action="/logout"><button>Log out</button></form></span>{{else}}<span class="auth"><a href="/login">Log in</a>{{if ne .Registration "closed"}} — <a href="/register">Register</a>{{end}}</span>{{end}}
24+{{if .User}}<span class="me">{{if .Admin}}<a href="/admin">admin</a>{{end}}<span>Logged in as <a href="/~{{.User.Name}}">~{{.User.Name}}</a></span><form method="post" action="/logout"><button>Log out</button></form></span>{{else}}<span class="me auth"><a href="/login">Log in</a>{{if ne .Registration "closed"}}<a href="/register">Register</a>{{end}}</span>{{end}}
2525 </nav>
2626 {{with .Data}}{{with index . "Settings"}}
2727 <nav class="subtabs">

templates/org.html modified

@@ -13,10 +13,11 @@
1313 <li title="{{date $o.Created}}"><svg viewBox="0 0 16 16" aria-hidden="true"><rect x="2" y="3" width="12" height="11" rx="1.5"/><path d="M2 6.5h12M5.5 1.5v3M10.5 1.5v3"/></svg>Since {{$o.Created.Format "January 2006"}}</li>
1414 </ul>
1515 </div>
16-{{if .Data.Member}}<div class="orgactions"><a class="btn" href="/~{{$o.Name}}/settings">Edit organisation</a><a class="btn primary" href="/create?owner={{$o.Name}}">New repository</a></div>{{end}}
16+{{if .Data.Member}}<div class="orgactions"><a class="btn" href="/~{{$o.Name}}/settings">Edit organisation</a></div>{{end}}
1717 </header>
1818 <div class="columns orgbody">
1919 <div class="main">
20+<nav class="tabs small orgtabs"><a class="active" href="/~{{$o.Name}}">about</a><a href="/~{{$o.Name}}/repos">repos{{if .Data.Total}} <span class="count">{{.Data.Total}}</span>{{end}}</a><a href="/~{{$o.Name}}/feed">feed</a></nav>
2021 {{with .Data.Activity}}<section class="activity"><div class="heathead"><p class="muted small">{{.Total}} commit{{if ne .Total 1}}s{{end}} across the organisation {{if .Year}}in {{.Year}}{{else}}in the past 12 months{{end}}</p><nav class="years"><a href="?"{{if not .Year}} class="active"{{end}}>past 12 months</a>{{range .Years}}<a href="?year={{.}}"{{if eq . $.Data.Activity.Year}} class="active"{{end}}>{{.}}</a>{{end}}</nav></div>{{.Grid}}<p class="legend muted small">less <i class="h0"></i><i class="h1"></i><i class="h2"></i><i class="h3"></i><i class="h4"></i> more</p></section>{{end}}
2122 {{if .Data.Repos}}<div class="events">{{range .Data.Repos}}{{template "repoitem" .}}{{end}}</div>{{end}}
2223 </div>

templates/repo.html modified

@@ -7,7 +7,7 @@ git push -u origin {{$p.Ref}}</pre>
77 {{else}}
88 <div class="summary">
99 <div class="commits">
10-{{range .Data.Commits}}<div class="event"><div class="row"><span><a class="hash" href="/{{$p.Repo.Path}}/commit/{{.Hash}}">{{short .Hash}}</a> — {{template "who" .}}{{with signer .}}<span class="verified" title="Signed with a key registered by ~{{.}}">Verified</span>{{end}}</span><a class="when" href="/{{$p.Repo.Path}}/commit/{{.Hash}}" title="{{date .Time}}">{{ago .Time}}</a></div><pre class="subject">{{.Subject}}</pre></div>{{end}}
10+{{range .Data.Commits}}<div class="event"><div class="row"><span><a class="hash" href="/{{$p.Repo.Path}}/commit/{{.Hash}}">{{short .Hash}}</a> {{template "who" .}}{{with signer .}}<span class="verified" title="Signed with a key registered by ~{{.}}">Verified</span>{{end}}</span><a class="when" href="/{{$p.Repo.Path}}/commit/{{.Hash}}" title="{{date .Time}}">{{ago .Time}}</a></div><pre class="subject">{{.Subject}}</pre></div>{{end}}
1111 </div>
1212 <div class="refs">
1313 <h3>refs</h3>
@@ -19,7 +19,7 @@ git push -u origin {{$p.Ref}}</pre>
1919 <div class="langbar">{{range .}}<span style="width:{{printf "%.2f" .Percent}}%;background:{{.Colour}}" title="{{.Name}} {{printf "%.1f" .Percent}}%"></span>{{end}}</div>
2020 <ul class="langlist">{{range .}}<li><i class="dot" style="background:{{.Colour}}"></i>{{.Name}}<span class="pct">{{printf "%.1f" .Percent}}%</span></li>{{end}}</ul>
2121 <h3 class="rule">clone</h3>{{else}}<h3>clone</h3>{{end}}
22-<strong>read-only</strong>
22+<strong>read only</strong>
2323 <div><a href="https://{{.Host}}/{{$p.Repo.Path}}">https://{{.Host}}/{{$p.Repo.Path}}</a></div>
2424 {{if $p.Owner}}<strong>read/write</strong>
2525 <div>{{.SSHUser}}@{{.Host}}:{{$p.Repo.Path}}</div>{{end}}

templates/repos.html modified

@@ -3,6 +3,7 @@
33 <div class="userhead">
44 <h2>~{{$d.Owner.Name}}</h2>
55 <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+{{if $d.Member}}<a class="btn primary newrepo" href="/create{{if $d.Org}}?owner={{$d.Owner.Name}}{{end}}">New repository</a>{{end}}
67 </div>
78 {{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}}
89 {{end}}

templates/reposettings.html modified

@@ -4,7 +4,7 @@
44 <form method="post" action="/{{$p.Repo.Path}}/settings" class="twocol">
55 <div>
66 <label>Description <input name="description" value="{{$p.Repo.Description}}" maxlength="200"></label>
7-<label>Tags <input name="tags" value="{{range $i, $t := $p.Repo.Tags}}{{if $i}}, {{end}}{{$t}}{{end}}" placeholder="Up to three comma-separated topics"></label>
7+<label>Tags <input name="tags" value="{{range $i, $t := $p.Repo.Tags}}{{if $i}}, {{end}}{{$t}}{{end}}" placeholder="Up to three comma separated topics"></label>
88 <label class="check"><input type="checkbox" name="pinned"{{if .Data.Pinned}} checked{{end}}> Pin to profile</label>
99 <div class="actions"><button class="btn primary">Save ▸</button></div>
1010 </div>

templates/tree.html modified

@@ -7,7 +7,7 @@
77 <td class="mode">{{perm .Mode}}</td>
88 <td class="name">{{if eq .Type "tree"}}<a href="/{{$p.Repo.Path}}/tree/{{$p.Ref}}/{{if $.Data.Path}}{{$.Data.Path}}/{{end}}{{.Name}}/">{{.Name}}/</a>{{else if eq .Type "blob"}}<a href="/{{$p.Repo.Path}}/tree/{{$p.Ref}}/{{if $.Data.Path}}{{$.Data.Path}}/{{end}}{{.Name}}">{{.Name}}</a>{{else}}{{.Name}} <span class="muted">({{.Type}})</span>{{end}}</td>
99 <td class="size">{{if eq .Type "blob"}}{{size .Size}}{{end}}</td>
10-<td class="last">{{if $c.Hash}}<a class="hash" href="/{{$p.Repo.Path}}/commit/{{$c.Hash}}">{{short $c.Hash}}</a> — {{$c.Subject}}{{end}}</td>
10+<td class="last">{{if $c.Hash}}<a class="hash" href="/{{$p.Repo.Path}}/commit/{{$c.Hash}}">{{short $c.Hash}}</a> {{$c.Subject}}{{end}}</td>
1111 <td class="when">{{if $c.Hash}}{{ago $c.Time}}{{end}}</td>
1212 </tr>
1313 {{end}}
@@ -21,6 +21,6 @@
2121 {{if .Entry}}{{if eq .Entry.Type "blob"}}<a class="active" href="/{{$p.Repo.Path}}/tree/{{$p.Ref}}/{{.Path}}">View</a><a href="/{{$p.Repo.Path}}/log/{{$p.Ref}}?path={{.Path}}">Log</a><a href="/{{$p.Repo.Path}}/blame/{{$p.Ref}}/{{.Path}}">Blame</a><a href="/{{$p.Repo.Path}}/raw/{{$p.Ref}}/{{.Path}}">View raw</a><a href="/{{$p.Repo.Path}}/tree/{{$p.Commit}}/{{.Path}}">Permalink</a>{{else}}<a href="/{{$p.Repo.Path}}/log/{{$p.Ref}}?path={{.Path}}">Log</a><a href="/{{$p.Repo.Path}}/tree/{{$p.Commit}}/{{.Path}}/">Permalink</a>{{if and $p.Owner (not $p.Repo.Archived)}}<a href="/{{$p.Repo.Path}}/new/{{$p.Ref}}/{{.Path}}">New file</a>{{end}}{{end}}{{else}}<a href="/{{$p.Repo.Path}}/log/{{$p.Ref}}">Log</a><a href="/{{$p.Repo.Path}}/tree/{{$p.Commit}}/">Permalink</a>{{if and $p.Owner (not $p.Repo.Archived)}}<a href="/{{$p.Repo.Path}}/new/{{$p.Ref}}/">New file</a>{{end}}{{end}}
2222 <span class="spacer"></span>
2323 <form method="get" action="/{{$p.Repo.Path}}/search" class="filesearch"><input type="hidden" name="ref" value="{{$p.Ref}}"><input name="q" placeholder="Search files" value=""></form>
24-{{with .LastCommit}}<span class="lastcommit"><a class="hash" href="/{{$p.Repo.Path}}/commit/{{.Hash}}">{{short .Hash}}</a> — {{.Subject}} <span class="muted">{{ago .Time}}</span></span>{{end}}
24+{{with .LastCommit}}<span class="lastcommit"><a class="hash" href="/{{$p.Repo.Path}}/commit/{{.Hash}}">{{short .Hash}}</a> {{.Subject}} <span class="muted">{{ago .Time}}</span></span>{{end}}
2525 </div>
2626 {{end}}

templates/user.html modified

@@ -17,7 +17,7 @@
1717 <li title="{{date .Data.Owner.Created}}"><svg viewBox="0 0 16 16" aria-hidden="true"><rect x="2" y="3" width="12" height="11" rx="1.5"/><path d="M2 6.5h12M5.5 1.5v3M10.5 1.5v3"/></svg>Joined {{.Data.Owner.Created.Format "January 2006"}}</li>
1818 </ul>
1919 {{with .Data.Orgs}}<div class="orglist"><h4>Organisations</h4>{{range .}}<a href="/~{{.Name}}" title="~{{.Name}}">{{if .Profile.Avatar}}<img src="/~{{.Name}}/avatar?v={{.Profile.Avatar}}" alt="">{{else}}<span>{{slice .Name 0 1}}</span>{{end}}{{with .Profile.Display}}{{.}}{{else}}{{.Name}}{{end}}</a>{{end}}</div>{{end}}
20-{{if $own}}<div class="ownactions"><a class="btn primary block" href="/create">New repository</a><a class="btn block" href="/settings">Edit profile</a></div>{{end}}
20+{{if $own}}<div class="ownactions"><a class="btn block" href="/settings">Edit profile</a></div>{{end}}
2121 </aside>
2222 <div class="main">
2323 {{with .Data.Intro.HTML}}<section class="intro"><p class="introhead"><a href="/{{$.Data.Intro.Path}}">{{$.Data.Intro.Path}}</a> / <a href="/{{$.Data.Intro.Path}}/tree/{{$.Data.Intro.Ref}}/{{$.Data.Intro.Name}}">{{$.Data.Intro.Name}}</a></p><div class="readme">{{.}}</div></section>{{end}}

web.go modified

@@ -12,6 +12,7 @@ import (
1212 "io"
1313 "io/fs"
1414 "log"
15+ "math/rand/v2"
1516 "mime"
1617 "net/http"
1718 "net/url"
@@ -376,7 +377,7 @@ func (s *Server) require(w http.ResponseWriter, r *http.Request) *User {
376377
377378 func (s *Server) createForm(w http.ResponseWriter, r *http.Request) {
378379 if u := s.require(w, r); u != nil {
379- s.render(w, r, "create", page{Title: "New repository", User: u, Data: map[string]any{"Orgs": s.store.Orgs(u.ID), "Owner": r.URL.Query().Get("owner")}})
380+ s.render(w, r, "create", page{Title: "New repository", User: u, Data: map[string]any{"Orgs": s.store.Orgs(u.ID), "Owner": r.URL.Query().Get("owner"), "Suggest": suggestName()}})
380381 }
381382 }
382383
@@ -398,7 +399,7 @@ func (s *Server) create(w http.ResponseWriter, r *http.Request) {
398399 repo, err := s.store.CreateRepo(owner, name, strings.TrimSpace(r.FormValue("description")), visibility(r.FormValue("visibility")), r.FormValue("tags"))
399400 if err != nil {
400401 w.WriteHeader(400)
401- s.render(w, r, "create", page{Title: "New repository", User: u, Error: err.Error(), Data: map[string]any{"Orgs": s.store.Orgs(u.ID), "Owner": owner.Name, "Name": name, "Description": r.FormValue("description"), "Tags": r.FormValue("tags")}})
402+ s.render(w, r, "create", page{Title: "New repository", User: u, Error: err.Error(), Data: map[string]any{"Orgs": s.store.Orgs(u.ID), "Suggest": suggestName(), "Owner": owner.Name, "Name": name, "Description": r.FormValue("description"), "Tags": r.FormValue("tags")}})
402403 return
403404 }
404405 dir := s.repoDir(repo)
@@ -1603,7 +1604,7 @@ func (s *Server) repos(w http.ResponseWriter, r *http.Request, owner User, user
16031604 return
16041605 }
16051606 starred, _ := s.store.StarredRepos(owner.ID)
1606- data := map[string]any{"Owner": owner, "Repos": s.byUpdate(repos), "Count": len(starred), "Org": s.store.IsOrg(owner.ID)}
1607+ data := map[string]any{"Owner": owner, "Repos": s.byUpdate(repos), "Member": member, "Count": len(starred), "Org": s.store.IsOrg(owner.ID)}
16071608 s.render(w, r, "repos", page{Title: "~" + owner.Name + " repos", User: user, Data: data})
16081609 }
16091610
@@ -1647,3 +1648,9 @@ func (s *Server) profileReadme(owner User) intro {
16471648 introCache.Unlock()
16481649 return in
16491650 }
1651+
1652+var nameWords = []string{"heron", "lantern", "harbour", "kestrel", "thicket", "anvil", "orchard", "beacon", "lattice", "meadow", "quarry", "sparrow", "tundra", "compass", "furnace", "willow", "ledger", "marrow", "pebble", "spindle", "cinder", "bramble", "atlas", "ferry", "loom", "estuary", "magpie", "bellows", "cairn", "fathom", "gantry", "hearth", "juniper", "keel", "lichen", "mortar", "nettle", "osprey", "plinth", "quill", "rookery", "sextant", "tinder", "umber", "vellum", "wicket", "yarrow", "zephyr", "sorrel", "flint"}
1653+
1654+func suggestName() string {
1655+ return nameWords[rand.IntN(len(nameWords))]
1656+}