detached 221e8de

fix(web): put the repo description above content and rail

commit
221e8de8c404161819df1de5ae6748dd7188af98
author
brice · · 2026-10-11 12:28 UTC
parent
c8e4042
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
9 files · +294 -292
M cmd/ermite/testdata/web/summary.html +1 -1
@@ -75,8 +75,8 @@
7575 </nav>
7676 </header>
7777 <div class="work has-rail">
78+<p class="lede work-lede">A demo repository</p>
7879 <main id="main" tabindex="-1">
79-<p class="lede">A demo repository</p>
8080 <section class="card readme" aria-labelledby="readme-h">
8181 <h2 class="card-h" id="readme-h">
8282 <span class="ico i-file" aria-hidden="true">
@@ -75,8 +75,8 @@
75 </nav>75 </nav>
76 </header>76 </header>
77 <div class="work has-rail">77 <div class="work has-rail">
78+<p class="lede work-lede">A demo repository</p>
78 <main id="main" tabindex="-1">79 <main id="main" tabindex="-1">
79-<p class="lede">A demo repository</p>
80 <section class="card readme" aria-labelledby="readme-h">80 <section class="card readme" aria-labelledby="readme-h">
81 <h2 class="card-h" id="readme-h">81 <h2 class="card-h" id="readme-h">
82 <span class="ico i-file" aria-hidden="true">82 <span class="ico i-file" aria-hidden="true">
M internal/adapters/web/assets.go +1 -1
@@ -4,9 +4,9 @@ package web
44
55 import (
66 "crypto/sha256"
7- "errors"
87 "embed"
98 "encoding/hex"
9+ "errors"
1010 "io/fs"
1111 "net/http"
1212 "path"
@@ -4,9 +4,9 @@ package web
4 4
5 import (5 import (
6 "crypto/sha256"6 "crypto/sha256"
7- "errors"
8 "embed"7 "embed"
9 "encoding/hex"8 "encoding/hex"
9+ "errors"
10 "io/fs"10 "io/fs"
11 "net/http"11 "net/http"
12 "path"12 "path"
M internal/adapters/web/pages.templ +0 -3
@@ -48,9 +48,6 @@ templ Home(l Layout, p HomePage) {
4848 // column at the reading measure; what one acts on sits in the rail.
4949 templ Summary(l Layout, p SummaryPage) {
5050 @Shell(l, summaryRail(p)) {
51- if p.Desc != "" {
52- <p class="lede">{ p.Desc }</p>
53- }
5451 if p.Readme != nil {
5552 @ReadmeCard(*p.Readme)
5653 }
@@ -48,9 +48,6 @@ templ Home(l Layout, p HomePage) {
48 // column at the reading measure; what one acts on sits in the rail.48 // column at the reading measure; what one acts on sits in the rail.
49 templ Summary(l Layout, p SummaryPage) {49 templ Summary(l Layout, p SummaryPage) {
50 @Shell(l, summaryRail(p)) {50 @Shell(l, summaryRail(p)) {
51- if p.Desc != "" {
52- <p class="lede">{ p.Desc }</p>
53- }
54 if p.Readme != nil {51 if p.Readme != nil {
55 @ReadmeCard(*p.Readme)52 @ReadmeCard(*p.Readme)
56 }53 }
M internal/adapters/web/pages_templ.go +157 -180 generated file: collapsed
M internal/adapters/web/shell.templ +3 -0
@@ -25,6 +25,9 @@ templ Shell(l Layout, rail templ.Component) {
2525 <a class="skip" href="#main">skip to content</a>
2626 @Header(l)
2727 <div class={ "work", templ.KV("has-rail", l.HasRail && rail != nil) }>
28+ if l.Lede != "" {
29+ <p class="lede work-lede">{ l.Lede }</p>
30+ }
2831 <main id="main" tabindex="-1">
2932 { children... }
3033 </main>
@@ -25,6 +25,9 @@ templ Shell(l Layout, rail templ.Component) {
25 <a class="skip" href="#main">skip to content</a>25 <a class="skip" href="#main">skip to content</a>
26 @Header(l)26 @Header(l)
27 <div class={ "work", templ.KV("has-rail", l.HasRail && rail != nil) }>27 <div class={ "work", templ.KV("has-rail", l.HasRail && rail != nil) }>
28+ if l.Lede != "" {
29+ <p class="lede work-lede">{ l.Lede }</p>
30+ }
28 <main id="main" tabindex="-1">31 <main id="main" tabindex="-1">
29 { children... }32 { children... }
30 </main>33 </main>
M internal/adapters/web/shell_templ.go +128 -105
@@ -190,7 +190,30 @@ func Shell(l Layout, rail templ.Component) templ.Component {
190190 if templ_7745c5c3_Err != nil {
191191 return templ_7745c5c3_Err
192192 }
193- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\"><main id=\"main\" tabindex=\"-1\">")
193+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">")
194+ if templ_7745c5c3_Err != nil {
195+ return templ_7745c5c3_Err
196+ }
197+ if l.Lede != "" {
198+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<p class=\"lede work-lede\">")
199+ if templ_7745c5c3_Err != nil {
200+ return templ_7745c5c3_Err
201+ }
202+ var templ_7745c5c3_Var14 string
203+ templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(l.Lede)
204+ if templ_7745c5c3_Err != nil {
205+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 29, Col: 39}
206+ }
207+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
208+ if templ_7745c5c3_Err != nil {
209+ return templ_7745c5c3_Err
210+ }
211+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</p>")
212+ if templ_7745c5c3_Err != nil {
213+ return templ_7745c5c3_Err
214+ }
215+ }
216+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<main id=\"main\" tabindex=\"-1\">")
194217 if templ_7745c5c3_Err != nil {
195218 return templ_7745c5c3_Err
196219 }
@@ -198,12 +221,12 @@ func Shell(l Layout, rail templ.Component) templ.Component {
198221 if templ_7745c5c3_Err != nil {
199222 return templ_7745c5c3_Err
200223 }
201- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</main>")
224+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</main>")
202225 if templ_7745c5c3_Err != nil {
203226 return templ_7745c5c3_Err
204227 }
205228 if l.HasRail && rail != nil {
206- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<aside class=\"rail\" aria-label=\"Context\">")
229+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "<aside class=\"rail\" aria-label=\"Context\">")
207230 if templ_7745c5c3_Err != nil {
208231 return templ_7745c5c3_Err
209232 }
@@ -211,12 +234,12 @@ func Shell(l Layout, rail templ.Component) templ.Component {
211234 if templ_7745c5c3_Err != nil {
212235 return templ_7745c5c3_Err
213236 }
214- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</aside>")
237+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</aside>")
215238 if templ_7745c5c3_Err != nil {
216239 return templ_7745c5c3_Err
217240 }
218241 }
219- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</div>")
242+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</div>")
220243 if templ_7745c5c3_Err != nil {
221244 return templ_7745c5c3_Err
222245 }
@@ -244,7 +267,7 @@ func Shell(l Layout, rail templ.Component) templ.Component {
244267 if templ_7745c5c3_Err != nil {
245268 return templ_7745c5c3_Err
246269 }
247- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</body></html>")
270+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</body></html>")
248271 if templ_7745c5c3_Err != nil {
249272 return templ_7745c5c3_Err
250273 }
@@ -270,260 +293,260 @@ func Header(l Layout) templ.Component {
270293 }()
271294 }
272295 ctx = templ.InitializeContext(ctx)
273- templ_7745c5c3_Var14 := templ.GetChildren(ctx)
274- if templ_7745c5c3_Var14 == nil {
275- templ_7745c5c3_Var14 = templ.NopComponent
296+ templ_7745c5c3_Var15 := templ.GetChildren(ctx)
297+ if templ_7745c5c3_Var15 == nil {
298+ templ_7745c5c3_Var15 = templ.NopComponent
276299 }
277300 ctx = templ.ClearChildren(ctx)
278- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<header class=\"hdr\"><div class=\"hdr-top\"><a class=\"brand\" href=\"/\" data-g=\"h\" title=\"home (g h)\"><span class=\"brand-mark\" aria-hidden=\"true\"></span> <span class=\"brand-name\">")
301+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<header class=\"hdr\"><div class=\"hdr-top\"><a class=\"brand\" href=\"/\" data-g=\"h\" title=\"home (g h)\"><span class=\"brand-mark\" aria-hidden=\"true\"></span> <span class=\"brand-name\">")
279302 if templ_7745c5c3_Err != nil {
280303 return templ_7745c5c3_Err
281304 }
282- var templ_7745c5c3_Var15 string
283- templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(l.Instance)
305+ var templ_7745c5c3_Var16 string
306+ templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(l.Instance)
284307 if templ_7745c5c3_Err != nil {
285- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 54, Col: 41}
308+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 57, Col: 41}
286309 }
287- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
310+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
288311 if templ_7745c5c3_Err != nil {
289312 return templ_7745c5c3_Err
290313 }
291- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</span></a> ")
314+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</span></a> ")
292315 if templ_7745c5c3_Err != nil {
293316 return templ_7745c5c3_Err
294317 }
295318 if len(l.Crumbs) > 0 {
296- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<nav class=\"crumbs\" aria-label=\"Path\"><ol>")
319+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "<nav class=\"crumbs\" aria-label=\"Path\"><ol>")
297320 if templ_7745c5c3_Err != nil {
298321 return templ_7745c5c3_Err
299322 }
300323 for _, c := range l.Crumbs {
301- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<li>")
324+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<li>")
302325 if templ_7745c5c3_Err != nil {
303326 return templ_7745c5c3_Err
304327 }
305328 if c.Href != "" {
306- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<a href=\"")
329+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<a href=\"")
307330 if templ_7745c5c3_Err != nil {
308331 return templ_7745c5c3_Err
309332 }
310- var templ_7745c5c3_Var16 templ.SafeURL
311- templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))
333+ var templ_7745c5c3_Var17 templ.SafeURL
334+ templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))
312335 if templ_7745c5c3_Err != nil {
313- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 63, Col: 38}
336+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 66, Col: 38}
314337 }
315- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
338+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
316339 if templ_7745c5c3_Err != nil {
317340 return templ_7745c5c3_Err
318341 }
319- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "\"")
342+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\"")
320343 if templ_7745c5c3_Err != nil {
321344 return templ_7745c5c3_Err
322345 }
323346 if c.Current {
324- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, " aria-current=\"page\"")
347+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, " aria-current=\"page\"")
325348 if templ_7745c5c3_Err != nil {
326349 return templ_7745c5c3_Err
327350 }
328351 }
329- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, ">")
352+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, ">")
330353 if templ_7745c5c3_Err != nil {
331354 return templ_7745c5c3_Err
332355 }
333- var templ_7745c5c3_Var17 string
334- templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(c.Label)
356+ var templ_7745c5c3_Var18 string
357+ templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(c.Label)
335358 if templ_7745c5c3_Err != nil {
336- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 67, Col: 19}
359+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 70, Col: 19}
337360 }
338- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
361+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
339362 if templ_7745c5c3_Err != nil {
340363 return templ_7745c5c3_Err
341364 }
342- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</a>")
365+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "</a>")
343366 if templ_7745c5c3_Err != nil {
344367 return templ_7745c5c3_Err
345368 }
346369 } else {
347- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<span")
370+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "<span")
348371 if templ_7745c5c3_Err != nil {
349372 return templ_7745c5c3_Err
350373 }
351374 if c.Current {
352- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, " aria-current=\"page\"")
375+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, " aria-current=\"page\"")
353376 if templ_7745c5c3_Err != nil {
354377 return templ_7745c5c3_Err
355378 }
356379 }
357- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, ">")
380+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, ">")
358381 if templ_7745c5c3_Err != nil {
359382 return templ_7745c5c3_Err
360383 }
361- var templ_7745c5c3_Var18 string
362- templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(c.Label)
384+ var templ_7745c5c3_Var19 string
385+ templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(c.Label)
363386 if templ_7745c5c3_Err != nil {
364- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 73, Col: 19}
387+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 76, Col: 19}
365388 }
366- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
389+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
367390 if templ_7745c5c3_Err != nil {
368391 return templ_7745c5c3_Err
369392 }
370- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "</span>")
393+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "</span>")
371394 if templ_7745c5c3_Err != nil {
372395 return templ_7745c5c3_Err
373396 }
374397 }
375- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</li>")
398+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "</li>")
376399 if templ_7745c5c3_Err != nil {
377400 return templ_7745c5c3_Err
378401 }
379402 }
380- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</ol></nav>")
403+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</ol></nav>")
381404 if templ_7745c5c3_Err != nil {
382405 return templ_7745c5c3_Err
383406 }
384407 }
385- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "<div class=\"hdr-acts\">")
408+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "<div class=\"hdr-acts\">")
386409 if templ_7745c5c3_Err != nil {
387410 return templ_7745c5c3_Err
388411 }
389412 if l.Ref != "" {
390- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "<button type=\"button\" class=\"btn ref\" aria-haspopup=\"dialog\" aria-controls=\"panel-refs\" aria-keyshortcuts=\"b\" title=\"switch branch or tag (b)\" hx-on:click=\"document.body.dispatchEvent(new CustomEvent('k-refs'))\"><span class=\"ico i-branch\" aria-hidden=\"true\"></span> <span class=\"ref-name\">")
413+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "<button type=\"button\" class=\"btn ref\" aria-haspopup=\"dialog\" aria-controls=\"panel-refs\" aria-keyshortcuts=\"b\" title=\"switch branch or tag (b)\" hx-on:click=\"document.body.dispatchEvent(new CustomEvent('k-refs'))\"><span class=\"ico i-branch\" aria-hidden=\"true\"></span> <span class=\"ref-name\">")
391414 if templ_7745c5c3_Err != nil {
392415 return templ_7745c5c3_Err
393416 }
394- var templ_7745c5c3_Var19 string
395- templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(l.Ref)
417+ var templ_7745c5c3_Var20 string
418+ templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(l.Ref)
396419 if templ_7745c5c3_Err != nil {
397- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 92, Col: 36}
420+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 95, Col: 36}
398421 }
399- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
422+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
400423 if templ_7745c5c3_Err != nil {
401424 return templ_7745c5c3_Err
402425 }
403- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</span> <span class=\"sha\">")
426+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "</span> <span class=\"sha\">")
404427 if templ_7745c5c3_Err != nil {
405428 return templ_7745c5c3_Err
406429 }
407- var templ_7745c5c3_Var20 string
408- templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(l.Short)
430+ var templ_7745c5c3_Var21 string
431+ templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(l.Short)
409432 if templ_7745c5c3_Err != nil {
410- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 93, Col: 33}
433+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 96, Col: 33}
411434 }
412- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
435+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
413436 if templ_7745c5c3_Err != nil {
414437 return templ_7745c5c3_Err
415438 }
416- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "</span></button> ")
439+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "</span></button> ")
417440 if templ_7745c5c3_Err != nil {
418441 return templ_7745c5c3_Err
419442 }
420443 }
421- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "<button type=\"button\" class=\"btn search\" aria-haspopup=\"dialog\" aria-controls=\"panel-cmd\" aria-keyshortcuts=\"Control+K :\" title=\"go to a section, ref, file or repo (ctrl k or :)\" hx-on:click=\"document.body.dispatchEvent(new CustomEvent('k-cmd'))\"><span class=\"ico i-search\" aria-hidden=\"true\"></span> <span class=\"search-label\">Go to…</span> <kbd aria-hidden=\"true\">ctrl k</kbd></button> <button type=\"button\" class=\"btn icon\" aria-haspopup=\"dialog\" aria-controls=\"panel-help\" aria-keyshortcuts=\"?\" aria-label=\"Keyboard shortcuts\" title=\"keyboard shortcuts (?)\" hx-on:click=\"document.body.dispatchEvent(new CustomEvent('k-help'))\">?</button> ")
444+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "<button type=\"button\" class=\"btn search\" aria-haspopup=\"dialog\" aria-controls=\"panel-cmd\" aria-keyshortcuts=\"Control+K :\" title=\"go to a section, ref, file or repo (ctrl k or :)\" hx-on:click=\"document.body.dispatchEvent(new CustomEvent('k-cmd'))\"><span class=\"ico i-search\" aria-hidden=\"true\"></span> <span class=\"search-label\">Go to…</span> <kbd aria-hidden=\"true\">ctrl k</kbd></button> <button type=\"button\" class=\"btn icon\" aria-haspopup=\"dialog\" aria-controls=\"panel-help\" aria-keyshortcuts=\"?\" aria-label=\"Keyboard shortcuts\" title=\"keyboard shortcuts (?)\" hx-on:click=\"document.body.dispatchEvent(new CustomEvent('k-help'))\">?</button> ")
422445 if templ_7745c5c3_Err != nil {
423446 return templ_7745c5c3_Err
424447 }
425448 if SignedIn(ctx) {
426- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "<form class=\"owner\" method=\"post\" action=\"/-/logout\"><span class=\"owner-badge\" title=\"signed in as the owner\">owner</span> <button type=\"submit\" class=\"btn\" title=\"sign out of this browser\">Sign out</button></form>")
449+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<form class=\"owner\" method=\"post\" action=\"/-/logout\"><span class=\"owner-badge\" title=\"signed in as the owner\">owner</span> <button type=\"submit\" class=\"btn\" title=\"sign out of this browser\">Sign out</button></form>")
427450 if templ_7745c5c3_Err != nil {
428451 return templ_7745c5c3_Err
429452 }
430453 }
431- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "</div></div>")
454+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "</div></div>")
432455 if templ_7745c5c3_Err != nil {
433456 return templ_7745c5c3_Err
434457 }
435458 if len(l.Sections) > 0 {
436- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "<nav class=\"tabs\" aria-label=\"Sections\"><ul>")
459+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "<nav class=\"tabs\" aria-label=\"Sections\"><ul>")
437460 if templ_7745c5c3_Err != nil {
438461 return templ_7745c5c3_Err
439462 }
440463 for _, s := range l.Sections {
441- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<li><a href=\"")
464+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "<li><a href=\"")
442465 if templ_7745c5c3_Err != nil {
443466 return templ_7745c5c3_Err
444467 }
445- var templ_7745c5c3_Var21 templ.SafeURL
446- templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(s.Href))
468+ var templ_7745c5c3_Var22 templ.SafeURL
469+ templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(s.Href))
447470 if templ_7745c5c3_Err != nil {
448- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 124, Col: 36}
471+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 127, Col: 36}
449472 }
450- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
473+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
451474 if templ_7745c5c3_Err != nil {
452475 return templ_7745c5c3_Err
453476 }
454- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "\" data-key=\"")
477+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "\" data-key=\"")
455478 if templ_7745c5c3_Err != nil {
456479 return templ_7745c5c3_Err
457480 }
458- var templ_7745c5c3_Var22 string
459- templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.ResolveAttributeValue(s.Key)
481+ var templ_7745c5c3_Var23 string
482+ templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.ResolveAttributeValue(s.Key)
460483 if templ_7745c5c3_Err != nil {
461- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 125, Col: 24}
484+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 128, Col: 24}
462485 }
463- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var22)
486+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var23)
464487 if templ_7745c5c3_Err != nil {
465488 return templ_7745c5c3_Err
466489 }
467- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "\" aria-keyshortcuts=\"")
490+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "\" aria-keyshortcuts=\"")
468491 if templ_7745c5c3_Err != nil {
469492 return templ_7745c5c3_Err
470493 }
471- var templ_7745c5c3_Var23 string
472- templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.ResolveAttributeValue(s.Key)
494+ var templ_7745c5c3_Var24 string
495+ templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.ResolveAttributeValue(s.Key)
473496 if templ_7745c5c3_Err != nil {
474- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 126, Col: 33}
497+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 129, Col: 33}
475498 }
476- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var23)
499+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var24)
477500 if templ_7745c5c3_Err != nil {
478501 return templ_7745c5c3_Err
479502 }
480- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "\"")
503+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "\"")
481504 if templ_7745c5c3_Err != nil {
482505 return templ_7745c5c3_Err
483506 }
484507 if s.Current {
485- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, " aria-current=\"page\"")
508+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, " aria-current=\"page\"")
486509 if templ_7745c5c3_Err != nil {
487510 return templ_7745c5c3_Err
488511 }
489512 }
490- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, ">")
513+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, ">")
491514 if templ_7745c5c3_Err != nil {
492515 return templ_7745c5c3_Err
493516 }
494- var templ_7745c5c3_Var24 string
495- templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(s.Label)
517+ var templ_7745c5c3_Var25 string
518+ templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(s.Label)
496519 if templ_7745c5c3_Err != nil {
497- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 130, Col: 17}
520+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 133, Col: 17}
498521 }
499- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
522+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
500523 if templ_7745c5c3_Err != nil {
501524 return templ_7745c5c3_Err
502525 }
503- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "<kbd aria-hidden=\"true\">")
526+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "<kbd aria-hidden=\"true\">")
504527 if templ_7745c5c3_Err != nil {
505528 return templ_7745c5c3_Err
506529 }
507- var templ_7745c5c3_Var25 string
508- templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(s.Key)
530+ var templ_7745c5c3_Var26 string
531+ templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(s.Key)
509532 if templ_7745c5c3_Err != nil {
510- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 130, Col: 50}
533+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 133, Col: 50}
511534 }
512- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
535+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
513536 if templ_7745c5c3_Err != nil {
514537 return templ_7745c5c3_Err
515538 }
516- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "</kbd></a></li>")
539+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "</kbd></a></li>")
517540 if templ_7745c5c3_Err != nil {
518541 return templ_7745c5c3_Err
519542 }
520543 }
521- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "</ul></nav>")
544+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "</ul></nav>")
522545 if templ_7745c5c3_Err != nil {
523546 return templ_7745c5c3_Err
524547 }
525548 }
526- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "</header>")
549+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "</header>")
527550 if templ_7745c5c3_Err != nil {
528551 return templ_7745c5c3_Err
529552 }
@@ -549,38 +572,38 @@ func Footer(l Layout) templ.Component {
549572 }()
550573 }
551574 ctx = templ.InitializeContext(ctx)
552- templ_7745c5c3_Var26 := templ.GetChildren(ctx)
553- if templ_7745c5c3_Var26 == nil {
554- templ_7745c5c3_Var26 = templ.NopComponent
575+ templ_7745c5c3_Var27 := templ.GetChildren(ctx)
576+ if templ_7745c5c3_Var27 == nil {
577+ templ_7745c5c3_Var27 = templ.NopComponent
555578 }
556579 ctx = templ.ClearChildren(ctx)
557- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "<footer class=\"foot\"><span>ermite ")
580+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "<footer class=\"foot\"><span>ermite ")
558581 if templ_7745c5c3_Err != nil {
559582 return templ_7745c5c3_Err
560583 }
561- var templ_7745c5c3_Var27 string
562- templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(l.Version)
584+ var templ_7745c5c3_Var28 string
585+ templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(l.Version)
563586 if templ_7745c5c3_Err != nil {
564- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 143, Col: 26}
587+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 146, Col: 26}
565588 }
566- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
589+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
567590 if templ_7745c5c3_Err != nil {
568591 return templ_7745c5c3_Err
569592 }
570- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "</span> <a href=\"")
593+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "</span> <a href=\"")
571594 if templ_7745c5c3_Err != nil {
572595 return templ_7745c5c3_Err
573596 }
574- var templ_7745c5c3_Var28 templ.SafeURL
575- templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(l.SourceURL))
597+ var templ_7745c5c3_Var29 templ.SafeURL
598+ templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(l.SourceURL))
576599 if templ_7745c5c3_Err != nil {
577- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 144, Col: 38}
600+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 147, Col: 38}
578601 }
579- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
602+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
580603 if templ_7745c5c3_Err != nil {
581604 return templ_7745c5c3_Err
582605 }
583- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "\" rel=\"noopener\" title=\"source of this version (AGPL-3.0-or-later)\">source</a> <span class=\"foot-keys\"><kbd>?</kbd> keyboard shortcuts</span></footer>")
606+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "\" rel=\"noopener\" title=\"source of this version (AGPL-3.0-or-later)\">source</a> <span class=\"foot-keys\"><kbd>?</kbd> keyboard shortcuts</span></footer>")
584607 if templ_7745c5c3_Err != nil {
585608 return templ_7745c5c3_Err
586609 }
@@ -608,12 +631,12 @@ func Hint(l Layout) templ.Component {
608631 }()
609632 }
610633 ctx = templ.InitializeContext(ctx)
611- templ_7745c5c3_Var29 := templ.GetChildren(ctx)
612- if templ_7745c5c3_Var29 == nil {
613- templ_7745c5c3_Var29 = templ.NopComponent
634+ templ_7745c5c3_Var30 := templ.GetChildren(ctx)
635+ if templ_7745c5c3_Var30 == nil {
636+ templ_7745c5c3_Var30 = templ.NopComponent
614637 }
615638 ctx = templ.ClearChildren(ctx)
616- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "<div class=\"hint\" role=\"status\" aria-live=\"polite\"><span class=\"hint-nav\" :text=\"document.body.dataset.nav || ''\"></span> <span class=\"hint-sel\" :text=\"document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''\"></span> <span class=\"hint-flash\" :text=\"document.body.dataset.flash || ''\"></span>")
639+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "<div class=\"hint\" role=\"status\" aria-live=\"polite\"><span class=\"hint-nav\" :text=\"document.body.dataset.nav || ''\"></span> <span class=\"hint-sel\" :text=\"document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''\"></span> <span class=\"hint-flash\" :text=\"document.body.dataset.flash || ''\"></span>")
617640 if templ_7745c5c3_Err != nil {
618641 return templ_7745c5c3_Err
619642 }
@@ -621,7 +644,7 @@ func Hint(l Layout) templ.Component {
621644 if templ_7745c5c3_Err != nil {
622645 return templ_7745c5c3_Err
623646 }
624- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "</div>")
647+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "</div>")
625648 if templ_7745c5c3_Err != nil {
626649 return templ_7745c5c3_Err
627650 }
@@ -190,7 +190,30 @@ func Shell(l Layout, rail templ.Component) templ.Component {
190 if templ_7745c5c3_Err != nil {190 if templ_7745c5c3_Err != nil {
191 return templ_7745c5c3_Err191 return templ_7745c5c3_Err
192 }192 }
193- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\"><main id=\"main\" tabindex=\"-1\">")193+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">")
194+ if templ_7745c5c3_Err != nil {
195+ return templ_7745c5c3_Err
196+ }
197+ if l.Lede != "" {
198+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<p class=\"lede work-lede\">")
199+ if templ_7745c5c3_Err != nil {
200+ return templ_7745c5c3_Err
201+ }
202+ var templ_7745c5c3_Var14 string
203+ templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(l.Lede)
204+ if templ_7745c5c3_Err != nil {
205+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 29, Col: 39}
206+ }
207+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
208+ if templ_7745c5c3_Err != nil {
209+ return templ_7745c5c3_Err
210+ }
211+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</p>")
212+ if templ_7745c5c3_Err != nil {
213+ return templ_7745c5c3_Err
214+ }
215+ }
216+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<main id=\"main\" tabindex=\"-1\">")
194 if templ_7745c5c3_Err != nil {217 if templ_7745c5c3_Err != nil {
195 return templ_7745c5c3_Err218 return templ_7745c5c3_Err
196 }219 }
@@ -198,12 +221,12 @@ func Shell(l Layout, rail templ.Component) templ.Component {
198 if templ_7745c5c3_Err != nil {221 if templ_7745c5c3_Err != nil {
199 return templ_7745c5c3_Err222 return templ_7745c5c3_Err
200 }223 }
201- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</main>")224+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</main>")
202 if templ_7745c5c3_Err != nil {225 if templ_7745c5c3_Err != nil {
203 return templ_7745c5c3_Err226 return templ_7745c5c3_Err
204 }227 }
205 if l.HasRail && rail != nil {228 if l.HasRail && rail != nil {
206- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<aside class=\"rail\" aria-label=\"Context\">")229+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "<aside class=\"rail\" aria-label=\"Context\">")
207 if templ_7745c5c3_Err != nil {230 if templ_7745c5c3_Err != nil {
208 return templ_7745c5c3_Err231 return templ_7745c5c3_Err
209 }232 }
@@ -211,12 +234,12 @@ func Shell(l Layout, rail templ.Component) templ.Component {
211 if templ_7745c5c3_Err != nil {234 if templ_7745c5c3_Err != nil {
212 return templ_7745c5c3_Err235 return templ_7745c5c3_Err
213 }236 }
214- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</aside>")237+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</aside>")
215 if templ_7745c5c3_Err != nil {238 if templ_7745c5c3_Err != nil {
216 return templ_7745c5c3_Err239 return templ_7745c5c3_Err
217 }240 }
218 }241 }
219- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</div>")242+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</div>")
220 if templ_7745c5c3_Err != nil {243 if templ_7745c5c3_Err != nil {
221 return templ_7745c5c3_Err244 return templ_7745c5c3_Err
222 }245 }
@@ -244,7 +267,7 @@ func Shell(l Layout, rail templ.Component) templ.Component {
244 if templ_7745c5c3_Err != nil {267 if templ_7745c5c3_Err != nil {
245 return templ_7745c5c3_Err268 return templ_7745c5c3_Err
246 }269 }
247- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</body></html>")270+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</body></html>")
248 if templ_7745c5c3_Err != nil {271 if templ_7745c5c3_Err != nil {
249 return templ_7745c5c3_Err272 return templ_7745c5c3_Err
250 }273 }
@@ -270,260 +293,260 @@ func Header(l Layout) templ.Component {
270 }()293 }()
271 }294 }
272 ctx = templ.InitializeContext(ctx)295 ctx = templ.InitializeContext(ctx)
273- templ_7745c5c3_Var14 := templ.GetChildren(ctx)296+ templ_7745c5c3_Var15 := templ.GetChildren(ctx)
274- if templ_7745c5c3_Var14 == nil {297+ if templ_7745c5c3_Var15 == nil {
275- templ_7745c5c3_Var14 = templ.NopComponent298+ templ_7745c5c3_Var15 = templ.NopComponent
276 }299 }
277 ctx = templ.ClearChildren(ctx)300 ctx = templ.ClearChildren(ctx)
278- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<header class=\"hdr\"><div class=\"hdr-top\"><a class=\"brand\" href=\"/\" data-g=\"h\" title=\"home (g h)\"><span class=\"brand-mark\" aria-hidden=\"true\"></span> <span class=\"brand-name\">")301+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<header class=\"hdr\"><div class=\"hdr-top\"><a class=\"brand\" href=\"/\" data-g=\"h\" title=\"home (g h)\"><span class=\"brand-mark\" aria-hidden=\"true\"></span> <span class=\"brand-name\">")
279 if templ_7745c5c3_Err != nil {302 if templ_7745c5c3_Err != nil {
280 return templ_7745c5c3_Err303 return templ_7745c5c3_Err
281 }304 }
282- var templ_7745c5c3_Var15 string305+ var templ_7745c5c3_Var16 string
283- templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(l.Instance)306+ templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(l.Instance)
284 if templ_7745c5c3_Err != nil {307 if templ_7745c5c3_Err != nil {
285- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 54, Col: 41}308+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 57, Col: 41}
286 }309 }
287- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))310+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
288 if templ_7745c5c3_Err != nil {311 if templ_7745c5c3_Err != nil {
289 return templ_7745c5c3_Err312 return templ_7745c5c3_Err
290 }313 }
291- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</span></a> ")314+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</span></a> ")
292 if templ_7745c5c3_Err != nil {315 if templ_7745c5c3_Err != nil {
293 return templ_7745c5c3_Err316 return templ_7745c5c3_Err
294 }317 }
295 if len(l.Crumbs) > 0 {318 if len(l.Crumbs) > 0 {
296- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<nav class=\"crumbs\" aria-label=\"Path\"><ol>")319+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "<nav class=\"crumbs\" aria-label=\"Path\"><ol>")
297 if templ_7745c5c3_Err != nil {320 if templ_7745c5c3_Err != nil {
298 return templ_7745c5c3_Err321 return templ_7745c5c3_Err
299 }322 }
300 for _, c := range l.Crumbs {323 for _, c := range l.Crumbs {
301- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<li>")324+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<li>")
302 if templ_7745c5c3_Err != nil {325 if templ_7745c5c3_Err != nil {
303 return templ_7745c5c3_Err326 return templ_7745c5c3_Err
304 }327 }
305 if c.Href != "" {328 if c.Href != "" {
306- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<a href=\"")329+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<a href=\"")
307 if templ_7745c5c3_Err != nil {330 if templ_7745c5c3_Err != nil {
308 return templ_7745c5c3_Err331 return templ_7745c5c3_Err
309 }332 }
310- var templ_7745c5c3_Var16 templ.SafeURL333+ var templ_7745c5c3_Var17 templ.SafeURL
311- templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))334+ templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(c.Href))
312 if templ_7745c5c3_Err != nil {335 if templ_7745c5c3_Err != nil {
313- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 63, Col: 38}336+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 66, Col: 38}
314 }337 }
315- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))338+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
316 if templ_7745c5c3_Err != nil {339 if templ_7745c5c3_Err != nil {
317 return templ_7745c5c3_Err340 return templ_7745c5c3_Err
318 }341 }
319- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "\"")342+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\"")
320 if templ_7745c5c3_Err != nil {343 if templ_7745c5c3_Err != nil {
321 return templ_7745c5c3_Err344 return templ_7745c5c3_Err
322 }345 }
323 if c.Current {346 if c.Current {
324- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, " aria-current=\"page\"")347+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, " aria-current=\"page\"")
325 if templ_7745c5c3_Err != nil {348 if templ_7745c5c3_Err != nil {
326 return templ_7745c5c3_Err349 return templ_7745c5c3_Err
327 }350 }
328 }351 }
329- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, ">")352+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, ">")
330 if templ_7745c5c3_Err != nil {353 if templ_7745c5c3_Err != nil {
331 return templ_7745c5c3_Err354 return templ_7745c5c3_Err
332 }355 }
333- var templ_7745c5c3_Var17 string356+ var templ_7745c5c3_Var18 string
334- templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(c.Label)357+ templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(c.Label)
335 if templ_7745c5c3_Err != nil {358 if templ_7745c5c3_Err != nil {
336- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 67, Col: 19}359+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 70, Col: 19}
337 }360 }
338- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))361+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
339 if templ_7745c5c3_Err != nil {362 if templ_7745c5c3_Err != nil {
340 return templ_7745c5c3_Err363 return templ_7745c5c3_Err
341 }364 }
342- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</a>")365+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "</a>")
343 if templ_7745c5c3_Err != nil {366 if templ_7745c5c3_Err != nil {
344 return templ_7745c5c3_Err367 return templ_7745c5c3_Err
345 }368 }
346 } else {369 } else {
347- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<span")370+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "<span")
348 if templ_7745c5c3_Err != nil {371 if templ_7745c5c3_Err != nil {
349 return templ_7745c5c3_Err372 return templ_7745c5c3_Err
350 }373 }
351 if c.Current {374 if c.Current {
352- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, " aria-current=\"page\"")375+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, " aria-current=\"page\"")
353 if templ_7745c5c3_Err != nil {376 if templ_7745c5c3_Err != nil {
354 return templ_7745c5c3_Err377 return templ_7745c5c3_Err
355 }378 }
356 }379 }
357- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, ">")380+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, ">")
358 if templ_7745c5c3_Err != nil {381 if templ_7745c5c3_Err != nil {
359 return templ_7745c5c3_Err382 return templ_7745c5c3_Err
360 }383 }
361- var templ_7745c5c3_Var18 string384+ var templ_7745c5c3_Var19 string
362- templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(c.Label)385+ templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(c.Label)
363 if templ_7745c5c3_Err != nil {386 if templ_7745c5c3_Err != nil {
364- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 73, Col: 19}387+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 76, Col: 19}
365 }388 }
366- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))389+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
367 if templ_7745c5c3_Err != nil {390 if templ_7745c5c3_Err != nil {
368 return templ_7745c5c3_Err391 return templ_7745c5c3_Err
369 }392 }
370- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "</span>")393+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "</span>")
371 if templ_7745c5c3_Err != nil {394 if templ_7745c5c3_Err != nil {
372 return templ_7745c5c3_Err395 return templ_7745c5c3_Err
373 }396 }
374 }397 }
375- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</li>")398+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "</li>")
376 if templ_7745c5c3_Err != nil {399 if templ_7745c5c3_Err != nil {
377 return templ_7745c5c3_Err400 return templ_7745c5c3_Err
378 }401 }
379 }402 }
380- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</ol></nav>")403+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</ol></nav>")
381 if templ_7745c5c3_Err != nil {404 if templ_7745c5c3_Err != nil {
382 return templ_7745c5c3_Err405 return templ_7745c5c3_Err
383 }406 }
384 }407 }
385- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "<div class=\"hdr-acts\">")408+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "<div class=\"hdr-acts\">")
386 if templ_7745c5c3_Err != nil {409 if templ_7745c5c3_Err != nil {
387 return templ_7745c5c3_Err410 return templ_7745c5c3_Err
388 }411 }
389 if l.Ref != "" {412 if l.Ref != "" {
390- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "<button type=\"button\" class=\"btn ref\" aria-haspopup=\"dialog\" aria-controls=\"panel-refs\" aria-keyshortcuts=\"b\" title=\"switch branch or tag (b)\" hx-on:click=\"document.body.dispatchEvent(new CustomEvent('k-refs'))\"><span class=\"ico i-branch\" aria-hidden=\"true\"></span> <span class=\"ref-name\">")413+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "<button type=\"button\" class=\"btn ref\" aria-haspopup=\"dialog\" aria-controls=\"panel-refs\" aria-keyshortcuts=\"b\" title=\"switch branch or tag (b)\" hx-on:click=\"document.body.dispatchEvent(new CustomEvent('k-refs'))\"><span class=\"ico i-branch\" aria-hidden=\"true\"></span> <span class=\"ref-name\">")
391 if templ_7745c5c3_Err != nil {414 if templ_7745c5c3_Err != nil {
392 return templ_7745c5c3_Err415 return templ_7745c5c3_Err
393 }416 }
394- var templ_7745c5c3_Var19 string417+ var templ_7745c5c3_Var20 string
395- templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(l.Ref)418+ templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(l.Ref)
396 if templ_7745c5c3_Err != nil {419 if templ_7745c5c3_Err != nil {
397- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 92, Col: 36}420+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 95, Col: 36}
398 }421 }
399- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))422+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
400 if templ_7745c5c3_Err != nil {423 if templ_7745c5c3_Err != nil {
401 return templ_7745c5c3_Err424 return templ_7745c5c3_Err
402 }425 }
403- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</span> <span class=\"sha\">")426+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "</span> <span class=\"sha\">")
404 if templ_7745c5c3_Err != nil {427 if templ_7745c5c3_Err != nil {
405 return templ_7745c5c3_Err428 return templ_7745c5c3_Err
406 }429 }
407- var templ_7745c5c3_Var20 string430+ var templ_7745c5c3_Var21 string
408- templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(l.Short)431+ templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(l.Short)
409 if templ_7745c5c3_Err != nil {432 if templ_7745c5c3_Err != nil {
410- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 93, Col: 33}433+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 96, Col: 33}
411 }434 }
412- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))435+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
413 if templ_7745c5c3_Err != nil {436 if templ_7745c5c3_Err != nil {
414 return templ_7745c5c3_Err437 return templ_7745c5c3_Err
415 }438 }
416- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "</span></button> ")439+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "</span></button> ")
417 if templ_7745c5c3_Err != nil {440 if templ_7745c5c3_Err != nil {
418 return templ_7745c5c3_Err441 return templ_7745c5c3_Err
419 }442 }
420 }443 }
421- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "<button type=\"button\" class=\"btn search\" aria-haspopup=\"dialog\" aria-controls=\"panel-cmd\" aria-keyshortcuts=\"Control+K :\" title=\"go to a section, ref, file or repo (ctrl k or :)\" hx-on:click=\"document.body.dispatchEvent(new CustomEvent('k-cmd'))\"><span class=\"ico i-search\" aria-hidden=\"true\"></span> <span class=\"search-label\">Go to…</span> <kbd aria-hidden=\"true\">ctrl k</kbd></button> <button type=\"button\" class=\"btn icon\" aria-haspopup=\"dialog\" aria-controls=\"panel-help\" aria-keyshortcuts=\"?\" aria-label=\"Keyboard shortcuts\" title=\"keyboard shortcuts (?)\" hx-on:click=\"document.body.dispatchEvent(new CustomEvent('k-help'))\">?</button> ")444+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "<button type=\"button\" class=\"btn search\" aria-haspopup=\"dialog\" aria-controls=\"panel-cmd\" aria-keyshortcuts=\"Control+K :\" title=\"go to a section, ref, file or repo (ctrl k or :)\" hx-on:click=\"document.body.dispatchEvent(new CustomEvent('k-cmd'))\"><span class=\"ico i-search\" aria-hidden=\"true\"></span> <span class=\"search-label\">Go to…</span> <kbd aria-hidden=\"true\">ctrl k</kbd></button> <button type=\"button\" class=\"btn icon\" aria-haspopup=\"dialog\" aria-controls=\"panel-help\" aria-keyshortcuts=\"?\" aria-label=\"Keyboard shortcuts\" title=\"keyboard shortcuts (?)\" hx-on:click=\"document.body.dispatchEvent(new CustomEvent('k-help'))\">?</button> ")
422 if templ_7745c5c3_Err != nil {445 if templ_7745c5c3_Err != nil {
423 return templ_7745c5c3_Err446 return templ_7745c5c3_Err
424 }447 }
425 if SignedIn(ctx) {448 if SignedIn(ctx) {
426- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "<form class=\"owner\" method=\"post\" action=\"/-/logout\"><span class=\"owner-badge\" title=\"signed in as the owner\">owner</span> <button type=\"submit\" class=\"btn\" title=\"sign out of this browser\">Sign out</button></form>")449+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<form class=\"owner\" method=\"post\" action=\"/-/logout\"><span class=\"owner-badge\" title=\"signed in as the owner\">owner</span> <button type=\"submit\" class=\"btn\" title=\"sign out of this browser\">Sign out</button></form>")
427 if templ_7745c5c3_Err != nil {450 if templ_7745c5c3_Err != nil {
428 return templ_7745c5c3_Err451 return templ_7745c5c3_Err
429 }452 }
430 }453 }
431- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "</div></div>")454+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "</div></div>")
432 if templ_7745c5c3_Err != nil {455 if templ_7745c5c3_Err != nil {
433 return templ_7745c5c3_Err456 return templ_7745c5c3_Err
434 }457 }
435 if len(l.Sections) > 0 {458 if len(l.Sections) > 0 {
436- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "<nav class=\"tabs\" aria-label=\"Sections\"><ul>")459+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "<nav class=\"tabs\" aria-label=\"Sections\"><ul>")
437 if templ_7745c5c3_Err != nil {460 if templ_7745c5c3_Err != nil {
438 return templ_7745c5c3_Err461 return templ_7745c5c3_Err
439 }462 }
440 for _, s := range l.Sections {463 for _, s := range l.Sections {
441- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<li><a href=\"")464+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "<li><a href=\"")
442 if templ_7745c5c3_Err != nil {465 if templ_7745c5c3_Err != nil {
443 return templ_7745c5c3_Err466 return templ_7745c5c3_Err
444 }467 }
445- var templ_7745c5c3_Var21 templ.SafeURL468+ var templ_7745c5c3_Var22 templ.SafeURL
446- templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(s.Href))469+ templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(s.Href))
447 if templ_7745c5c3_Err != nil {470 if templ_7745c5c3_Err != nil {
448- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 124, Col: 36}471+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 127, Col: 36}
449 }472 }
450- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))473+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
451 if templ_7745c5c3_Err != nil {474 if templ_7745c5c3_Err != nil {
452 return templ_7745c5c3_Err475 return templ_7745c5c3_Err
453 }476 }
454- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "\" data-key=\"")477+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "\" data-key=\"")
455 if templ_7745c5c3_Err != nil {478 if templ_7745c5c3_Err != nil {
456 return templ_7745c5c3_Err479 return templ_7745c5c3_Err
457 }480 }
458- var templ_7745c5c3_Var22 string481+ var templ_7745c5c3_Var23 string
459- templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.ResolveAttributeValue(s.Key)482+ templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.ResolveAttributeValue(s.Key)
460 if templ_7745c5c3_Err != nil {483 if templ_7745c5c3_Err != nil {
461- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 125, Col: 24}484+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 128, Col: 24}
462 }485 }
463- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var22)486+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var23)
464 if templ_7745c5c3_Err != nil {487 if templ_7745c5c3_Err != nil {
465 return templ_7745c5c3_Err488 return templ_7745c5c3_Err
466 }489 }
467- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "\" aria-keyshortcuts=\"")490+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "\" aria-keyshortcuts=\"")
468 if templ_7745c5c3_Err != nil {491 if templ_7745c5c3_Err != nil {
469 return templ_7745c5c3_Err492 return templ_7745c5c3_Err
470 }493 }
471- var templ_7745c5c3_Var23 string494+ var templ_7745c5c3_Var24 string
472- templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.ResolveAttributeValue(s.Key)495+ templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.ResolveAttributeValue(s.Key)
473 if templ_7745c5c3_Err != nil {496 if templ_7745c5c3_Err != nil {
474- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 126, Col: 33}497+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 129, Col: 33}
475 }498 }
476- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var23)499+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var24)
477 if templ_7745c5c3_Err != nil {500 if templ_7745c5c3_Err != nil {
478 return templ_7745c5c3_Err501 return templ_7745c5c3_Err
479 }502 }
480- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "\"")503+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "\"")
481 if templ_7745c5c3_Err != nil {504 if templ_7745c5c3_Err != nil {
482 return templ_7745c5c3_Err505 return templ_7745c5c3_Err
483 }506 }
484 if s.Current {507 if s.Current {
485- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, " aria-current=\"page\"")508+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, " aria-current=\"page\"")
486 if templ_7745c5c3_Err != nil {509 if templ_7745c5c3_Err != nil {
487 return templ_7745c5c3_Err510 return templ_7745c5c3_Err
488 }511 }
489 }512 }
490- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, ">")513+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, ">")
491 if templ_7745c5c3_Err != nil {514 if templ_7745c5c3_Err != nil {
492 return templ_7745c5c3_Err515 return templ_7745c5c3_Err
493 }516 }
494- var templ_7745c5c3_Var24 string517+ var templ_7745c5c3_Var25 string
495- templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(s.Label)518+ templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(s.Label)
496 if templ_7745c5c3_Err != nil {519 if templ_7745c5c3_Err != nil {
497- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 130, Col: 17}520+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 133, Col: 17}
498 }521 }
499- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))522+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
500 if templ_7745c5c3_Err != nil {523 if templ_7745c5c3_Err != nil {
501 return templ_7745c5c3_Err524 return templ_7745c5c3_Err
502 }525 }
503- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "<kbd aria-hidden=\"true\">")526+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "<kbd aria-hidden=\"true\">")
504 if templ_7745c5c3_Err != nil {527 if templ_7745c5c3_Err != nil {
505 return templ_7745c5c3_Err528 return templ_7745c5c3_Err
506 }529 }
507- var templ_7745c5c3_Var25 string530+ var templ_7745c5c3_Var26 string
508- templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(s.Key)531+ templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(s.Key)
509 if templ_7745c5c3_Err != nil {532 if templ_7745c5c3_Err != nil {
510- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 130, Col: 50}533+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 133, Col: 50}
511 }534 }
512- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))535+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
513 if templ_7745c5c3_Err != nil {536 if templ_7745c5c3_Err != nil {
514 return templ_7745c5c3_Err537 return templ_7745c5c3_Err
515 }538 }
516- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "</kbd></a></li>")539+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "</kbd></a></li>")
517 if templ_7745c5c3_Err != nil {540 if templ_7745c5c3_Err != nil {
518 return templ_7745c5c3_Err541 return templ_7745c5c3_Err
519 }542 }
520 }543 }
521- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "</ul></nav>")544+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "</ul></nav>")
522 if templ_7745c5c3_Err != nil {545 if templ_7745c5c3_Err != nil {
523 return templ_7745c5c3_Err546 return templ_7745c5c3_Err
524 }547 }
525 }548 }
526- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "</header>")549+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "</header>")
527 if templ_7745c5c3_Err != nil {550 if templ_7745c5c3_Err != nil {
528 return templ_7745c5c3_Err551 return templ_7745c5c3_Err
529 }552 }
@@ -549,38 +572,38 @@ func Footer(l Layout) templ.Component {
549 }()572 }()
550 }573 }
551 ctx = templ.InitializeContext(ctx)574 ctx = templ.InitializeContext(ctx)
552- templ_7745c5c3_Var26 := templ.GetChildren(ctx)575+ templ_7745c5c3_Var27 := templ.GetChildren(ctx)
553- if templ_7745c5c3_Var26 == nil {576+ if templ_7745c5c3_Var27 == nil {
554- templ_7745c5c3_Var26 = templ.NopComponent577+ templ_7745c5c3_Var27 = templ.NopComponent
555 }578 }
556 ctx = templ.ClearChildren(ctx)579 ctx = templ.ClearChildren(ctx)
557- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "<footer class=\"foot\"><span>ermite ")580+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "<footer class=\"foot\"><span>ermite ")
558 if templ_7745c5c3_Err != nil {581 if templ_7745c5c3_Err != nil {
559 return templ_7745c5c3_Err582 return templ_7745c5c3_Err
560 }583 }
561- var templ_7745c5c3_Var27 string584+ var templ_7745c5c3_Var28 string
562- templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(l.Version)585+ templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(l.Version)
563 if templ_7745c5c3_Err != nil {586 if templ_7745c5c3_Err != nil {
564- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 143, Col: 26}587+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 146, Col: 26}
565 }588 }
566- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))589+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
567 if templ_7745c5c3_Err != nil {590 if templ_7745c5c3_Err != nil {
568 return templ_7745c5c3_Err591 return templ_7745c5c3_Err
569 }592 }
570- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "</span> <a href=\"")593+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "</span> <a href=\"")
571 if templ_7745c5c3_Err != nil {594 if templ_7745c5c3_Err != nil {
572 return templ_7745c5c3_Err595 return templ_7745c5c3_Err
573 }596 }
574- var templ_7745c5c3_Var28 templ.SafeURL597+ var templ_7745c5c3_Var29 templ.SafeURL
575- templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(l.SourceURL))598+ templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(l.SourceURL))
576 if templ_7745c5c3_Err != nil {599 if templ_7745c5c3_Err != nil {
577- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 144, Col: 38}600+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/adapters/web/shell.templ`, Line: 147, Col: 38}
578 }601 }
579- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))602+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
580 if templ_7745c5c3_Err != nil {603 if templ_7745c5c3_Err != nil {
581 return templ_7745c5c3_Err604 return templ_7745c5c3_Err
582 }605 }
583- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "\" rel=\"noopener\" title=\"source of this version (AGPL-3.0-or-later)\">source</a> <span class=\"foot-keys\"><kbd>?</kbd> keyboard shortcuts</span></footer>")606+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "\" rel=\"noopener\" title=\"source of this version (AGPL-3.0-or-later)\">source</a> <span class=\"foot-keys\"><kbd>?</kbd> keyboard shortcuts</span></footer>")
584 if templ_7745c5c3_Err != nil {607 if templ_7745c5c3_Err != nil {
585 return templ_7745c5c3_Err608 return templ_7745c5c3_Err
586 }609 }
@@ -608,12 +631,12 @@ func Hint(l Layout) templ.Component {
608 }()631 }()
609 }632 }
610 ctx = templ.InitializeContext(ctx)633 ctx = templ.InitializeContext(ctx)
611- templ_7745c5c3_Var29 := templ.GetChildren(ctx)634+ templ_7745c5c3_Var30 := templ.GetChildren(ctx)
612- if templ_7745c5c3_Var29 == nil {635+ if templ_7745c5c3_Var30 == nil {
613- templ_7745c5c3_Var29 = templ.NopComponent636+ templ_7745c5c3_Var30 = templ.NopComponent
614 }637 }
615 ctx = templ.ClearChildren(ctx)638 ctx = templ.ClearChildren(ctx)
616- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "<div class=\"hint\" role=\"status\" aria-live=\"polite\"><span class=\"hint-nav\" :text=\"document.body.dataset.nav || ''\"></span> <span class=\"hint-sel\" :text=\"document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''\"></span> <span class=\"hint-flash\" :text=\"document.body.dataset.flash || ''\"></span>")639+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "<div class=\"hint\" role=\"status\" aria-live=\"polite\"><span class=\"hint-nav\" :text=\"document.body.dataset.nav || ''\"></span> <span class=\"hint-sel\" :text=\"document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''\"></span> <span class=\"hint-flash\" :text=\"document.body.dataset.flash || ''\"></span>")
617 if templ_7745c5c3_Err != nil {640 if templ_7745c5c3_Err != nil {
618 return templ_7745c5c3_Err641 return templ_7745c5c3_Err
619 }642 }
@@ -621,7 +644,7 @@ func Hint(l Layout) templ.Component {
621 if templ_7745c5c3_Err != nil {644 if templ_7745c5c3_Err != nil {
622 return templ_7745c5c3_Err645 return templ_7745c5c3_Err
623 }646 }
624- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "</div>")647+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "</div>")
625 if templ_7745c5c3_Err != nil {648 if templ_7745c5c3_Err != nil {
626 return templ_7745c5c3_Err649 return templ_7745c5c3_Err
627 }650 }
M internal/adapters/web/static/css/20-shell.css +1 -0
@@ -108,6 +108,7 @@
108108 }
109109 .work.has-rail { grid-template-columns: minmax(0, 1fr) var(--rail); }
110110 .rail { display: flex; flex-direction: column; gap: var(--s4); min-width: 0; }
111+ .work-lede { grid-column: 1 / -1; margin-bottom: calc(-1 * var(--s2)); }
111112 main > * + * { margin-top: var(--s4); }
112113
113114 /* blocks: a surface with a header; rail sections are blocks too */
@@ -108,6 +108,7 @@
108 }108 }
109 .work.has-rail { grid-template-columns: minmax(0, 1fr) var(--rail); }109 .work.has-rail { grid-template-columns: minmax(0, 1fr) var(--rail); }
110 .rail { display: flex; flex-direction: column; gap: var(--s4); min-width: 0; }110 .rail { display: flex; flex-direction: column; gap: var(--s4); min-width: 0; }
111+ .work-lede { grid-column: 1 / -1; margin-bottom: calc(-1 * var(--s2)); }
111 main > * + * { margin-top: var(--s4); }112 main > * + * { margin-top: var(--s4); }
112 113
113 /* blocks: a surface with a header; rail sections are blocks too */114 /* blocks: a surface with a header; rail sections are blocks too */
M internal/adapters/web/summary.go +1 -1
@@ -44,7 +44,6 @@ func (s *Server) summary(ctx context.Context, r *http.Request) (templ.Component,
4444 now := s.cfg.Now()
4545
4646 p := SummaryPage{
47- Desc: d.repo.GetDescription(),
4847 AllHref: repoHref(d.name(), "commits", ref),
4948 Clone: Clone{ID: "clone-" + d.name(), Lines: []string{"git clone " + s.cloneURL(d.name())}},
5049 }
@@ -74,6 +73,7 @@ func (s *Server) summary(ctx context.Context, r *http.Request) (templ.Component,
7473 l.Title = d.name() + " · " + s.instance
7574 l.Live, l.LiveURL = true, liveURL("repo:"+d.name(), "view=summary")
7675 l.HasRail = true
76+ l.Lede = d.repo.GetDescription()
7777 return Summary(l, p), http.StatusOK, nil
7878 }
7979
@@ -44,7 +44,6 @@ func (s *Server) summary(ctx context.Context, r *http.Request) (templ.Component,
44 now := s.cfg.Now()44 now := s.cfg.Now()
45 45
46 p := SummaryPage{46 p := SummaryPage{
47- Desc: d.repo.GetDescription(),
48 AllHref: repoHref(d.name(), "commits", ref),47 AllHref: repoHref(d.name(), "commits", ref),
49 Clone: Clone{ID: "clone-" + d.name(), Lines: []string{"git clone " + s.cloneURL(d.name())}},48 Clone: Clone{ID: "clone-" + d.name(), Lines: []string{"git clone " + s.cloneURL(d.name())}},
50 }49 }
@@ -74,6 +73,7 @@ func (s *Server) summary(ctx context.Context, r *http.Request) (templ.Component,
74 l.Title = d.name() + " · " + s.instance73 l.Title = d.name() + " · " + s.instance
75 l.Live, l.LiveURL = true, liveURL("repo:"+d.name(), "view=summary")74 l.Live, l.LiveURL = true, liveURL("repo:"+d.name(), "view=summary")
76 l.HasRail = true75 l.HasRail = true
76+ l.Lede = d.repo.GetDescription()
77 return Summary(l, p), http.StatusOK, nil77 return Summary(l, p), http.StatusOK, nil
78 }78 }
79 79
M internal/adapters/web/view.go +2 -1
@@ -50,6 +50,8 @@ type Layout struct {
5050 Tags []RefItem
5151 Cmd []CmdItem
5252 HasRail bool
53+ // Lede is a line above the content and the rail, so both start level.
54+ Lede string
5355 // Live connects the page to the event stream (/-/events).
5456 Live bool
5557 // LiveURL is the stream the page follows, with its query.
@@ -133,7 +135,6 @@ type CommitRow struct {
133135
134136 // SummaryPage is the repository summary.
135137 type SummaryPage struct {
136- Desc string
137138 Facts []Fact
138139 Clone Clone
139140 Recent []CommitRow
@@ -50,6 +50,8 @@ type Layout struct {
50 Tags []RefItem50 Tags []RefItem
51 Cmd []CmdItem51 Cmd []CmdItem
52 HasRail bool52 HasRail bool
53+ // Lede is a line above the content and the rail, so both start level.
54+ Lede string
53 // Live connects the page to the event stream (/-/events).55 // Live connects the page to the event stream (/-/events).
54 Live bool56 Live bool
55 // LiveURL is the stream the page follows, with its query.57 // LiveURL is the stream the page follows, with its query.
@@ -133,7 +135,6 @@ type CommitRow struct {
133 135
134 // SummaryPage is the repository summary.136 // SummaryPage is the repository summary.
135 type SummaryPage struct {137 type SummaryPage struct {
136- Desc string
137 Facts []Fact138 Facts []Fact
138 Clone Clone139 Clone Clone
139 Recent []CommitRow140 Recent []CommitRow

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 45

↑↓ moveenter openesc close