Fix mobile layout overflows and link mirror targets !37

merged merged by cmc on 2026-08-25 15:08 UTC · krz/gitbay:web-mirror-mobile-fixes into main

4 files changed, +12 −7

Layout: unified · split

e2e/mirror_test.go +1 −1
@@ -119,7 +119,7 @@ func TestMirrors(t *testing.T) {
119 if status, _ := browserGet(t, browser, inst.base()+loginPath); status != 200 { 119 if status, _ := browserGet(t, browser, inst.base()+loginPath); status != 200 {
120 t.Fatalf("login: %d", status) 120 t.Fatalf("login: %d", status)
121 } 121 }
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) {
123 t.Fatalf("admin repo page missing mirror line:\n%s", body) 123 t.Fatalf("admin repo page missing mirror line:\n%s", body)
124 } 124 }
125 if _, body := browserGet(t, newBrowser(t), inst.base()+"/alice/app"); strings.Contains(body, "mirrors to") { 125 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 {
222} 222}
223 223
224// mirrorLine is the admin-only mirror status shown in the repo header. 224// 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.
226type mirrorLine struct { 226type mirrorLine struct {
227 Direction string 227 Direction string
228 Target string // URL without the scheme 228 URL string
229 Target string // URL without the scheme, for display
229 Synced string 230 Synced string
230 Error string 231 Error string
231} 232}
@@ -276,6 +277,7 @@ func (s *Server) repoFor(w http.ResponseWriter, r *http.Request, ref string) (re
276 for _, m := range ms { 277 for _, m := range ms {
277 mirrors = append(mirrors, mirrorLine{ 278 mirrors = append(mirrors, mirrorLine{
278 Direction: m.Direction, 279 Direction: m.Direction,
280 URL: m.URL,
279 Target: strings.TrimPrefix(strings.TrimPrefix(m.URL, "https://"), "http://"), 281 Target: strings.TrimPrefix(strings.TrimPrefix(m.URL, "https://"), "http://"),
280 Synced: syncedAt(m.LastSync), 282 Synced: syncedAt(m.LastSync),
281 Error: m.LastError, 283 Error: m.LastError,
internal/web/static/style.css +6 −3
@@ -68,7 +68,7 @@
68} 68}
69 69
70* { box-sizing: border-box; } 70* { box-sizing: border-box; }
71html { font-size: 15px; } 71html { font-size: 15px; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
72body { 72body {
73 margin: 0; 73 margin: 0;
74 background: var(--bg); 74 background: var(--bg);
@@ -765,7 +765,10 @@ pre.matchline mark {
765.wikinav li a:hover { color: var(--accent); text-decoration: none; } 765.wikinav li a:hover { color: var(--accent); text-decoration: none; }
766.wikinav li a.active { color: var(--accent); font-weight: 550; } 766.wikinav li a.active { color: var(--accent); font-weight: 550; }
767@media (max-width: 40rem) { 767@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; }
769 .wikinav { width: auto; padding-top: 0; } 772 .wikinav { width: auto; padding-top: 0; }
770} 773}
771 774
@@ -819,7 +822,7 @@ pre.matchline mark {
819 main.container { padding-top: var(--sp-2); } 822 main.container { padding-top: var(--sp-2); }
820 .repogrid { grid-template-columns: 1fr; } 823 .repogrid { grid-template-columns: 1fr; }
821 .thread { margin-left: var(--sp-3); } 824 .thread { margin-left: var(--sp-3); }
822 table.tree td.mode { display: none; } 825 table.tree td.mode, table.tree th.mode { display: none; }
823 .readme, .code { padding: var(--sp-3); } 826 .readme, .code { padding: var(--sp-3); }
824 .blamehunk { flex-direction: column; gap: 0; } 827 .blamehunk { flex-direction: column; gap: 0; }
825 .blameinfo { width: auto; } 828 .blameinfo { width: auto; }
internal/web/templates/layout.html +1 −1
@@ -32,7 +32,7 @@
32<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> 32<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>
33{{if .Desc}}<p class="desc">{{.Desc}}</p>{{end}} 33{{if .Desc}}<p class="desc">{{.Desc}}</p>{{end}}
34{{if .Topics}}<p class="topics">{{range .Topics}}<span class="chip topic">{{.}}</span> {{end}}</p>{{end}} 34{{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>
36{{end}}<nav class="tabs"> 36{{end}}<nav class="tabs">
37 <a {{if eq .Tab "files"}}class="active" {{end}}href="/{{.Repo.OwnerName}}/{{.Repo.Name}}">files</a> 37 <a {{if eq .Tab "files"}}class="active" {{end}}href="/{{.Repo.OwnerName}}/{{.Repo.Name}}">files</a>
38 <a {{if eq .Tab "log"}}class="active" {{end}}href="/{{.Repo.OwnerName}}/{{.Repo.Name}}/log">log</a> 38 <a {{if eq .Tab "log"}}class="active" {{end}}href="/{{.Repo.OwnerName}}/{{.Repo.Name}}/log">log</a>