A CLI-first git forge.

cli forge git self-hosted

https://gitbay.org

Commit 794702c58d

794702c58d07759975699235f4408486305f8008

parent: 471902dd14

Verified · cmc

cmc <hello@cleberg.net> · 2026-08-25T15:07:24Z

Fix mobile layout overflows and link mirror targets

- The repo-header mirror line links to the mirror URL.
- Hide the tree mode header on mobile along with its cells; the
  leftover th kept a phantom third column that broke row borders.
- Wiki pages with wide code blocks overflowed the viewport on mobile:
  column-direction .wikilayout inherited align-items:flex-start, so
  .wikipage took its content's intrinsic width. Stretch pins it to the
  container; text-size-adjust stops the iOS font inflation the
  overflow triggered. #10
e2e/mirror_test.go +1 −1
@@ -119,7 +119,7 @@ func TestMirrors(t *testing.T) {
119119 if status, _ := browserGet(t, browser, inst.base()+loginPath); status != 200 {
120120 t.Fatalf("login: %d", status)
121121 }
122 if _, body := browserGet(t, browser, inst.base()+"/alice/app"); !strings.Contains(body, "mirrors to") {
122 if _, body := browserGet(t, browser, inst.base()+"/alice/app"); !strings.Contains(body, "mirrors to <a href=\""+remoteURL) {
123123 t.Fatalf("admin repo page missing mirror line:\n%s", body)
124124 }
125125 if _, body := browserGet(t, newBrowser(t), inst.base()+"/alice/app"); strings.Contains(body, "mirrors to") {
internal/httpd/web.go +4 −2
@@ -222,10 +222,11 @@ type repoPage struct {
222222 }
223223
224224 // mirrorLine is the admin-only mirror status shown in the repo header.
225// It carries no credentials: URL host/path only, sync time, and error.
225// It carries no credentials: the stored URL is credential-free.
226226 type mirrorLine struct {
227227 Direction string
228 Target string // URL without the scheme
228 URL string
229 Target string // URL without the scheme, for display
229230 Synced string
230231 Error string
231232 }
@@ -276,6 +277,7 @@ func (s *Server) repoFor(w http.ResponseWriter, r *http.Request, ref string) (re
276277 for _, m := range ms {
277278 mirrors = append(mirrors, mirrorLine{
278279 Direction: m.Direction,
280 URL: m.URL,
279281 Target: strings.TrimPrefix(strings.TrimPrefix(m.URL, "https://"), "http://"),
280282 Synced: syncedAt(m.LastSync),
281283 Error: m.LastError,
internal/web/static/style.css +6 −3
@@ -68,7 +68,7 @@
6868 }
6969
7070 * { box-sizing: border-box; }
71html { font-size: 15px; }
71html { font-size: 15px; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
7272 body {
7373 margin: 0;
7474 background: var(--bg);
@@ -765,7 +765,10 @@ pre.matchline mark {
765765 .wikinav li a:hover { color: var(--accent); text-decoration: none; }
766766 .wikinav li a.active { color: var(--accent); font-weight: 550; }
767767 @media (max-width: 40rem) {
768 .wikilayout { flex-direction: column; }
768 /* Column direction + the desktop align-items:flex-start lets .wikipage
769 take its content's intrinsic width, overflowing the viewport (and
770 triggering iOS font inflation). Stretch pins it to the container. */
771 .wikilayout { flex-direction: column; align-items: stretch; }
769772 .wikinav { width: auto; padding-top: 0; }
770773 }
771774
@@ -819,7 +822,7 @@ pre.matchline mark {
819822 main.container { padding-top: var(--sp-2); }
820823 .repogrid { grid-template-columns: 1fr; }
821824 .thread { margin-left: var(--sp-3); }
822 table.tree td.mode { display: none; }
825 table.tree td.mode, table.tree th.mode { display: none; }
823826 .readme, .code { padding: var(--sp-3); }
824827 .blamehunk { flex-direction: column; gap: 0; }
825828 .blameinfo { width: auto; }
internal/web/templates/layout.html +1 −1
@@ -32,7 +32,7 @@
3232 <h1 class="repotitle"><a class="owner" href="/{{.Repo.OwnerName}}">{{.Repo.OwnerName}}</a><span class="sep">/</span><a href="/{{.Repo.OwnerName}}/{{.Repo.Name}}">{{.Repo.Name}}</a>{{if eq .Repo.Visibility "private"}} <span class="chip chip-neutral">private</span>{{end}}{{if .Repo.Settings.Archived}} <span class="chip chip-stale">archived</span>{{end}}{{if .Viewer}}<form method="post" action="/{{.Repo.OwnerName}}/{{.Repo.Name}}/pin" class="inline pinform"><button type="submit" class="pinbtn{{if .Pinned}} pinned{{end}}" title="{{if .Pinned}}unpin from dashboard{{else}}pin to dashboard{{end}}">{{if .Pinned}}★ pinned{{else}}☆ pin{{end}}</button></form>{{end}}</h1>
3333 {{if .Desc}}<p class="desc">{{.Desc}}</p>{{end}}
3434 {{if .Topics}}<p class="topics">{{range .Topics}}<span class="chip topic">{{.}}</span> {{end}}</p>{{end}}
35{{range .Mirrors}}<p class="meta mirrorline">{{if eq .Direction "push"}}mirrors to{{else}}mirrors from{{end}} {{.Target}}{{if .Error}} · <span class="mirrorerr">sync error: {{.Error}}</span>{{else if .Synced}} · synced {{.Synced}}{{end}}</p>
35{{range .Mirrors}}<p class="meta mirrorline">{{if eq .Direction "push"}}mirrors to{{else}}mirrors from{{end}} <a href="{{.URL}}" rel="nofollow">{{.Target}}</a>{{if .Error}} · <span class="mirrorerr">sync error: {{.Error}}</span>{{else if .Synced}} · synced {{.Synced}}{{end}}</p>
3636 {{end}}<nav class="tabs">
3737 <a {{if eq .Tab "files"}}class="active" {{end}}href="/{{.Repo.OwnerName}}/{{.Repo.Name}}">files</a>
3838 <a {{if eq .Tab "log"}}class="active" {{end}}href="/{{.Repo.OwnerName}}/{{.Repo.Name}}/log">log</a>