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>m</kbd> <kbd>g m</kbd></dt><dd>merge requests (when shown)</dd></div>
23 <div><dt><kbd>d</kbd> <kbd>u</kbd> <kbd>x</kbd></dt><dd>diff: split / unified / collapse all</dd></div>
24 <div><dt><kbd>n</kbd></dt><dd>merge request: next note in the diff</dd></div>
25 <div><dt><kbd>esc</kbd></dt><dd>close panel</dd></div>
26 </dl>
27 </dialog>
28}
29
30// OverlayRefs is the ref switcher. It exists only inside a repository.
31templ OverlayRefs(l Layout) {
32 if l.Ref != "" {
33 <dialog id="panel-refs" class="panel" aria-label="Switch ref" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())">
34 <div class="panel-head">
35 <label for="refs-filter">ref></label>
36 <input
37 id="refs-filter"
38 type="search"
39 placeholder="filter branches and tags"
40 autocomplete="off"
41 data-pick
42 hx-on:input="let t = this.value.toLowerCase(); q('#panel-refs li').arr().forEach(li => li.hidden = !li.textContent.toLowerCase().includes(t))"
43 />
44 <button type="button" hx-on:click="closest('dialog').close()">[esc] close</button>
45 </div>
46 <div class="panel-cols" data-picklist>
47 <section aria-label="Branches">
48 <h2>branches <span class="mute">{ itoa(len(l.Heads)) }</span></h2>
49 <ul>
50 for _, r := range l.Heads {
51 @refItem(r)
52 }
53 </ul>
54 </section>
55 <section aria-label="Tags">
56 <h2>tags <span class="mute">{ itoa(len(l.Tags)) }</span></h2>
57 <ul>
58 for _, r := range l.Tags {
59 @refItem(r)
60 }
61 </ul>
62 </section>
63 </div>
64 </dialog>
65 }
66}
67
68templ refItem(r RefItem) {
69 <li>
70 <a
71 href={ templ.SafeURL(r.Href) }
72 if r.Current {
73 aria-current="true"
74 }
75 >
76 <span class="mark" aria-hidden="true">
77 if r.Current {
78 ●
79 } else {
80
81 }
82 </span>{ r.Name }
83 </a>
84 </li>
85}
86
87// OverlayCmd is the ":" command line: one filterable list mixing sections,
88// refs, files of this directory and repos.
89templ OverlayCmd(items []CmdItem) {
90 <dialog id="panel-cmd" class="panel" aria-label="Go to" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())">
91 <div class="panel-head">
92 <label for="cmd-q" class="hi">:</label>
93 <input
94 id="cmd-q"
95 type="search"
96 placeholder="section, ref, file or repo"
97 autocomplete="off"
98 spellcheck="false"
99 aria-controls="cmd-list"
100 hx-on:input="let t = this.value.toLowerCase().trim();
101 q('#cmd-list > li').arr().forEach(li => li.hidden = !li.dataset.k.includes(t));
102 let first = q('#cmd-list > li:not([hidden])').arr()[0]; first && q(first).take('data-cursor', '#cmd-list > li')"
103 hx-on:keydown="let vis = q('#cmd-list > li:not([hidden])').arr();
104 let i = vis.findIndex(li => li.hasAttribute('data-cursor'));
105 let step = event.key === 'ArrowDown' ? 1 : event.key === 'ArrowUp' ? -1 : 0;
106 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' })) }
107 else if (event.key === 'Enter') { event.preventDefault(); vis[Math.max(i, 0)]?.querySelector('a').click() }"
108 />
109 <button type="button" hx-on:click="closest('dialog').close()">[esc] close</button>
110 </div>
111 <ul id="cmd-list" class="cmd-list">
112 for i, c := range items {
113 <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>
114 }
115 </ul>
116 </dialog>
117}