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></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
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}