v0.1.0 3f267b5

overlays.templ RawHistoryFolder

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package web
4
5import "strings"
6
7// OverlayHelp is the keyboard map panel.
8templ OverlayHelp() {
9	<dialog id="panel-help" class="panel" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())">
10		<div class="panel-head"><span>keys</span><button type="button" hx-on:click="closest('dialog').close()">[esc] close</button></div>
11		<dl class="keys">
12			<div><dt><kbd>j</kbd> <kbd>k</kbd></dt><dd>move cursor down / up</dd></div>
13			<div><dt><kbd>enter</kbd></dt><dd>open row under cursor</dd></div>
14			<div><dt><kbd>g</kbd> <kbd>g</kbd> / <kbd>G</kbd></dt><dd>first / last row</dd></div>
15			<div><dt><kbd>/</kbd></dt><dd>focus the filter</dd></div>
16			<div><dt><kbd>g h</kbd> <kbd>g t</kbd></dt><dd>go home / tree</dd></div>
17			<div><dt><kbd>g c</kbd> <kbd>g r</kbd></dt><dd>go commits / refs</dd></div>
18			<div><dt><kbd>b</kbd></dt><dd>{ "switch" } ref (branches, tags)</dd></div>
19			<div><dt><kbd>:</kbd> <kbd>f</kbd></dt><dd>go to: section, ref, file, repo</dd></div>
20			<div><dt><kbd>y</kbd></dt><dd>permalink: ref becomes the full sha</dd></div>
21			<div><dt><kbd>s</kbd> <kbd>t</kbd> <kbd>c</kbd> <kbd>r</kbd></dt><dd>repo sections (when shown)</dd></div>
22			<div><dt><kbd>d</kbd> <kbd>u</kbd> <kbd>x</kbd></dt><dd>commit: split / unified / collapse all</dd></div>
23			<div><dt><kbd>esc</kbd></dt><dd>close panel</dd></div>
24		</dl>
25	</dialog>
26}
27
28// OverlayRefs is the ref switcher. It exists only inside a repository.
29templ OverlayRefs(l Layout) {
30	if l.Ref != "" {
31		<dialog id="panel-refs" class="panel" aria-label="Switch ref" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())">
32			<div class="panel-head">
33				<label for="refs-filter">ref&gt;</label>
34				<input
35					id="refs-filter"
36					type="search"
37					placeholder="filter branches and tags"
38					autocomplete="off"
39					data-pick
40					hx-on:input="let t = this.value.toLowerCase(); q('#panel-refs li').arr().forEach(li => li.hidden = !li.textContent.toLowerCase().includes(t))"
41				/>
42				<button type="button" hx-on:click="closest('dialog').close()">[esc] close</button>
43			</div>
44			<div class="panel-cols" data-picklist>
45				<section aria-label="Branches">
46					<h2>branches <span class="mute">{ itoa(len(l.Heads)) }</span></h2>
47					<ul>
48						for _, r := range l.Heads {
49							@refItem(r)
50						}
51					</ul>
52				</section>
53				<section aria-label="Tags">
54					<h2>tags <span class="mute">{ itoa(len(l.Tags)) }</span></h2>
55					<ul>
56						for _, r := range l.Tags {
57							@refItem(r)
58						}
59					</ul>
60				</section>
61			</div>
62		</dialog>
63	}
64}
65
66templ refItem(r RefItem) {
67	<li>
68		<a
69			href={ templ.SafeURL(r.Href) }
70			if r.Current {
71				aria-current="true"
72			}
73		>
74			<span class="mark" aria-hidden="true">
75				if r.Current {
76					●
77				} else {
78					&nbsp;
79				}
80			</span>{ r.Name }
81		</a>
82	</li>
83}
84
85// OverlayCmd is the ":" command line: one filterable list mixing sections,
86// refs, files of this directory and repos.
87templ OverlayCmd(items []CmdItem) {
88	<dialog id="panel-cmd" class="panel" aria-label="Go to" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())">
89		<div class="panel-head">
90			<label for="cmd-q" class="hi">:</label>
91			<input
92				id="cmd-q"
93				type="search"
94				placeholder="section, ref, file or repo"
95				autocomplete="off"
96				spellcheck="false"
97				aria-controls="cmd-list"
98				hx-on:input="let t = this.value.toLowerCase().trim();
99        q('#cmd-list > li').arr().forEach(li => li.hidden = !li.dataset.k.includes(t));
100        let first = q('#cmd-list > li:not([hidden])').arr()[0]; first && q(first).take('data-cursor', '#cmd-list > li')"
101				hx-on:keydown="let vis = q('#cmd-list > li:not([hidden])').arr();
102        let i = vis.findIndex(li => li.hasAttribute('data-cursor'));
103        let step = event.key === 'ArrowDown' ? 1 : event.key === 'ArrowUp' ? -1 : 0;
104        if (step) { event.preventDefault(); let n = vis[Math.max(0, Math.min(vis.length - 1, i + step))]; n && (q(n).take('data-cursor', '#cmd-list > li'), n.scrollIntoView({ block: 'nearest' })) }
105        else if (event.key === 'Enter') { event.preventDefault(); vis[Math.max(i, 0)]?.querySelector('a').click() }"
106			/>
107			<button type="button" hx-on:click="closest('dialog').close()">[esc] close</button>
108		</div>
109		<ul id="cmd-list" class="cmd-list">
110			for i, c := range items {
111				<li data-k={ strings.ToLower(c.Kind + " " + c.Label) } data-cursor?={ i == 0 }><a href={ templ.SafeURL(c.Href) } tabindex="-1"><span class="k">{ c.Kind }</span>{ c.Label }</a></li>
112			}
113		</ul>
114	</dialog>
115}

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