From 171553c1370712ee9d57db4a289b88d13db2bad2 Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 25 May 2026 22:15:54 -0700 Subject: [PATCH] Keyboard shortcuts for the web UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four shortcuts: `/` focuses the filter input, `r` triggers a library rescan, `Esc` closes the topmost modal, `?` opens a help dialog listing the bindings. All disabled while the focus is inside a text input / textarea / contentEditable element so typing a video title doesn't accidentally fire actions — except Esc, which always closes modals (even from an input). A new `?` button next to the existing rescan / maintenance / settings icons makes the shortcuts discoverable; the help dialog is plain HTML table with monospace key chips. Co-Authored-By: Claude Opus 4.7 --- src/web_ui/index.html | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/web_ui/index.html b/src/web_ui/index.html index 661552b..ef6c32b 100644 --- a/src/web_ui/index.html +++ b/src/web_ui/index.html @@ -134,6 +134,7 @@ + @@ -1445,6 +1446,52 @@ function schedulePoll(ms){ } schedulePoll(600); +/* ── Keyboard shortcuts ─────────────────────────────────────────── */ +// Listed in the ? help dialog below. Skip when the user is typing in a +// text input — otherwise pressing `r` while typing a filename would +// trigger a rescan. +document.addEventListener('keydown',(e)=>{ + const tag=(document.activeElement?.tagName||'').toLowerCase(); + const inField=tag==='input'||tag==='textarea'||document.activeElement?.isContentEditable; + // Esc always closes the topmost modal — even from within an input. + if(e.key==='Escape'){ + const modals=document.querySelectorAll('.modal-bg'); + if(modals.length){modals[modals.length-1].remove();e.preventDefault();return} + } + if(inField)return; + switch(e.key){ + case '/': + document.getElementById('search')?.focus(); + e.preventDefault(); + break; + case 'r': + rescan(); + e.preventDefault(); + break; + case '?': + showShortcutsHelp(); + e.preventDefault(); + break; + } +}); +function showShortcutsHelp(){ + if(document.getElementById('shortcuts-help'))return; + const bg=document.createElement('div');bg.className='modal-bg';bg.id='shortcuts-help'; + bg.onclick=e=>{if(e.target===bg)bg.remove()}; + const row=(k,d)=>`${k}${d}`; + bg.innerHTML=``; + document.body.appendChild(bg); +} + /* ── Utilities ──────────────────────────────────────────────────── */ function fmtDur(s){s=Math.floor(s);const h=Math.floor(s/3600),m=Math.floor((s%3600)/60),sec=s%60;return h?`${h}:${p(m)}:${p(sec)}`:`${m}:${p(sec)}`} function fmtSize(b){if(b>=1073741824)return(b/1073741824).toFixed(1)+' GB';if(b>=1048576)return Math.round(b/1048576)+' MB';return Math.round(b/1024)+' KB'}