Commit f4cdc0af49
f4cdc0af496e3812e103fd86cd4dc22074f8ae10
parent: bbfca815b0
Verified · cmc
cmc <hello@cleberg.net> · 2026-09-17 15:44 UTC
web: content width chosen per page
Ref #218
internal/web/templates/404.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}not found · {{.Site}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <div class="notfound"> |
internal/web/templates/account.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}account settings{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1>Account settings</h1> |
internal/web/templates/admin.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}admin · {{.Site}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1>Admin</h1> |
internal/web/templates/blame.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}wide{{end}} |
| 1 | 2 | {{define "title"}}blame: {{.Path}} · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1 class="vh">Blame: {{.Path}}</h1> |
internal/web/templates/blob.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}wide{{end}} |
| 1 | 2 | {{define "title"}}{{.Path}} · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1 class="vh">{{.Path}}</h1> |
internal/web/templates/build.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}wide{{end}} |
| 1 | 2 | {{define "title"}}build {{.Build.Number}} · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | {{if .Notice}}<p class="error" role="alert">{{.Notice}}</p>{{end}} |
internal/web/templates/builds.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}wide{{end}} |
| 1 | 2 | {{define "title"}}builds · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1>Builds</h1> |
internal/web/templates/commit.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}wide{{end}} |
| 1 | 2 | {{define "title"}}{{.ShortSHA}} · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <div class="commithead"> |
internal/web/templates/compare.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}wide{{end}} |
| 1 | 2 | {{define "title"}}compare {{.Base}}...{{.Head}} · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1>Compare <code>{{.Base}}</code> … <code>{{.Head}}</code></h1> |
internal/web/templates/edit.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}edit {{.Path}} · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1>edit {{.Repo.OwnerName}}/{{.Repo.Name}} : {{.Path}} @ {{.Ref}}</h1> |
internal/web/templates/globalsearch.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}wide{{end}} |
| 1 | 2 | {{define "title"}}search · {{.Site}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <div class="listhead"> |
internal/web/templates/issuenew.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}new issue · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1>New issue</h1> |
internal/web/templates/landing.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}{{.Site}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <div class="landing"> |
internal/web/templates/layout.html
+2 −1
| @@ -91,7 +91,7 @@ |
| 91 | 91 | </header> |
| 92 | 92 | {{end}} |
| 93 | 93 | |
| 94 | | <main id="content" class="content"> |
| 94 | <main id="content" class="content {{template "width" .}}"> |
| 95 | 95 | {{template "content" .}} |
| 96 | 96 | </main> |
| 97 | 97 | |
| @@ -104,6 +104,7 @@ |
| 104 | 104 | </html>{{end}} |
| 105 | 105 | |
| 106 | 106 | {{define "mark"}}<svg class="mark" width="19" height="19" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2.25 18.75 12H5.25z" fill="#ff6b3d"/><rect x="3" y="13.5" width="18" height="3" fill="currentColor"/><rect x="7.5" y="18" width="9" height="3" fill="currentColor"/></svg>{{end}} |
| 107 | {{define "width"}}reading{{end}} |
| 107 | 108 | |
| 108 | 109 | {{define "reporow"}}<li> |
| 109 | 110 | <p class="reponame"><a href="/{{.OwnerName}}/{{.Name}}">{{.OwnerName}}<span class="sep">/</span><strong>{{.Name}}</strong></a>{{if eq .Visibility "private"}} <span class="chip">Private</span>{{end}}{{if .Archived}} <span class="chip">Archived</span>{{end}}</p> |
internal/web/templates/log.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}wide{{end}} |
| 1 | 2 | {{define "title"}}log · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1 class="vh">Commits</h1> |
internal/web/templates/login.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}login · {{.Site}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1>Sign in</h1> |
internal/web/templates/mrnew.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}new merge request · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1>New merge request</h1> |
internal/web/templates/new.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}new repository · {{.Site}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1>New repository</h1> |
internal/web/templates/privacy.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}privacy · {{.Site}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <div class="landing"> |
internal/web/templates/register.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}register · {{.Site}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <div class="landing"> |
internal/web/templates/registered.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}welcome · {{.Site}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <div class="landing"> |
internal/web/templates/search.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}wide{{end}} |
| 1 | 2 | {{define "title"}}search · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1>Search</h1> |
internal/web/templates/settings.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}settings · {{.Repo.OwnerName}}/{{.Repo.Name}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | {{$base := printf "/%s/%s/settings" .Repo.OwnerName .Repo.Name}} |
internal/web/templates/snippetnew.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}bounded{{end}} |
| 1 | 2 | {{define "title"}}new snippet · {{.Owner}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | <h1>New snippet</h1> |
internal/web/templates/tree.html
+1
| @@ -1,3 +1,4 @@ |
| 1 | {{define "width"}}wide{{end}} |
| 1 | 2 | {{define "title"}}{{.Repo.OwnerName}}/{{.Repo.Name}}{{end}} |
| 2 | 3 | {{define "content"}} |
| 3 | 4 | {{if .Notice}}<p class="error" role="alert">{{.Notice}}</p>{{end}} |
internal/web/web_test.go
+33
| @@ -83,3 +83,36 @@ func TestWhenNamesTheZone(t *testing.T) { |
| 83 | 83 | t.Fatalf("passthrough: %q", got) |
| 84 | 84 | } |
| 85 | 85 | } |
| 86 | |
| 87 | // TestMainWidthClass renders every page against an empty struct and |
| 88 | // checks main carries exactly one width class, and that the pages the |
| 89 | // spec calls wide or bounded say so. |
| 90 | func TestMainWidthClass(t *testing.T) { |
| 91 | wide := map[string]bool{"tree.html": true, "blob.html": true, "blame.html": true, "log.html": true, "commit.html": true, "compare.html": true, "builds.html": true, "build.html": true, "search.html": true, "globalsearch.html": true} |
| 92 | bounded := map[string]bool{"landing.html": true, "login.html": true, "register.html": true, "registered.html": true, "new.html": true, "issuenew.html": true, "mrnew.html": true, "settings.html": true, "account.html": true, "admin.html": true, "edit.html": true, "snippetnew.html": true, "privacy.html": true, "404.html": true} |
| 93 | for _, name := range Pages() { |
| 94 | src, err := TemplateSource(name) |
| 95 | if err != nil { |
| 96 | t.Fatal(err) |
| 97 | } |
| 98 | has := strings.Contains(src, `{{define "width"}}`) |
| 99 | switch { |
| 100 | case wide[name] && !strings.Contains(src, `{{define "width"}}wide{{end}}`): |
| 101 | t.Errorf("%s: want width wide", name) |
| 102 | case bounded[name] && !strings.Contains(src, `{{define "width"}}bounded{{end}}`): |
| 103 | t.Errorf("%s: want width bounded", name) |
| 104 | case !wide[name] && !bounded[name] && has: |
| 105 | t.Errorf("%s: defines a width but the spec calls it reading", name) |
| 106 | } |
| 107 | } |
| 108 | layout, err := TemplateSource("layout.html") |
| 109 | if err != nil { |
| 110 | t.Fatal(err) |
| 111 | } |
| 112 | if !strings.Contains(layout, `<main id="content" class="content {{template "width" .}}">`) { |
| 113 | t.Error("layout.html: main does not carry the width block") |
| 114 | } |
| 115 | if !strings.Contains(layout, `{{define "width"}}reading{{end}}`) { |
| 116 | t.Error("layout.html: no default width") |
| 117 | } |
| 118 | } |