Commit 03fe6e4437

03fe6e44370f8129c9ac68f13fe674cc271f5ffa

parent: 43a8eaa579

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-04 04:20 UTC

web: tabs wrap on a phone, and the landing page says what the forge does

On a phone the tab bar scrolled sideways with its scrollbar hidden, so
the tabs past the edge looked absent; they wrap to a second row
instead. The landing page had a paragraph and a code block; it now
says in three short sections what a reader, a writer and a reviewer
can do.

The header stays the same on every tab: it sits above the tab bar,
and hiding the description and topics off the code tab moved the
navigation between clicks, which TestReadmeRelativeLinks guards.

Closes #134

Layout: unified · split

internal/web/static/style.css +7
@@ -420,6 +420,9 @@ nav.tabs a i {
420420 .railpinned { border-top: 0; padding: 0; }
421421 .content { padding: var(--sp-4) var(--sp-4) var(--sp-5); }
422422 .repohead { padding: var(--sp-3) var(--sp-4) 0; }
423 /* seven tabs do not fit a phone in one row; a hidden scrollbar made
424 the ones past the edge look absent. Two rows show all of them. */
425 nav.tabs { flex-wrap: wrap; overflow: visible; }
423426}
424427
425428/* tables */
@@ -740,6 +743,10 @@ pre.quickstart {
740743 margin: 0 0 var(--sp-4);
741744}
742745.landing .explorelink { font-weight: 550; }
746.landing .facets { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); margin: var(--sp-5) 0; }
747.landing .facets h2 { font-size: var(--fs-3); margin: 0 0 var(--sp-1); }
748.landing .facets p { margin: 0; color: var(--muted); font-size: var(--fs-2); line-height: 1.6; }
749@media (max-width: 40rem) { .landing .facets { grid-template-columns: 1fr; gap: var(--sp-4); } }
743750
744751/* index toolbar */
745752p.toolbar { color: var(--muted); font-size: var(--fs-2); margin-top: var(--sp-4); }
internal/web/templates/landing.html +5
@@ -7,6 +7,11 @@ merge requests are managed from your terminal with nothing but OpenSSH —
77the web is a fast, readable rendering of that state.</p>
88<pre class="quickstart">ssh git@{{.Host}} help # every command, no client needed
99git clone ssh://git@{{.Host}}/owner/repo.git</pre>
10<div class="facets">
11 <section><h2>Read</h2><p>Browse and clone any public repository, over HTTPS or <code>git://</code>, with no account. Every commit shows whether its signature was verified.</p></section>
12 <section><h2>Write</h2><p>Push over SSH with the key you already have. <code>ssh git@{{.Host}} repo create you/project</code> is the whole onboarding; issues, merge requests and reviews are commands too.</p></section>
13 <section><h2>Review</h2><p>The web is a rendering of the same state: read a diff, comment on a line, approve, merge. Everything it can do, the terminal can do first.</p></section>
14</div>
1015<p><a class="explorelink" href="/explore">explore public repositories →</a></p>
1116{{if .Accounts}}<p class="meta">have an account? mint a browser session from your terminal: <code>gitbay web login</code>{{if .Signup}} · new here? <a href="/register">create an account</a>{{end}}</p>{{end}}
1217</div>
internal/web/templates/layout.html +4 −1
@@ -61,13 +61,16 @@
6161 <span class="grow"></span>
6262 {{if $.Viewer}}<form method="post" action="/{{.OwnerName}}/{{.Name}}/pin" class="inline"><button type="submit" class="btn" aria-pressed="{{if field $ "Pinned"}}true{{else}}false{{end}}"><span aria-hidden="true">{{if field $ "Pinned"}}★{{else}}☆{{end}}</span> {{if field $ "Pinned"}}Pinned{{else}}Pin{{end}}</button></form>{{end}}
6363 </div>
64 {{$top := topTab (str $ "Tab")}}
65 {{/* The header is the same on every tab: it sits above the tab bar,
66 and anything shown on one tab and not another would move the
67 navigation between clicks of that navigation. */}}
6468 {{with field $ "Desc"}}<p class="repodesc">{{.}}</p>{{end}}
6569 {{with field $ "Topics"}}<p class="topics">{{range .}}<a class="chip topic" href="/explore?q={{.}}">{{.}}</a> {{end}}</p>{{end}}
6670 {{with $.Repo.Settings.Website}}<p class="repometa"><a href="{{.}}" rel="nofollow">{{.}}</a></p>{{end}}
6771 {{range field $ "Mirrors"}}<p class="repometa">{{if eq .Direction "push"}}Mirrors to{{else}}Mirrors from{{end}} <a href="{{.URL}}" rel="nofollow">{{.Target}}</a>{{if .Error}} · <span class="bad">sync error: {{.Error}}</span>{{else if .Synced}} · synced {{.Synced}}{{end}}</p>
6872 {{end}}
6973 <nav class="tabs" aria-label="Repository">
70 {{$top := topTab (str $ "Tab")}}
7174 <a {{if eq $top "code"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}">Code</a>
7275 <a {{if eq $top "issues"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/issues">Issues{{with field $ "OpenIssues"}}{{if .}} <i>{{.}}</i>{{end}}{{end}}</a>
7376 <a {{if eq $top "mrs"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/mrs">Merge requests{{with field $ "OpenMRs"}}{{if .}} <i>{{.}}</i>{{end}}{{end}}</a>