detached f5cbe22

#31 fix(web): ARIA semantics for MR panels, dialogs, palette, forms and status regions

state
merged · 5d69f2b · squash
branch
fix/a11y → main
opened
bnema ·
updated
CommitSubjectAuthorDateSignatureStatus
f5cbe22test(app): update web goldens for the ARIA changesbriceGPG Verified
1f47bc8fix(web): keep MR panels open on refresh, expose one option per palette result, clear finder statusbriceGPG Verified
21b3830fix(web): improve ARIA semantics of MR panels, dialogs, palette, forms and status regionsbriceGPG Verified

Checks 4

55 files · +1051 -671
4/4
A internal/adapters/web/accessibility_test.go +53 -0
M internal/adapters/web/fragments.templ +1 -0
M internal/adapters/web/fragments_templ.go +2 -2
M internal/adapters/web/issues_form.templ +47 -9
M internal/adapters/web/issues_form_templ.go +161 -84
M internal/adapters/web/issues_form_test.go +2 -2
M internal/adapters/web/jstest/a11y.test.mjs +79 -1
M internal/adapters/web/jstest/finder.test.mjs +9 -8
M internal/adapters/web/jstest/mr.test.mjs +33 -1
M internal/adapters/web/mr.templ +9 -9
M internal/adapters/web/mr_templ.go +7 -7
M internal/adapters/web/mr_test.go +8 -7
M internal/adapters/web/overlays.templ +5 -5
M internal/adapters/web/overlays_templ.go +35 -12
M internal/adapters/web/shell.templ +4 -4
M internal/adapters/web/shell_templ.go +1 -1
M internal/adapters/web/static/css/20-shell.css +2 -1
M internal/adapters/web/static/css/60-mr.css +5 -8
M internal/adapters/web/static/css/85-mobile.css +1 -1
M internal/adapters/web/static/js/ermite.js +15 -0
M internal/adapters/web/static/js/files.js +4 -3
M internal/adapters/web/static/js/mr.js +3 -3
M internal/adapters/web/tree.templ +1 -1
M internal/adapters/web/tree_templ.go +1 -1
M internal/app/testdata/web/blob-binary.html +19 -17
M internal/app/testdata/web/blob-code.html +19 -17
M internal/app/testdata/web/blob-empty.html +19 -17
M internal/app/testdata/web/blob-image.html +19 -17
M internal/app/testdata/web/blob-markdown.html +19 -17
M internal/app/testdata/web/blob-svg.html +19 -17
M internal/app/testdata/web/blob-text.html +19 -17
M internal/app/testdata/web/blob-too-large.html +19 -17
M internal/app/testdata/web/blob-trojan.html +19 -17
M internal/app/testdata/web/commit-big.html +19 -17
M internal/app/testdata/web/commit-binary.html +19 -17
M internal/app/testdata/web/commit-merge.html +19 -17
M internal/app/testdata/web/commit-modify-split.html +19 -17
M internal/app/testdata/web/commit-modify.html +19 -17
M internal/app/testdata/web/commit-rename.html +19 -17
M internal/app/testdata/web/commit-root.html +19 -17
M internal/app/testdata/web/commit-trojan.html +19 -17
M internal/app/testdata/web/commits-page2.html +18 -16
M internal/app/testdata/web/commits-path.html +18 -16
M internal/app/testdata/web/commits-root.html +19 -17
M internal/app/testdata/web/commits-small.html +21 -19
M internal/app/testdata/web/empty.html +9 -7
M internal/app/testdata/web/home.html +11 -9
M internal/app/testdata/web/not-found-page.html +8 -6
M internal/app/testdata/web/not-found.html +8 -6
M internal/app/testdata/web/refs.html +22 -20
M internal/app/testdata/web/summary.html +22 -20
@@ -218,14 +218,16 @@
218218 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">
219219 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>
220220 </footer>
221-<div class="hint" role="status" aria-live="polite">
222-<span class="hint-nav" :text="document.body.dataset.nav || ''">
221+<div class="hint">
222+<span aria-hidden="true" class="hint-nav" :text="document.body.dataset.nav || ''">
223223 </span>
224+<span role="status" aria-live="polite">
224225 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">
225226 </span>
226227 <span class="hint-flash" :text="document.body.dataset.flash || ''">
227228 </span>
228-<span class="hint-live" data-state="connecting" hx-sse:connect="/-/events?topic=repo%3Ademo&amp;view=summary" hx-swap="none" :text="data.state === 'offline' ? 'live updates paused' : ''" hx-on="htmx:sse:after:connection -> ermiteLive.back();
229+</span>
230+<span class="hint-live" role="status" data-state="connecting" hx-sse:connect="/-/events?topic=repo%3Ademo&amp;view=summary" hx-swap="none" :text="data.state === 'offline' ? 'live updates paused' : ''" hx-on="htmx:sse:after:connection -> ermiteLive.back();
229231 htmx:sse:close, htmx:sse:error -> ermiteLive.lost();
230232 htmx:sse:error -> ermiteLive.error(event.detail.status);
231233 htmx:sse:before:connection -> ermiteLive.gate(event);
@@ -237,7 +239,7 @@
237239 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">
238240 <div class="panel-head">
239241 <h2>Keyboard shortcuts</h2>
240-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
242+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
241243 <kbd>esc</kbd> close</button>
242244 </div>
243245 <div class="keys-pref">
@@ -371,7 +373,7 @@
371373 <div class="panel-head">
372374 <label for="refs-filter" class="sr">filter branches and tags</label>
373375 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">
374-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
376+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
375377 <kbd>esc</kbd>
376378 </button>
377379 </div>
@@ -410,91 +412,91 @@
410412 <div class="panel-head">
411413 <label for="cmd-q" class="sr">go to</label>
412414 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">
413-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
415+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
414416 <kbd>esc</kbd>
415417 </button>
416418 </div>
417419 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">
418420 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>
419-<a href="/" tabindex="-1">
421+<a role="presentation" data-href="/">
420422 <span class="lbl">home</span>
421423 <span class="k">go</span>
422424 </a>
423425 </li>
424426 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">
425-<a href="/demo" tabindex="-1">
427+<a role="presentation" data-href="/demo">
426428 <span class="lbl">summary</span>
427429 <span class="k">section</span>
428430 </a>
429431 </li>
430432 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">
431-<a href="/demo/tree/main" tabindex="-1">
433+<a role="presentation" data-href="/demo/tree/main">
432434 <span class="lbl">files</span>
433435 <span class="k">section</span>
434436 </a>
435437 </li>
436438 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">
437-<a href="/demo/commits/main" tabindex="-1">
439+<a role="presentation" data-href="/demo/commits/main">
438440 <span class="lbl">commits</span>
439441 <span class="k">section</span>
440442 </a>
441443 </li>
442444 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">
443-<a href="/demo/refs" tabindex="-1">
445+<a role="presentation" data-href="/demo/refs">
444446 <span class="lbl">branches &amp; tags</span>
445447 <span class="k">section</span>
446448 </a>
447449 </li>
448450 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">
449-<a href="/demo/merge-requests" tabindex="-1">
451+<a role="presentation" data-href="/demo/merge-requests">
450452 <span class="lbl">merge requests</span>
451453 <span class="k">section</span>
452454 </a>
453455 </li>
454456 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
455-<a href="/demo/releases" tabindex="-1">
457+<a role="presentation" data-href="/demo/releases">
456458 <span class="lbl">releases</span>
457459 <span class="k">section</span>
458460 </a>
459461 </li>
460462 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
461-<a href="/demo/actions" tabindex="-1">
463+<a role="presentation" data-href="/demo/actions">
462464 <span class="lbl">actions</span>
463465 <span class="k">section</span>
464466 </a>
465467 </li>
466468 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
467-<a href="/demo/tree/feature/x" tabindex="-1">
469+<a role="presentation" data-href="/demo/tree/feature/x">
468470 <span class="lbl">feature/x</span>
469471 <span class="k">branch</span>
470472 </a>
471473 </li>
472474 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
473-<a href="/demo/tree/main" tabindex="-1">
475+<a role="presentation" data-href="/demo/tree/main">
474476 <span class="lbl">main</span>
475477 <span class="k">branch</span>
476478 </a>
477479 </li>
478480 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v0.1.0">
479-<a href="/demo/tree/v0.1.0" tabindex="-1">
481+<a role="presentation" data-href="/demo/tree/v0.1.0">
480482 <span class="lbl">v0.1.0</span>
481483 <span class="k">tag</span>
482484 </a>
483485 </li>
484486 <li id="cmd-o11" role="option" aria-selected="false" data-k="tag v0.2.0">
485-<a href="/demo/tree/v0.2.0" tabindex="-1">
487+<a role="presentation" data-href="/demo/tree/v0.2.0">
486488 <span class="lbl">v0.2.0</span>
487489 <span class="k">tag</span>
488490 </a>
489491 </li>
490492 <li id="cmd-o12" role="option" aria-selected="false" data-k="repo quiet">
491-<a href="/quiet" tabindex="-1">
493+<a role="presentation" data-href="/quiet">
492494 <span class="lbl">quiet</span>
493495 <span class="k">repo</span>
494496 </a>
495497 </li>
496498 <li id="cmd-o13" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
497-<a href="#" data-fire="keys" tabindex="-1">
499+<a role="presentation" data-fire="keys">
498500 <span class="lbl">turn single-key shortcuts off</span>
499501 <span class="k">action</span>
500502 </a>
@@ -218,14 +218,16 @@
218 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">218 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">
219 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>219 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>
220 </footer>220 </footer>
221-<div class="hint" role="status" aria-live="polite">221+<div class="hint">
222-<span class="hint-nav" :text="document.body.dataset.nav || ''">222+<span aria-hidden="true" class="hint-nav" :text="document.body.dataset.nav || ''">
223 </span>223 </span>
224+<span role="status" aria-live="polite">
224 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">225 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">
225 </span>226 </span>
226 <span class="hint-flash" :text="document.body.dataset.flash || ''">227 <span class="hint-flash" :text="document.body.dataset.flash || ''">
227 </span>228 </span>
228-<span class="hint-live" data-state="connecting" hx-sse:connect="/-/events?topic=repo%3Ademo&amp;view=summary" hx-swap="none" :text="data.state === 'offline' ? 'live updates paused' : ''" hx-on="htmx:sse:after:connection -> ermiteLive.back();229+</span>
230+<span class="hint-live" role="status" data-state="connecting" hx-sse:connect="/-/events?topic=repo%3Ademo&amp;view=summary" hx-swap="none" :text="data.state === 'offline' ? 'live updates paused' : ''" hx-on="htmx:sse:after:connection -> ermiteLive.back();
229 htmx:sse:close, htmx:sse:error -> ermiteLive.lost();231 htmx:sse:close, htmx:sse:error -> ermiteLive.lost();
230 htmx:sse:error -> ermiteLive.error(event.detail.status);232 htmx:sse:error -> ermiteLive.error(event.detail.status);
231 htmx:sse:before:connection -> ermiteLive.gate(event);233 htmx:sse:before:connection -> ermiteLive.gate(event);
@@ -237,7 +239,7 @@
237 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">239 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">
238 <div class="panel-head">240 <div class="panel-head">
239 <h2>Keyboard shortcuts</h2>241 <h2>Keyboard shortcuts</h2>
240-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">242+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
241 <kbd>esc</kbd> close</button>243 <kbd>esc</kbd> close</button>
242 </div>244 </div>
243 <div class="keys-pref">245 <div class="keys-pref">
@@ -371,7 +373,7 @@
371 <div class="panel-head">373 <div class="panel-head">
372 <label for="refs-filter" class="sr">filter branches and tags</label>374 <label for="refs-filter" class="sr">filter branches and tags</label>
373 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">375 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">
374-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">376+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
375 <kbd>esc</kbd>377 <kbd>esc</kbd>
376 </button>378 </button>
377 </div>379 </div>
@@ -410,91 +412,91 @@
410 <div class="panel-head">412 <div class="panel-head">
411 <label for="cmd-q" class="sr">go to</label>413 <label for="cmd-q" class="sr">go to</label>
412 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">414 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">
413-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">415+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
414 <kbd>esc</kbd>416 <kbd>esc</kbd>
415 </button>417 </button>
416 </div>418 </div>
417 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">419 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">
418 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>420 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>
419-<a href="/" tabindex="-1">421+<a role="presentation" data-href="/">
420 <span class="lbl">home</span>422 <span class="lbl">home</span>
421 <span class="k">go</span>423 <span class="k">go</span>
422 </a>424 </a>
423 </li>425 </li>
424 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">426 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">
425-<a href="/demo" tabindex="-1">427+<a role="presentation" data-href="/demo">
426 <span class="lbl">summary</span>428 <span class="lbl">summary</span>
427 <span class="k">section</span>429 <span class="k">section</span>
428 </a>430 </a>
429 </li>431 </li>
430 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">432 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">
431-<a href="/demo/tree/main" tabindex="-1">433+<a role="presentation" data-href="/demo/tree/main">
432 <span class="lbl">files</span>434 <span class="lbl">files</span>
433 <span class="k">section</span>435 <span class="k">section</span>
434 </a>436 </a>
435 </li>437 </li>
436 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">438 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">
437-<a href="/demo/commits/main" tabindex="-1">439+<a role="presentation" data-href="/demo/commits/main">
438 <span class="lbl">commits</span>440 <span class="lbl">commits</span>
439 <span class="k">section</span>441 <span class="k">section</span>
440 </a>442 </a>
441 </li>443 </li>
442 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">444 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">
443-<a href="/demo/refs" tabindex="-1">445+<a role="presentation" data-href="/demo/refs">
444 <span class="lbl">branches &amp; tags</span>446 <span class="lbl">branches &amp; tags</span>
445 <span class="k">section</span>447 <span class="k">section</span>
446 </a>448 </a>
447 </li>449 </li>
448 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">450 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">
449-<a href="/demo/merge-requests" tabindex="-1">451+<a role="presentation" data-href="/demo/merge-requests">
450 <span class="lbl">merge requests</span>452 <span class="lbl">merge requests</span>
451 <span class="k">section</span>453 <span class="k">section</span>
452 </a>454 </a>
453 </li>455 </li>
454 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">456 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
455-<a href="/demo/releases" tabindex="-1">457+<a role="presentation" data-href="/demo/releases">
456 <span class="lbl">releases</span>458 <span class="lbl">releases</span>
457 <span class="k">section</span>459 <span class="k">section</span>
458 </a>460 </a>
459 </li>461 </li>
460 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">462 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
461-<a href="/demo/actions" tabindex="-1">463+<a role="presentation" data-href="/demo/actions">
462 <span class="lbl">actions</span>464 <span class="lbl">actions</span>
463 <span class="k">section</span>465 <span class="k">section</span>
464 </a>466 </a>
465 </li>467 </li>
466 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">468 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
467-<a href="/demo/tree/feature/x" tabindex="-1">469+<a role="presentation" data-href="/demo/tree/feature/x">
468 <span class="lbl">feature/x</span>470 <span class="lbl">feature/x</span>
469 <span class="k">branch</span>471 <span class="k">branch</span>
470 </a>472 </a>
471 </li>473 </li>
472 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">474 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
473-<a href="/demo/tree/main" tabindex="-1">475+<a role="presentation" data-href="/demo/tree/main">
474 <span class="lbl">main</span>476 <span class="lbl">main</span>
475 <span class="k">branch</span>477 <span class="k">branch</span>
476 </a>478 </a>
477 </li>479 </li>
478 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v0.1.0">480 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v0.1.0">
479-<a href="/demo/tree/v0.1.0" tabindex="-1">481+<a role="presentation" data-href="/demo/tree/v0.1.0">
480 <span class="lbl">v0.1.0</span>482 <span class="lbl">v0.1.0</span>
481 <span class="k">tag</span>483 <span class="k">tag</span>
482 </a>484 </a>
483 </li>485 </li>
484 <li id="cmd-o11" role="option" aria-selected="false" data-k="tag v0.2.0">486 <li id="cmd-o11" role="option" aria-selected="false" data-k="tag v0.2.0">
485-<a href="/demo/tree/v0.2.0" tabindex="-1">487+<a role="presentation" data-href="/demo/tree/v0.2.0">
486 <span class="lbl">v0.2.0</span>488 <span class="lbl">v0.2.0</span>
487 <span class="k">tag</span>489 <span class="k">tag</span>
488 </a>490 </a>
489 </li>491 </li>
490 <li id="cmd-o12" role="option" aria-selected="false" data-k="repo quiet">492 <li id="cmd-o12" role="option" aria-selected="false" data-k="repo quiet">
491-<a href="/quiet" tabindex="-1">493+<a role="presentation" data-href="/quiet">
492 <span class="lbl">quiet</span>494 <span class="lbl">quiet</span>
493 <span class="k">repo</span>495 <span class="k">repo</span>
494 </a>496 </a>
495 </li>497 </li>
496 <li id="cmd-o13" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">498 <li id="cmd-o13" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
497-<a href="#" data-fire="keys" tabindex="-1">499+<a role="presentation" data-fire="keys">
498 <span class="lbl">turn single-key shortcuts off</span>500 <span class="lbl">turn single-key shortcuts off</span>
499 <span class="k">action</span>501 <span class="k">action</span>
500 </a>502 </a>
M internal/app/testdata/web/tree-nested.html +21 -19
@@ -117,9 +117,9 @@
117117 <kbd>j</kbd>
118118 <kbd>k</kbd> move · <kbd>l</kbd> open · <kbd>h</kbd> back</p>
119119 </div>
120-<div id="finder" class="tree-card" hidden>
121-<p id="finder-status" class="dim" aria-live="polite">
120+<p id="finder-status" class="dim" role="status">
122121 </p>
122+<div id="finder" class="tree-card" hidden>
123123 <ul id="finder-list" class="cmd-list" role="listbox" aria-label="Files">
124124 </ul>
125125 </div>
@@ -156,18 +156,20 @@
156156 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">
157157 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>
158158 </footer>
159-<div class="hint" role="status" aria-live="polite">
160-<span class="hint-nav" :text="document.body.dataset.nav || ''">
159+<div class="hint">
160+<span aria-hidden="true" class="hint-nav" :text="document.body.dataset.nav || ''">
161161 </span>
162+<span role="status" aria-live="polite">
162163 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">
163164 </span>
164165 <span class="hint-flash" :text="document.body.dataset.flash || ''">
165166 </span>
167+</span>
166168 </div>
167169 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">
168170 <div class="panel-head">
169171 <h2>Keyboard shortcuts</h2>
170-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
172+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
171173 <kbd>esc</kbd> close</button>
172174 </div>
173175 <div class="keys-pref">
@@ -301,7 +303,7 @@
301303 <div class="panel-head">
302304 <label for="refs-filter" class="sr">filter branches and tags</label>
303305 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">
304-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
306+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
305307 <kbd>esc</kbd>
306308 </button>
307309 </div>
@@ -336,79 +338,79 @@
336338 <div class="panel-head">
337339 <label for="cmd-q" class="sr">go to</label>
338340 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">
339-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
341+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
340342 <kbd>esc</kbd>
341343 </button>
342344 </div>
343345 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">
344346 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>
345-<a href="/" tabindex="-1">
347+<a role="presentation" data-href="/">
346348 <span class="lbl">home</span>
347349 <span class="k">go</span>
348350 </a>
349351 </li>
350352 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">
351-<a href="/files" tabindex="-1">
353+<a role="presentation" data-href="/files">
352354 <span class="lbl">summary</span>
353355 <span class="k">section</span>
354356 </a>
355357 </li>
356358 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">
357-<a href="/files/tree/main" tabindex="-1">
359+<a role="presentation" data-href="/files/tree/main">
358360 <span class="lbl">files</span>
359361 <span class="k">section</span>
360362 </a>
361363 </li>
362364 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">
363-<a href="/files/commits/main" tabindex="-1">
365+<a role="presentation" data-href="/files/commits/main">
364366 <span class="lbl">commits</span>
365367 <span class="k">section</span>
366368 </a>
367369 </li>
368370 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">
369-<a href="/files/refs" tabindex="-1">
371+<a role="presentation" data-href="/files/refs">
370372 <span class="lbl">branches &amp; tags</span>
371373 <span class="k">section</span>
372374 </a>
373375 </li>
374376 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">
375-<a href="/files/merge-requests" tabindex="-1">
377+<a role="presentation" data-href="/files/merge-requests">
376378 <span class="lbl">merge requests</span>
377379 <span class="k">section</span>
378380 </a>
379381 </li>
380382 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
381-<a href="/files/releases" tabindex="-1">
383+<a role="presentation" data-href="/files/releases">
382384 <span class="lbl">releases</span>
383385 <span class="k">section</span>
384386 </a>
385387 </li>
386388 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
387-<a href="/files/actions" tabindex="-1">
389+<a role="presentation" data-href="/files/actions">
388390 <span class="lbl">actions</span>
389391 <span class="k">section</span>
390392 </a>
391393 </li>
392394 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
393-<a href="/files/tree/feature/x" tabindex="-1">
395+<a role="presentation" data-href="/files/tree/feature/x">
394396 <span class="lbl">feature/x</span>
395397 <span class="k">branch</span>
396398 </a>
397399 </li>
398400 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
399-<a href="/files/tree/main" tabindex="-1">
401+<a role="presentation" data-href="/files/tree/main">
400402 <span class="lbl">main</span>
401403 <span class="k">branch</span>
402404 </a>
403405 </li>
404406 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
405-<a href="/files/tree/v1.0" tabindex="-1">
407+<a role="presentation" data-href="/files/tree/v1.0">
406408 <span class="lbl">v1.0</span>
407409 <span class="k">tag</span>
408410 </a>
409411 </li>
410412 <li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
411-<a href="#" data-fire="keys" tabindex="-1">
413+<a role="presentation" data-fire="keys">
412414 <span class="lbl">turn single-key shortcuts off</span>
413415 <span class="k">action</span>
414416 </a>
@@ -117,9 +117,9 @@
117 <kbd>j</kbd>117 <kbd>j</kbd>
118 <kbd>k</kbd> move · <kbd>l</kbd> open · <kbd>h</kbd> back</p>118 <kbd>k</kbd> move · <kbd>l</kbd> open · <kbd>h</kbd> back</p>
119 </div>119 </div>
120-<div id="finder" class="tree-card" hidden>120+<p id="finder-status" class="dim" role="status">
121-<p id="finder-status" class="dim" aria-live="polite">
122 </p>121 </p>
122+<div id="finder" class="tree-card" hidden>
123 <ul id="finder-list" class="cmd-list" role="listbox" aria-label="Files">123 <ul id="finder-list" class="cmd-list" role="listbox" aria-label="Files">
124 </ul>124 </ul>
125 </div>125 </div>
@@ -156,18 +156,20 @@
156 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">156 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">
157 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>157 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>
158 </footer>158 </footer>
159-<div class="hint" role="status" aria-live="polite">159+<div class="hint">
160-<span class="hint-nav" :text="document.body.dataset.nav || ''">160+<span aria-hidden="true" class="hint-nav" :text="document.body.dataset.nav || ''">
161 </span>161 </span>
162+<span role="status" aria-live="polite">
162 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">163 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">
163 </span>164 </span>
164 <span class="hint-flash" :text="document.body.dataset.flash || ''">165 <span class="hint-flash" :text="document.body.dataset.flash || ''">
165 </span>166 </span>
167+</span>
166 </div>168 </div>
167 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">169 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">
168 <div class="panel-head">170 <div class="panel-head">
169 <h2>Keyboard shortcuts</h2>171 <h2>Keyboard shortcuts</h2>
170-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">172+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
171 <kbd>esc</kbd> close</button>173 <kbd>esc</kbd> close</button>
172 </div>174 </div>
173 <div class="keys-pref">175 <div class="keys-pref">
@@ -301,7 +303,7 @@
301 <div class="panel-head">303 <div class="panel-head">
302 <label for="refs-filter" class="sr">filter branches and tags</label>304 <label for="refs-filter" class="sr">filter branches and tags</label>
303 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">305 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">
304-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">306+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
305 <kbd>esc</kbd>307 <kbd>esc</kbd>
306 </button>308 </button>
307 </div>309 </div>
@@ -336,79 +338,79 @@
336 <div class="panel-head">338 <div class="panel-head">
337 <label for="cmd-q" class="sr">go to</label>339 <label for="cmd-q" class="sr">go to</label>
338 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">340 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">
339-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">341+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
340 <kbd>esc</kbd>342 <kbd>esc</kbd>
341 </button>343 </button>
342 </div>344 </div>
343 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">345 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">
344 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>346 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>
345-<a href="/" tabindex="-1">347+<a role="presentation" data-href="/">
346 <span class="lbl">home</span>348 <span class="lbl">home</span>
347 <span class="k">go</span>349 <span class="k">go</span>
348 </a>350 </a>
349 </li>351 </li>
350 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">352 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">
351-<a href="/files" tabindex="-1">353+<a role="presentation" data-href="/files">
352 <span class="lbl">summary</span>354 <span class="lbl">summary</span>
353 <span class="k">section</span>355 <span class="k">section</span>
354 </a>356 </a>
355 </li>357 </li>
356 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">358 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">
357-<a href="/files/tree/main" tabindex="-1">359+<a role="presentation" data-href="/files/tree/main">
358 <span class="lbl">files</span>360 <span class="lbl">files</span>
359 <span class="k">section</span>361 <span class="k">section</span>
360 </a>362 </a>
361 </li>363 </li>
362 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">364 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">
363-<a href="/files/commits/main" tabindex="-1">365+<a role="presentation" data-href="/files/commits/main">
364 <span class="lbl">commits</span>366 <span class="lbl">commits</span>
365 <span class="k">section</span>367 <span class="k">section</span>
366 </a>368 </a>
367 </li>369 </li>
368 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">370 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">
369-<a href="/files/refs" tabindex="-1">371+<a role="presentation" data-href="/files/refs">
370 <span class="lbl">branches &amp; tags</span>372 <span class="lbl">branches &amp; tags</span>
371 <span class="k">section</span>373 <span class="k">section</span>
372 </a>374 </a>
373 </li>375 </li>
374 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">376 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">
375-<a href="/files/merge-requests" tabindex="-1">377+<a role="presentation" data-href="/files/merge-requests">
376 <span class="lbl">merge requests</span>378 <span class="lbl">merge requests</span>
377 <span class="k">section</span>379 <span class="k">section</span>
378 </a>380 </a>
379 </li>381 </li>
380 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">382 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
381-<a href="/files/releases" tabindex="-1">383+<a role="presentation" data-href="/files/releases">
382 <span class="lbl">releases</span>384 <span class="lbl">releases</span>
383 <span class="k">section</span>385 <span class="k">section</span>
384 </a>386 </a>
385 </li>387 </li>
386 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">388 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
387-<a href="/files/actions" tabindex="-1">389+<a role="presentation" data-href="/files/actions">
388 <span class="lbl">actions</span>390 <span class="lbl">actions</span>
389 <span class="k">section</span>391 <span class="k">section</span>
390 </a>392 </a>
391 </li>393 </li>
392 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">394 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
393-<a href="/files/tree/feature/x" tabindex="-1">395+<a role="presentation" data-href="/files/tree/feature/x">
394 <span class="lbl">feature/x</span>396 <span class="lbl">feature/x</span>
395 <span class="k">branch</span>397 <span class="k">branch</span>
396 </a>398 </a>
397 </li>399 </li>
398 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">400 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
399-<a href="/files/tree/main" tabindex="-1">401+<a role="presentation" data-href="/files/tree/main">
400 <span class="lbl">main</span>402 <span class="lbl">main</span>
401 <span class="k">branch</span>403 <span class="k">branch</span>
402 </a>404 </a>
403 </li>405 </li>
404 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">406 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
405-<a href="/files/tree/v1.0" tabindex="-1">407+<a role="presentation" data-href="/files/tree/v1.0">
406 <span class="lbl">v1.0</span>408 <span class="lbl">v1.0</span>
407 <span class="k">tag</span>409 <span class="k">tag</span>
408 </a>410 </a>
409 </li>411 </li>
410 <li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">412 <li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
411-<a href="#" data-fire="keys" tabindex="-1">413+<a role="presentation" data-fire="keys">
412 <span class="lbl">turn single-key shortcuts off</span>414 <span class="lbl">turn single-key shortcuts off</span>
413 <span class="k">action</span>415 <span class="k">action</span>
414 </a>416 </a>
M internal/app/testdata/web/tree-root.html +21 -19
@@ -111,9 +111,9 @@
111111 <kbd>j</kbd>
112112 <kbd>k</kbd> move · <kbd>l</kbd> open · <kbd>h</kbd> back</p>
113113 </div>
114-<div id="finder" class="tree-card" hidden>
115-<p id="finder-status" class="dim" aria-live="polite">
114+<p id="finder-status" class="dim" role="status">
116115 </p>
116+<div id="finder" class="tree-card" hidden>
117117 <ul id="finder-list" class="cmd-list" role="listbox" aria-label="Files">
118118 </ul>
119119 </div>
@@ -377,18 +377,20 @@
377377 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">
378378 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>
379379 </footer>
380-<div class="hint" role="status" aria-live="polite">
381-<span class="hint-nav" :text="document.body.dataset.nav || ''">
380+<div class="hint">
381+<span aria-hidden="true" class="hint-nav" :text="document.body.dataset.nav || ''">
382382 </span>
383+<span role="status" aria-live="polite">
383384 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">
384385 </span>
385386 <span class="hint-flash" :text="document.body.dataset.flash || ''">
386387 </span>
388+</span>
387389 </div>
388390 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">
389391 <div class="panel-head">
390392 <h2>Keyboard shortcuts</h2>
391-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
393+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
392394 <kbd>esc</kbd> close</button>
393395 </div>
394396 <div class="keys-pref">
@@ -522,7 +524,7 @@
522524 <div class="panel-head">
523525 <label for="refs-filter" class="sr">filter branches and tags</label>
524526 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">
525-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
527+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
526528 <kbd>esc</kbd>
527529 </button>
528530 </div>
@@ -557,79 +559,79 @@
557559 <div class="panel-head">
558560 <label for="cmd-q" class="sr">go to</label>
559561 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">
560-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
562+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
561563 <kbd>esc</kbd>
562564 </button>
563565 </div>
564566 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">
565567 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>
566-<a href="/" tabindex="-1">
568+<a role="presentation" data-href="/">
567569 <span class="lbl">home</span>
568570 <span class="k">go</span>
569571 </a>
570572 </li>
571573 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">
572-<a href="/files" tabindex="-1">
574+<a role="presentation" data-href="/files">
573575 <span class="lbl">summary</span>
574576 <span class="k">section</span>
575577 </a>
576578 </li>
577579 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">
578-<a href="/files/tree/main" tabindex="-1">
580+<a role="presentation" data-href="/files/tree/main">
579581 <span class="lbl">files</span>
580582 <span class="k">section</span>
581583 </a>
582584 </li>
583585 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">
584-<a href="/files/commits/main" tabindex="-1">
586+<a role="presentation" data-href="/files/commits/main">
585587 <span class="lbl">commits</span>
586588 <span class="k">section</span>
587589 </a>
588590 </li>
589591 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">
590-<a href="/files/refs" tabindex="-1">
592+<a role="presentation" data-href="/files/refs">
591593 <span class="lbl">branches &amp; tags</span>
592594 <span class="k">section</span>
593595 </a>
594596 </li>
595597 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">
596-<a href="/files/merge-requests" tabindex="-1">
598+<a role="presentation" data-href="/files/merge-requests">
597599 <span class="lbl">merge requests</span>
598600 <span class="k">section</span>
599601 </a>
600602 </li>
601603 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
602-<a href="/files/releases" tabindex="-1">
604+<a role="presentation" data-href="/files/releases">
603605 <span class="lbl">releases</span>
604606 <span class="k">section</span>
605607 </a>
606608 </li>
607609 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
608-<a href="/files/actions" tabindex="-1">
610+<a role="presentation" data-href="/files/actions">
609611 <span class="lbl">actions</span>
610612 <span class="k">section</span>
611613 </a>
612614 </li>
613615 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
614-<a href="/files/tree/feature/x" tabindex="-1">
616+<a role="presentation" data-href="/files/tree/feature/x">
615617 <span class="lbl">feature/x</span>
616618 <span class="k">branch</span>
617619 </a>
618620 </li>
619621 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
620-<a href="/files/tree/main" tabindex="-1">
622+<a role="presentation" data-href="/files/tree/main">
621623 <span class="lbl">main</span>
622624 <span class="k">branch</span>
623625 </a>
624626 </li>
625627 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
626-<a href="/files/tree/v1.0" tabindex="-1">
628+<a role="presentation" data-href="/files/tree/v1.0">
627629 <span class="lbl">v1.0</span>
628630 <span class="k">tag</span>
629631 </a>
630632 </li>
631633 <li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
632-<a href="#" data-fire="keys" tabindex="-1">
634+<a role="presentation" data-fire="keys">
633635 <span class="lbl">turn single-key shortcuts off</span>
634636 <span class="k">action</span>
635637 </a>
@@ -111,9 +111,9 @@
111 <kbd>j</kbd>111 <kbd>j</kbd>
112 <kbd>k</kbd> move · <kbd>l</kbd> open · <kbd>h</kbd> back</p>112 <kbd>k</kbd> move · <kbd>l</kbd> open · <kbd>h</kbd> back</p>
113 </div>113 </div>
114-<div id="finder" class="tree-card" hidden>114+<p id="finder-status" class="dim" role="status">
115-<p id="finder-status" class="dim" aria-live="polite">
116 </p>115 </p>
116+<div id="finder" class="tree-card" hidden>
117 <ul id="finder-list" class="cmd-list" role="listbox" aria-label="Files">117 <ul id="finder-list" class="cmd-list" role="listbox" aria-label="Files">
118 </ul>118 </ul>
119 </div>119 </div>
@@ -377,18 +377,20 @@
377 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">377 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">
378 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>378 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>
379 </footer>379 </footer>
380-<div class="hint" role="status" aria-live="polite">380+<div class="hint">
381-<span class="hint-nav" :text="document.body.dataset.nav || ''">381+<span aria-hidden="true" class="hint-nav" :text="document.body.dataset.nav || ''">
382 </span>382 </span>
383+<span role="status" aria-live="polite">
383 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">384 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">
384 </span>385 </span>
385 <span class="hint-flash" :text="document.body.dataset.flash || ''">386 <span class="hint-flash" :text="document.body.dataset.flash || ''">
386 </span>387 </span>
388+</span>
387 </div>389 </div>
388 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">390 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">
389 <div class="panel-head">391 <div class="panel-head">
390 <h2>Keyboard shortcuts</h2>392 <h2>Keyboard shortcuts</h2>
391-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">393+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
392 <kbd>esc</kbd> close</button>394 <kbd>esc</kbd> close</button>
393 </div>395 </div>
394 <div class="keys-pref">396 <div class="keys-pref">
@@ -522,7 +524,7 @@
522 <div class="panel-head">524 <div class="panel-head">
523 <label for="refs-filter" class="sr">filter branches and tags</label>525 <label for="refs-filter" class="sr">filter branches and tags</label>
524 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">526 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">
525-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">527+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
526 <kbd>esc</kbd>528 <kbd>esc</kbd>
527 </button>529 </button>
528 </div>530 </div>
@@ -557,79 +559,79 @@
557 <div class="panel-head">559 <div class="panel-head">
558 <label for="cmd-q" class="sr">go to</label>560 <label for="cmd-q" class="sr">go to</label>
559 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">561 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">
560-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">562+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
561 <kbd>esc</kbd>563 <kbd>esc</kbd>
562 </button>564 </button>
563 </div>565 </div>
564 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">566 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">
565 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>567 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>
566-<a href="/" tabindex="-1">568+<a role="presentation" data-href="/">
567 <span class="lbl">home</span>569 <span class="lbl">home</span>
568 <span class="k">go</span>570 <span class="k">go</span>
569 </a>571 </a>
570 </li>572 </li>
571 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">573 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">
572-<a href="/files" tabindex="-1">574+<a role="presentation" data-href="/files">
573 <span class="lbl">summary</span>575 <span class="lbl">summary</span>
574 <span class="k">section</span>576 <span class="k">section</span>
575 </a>577 </a>
576 </li>578 </li>
577 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">579 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">
578-<a href="/files/tree/main" tabindex="-1">580+<a role="presentation" data-href="/files/tree/main">
579 <span class="lbl">files</span>581 <span class="lbl">files</span>
580 <span class="k">section</span>582 <span class="k">section</span>
581 </a>583 </a>
582 </li>584 </li>
583 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">585 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">
584-<a href="/files/commits/main" tabindex="-1">586+<a role="presentation" data-href="/files/commits/main">
585 <span class="lbl">commits</span>587 <span class="lbl">commits</span>
586 <span class="k">section</span>588 <span class="k">section</span>
587 </a>589 </a>
588 </li>590 </li>
589 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">591 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">
590-<a href="/files/refs" tabindex="-1">592+<a role="presentation" data-href="/files/refs">
591 <span class="lbl">branches &amp; tags</span>593 <span class="lbl">branches &amp; tags</span>
592 <span class="k">section</span>594 <span class="k">section</span>
593 </a>595 </a>
594 </li>596 </li>
595 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">597 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">
596-<a href="/files/merge-requests" tabindex="-1">598+<a role="presentation" data-href="/files/merge-requests">
597 <span class="lbl">merge requests</span>599 <span class="lbl">merge requests</span>
598 <span class="k">section</span>600 <span class="k">section</span>
599 </a>601 </a>
600 </li>602 </li>
601 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">603 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
602-<a href="/files/releases" tabindex="-1">604+<a role="presentation" data-href="/files/releases">
603 <span class="lbl">releases</span>605 <span class="lbl">releases</span>
604 <span class="k">section</span>606 <span class="k">section</span>
605 </a>607 </a>
606 </li>608 </li>
607 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">609 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
608-<a href="/files/actions" tabindex="-1">610+<a role="presentation" data-href="/files/actions">
609 <span class="lbl">actions</span>611 <span class="lbl">actions</span>
610 <span class="k">section</span>612 <span class="k">section</span>
611 </a>613 </a>
612 </li>614 </li>
613 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">615 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
614-<a href="/files/tree/feature/x" tabindex="-1">616+<a role="presentation" data-href="/files/tree/feature/x">
615 <span class="lbl">feature/x</span>617 <span class="lbl">feature/x</span>
616 <span class="k">branch</span>618 <span class="k">branch</span>
617 </a>619 </a>
618 </li>620 </li>
619 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">621 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
620-<a href="/files/tree/main" tabindex="-1">622+<a role="presentation" data-href="/files/tree/main">
621 <span class="lbl">main</span>623 <span class="lbl">main</span>
622 <span class="k">branch</span>624 <span class="k">branch</span>
623 </a>625 </a>
624 </li>626 </li>
625 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">627 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
626-<a href="/files/tree/v1.0" tabindex="-1">628+<a role="presentation" data-href="/files/tree/v1.0">
627 <span class="lbl">v1.0</span>629 <span class="lbl">v1.0</span>
628 <span class="k">tag</span>630 <span class="k">tag</span>
629 </a>631 </a>
630 </li>632 </li>
631 <li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">633 <li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
632-<a href="#" data-fire="keys" tabindex="-1">634+<a role="presentation" data-fire="keys">
633 <span class="lbl">turn single-key shortcuts off</span>635 <span class="lbl">turn single-key shortcuts off</span>
634 <span class="k">action</span>636 <span class="k">action</span>
635 </a>637 </a>
M internal/app/testdata/web/tree-slash-ref.html +21 -19
@@ -114,9 +114,9 @@
114114 <kbd>j</kbd>
115115 <kbd>k</kbd> move · <kbd>l</kbd> open · <kbd>h</kbd> back</p>
116116 </div>
117-<div id="finder" class="tree-card" hidden>
118-<p id="finder-status" class="dim" aria-live="polite">
117+<p id="finder-status" class="dim" role="status">
119118 </p>
119+<div id="finder" class="tree-card" hidden>
120120 <ul id="finder-list" class="cmd-list" role="listbox" aria-label="Files">
121121 </ul>
122122 </div>
@@ -153,18 +153,20 @@
153153 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">
154154 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>
155155 </footer>
156-<div class="hint" role="status" aria-live="polite">
157-<span class="hint-nav" :text="document.body.dataset.nav || ''">
156+<div class="hint">
157+<span aria-hidden="true" class="hint-nav" :text="document.body.dataset.nav || ''">
158158 </span>
159+<span role="status" aria-live="polite">
159160 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">
160161 </span>
161162 <span class="hint-flash" :text="document.body.dataset.flash || ''">
162163 </span>
164+</span>
163165 </div>
164166 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">
165167 <div class="panel-head">
166168 <h2>Keyboard shortcuts</h2>
167-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
169+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
168170 <kbd>esc</kbd> close</button>
169171 </div>
170172 <div class="keys-pref">
@@ -298,7 +300,7 @@
298300 <div class="panel-head">
299301 <label for="refs-filter" class="sr">filter branches and tags</label>
300302 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">
301-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
303+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
302304 <kbd>esc</kbd>
303305 </button>
304306 </div>
@@ -333,79 +335,79 @@
333335 <div class="panel-head">
334336 <label for="cmd-q" class="sr">go to</label>
335337 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">
336-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
338+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
337339 <kbd>esc</kbd>
338340 </button>
339341 </div>
340342 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">
341343 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>
342-<a href="/" tabindex="-1">
344+<a role="presentation" data-href="/">
343345 <span class="lbl">home</span>
344346 <span class="k">go</span>
345347 </a>
346348 </li>
347349 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">
348-<a href="/files" tabindex="-1">
350+<a role="presentation" data-href="/files">
349351 <span class="lbl">summary</span>
350352 <span class="k">section</span>
351353 </a>
352354 </li>
353355 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">
354-<a href="/files/tree/main" tabindex="-1">
356+<a role="presentation" data-href="/files/tree/main">
355357 <span class="lbl">files</span>
356358 <span class="k">section</span>
357359 </a>
358360 </li>
359361 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">
360-<a href="/files/commits/main" tabindex="-1">
362+<a role="presentation" data-href="/files/commits/main">
361363 <span class="lbl">commits</span>
362364 <span class="k">section</span>
363365 </a>
364366 </li>
365367 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">
366-<a href="/files/refs" tabindex="-1">
368+<a role="presentation" data-href="/files/refs">
367369 <span class="lbl">branches &amp; tags</span>
368370 <span class="k">section</span>
369371 </a>
370372 </li>
371373 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">
372-<a href="/files/merge-requests" tabindex="-1">
374+<a role="presentation" data-href="/files/merge-requests">
373375 <span class="lbl">merge requests</span>
374376 <span class="k">section</span>
375377 </a>
376378 </li>
377379 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
378-<a href="/files/releases" tabindex="-1">
380+<a role="presentation" data-href="/files/releases">
379381 <span class="lbl">releases</span>
380382 <span class="k">section</span>
381383 </a>
382384 </li>
383385 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
384-<a href="/files/actions" tabindex="-1">
386+<a role="presentation" data-href="/files/actions">
385387 <span class="lbl">actions</span>
386388 <span class="k">section</span>
387389 </a>
388390 </li>
389391 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
390-<a href="/files/tree/feature/x" tabindex="-1">
392+<a role="presentation" data-href="/files/tree/feature/x">
391393 <span class="lbl">feature/x</span>
392394 <span class="k">branch</span>
393395 </a>
394396 </li>
395397 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
396-<a href="/files/tree/main" tabindex="-1">
398+<a role="presentation" data-href="/files/tree/main">
397399 <span class="lbl">main</span>
398400 <span class="k">branch</span>
399401 </a>
400402 </li>
401403 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
402-<a href="/files/tree/v1.0" tabindex="-1">
404+<a role="presentation" data-href="/files/tree/v1.0">
403405 <span class="lbl">v1.0</span>
404406 <span class="k">tag</span>
405407 </a>
406408 </li>
407409 <li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
408-<a href="#" data-fire="keys" tabindex="-1">
410+<a role="presentation" data-fire="keys">
409411 <span class="lbl">turn single-key shortcuts off</span>
410412 <span class="k">action</span>
411413 </a>
@@ -114,9 +114,9 @@
114 <kbd>j</kbd>114 <kbd>j</kbd>
115 <kbd>k</kbd> move · <kbd>l</kbd> open · <kbd>h</kbd> back</p>115 <kbd>k</kbd> move · <kbd>l</kbd> open · <kbd>h</kbd> back</p>
116 </div>116 </div>
117-<div id="finder" class="tree-card" hidden>117+<p id="finder-status" class="dim" role="status">
118-<p id="finder-status" class="dim" aria-live="polite">
119 </p>118 </p>
119+<div id="finder" class="tree-card" hidden>
120 <ul id="finder-list" class="cmd-list" role="listbox" aria-label="Files">120 <ul id="finder-list" class="cmd-list" role="listbox" aria-label="Files">
121 </ul>121 </ul>
122 </div>122 </div>
@@ -153,18 +153,20 @@
153 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">153 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">
154 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>154 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>
155 </footer>155 </footer>
156-<div class="hint" role="status" aria-live="polite">156+<div class="hint">
157-<span class="hint-nav" :text="document.body.dataset.nav || ''">157+<span aria-hidden="true" class="hint-nav" :text="document.body.dataset.nav || ''">
158 </span>158 </span>
159+<span role="status" aria-live="polite">
159 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">160 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">
160 </span>161 </span>
161 <span class="hint-flash" :text="document.body.dataset.flash || ''">162 <span class="hint-flash" :text="document.body.dataset.flash || ''">
162 </span>163 </span>
164+</span>
163 </div>165 </div>
164 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">166 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">
165 <div class="panel-head">167 <div class="panel-head">
166 <h2>Keyboard shortcuts</h2>168 <h2>Keyboard shortcuts</h2>
167-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">169+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
168 <kbd>esc</kbd> close</button>170 <kbd>esc</kbd> close</button>
169 </div>171 </div>
170 <div class="keys-pref">172 <div class="keys-pref">
@@ -298,7 +300,7 @@
298 <div class="panel-head">300 <div class="panel-head">
299 <label for="refs-filter" class="sr">filter branches and tags</label>301 <label for="refs-filter" class="sr">filter branches and tags</label>
300 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">302 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">
301-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">303+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
302 <kbd>esc</kbd>304 <kbd>esc</kbd>
303 </button>305 </button>
304 </div>306 </div>
@@ -333,79 +335,79 @@
333 <div class="panel-head">335 <div class="panel-head">
334 <label for="cmd-q" class="sr">go to</label>336 <label for="cmd-q" class="sr">go to</label>
335 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">337 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">
336-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">338+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
337 <kbd>esc</kbd>339 <kbd>esc</kbd>
338 </button>340 </button>
339 </div>341 </div>
340 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">342 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">
341 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>343 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>
342-<a href="/" tabindex="-1">344+<a role="presentation" data-href="/">
343 <span class="lbl">home</span>345 <span class="lbl">home</span>
344 <span class="k">go</span>346 <span class="k">go</span>
345 </a>347 </a>
346 </li>348 </li>
347 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">349 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">
348-<a href="/files" tabindex="-1">350+<a role="presentation" data-href="/files">
349 <span class="lbl">summary</span>351 <span class="lbl">summary</span>
350 <span class="k">section</span>352 <span class="k">section</span>
351 </a>353 </a>
352 </li>354 </li>
353 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">355 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">
354-<a href="/files/tree/main" tabindex="-1">356+<a role="presentation" data-href="/files/tree/main">
355 <span class="lbl">files</span>357 <span class="lbl">files</span>
356 <span class="k">section</span>358 <span class="k">section</span>
357 </a>359 </a>
358 </li>360 </li>
359 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">361 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">
360-<a href="/files/commits/main" tabindex="-1">362+<a role="presentation" data-href="/files/commits/main">
361 <span class="lbl">commits</span>363 <span class="lbl">commits</span>
362 <span class="k">section</span>364 <span class="k">section</span>
363 </a>365 </a>
364 </li>366 </li>
365 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">367 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">
366-<a href="/files/refs" tabindex="-1">368+<a role="presentation" data-href="/files/refs">
367 <span class="lbl">branches &amp; tags</span>369 <span class="lbl">branches &amp; tags</span>
368 <span class="k">section</span>370 <span class="k">section</span>
369 </a>371 </a>
370 </li>372 </li>
371 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">373 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">
372-<a href="/files/merge-requests" tabindex="-1">374+<a role="presentation" data-href="/files/merge-requests">
373 <span class="lbl">merge requests</span>375 <span class="lbl">merge requests</span>
374 <span class="k">section</span>376 <span class="k">section</span>
375 </a>377 </a>
376 </li>378 </li>
377 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">379 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
378-<a href="/files/releases" tabindex="-1">380+<a role="presentation" data-href="/files/releases">
379 <span class="lbl">releases</span>381 <span class="lbl">releases</span>
380 <span class="k">section</span>382 <span class="k">section</span>
381 </a>383 </a>
382 </li>384 </li>
383 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">385 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
384-<a href="/files/actions" tabindex="-1">386+<a role="presentation" data-href="/files/actions">
385 <span class="lbl">actions</span>387 <span class="lbl">actions</span>
386 <span class="k">section</span>388 <span class="k">section</span>
387 </a>389 </a>
388 </li>390 </li>
389 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">391 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
390-<a href="/files/tree/feature/x" tabindex="-1">392+<a role="presentation" data-href="/files/tree/feature/x">
391 <span class="lbl">feature/x</span>393 <span class="lbl">feature/x</span>
392 <span class="k">branch</span>394 <span class="k">branch</span>
393 </a>395 </a>
394 </li>396 </li>
395 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">397 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
396-<a href="/files/tree/main" tabindex="-1">398+<a role="presentation" data-href="/files/tree/main">
397 <span class="lbl">main</span>399 <span class="lbl">main</span>
398 <span class="k">branch</span>400 <span class="k">branch</span>
399 </a>401 </a>
400 </li>402 </li>
401 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">403 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
402-<a href="/files/tree/v1.0" tabindex="-1">404+<a role="presentation" data-href="/files/tree/v1.0">
403 <span class="lbl">v1.0</span>405 <span class="lbl">v1.0</span>
404 <span class="k">tag</span>406 <span class="k">tag</span>
405 </a>407 </a>
406 </li>408 </li>
407 <li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">409 <li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
408-<a href="#" data-fire="keys" tabindex="-1">410+<a role="presentation" data-fire="keys">
409 <span class="lbl">turn single-key shortcuts off</span>411 <span class="lbl">turn single-key shortcuts off</span>
410 <span class="k">action</span>412 <span class="k">action</span>
411 </a>413 </a>
M internal/app/testdata/web/tree-subdir.html +21 -19
@@ -114,9 +114,9 @@
114114 <kbd>j</kbd>
115115 <kbd>k</kbd> move · <kbd>l</kbd> open · <kbd>h</kbd> back</p>
116116 </div>
117-<div id="finder" class="tree-card" hidden>
118-<p id="finder-status" class="dim" aria-live="polite">
117+<p id="finder-status" class="dim" role="status">
119118 </p>
119+<div id="finder" class="tree-card" hidden>
120120 <ul id="finder-list" class="cmd-list" role="listbox" aria-label="Files">
121121 </ul>
122122 </div>
@@ -169,18 +169,20 @@
169169 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">
170170 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>
171171 </footer>
172-<div class="hint" role="status" aria-live="polite">
173-<span class="hint-nav" :text="document.body.dataset.nav || ''">
172+<div class="hint">
173+<span aria-hidden="true" class="hint-nav" :text="document.body.dataset.nav || ''">
174174 </span>
175+<span role="status" aria-live="polite">
175176 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">
176177 </span>
177178 <span class="hint-flash" :text="document.body.dataset.flash || ''">
178179 </span>
180+</span>
179181 </div>
180182 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">
181183 <div class="panel-head">
182184 <h2>Keyboard shortcuts</h2>
183-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
185+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
184186 <kbd>esc</kbd> close</button>
185187 </div>
186188 <div class="keys-pref">
@@ -314,7 +316,7 @@
314316 <div class="panel-head">
315317 <label for="refs-filter" class="sr">filter branches and tags</label>
316318 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">
317-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
319+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
318320 <kbd>esc</kbd>
319321 </button>
320322 </div>
@@ -349,79 +351,79 @@
349351 <div class="panel-head">
350352 <label for="cmd-q" class="sr">go to</label>
351353 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">
352-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">
354+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
353355 <kbd>esc</kbd>
354356 </button>
355357 </div>
356358 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">
357359 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>
358-<a href="/" tabindex="-1">
360+<a role="presentation" data-href="/">
359361 <span class="lbl">home</span>
360362 <span class="k">go</span>
361363 </a>
362364 </li>
363365 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">
364-<a href="/files" tabindex="-1">
366+<a role="presentation" data-href="/files">
365367 <span class="lbl">summary</span>
366368 <span class="k">section</span>
367369 </a>
368370 </li>
369371 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">
370-<a href="/files/tree/main" tabindex="-1">
372+<a role="presentation" data-href="/files/tree/main">
371373 <span class="lbl">files</span>
372374 <span class="k">section</span>
373375 </a>
374376 </li>
375377 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">
376-<a href="/files/commits/main" tabindex="-1">
378+<a role="presentation" data-href="/files/commits/main">
377379 <span class="lbl">commits</span>
378380 <span class="k">section</span>
379381 </a>
380382 </li>
381383 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">
382-<a href="/files/refs" tabindex="-1">
384+<a role="presentation" data-href="/files/refs">
383385 <span class="lbl">branches &amp; tags</span>
384386 <span class="k">section</span>
385387 </a>
386388 </li>
387389 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">
388-<a href="/files/merge-requests" tabindex="-1">
390+<a role="presentation" data-href="/files/merge-requests">
389391 <span class="lbl">merge requests</span>
390392 <span class="k">section</span>
391393 </a>
392394 </li>
393395 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
394-<a href="/files/releases" tabindex="-1">
396+<a role="presentation" data-href="/files/releases">
395397 <span class="lbl">releases</span>
396398 <span class="k">section</span>
397399 </a>
398400 </li>
399401 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
400-<a href="/files/actions" tabindex="-1">
402+<a role="presentation" data-href="/files/actions">
401403 <span class="lbl">actions</span>
402404 <span class="k">section</span>
403405 </a>
404406 </li>
405407 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
406-<a href="/files/tree/feature/x" tabindex="-1">
408+<a role="presentation" data-href="/files/tree/feature/x">
407409 <span class="lbl">feature/x</span>
408410 <span class="k">branch</span>
409411 </a>
410412 </li>
411413 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
412-<a href="/files/tree/main" tabindex="-1">
414+<a role="presentation" data-href="/files/tree/main">
413415 <span class="lbl">main</span>
414416 <span class="k">branch</span>
415417 </a>
416418 </li>
417419 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
418-<a href="/files/tree/v1.0" tabindex="-1">
420+<a role="presentation" data-href="/files/tree/v1.0">
419421 <span class="lbl">v1.0</span>
420422 <span class="k">tag</span>
421423 </a>
422424 </li>
423425 <li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
424-<a href="#" data-fire="keys" tabindex="-1">
426+<a role="presentation" data-fire="keys">
425427 <span class="lbl">turn single-key shortcuts off</span>
426428 <span class="k">action</span>
427429 </a>
@@ -114,9 +114,9 @@
114 <kbd>j</kbd>114 <kbd>j</kbd>
115 <kbd>k</kbd> move · <kbd>l</kbd> open · <kbd>h</kbd> back</p>115 <kbd>k</kbd> move · <kbd>l</kbd> open · <kbd>h</kbd> back</p>
116 </div>116 </div>
117-<div id="finder" class="tree-card" hidden>117+<p id="finder-status" class="dim" role="status">
118-<p id="finder-status" class="dim" aria-live="polite">
119 </p>118 </p>
119+<div id="finder" class="tree-card" hidden>
120 <ul id="finder-list" class="cmd-list" role="listbox" aria-label="Files">120 <ul id="finder-list" class="cmd-list" role="listbox" aria-label="Files">
121 </ul>121 </ul>
122 </div>122 </div>
@@ -169,18 +169,20 @@
169 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">169 <button type="button" class="foot-keys" data-js data-fire="help" aria-haspopup="dialog" aria-controls="panel-help" aria-keyshortcuts="?">
170 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>170 <kbd aria-hidden="true">?</kbd> keyboard shortcuts</button>
171 </footer>171 </footer>
172-<div class="hint" role="status" aria-live="polite">172+<div class="hint">
173-<span class="hint-nav" :text="document.body.dataset.nav || ''">173+<span aria-hidden="true" class="hint-nav" :text="document.body.dataset.nav || ''">
174 </span>174 </span>
175+<span role="status" aria-live="polite">
175 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">176 <span class="hint-sel" :text="document.body.dataset.sel ? document.body.dataset.sel + ' · y permalink' : ''">
176 </span>177 </span>
177 <span class="hint-flash" :text="document.body.dataset.flash || ''">178 <span class="hint-flash" :text="document.body.dataset.flash || ''">
178 </span>179 </span>
180+</span>
179 </div>181 </div>
180 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">182 <dialog id="panel-help" class="panel modal" aria-label="Keyboard shortcuts" hx-on:keydown="event.key === 'Escape' && (event.preventDefault(), this.close())" hx-on:click="event.target === this && this.close()">
181 <div class="panel-head">183 <div class="panel-head">
182 <h2>Keyboard shortcuts</h2>184 <h2>Keyboard shortcuts</h2>
183-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">185+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
184 <kbd>esc</kbd> close</button>186 <kbd>esc</kbd> close</button>
185 </div>187 </div>
186 <div class="keys-pref">188 <div class="keys-pref">
@@ -314,7 +316,7 @@
314 <div class="panel-head">316 <div class="panel-head">
315 <label for="refs-filter" class="sr">filter branches and tags</label>317 <label for="refs-filter" class="sr">filter branches and tags</label>
316 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">318 <input id="refs-filter" type="search" placeholder="Switch branch or tag…" autocomplete="off" data-pick="#panel-refs li" hx-on:input="ermite.filter(this)">
317-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">319+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
318 <kbd>esc</kbd>320 <kbd>esc</kbd>
319 </button>321 </button>
320 </div>322 </div>
@@ -349,79 +351,79 @@
349 <div class="panel-head">351 <div class="panel-head">
350 <label for="cmd-q" class="sr">go to</label>352 <label for="cmd-q" class="sr">go to</label>
351 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">353 <input id="cmd-q" type="search" placeholder="Go to a section, branch, tag, file or repository…" autocomplete="off" spellcheck="false" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="cmd-list" aria-activedescendant="cmd-o0" hx-on:input="ermite.cmdFilter(this); ermiteFinder.palette(this)" hx-on:keydown="ermite.cmdKey(event)">
352-<button type="button" class="panel-x" aria-label="Close" hx-on:click="closest('dialog').close()">354+<button type="button" class="panel-x" aria-label="Close (esc)" hx-on:click="closest('dialog').close()">
353 <kbd>esc</kbd>355 <kbd>esc</kbd>
354 </button>356 </button>
355 </div>357 </div>
356 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">358 <ul id="cmd-list" class="cmd-list" role="listbox" aria-label="Targets">
357 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>359 <li id="cmd-o0" role="option" aria-selected="true" data-k="go home" data-cursor>
358-<a href="/" tabindex="-1">360+<a role="presentation" data-href="/">
359 <span class="lbl">home</span>361 <span class="lbl">home</span>
360 <span class="k">go</span>362 <span class="k">go</span>
361 </a>363 </a>
362 </li>364 </li>
363 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">365 <li id="cmd-o1" role="option" aria-selected="false" data-k="section summary">
364-<a href="/files" tabindex="-1">366+<a role="presentation" data-href="/files">
365 <span class="lbl">summary</span>367 <span class="lbl">summary</span>
366 <span class="k">section</span>368 <span class="k">section</span>
367 </a>369 </a>
368 </li>370 </li>
369 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">371 <li id="cmd-o2" role="option" aria-selected="false" data-k="section files">
370-<a href="/files/tree/main" tabindex="-1">372+<a role="presentation" data-href="/files/tree/main">
371 <span class="lbl">files</span>373 <span class="lbl">files</span>
372 <span class="k">section</span>374 <span class="k">section</span>
373 </a>375 </a>
374 </li>376 </li>
375 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">377 <li id="cmd-o3" role="option" aria-selected="false" data-k="section commits">
376-<a href="/files/commits/main" tabindex="-1">378+<a role="presentation" data-href="/files/commits/main">
377 <span class="lbl">commits</span>379 <span class="lbl">commits</span>
378 <span class="k">section</span>380 <span class="k">section</span>
379 </a>381 </a>
380 </li>382 </li>
381 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">383 <li id="cmd-o4" role="option" aria-selected="false" data-k="section branches &amp; tags">
382-<a href="/files/refs" tabindex="-1">384+<a role="presentation" data-href="/files/refs">
383 <span class="lbl">branches &amp; tags</span>385 <span class="lbl">branches &amp; tags</span>
384 <span class="k">section</span>386 <span class="k">section</span>
385 </a>387 </a>
386 </li>388 </li>
387 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">389 <li id="cmd-o5" role="option" aria-selected="false" data-k="section merge requests">
388-<a href="/files/merge-requests" tabindex="-1">390+<a role="presentation" data-href="/files/merge-requests">
389 <span class="lbl">merge requests</span>391 <span class="lbl">merge requests</span>
390 <span class="k">section</span>392 <span class="k">section</span>
391 </a>393 </a>
392 </li>394 </li>
393 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">395 <li id="cmd-o6" role="option" aria-selected="false" data-k="section releases">
394-<a href="/files/releases" tabindex="-1">396+<a role="presentation" data-href="/files/releases">
395 <span class="lbl">releases</span>397 <span class="lbl">releases</span>
396 <span class="k">section</span>398 <span class="k">section</span>
397 </a>399 </a>
398 </li>400 </li>
399 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">401 <li id="cmd-o7" role="option" aria-selected="false" data-k="section actions">
400-<a href="/files/actions" tabindex="-1">402+<a role="presentation" data-href="/files/actions">
401 <span class="lbl">actions</span>403 <span class="lbl">actions</span>
402 <span class="k">section</span>404 <span class="k">section</span>
403 </a>405 </a>
404 </li>406 </li>
405 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">407 <li id="cmd-o8" role="option" aria-selected="false" data-k="branch feature/x">
406-<a href="/files/tree/feature/x" tabindex="-1">408+<a role="presentation" data-href="/files/tree/feature/x">
407 <span class="lbl">feature/x</span>409 <span class="lbl">feature/x</span>
408 <span class="k">branch</span>410 <span class="k">branch</span>
409 </a>411 </a>
410 </li>412 </li>
411 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">413 <li id="cmd-o9" role="option" aria-selected="false" data-k="branch main">
412-<a href="/files/tree/main" tabindex="-1">414+<a role="presentation" data-href="/files/tree/main">
413 <span class="lbl">main</span>415 <span class="lbl">main</span>
414 <span class="k">branch</span>416 <span class="k">branch</span>
415 </a>417 </a>
416 </li>418 </li>
417 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">419 <li id="cmd-o10" role="option" aria-selected="false" data-k="tag v1.0">
418-<a href="/files/tree/v1.0" tabindex="-1">420+<a role="presentation" data-href="/files/tree/v1.0">
419 <span class="lbl">v1.0</span>421 <span class="lbl">v1.0</span>
420 <span class="k">tag</span>422 <span class="k">tag</span>
421 </a>423 </a>
422 </li>424 </li>
423 <li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">425 <li id="cmd-o11" role="option" aria-selected="false" data-k="action turn single-key shortcuts on off keyboard">
424-<a href="#" data-fire="keys" tabindex="-1">426+<a role="presentation" data-fire="keys">
425 <span class="lbl">turn single-key shortcuts off</span>427 <span class="lbl">turn single-key shortcuts off</span>
426 <span class="k">action</span>428 <span class="k">action</span>
427 </a>429 </a>

Comments0 open / 0

no comments yet.

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
l
merge request: the list of files (j k move, enter opens, esc back)
M
merge request: the merge menu; there 1–3 pick the mode, D deletes the branch, enter merges
R
merge request: mark the head read
esc
close a dialog, leave a field

Branches 2

Tags 42

↑↓ moveenter openesc close