Commit 9ba992b54c

9ba992b54ce8e646f6f392804fa8e71917f2d340

parent: 1cfdd9630b

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-19 15:40 UTC

web: one centered container for header, main and footer

Ref #226
internal/web/layout_test.go added +31
@@ -0,0 +1,31 @@
1package web
2
3import (
4 "strings"
5 "testing"
6)
7
8// The repository header, main and footer share one centered container:
9// the header's inner content is wrapped, and the stylesheet caps and
10// centers all three on the same token (desktop layout spec).
11func TestSharedCenteredContainer(t *testing.T) {
12 layout, err := templateFS.ReadFile("templates/layout.html")
13 if err != nil {
14 t.Fatal(err)
15 }
16 if !strings.Contains(string(layout), "<header class=\"repohead\">\n<div class=\"wrap\">") {
17 t.Fatalf("repohead is not wrapped in .wrap")
18 }
19 css := string(StyleCSS)
20 for _, want := range []string{
21 "--container: 100rem;",
22 "main.content, footer { max-width: calc(var(--container) + 2 * var(--sp-6)); margin: 0 auto; }",
23 ".repohead .wrap { max-width: var(--container); margin: 0 auto; }",
24 "main.reading { max-width: calc(72rem + 2 * var(--sp-6)); margin: 0 auto; }",
25 "main.bounded { max-width: calc(48rem + 2 * var(--sp-6)); margin: 0 auto; }",
26 } {
27 if !strings.Contains(css, want) {
28 t.Errorf("style.css lacks %q", want)
29 }
30 }
31}
internal/web/static/style.css +12 −5
@@ -125,6 +125,9 @@
125125 --rail-mark: 24px;
126126 --rail-mark-box: 32px;
127127
128 /* the one page container: header content, main and footer align on it */
129 --container: 100rem;
130
128131 --r-ctl: 4px; /* controls and chips */
129132 --r-card: 6px; /* cards, lists, code blocks */
130133 --shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
@@ -372,9 +375,10 @@ main.content {
372375 width: 100%;
373376 padding: var(--sp-5) var(--sp-6) var(--sp-7);
374377}
375main.wide { max-width: none; }
376main.reading { max-width: calc(72rem + 2 * var(--sp-6)); }
377main.bounded { max-width: calc(48rem + 2 * var(--sp-6)); }
378main.content, footer { max-width: calc(var(--container) + 2 * var(--sp-6)); margin: 0 auto; }
379main.wide { max-width: calc(var(--container) + 2 * var(--sp-6)); }
380main.reading { max-width: calc(72rem + 2 * var(--sp-6)); margin: 0 auto; }
381main.bounded { max-width: calc(48rem + 2 * var(--sp-6)); margin: 0 auto; }
378382footer {
379383 width: 100%;
380384 padding: var(--sp-4) var(--sp-6);
@@ -388,9 +392,11 @@ footer a:hover { color: var(--link); }
388392
389393/* ---- repository header ---- */
390394.repohead {
391 padding: var(--sp-4) var(--sp-6) 0;
395 padding: var(--sp-4) 0 0;
392396 border-bottom: 1px solid var(--line);
393397}
398.repohead .wrap { max-width: var(--container); margin: 0 auto; }
399.repohead .wrap { padding: 0 var(--sp-6); }
394400.identity { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
395401.grow { flex: 1; }
396402/* h1 on the repo home, p elsewhere so each page keeps its own h1 but
@@ -1507,7 +1513,8 @@ svg.icon { vertical-align: -0.125em; }
15071513@media (max-width: 52rem) {
15081514 main.content { padding: var(--sp-4) var(--sp-4) var(--sp-5); }
15091515 footer { padding: var(--sp-4); }
1510 .repohead { padding: var(--sp-3) var(--sp-4) 0; }
1516 .repohead { padding: var(--sp-3) 0 0; }
1517 .repohead .wrap { padding: 0 var(--sp-4); }
15111518 /* seven tabs do not fit a phone in one row; a hidden scrollbar made the
15121519 ones past the edge look absent. Two rows show all of them. */
15131520 nav.tabs { flex-wrap: wrap; overflow: visible; }
internal/web/templates/layout.html +2
@@ -37,6 +37,7 @@
3737<div class="pane">
3838{{with field . "Repo"}}
3939<header class="repohead">
40<div class="wrap">
4041 <div class="identity">
4142 {{if field $ "RepoHome"}}<h1 class="repotitle"><a class="owner" href="/{{.OwnerName}}">{{.OwnerName}}</a><span class="sep">/</span>{{.Name}}</h1>
4243 {{else}}<p class="repotitle"><a class="owner" href="/{{.OwnerName}}">{{.OwnerName}}</a><span class="sep">/</span><a href="/{{.OwnerName}}/{{.Name}}">{{.Name}}</a></p>{{end}}
@@ -66,6 +67,7 @@
6667 {{if field $ "HasWiki"}}<a {{if eq $top "wiki"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/wiki">Wiki</a>{{end}}
6768 {{if field $ "CanAdmin"}}<a {{if eq $top "settings"}}aria-current="page" {{end}}href="/{{.OwnerName}}/{{.Name}}/settings">Settings</a>{{end}}
6869 </nav>
70</div>
6971</header>
7072{{end}}
7173