kicker: deep pages re-assert whose exhibit this is
commit 9f3639044e82add0c3ae0f5a37ee21ee6b70fede · parent 2d5549287a
· browse this tree
Ximianth, 2026-10-30 14:40:44 UTC
Tree, file, log, and commit pages carry the repo name above their heading, in the provenance register, linking home: a file's name matters, but so does the project context it sits in. Omitted on the root listing, whose heading is already the repo name.
diff --git a/chrome.go b/chrome.go index a813562..47f1d5e 100644 --- a/chrome.go +++ b/chrome.go @@ -338,6 +338,16 @@ footer.ground .colophon { margin: .5rem 0 1.1rem; } +/* The kicker: which project this sheet belongs to, re-asserted above the heading + on pages deep in a repo, in the provenance register; the name links home. */ +article .kicker { + margin: 0 0 -.6rem; + font-size: .78rem; + letter-spacing: .16em; + color: var(--ink-soft); +} +article .kicker a { color: inherit; } + /* The ledger: provenance rows on the log page. Subjects are prose and wrap freely; the attribution line stays soft and small. Links wear ink, not accent: a hundred accent rows would shout; hover answers the "is it live" question. */ diff --git a/pages.go b/pages.go index 4060649..139b168 100644 --- a/pages.go +++ b/pages.go @@ -333,7 +333,7 @@ func (s *server) renderReadme(rp *repo, ref, sha string) (template.HTML, readmeI // The catalogue: listings keep their tabular bones, with light hand-ruled row // separators and a drawer-tab mark ahead of directory names (the mark is the // link's own background, so it is part of the tap target). -var treeTmpl = template.Must(template.New("tree").Parse(`<h1>{{.Title}}</h1> +var treeTmpl = template.Must(template.New("tree").Parse(`{{template "kicker" .Kicker}}<h1>{{.Title}}</h1> <table class="tree"> <tbody> {{range .Rows}}<tr><td class="name{{if .Dir}} dir{{end}}">{{if .Href}}<a href="{{.Href}}">{{.Name}}</a>{{else}}{{.Name}}{{end}}</td><td class="size">{{.Size}}</td></tr> @@ -341,6 +341,12 @@ var treeTmpl = template.Must(template.New("tree").Parse(`<h1>{{.Title}}</h1> </table> `)) +// kickerTmpl is the shared context line above a page heading: which project this +// sheet belongs to, linking home. Deep pages re-assert it because a file's name +// matters, but so does whose exhibit it is; empty means the heading already says so. +var kickerTmpl = template.Must(template.New("kicker").Parse(`{{if .}}<p class="kicker"><a href="/{{.}}/">{{.}}</a></p> +{{end}}`)) + type treeRow struct { Name string Href string // empty renders unlinked (submodules) @@ -349,8 +355,9 @@ type treeRow struct { } type treeData struct { - Title string - Rows []treeRow + Title string + Kicker string // the repo name, when the title doesn't already say it + Rows []treeRow } func (s *server) serveTreeListing(w http.ResponseWriter, snap *snapshot, rp *repo, ref, sha, pth string) { @@ -359,9 +366,10 @@ func (s *server) serveTreeListing(w http.ResponseWriter, snap *snapshot, rp *rep httpError(w, err) return } - d := treeData{Title: pth} + d := treeData{Title: pth, Kicker: rp.name} if pth == "" { - d.Title = rp.name + // The root listing's heading is the repo name itself; a kicker would stutter. + d.Title, d.Kicker = rp.name, "" } if pth != "" { d.Rows = append(d.Rows, treeRow{Name: "..", Href: treeHref(rp.name, ref, parentDir(pth)) + "/"}) @@ -468,22 +476,26 @@ var ( preTmpl = template.Must(template.New("pre").Parse(`<pre class="file">{{.}}</pre>`)) plaqueTmpl = template.Must(template.New("plaque").Parse(`<p class="plaque">{{.Path}} · {{.Size}} · <code>{{.ShortSha}}</code></p> `)) - imageTmpl = template.Must(template.New("image").Parse(`<h1>{{.Name}}</h1> + imageTmpl = template.Must(template.New("image").Parse(`{{template "kicker" .Kicker}}<h1>{{.Name}}</h1> <div class="exhibit"><p><img class="file" src="{{.RawHref}}" alt="{{.Name}}"></p></div> {{template "plaque" .Plaque}}`)) - fileTmpl = template.Must(template.New("file").Parse(`<h1>{{.Name}}</h1> + fileTmpl = template.Must(template.New("file").Parse(`{{template "kicker" .Kicker}}<h1>{{.Name}}</h1> <div class="exhibit">{{.Body}}</div> {{template "plaque" .Plaque}}`)) - rawLinkTmpl = template.Must(template.New("rawlink").Parse(`<h1>{{.Name}}</h1> + rawLinkTmpl = template.Must(template.New("rawlink").Parse(`{{template "kicker" .Kicker}}<h1>{{.Name}}</h1> <p>{{.Size}} bytes of {{.Kind}}; <a href="{{.RawHref}}">view raw</a>.</p> `)) ) func init() { - // The plaque fragment is shared by the file-view templates. + // The plaque fragment is shared by the file-view templates, + // and the kicker by every template that re-asserts its project above the h1. for _, t := range []*template.Template{imageTmpl, fileTmpl} { template.Must(t.AddParseTree("plaque", plaqueTmpl.Tree)) } + for _, t := range []*template.Template{treeTmpl, imageTmpl, fileTmpl, rawLinkTmpl, logTmpl, commitTmpl} { + template.Must(t.AddParseTree("kicker", kickerTmpl.Tree)) + } } // plaqueData is the museum label under a file exhibit. @@ -516,16 +528,16 @@ func (s *server) serveFileView(w http.ResponseWriter, snap *snapshot, rp *repo, plq := plaqueData{Path: pth, Size: humanSize(size), ShortSha: shortSha(sha)} if isImagePath(pth) { s.render(w, snap, imageTmpl, struct { - Name, RawHref string - Plaque plaqueData - }{name, raw, plq}, pd) + Name, Kicker, RawHref string + Plaque plaqueData + }{name, rp.name, raw, plq}, pd) return } rawLink := func(kind string) { s.render(w, snap, rawLinkTmpl, struct { - Name, Kind, RawHref string - Size int64 - }{name, kind, raw, size}, pd) + Name, Kicker, Kind, RawHref string + Size int64 + }{name, rp.name, kind, raw, size}, pd) } if size > display.MaxRenderSize { rawLink("file, too large to display inline") @@ -547,10 +559,10 @@ func (s *server) serveFileView(w http.ResponseWriter, snap *snapshot, rp *repo, return } s.render(w, snap, fileTmpl, struct { - Name string - Body template.HTML - Plaque plaqueData - }{name, body, plq}, pd) + Name, Kicker string + Body template.HTML + Plaque plaqueData + }{name, rp.name, body, plq}, pd) return } var pre bytes.Buffer @@ -559,10 +571,10 @@ func (s *server) serveFileView(w http.ResponseWriter, snap *snapshot, rp *repo, return } s.render(w, snap, fileTmpl, struct { - Name string - Body template.HTML - Plaque plaqueData - }{name, template.HTML(pre.String()), plq}, pd) + Name, Kicker string + Body template.HTML + Plaque plaqueData + }{name, rp.name, template.HTML(pre.String()), plq}, pd) } // looksBinary applies the classic cheap heuristic: a NUL byte in the leading bytes means @@ -581,7 +593,7 @@ func looksBinary(b []byte) bool { // line -- the subject as prose, free to wrap, and a soft second line carrying the // sha (a chip-outlined button to the commit page), author, and absolute date. // This shape is also why the page survives phone widths. -var logTmpl = template.Must(template.New("log").Parse(`<h1>log: {{.Title}}</h1> +var logTmpl = template.Must(template.New("log").Parse(`{{template "kicker" .Kicker}}<h1>log: {{.Title}}</h1> <p class="provenance">provenance · newest first</p> <ul class="ledger"> {{range .Rows}}<li> @@ -602,6 +614,7 @@ type logRow struct { type logData struct { Title string + Kicker string Rows []logRow Capped bool Limit int @@ -610,7 +623,7 @@ type logData struct { // renderLog writes the log page. Commit shas link to the tree at that commit: // commit-diff pages are a later stretch goal, and browsing the snapshot is useful today. func (s *server) renderLog(w http.ResponseWriter, snap *snapshot, rp *repo, ref string, cs []commitInfo) { - d := logData{Title: shortSha(ref), Capped: len(cs) == logLimit, Limit: logLimit} + d := logData{Title: shortSha(ref), Kicker: rp.name, Capped: len(cs) == logLimit, Limit: logLimit} for _, c := range cs { d.Rows = append(d.Rows, logRow{ Sha: shortSha(c.hash), @@ -632,7 +645,7 @@ func (s *server) renderLog(w http.ResponseWriter, snap *snapshot, rp *repo, ref // ---- commit ---- -var commitTmpl = template.Must(template.New("commit").Parse(`<h1>{{.Subject}}</h1> +var commitTmpl = template.Must(template.New("commit").Parse(`{{template "kicker" .Kicker}}<h1>{{.Subject}}</h1> <p>commit <code>{{.Sha}}</code>{{range .Parents}} · parent <a href="{{.Href}}"><code>{{.Name}}</code></a>{{end}} · <a href="{{.TreeHref}}">browse this tree</a><br> {{.Author}}, {{.Date}}</p> @@ -644,6 +657,7 @@ var commitTmpl = template.Must(template.New("commit").Parse(`<h1>{{.Subject}}</h type commitData struct { Subject string + Kicker string Rest string // the message past its subject line, if any Sha string Author string @@ -659,6 +673,7 @@ func (s *server) renderCommit(w http.ResponseWriter, snap *snapshot, rp *repo, c subject, rest, _ := strings.Cut(c.message, "\n") d := commitData{ Subject: subject, + Kicker: rp.name, Rest: strings.TrimSpace(rest), Sha: c.hash, Author: c.author, diff --git a/testdata/pages.md b/testdata/pages.md index cf7a652..b83feb6 100644 --- a/testdata/pages.md +++ b/testdata/pages.md @@ -202,7 +202,8 @@ Content-Type: text/html; charset=utf-8 <a class="vb" href="/fixturama/log/main" title="commit log of main" style="--dy:18px">log</a> <a class="vc" href="/fixturama/" title="repo home" style="--dy:2px">home</a> </nav> -<main><article><h1>docs</h1> +<main><article><p class="kicker"><a href="/fixturama/">fixturama</a></p> +<h1>docs</h1> <table class="tree"> <tbody> <tr><td class="name"><a href="/fixturama/tree/main/">..</a></td><td class="size"></td></tr> @@ -258,7 +259,8 @@ Content-Type: text/html; charset=utf-8 <a class="vc" href="/fixturama/log/main" title="commit log of main" style="--dy:18px">log</a> <a class="va" href="/fixturama/" title="repo home" style="--dy:2px">home</a> </nav> -<main><article><h1>README.md</h1> +<main><article><p class="kicker"><a href="/fixturama/">fixturama</a></p> +<h1>README.md</h1> <div class="exhibit"><h1 id="fixturama">Fixturama<a href="#fixturama" class="anchor">🔗</a></h1> <p>A repo that exists to be looked at.</p> </div> @@ -304,7 +306,8 @@ Content-Type: text/html; charset=utf-8 <a class="vc" href="/fixturama/log/main" title="commit log of main" style="--dy:18px">log</a> <a class="va" href="/fixturama/" title="repo home" style="--dy:2px">home</a> </nav> -<main><article><h1>with space.txt</h1> +<main><article><p class="kicker"><a href="/fixturama/">fixturama</a></p> +<h1>with space.txt</h1> <div class="exhibit"><pre class="file">even this filename works </pre></div> <p class="plaque">docs/with space.txt · 25 B · <code>ced91a8519</code></p> @@ -350,7 +353,8 @@ Content-Type: text/html; charset=utf-8 <a class="vc" href="/fixturama/log/ced91a8519b59966124301e6383532f24223528b" title="commit log of ced91a8519" style="--dy:18px">log</a> <a class="va" href="/fixturama/" title="repo home" style="--dy:2px">home</a> </nav> -<main><article><h1>README.md</h1> +<main><article><p class="kicker"><a href="/fixturama/">fixturama</a></p> +<h1>README.md</h1> <div class="exhibit"><h1 id="fixturama">Fixturama<a href="#fixturama" class="anchor">🔗</a></h1> <p>A repo that exists to be looked at.</p> </div> @@ -398,7 +402,8 @@ Content-Type: text/html; charset=utf-8 <a class="va" href="/fixturama/tree/main/" title="browse the tree at main" style="--dy:18px">files</a> <a class="vb" href="/fixturama/" title="repo home" style="--dy:2px">home</a> </nav> -<main><article><h1>log: main</h1> +<main><article><p class="kicker"><a href="/fixturama/">fixturama</a></p> +<h1>log: main</h1> <p class="provenance">provenance · newest first</p> <ul class="ledger"> <li> @@ -457,7 +462,8 @@ Content-Type: text/html; charset=utf-8 <a class="vb" href="/fixturama/log/ced91a8519b59966124301e6383532f24223528b" title="the log from this commit" style="--dy:18px">log</a> <a class="vc" href="/fixturama/" title="repo home" style="--dy:2px">home</a> </nav> -<main><article><h1>add docs and src</h1> +<main><article><p class="kicker"><a href="/fixturama/">fixturama</a></p> +<h1>add docs and src</h1> <p>commit <code>ced91a8519b59966124301e6383532f24223528b</code> · parent <a href="/fixturama/commit/64ac67a35d36079e167cb8f929fd57f859c8b5d1"><code>64ac67a35d</code></a> · <a href="/fixturama/tree/ced91a8519b59966124301e6383532f24223528b/">browse this tree</a><br> Ada Fixture, 2026-01-02 03:04:05 UTC</p> @@ -570,7 +576,8 @@ Content-Type: text/html; charset=utf-8 <a class="vb" href="/fixturama/log/64ac67a35d36079e167cb8f929fd57f859c8b5d1" title="the log from this commit" style="--dy:18px">log</a> <a class="vc" href="/fixturama/" title="repo home" style="--dy:2px">home</a> </nav> -<main><article><h1>inaugurate with a readme</h1> +<main><article><p class="kicker"><a href="/fixturama/">fixturama</a></p> +<h1>inaugurate with a readme</h1> <p>commit <code>64ac67a35d36079e167cb8f929fd57f859c8b5d1</code> · <a href="/fixturama/tree/64ac67a35d36079e167cb8f929fd57f859c8b5d1/">browse this tree</a><br> Ada Fixture, 2026-01-02 03:04:05 UTC</p>