v0.4.0 3027a40

pages.templ RawHistoryFolder

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package web
4
5// Home is the repository list.
6templ Home(l Layout, p HomePage) {
7	@Shell(l, nil) {
8		<div class="filter">
9			<label for="home-filter">filter&gt;</label>
10			<input
11				id="home-filter"
12				type="search"
13				data-filter
14				placeholder="name or description  ( / )"
15				autocomplete="off"
16				hx-on:input="let t = this.value.toLowerCase(); q('#repo-rows > tr').arr().forEach(r => r.hidden = !r.textContent.toLowerCase().includes(t)); take('data-cursor', '#repo-rows > tr:not([hidden])')"
17			/>
18		</div>
19		<table class="list home" aria-label="Repositories">
20			<thead>
21				<tr>
22					<th class="cur"></th>
23					for _, c := range p.Cols {
24						<th class={ c.Class } aria-sort={ c.Dir }>
25							<a href={ templ.SafeURL(c.Href) }>
26								{ c.Label }
27								if c.Mark != "" {
28									<span aria-hidden="true">{ c.Mark }</span>
29								}
30							</a>
31						</th>
32					}
33				</tr>
34			</thead>
35			<tbody id="repo-rows" data-rows>
36				for _, r := range p.Rows {
37					@HomeRowView(r)
38				}
39			</tbody>
40		</table>
41		if len(p.Rows) == 0 {
42			<p class="lede dim">no repositories yet.</p>
43		}
44	}
45}
46
47// Summary is the summary of a repository: the README reads in the main
48// column at the reading measure; what one acts on sits in the rail.
49templ Summary(l Layout, p SummaryPage) {
50	@Shell(l, summaryRail(p)) {
51		if p.Desc != "" {
52			<p class="lede">{ p.Desc }</p>
53		}
54		if p.Readme != nil {
55			<h2 class="rule-h"><span>{ p.Readme.Name }</span></h2>
56			@ReadmeView(*p.Readme)
57		}
58	}
59}
60
61templ summaryRail(p SummaryPage) {
62	<section aria-labelledby="r-clone"><h2 id="r-clone">clone</h2>@CloneBlock(p.Clone)
63</section>
64	<section aria-labelledby="r-facts"><h2 id="r-facts">facts</h2>@Facts(p.Facts)
65</section>
66	if len(p.Recent) > 0 {
67		<section aria-labelledby="r-recent"><h2 id="r-recent">recent commits <a href={ templ.SafeURL(p.AllHref) }>all</a></h2>@CommitRows(p.Recent)
68</section>
69	}
70	if len(p.Outline) > 0 && p.Readme != nil {
71		<section aria-labelledby="r-outline"><h2 id="r-outline">{ p.Readme.Name }</h2>@Outline(p.Outline)
72</section>
73	}
74}
75
76// Refs lists the branches and tags of a repository.
77templ Refs(l Layout, p RefsPage) {
78	@Shell(l, refsRail(p)) {
79		<div class="filter">
80			<label for="ref-filter">filter&gt;</label>
81			<input
82				id="ref-filter"
83				type="search"
84				data-filter
85				placeholder="branch or tag  ( / )"
86				autocomplete="off"
87				hx-on:input="let t = this.value.toLowerCase(); q('#ref-rows > tr').arr().forEach(r => r.hidden = !r.textContent.toLowerCase().includes(t));
88      let first = q('#ref-rows > tr:not([hidden])').arr()[0]; first && q(first).take('data-cursor', '#ref-rows > tr')"
89			/>
90		</div>
91		<table class="list refs" aria-label="Branches and tags">
92			<thead>
93				<tr><th class="cur"></th><th class="c-kind">kind</th><th class="c-name">name</th><th class="c-sha">commit</th><th class="c-sub">subject</th><th class="c-when">date</th></tr>
94			</thead>
95			@RefsBody(p)
96		</table>
97		if p.Note != "" {
98			<p class="note">{ p.Note }</p>
99		}
100	}
101}
102
103templ refRow(kind string, r RefRow) {
104	<tr data-cursor?={ r.Cursor }>
105		<td class="cur" aria-hidden="true"></td>
106		<td class="c-kind mute">{ kind }</td>
107		<td class="c-name">
108			<a href={ templ.SafeURL(r.Href) }>{ r.Name }</a>
109			if r.Default {
110				<span class="tagged">*</span>
111			}
112		</td>
113		<td class="c-sha">
114			if r.CHref != "" {
115				<a href={ templ.SafeURL(r.CHref) }>{ r.Short }</a>
116			} else {
117				{ r.Short }
118			}
119		</td>
120		<td class="c-sub">{ r.Subject }</td>
121		<td class="c-when dim">
122			if r.WhenAt != "" {
123				<time datetime={ r.WhenAt } title={ r.WhenAt }>{ r.When }</time>
124			}
125		</td>
126	</tr>
127}
128
129templ refsRail(p RefsPage) {
130	<section aria-labelledby="r-refs">
131		<h2 id="r-refs">refs</h2>
132		@RefsKV(p)
133	</section>
134	<section aria-labelledby="r-legend">
135		<h2 id="r-legend">legend</h2>
136		<dl class="kv"><dt>*</dt><dd>default branch</dd></dl>
137	</section>
138}
139
140// State is a 404, 500 or empty-repository page inside the normal shell.
141templ State(l Layout, p StatePage) {
142	@Shell(l, nil) {
143		<section class="state" aria-labelledby="state-title">
144			<h1 id="state-title"><span class="code">{ p.Code }</span> { p.Title }</h1>
145			for _, line := range p.Lines {
146				<p class="dim">{ line }</p>
147			}
148			if p.Clone != nil {
149				@CloneBlock(*p.Clone)
150			}
151			<p class="state-back">
152				for _, b := range p.Back {
153					<a href={ templ.SafeURL(b.Href) }>{ b.Label }</a>
154				}
155			</p>
156		</section>
157	}
158}
159
160// Login asks the owner to confirm a login link. Opening the link consumes
161// nothing; only this form does. It is a state page with a button.
162templ Login(l Layout, p LoginPage) {
163	@Shell(l, nil) {
164		<section class="state" aria-labelledby="state-title">
165			<h1 id="state-title"><span class="code">login</span> { p.Title }</h1>
166			for _, line := range p.Lines {
167				<p class="dim">{ line }</p>
168			}
169			<form class="state-act" method="post" action={ templ.SafeURL(p.Action) }>
170				<button type="submit">{ p.Button }</button>
171			</form>
172			<p class="state-back"><a href="/">home</a></p>
173		</section>
174	}
175}

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 4

Tags 45

↑↓ moveenter openesc close