feat: add Alt+P keyboard shortcut for PiP pop-out

- Alt+P toggles Picture-in-Picture floating recorder on /voice page
- Works from both main window and PiP window
- Footer shows new shortcut hint when PiP is supported
- Browser extension Ctrl+Shift+V now opens PWA /voice page (with PiP)
  instead of extension-local voice.html

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-02-24 20:25:38 -08:00
parent a6ae90fd62
commit 4eb24038b6
3 changed files with 31 additions and 12 deletions

View File

@ -293,13 +293,14 @@ chrome.contextMenus.onClicked.addListener(async (info, tab) => {
// --- Keyboard shortcut handler ---
chrome.commands.onCommand.addListener((command) => {
chrome.commands.onCommand.addListener(async (command) => {
if (command === 'open-voice-recorder') {
const settings = await getSettings();
chrome.windows.create({
url: chrome.runtime.getURL('voice.html'),
url: `${settings.host}/voice`,
type: 'popup',
width: 380,
height: 520,
width: 400,
height: 600,
focused: true,
});
}

View File

@ -300,13 +300,14 @@ document.getElementById('unlockBtn').addEventListener('click', async () => {
}
});
document.getElementById('voiceBtn').addEventListener('click', () => {
// Open voice recorder in a small popup window
document.getElementById('voiceBtn').addEventListener('click', async () => {
// Open rVoice PWA page in a popup window (supports PiP pop-out)
const settings = await getSettings();
chrome.windows.create({
url: chrome.runtime.getURL('voice.html'),
url: `${settings.host}/voice`,
type: 'popup',
width: 380,
height: 520,
width: 400,
height: 600,
focused: true,
});
// Close the current popup

View File

@ -666,10 +666,16 @@ export default function VoicePage() {
e.preventDefault();
saveToRNotes();
}
// Alt+P toggles PiP
if (e.altKey && e.code === 'KeyP') {
e.preventDefault();
if (pipWindow) closePiP();
else openPiP();
}
};
window.addEventListener('keydown', handler);
return () => window.removeEventListener('keydown', handler);
}, [toggleRecording, saveToRNotes, state]);
}, [toggleRecording, saveToRNotes, state, pipWindow, openPiP, closePiP]);
// Keyboard events inside PiP window
useEffect(() => {
@ -687,12 +693,17 @@ export default function VoicePage() {
ke.preventDefault();
saveToRNotes();
}
// Alt+P closes PiP from within PiP window
if (ke.altKey && ke.code === 'KeyP') {
ke.preventDefault();
closePiP();
}
};
pipWindow.document.addEventListener('keydown', handler);
return () => {
try { pipWindow.document.removeEventListener('keydown', handler); } catch {}
};
}, [pipWindow, toggleRecording, saveToRNotes, state]);
}, [pipWindow, toggleRecording, saveToRNotes, state, closePiP]);
// --- Render ---
@ -1032,8 +1043,14 @@ export default function VoicePage() {
<div className="flex gap-3">
<kbd className="px-1.5 py-0.5 bg-slate-900 border border-slate-700 rounded text-[10px]">Space</kbd>
<span>record</span>
<kbd className="px-1.5 py-0.5 bg-slate-900 border border-slate-700 rounded text-[10px]">Ctrl+Enter</kbd>
<kbd className="px-1.5 py-0.5 bg-slate-900 border border-slate-700 rounded text-[10px]">Ctrl+&#x23CE;</kbd>
<span>save</span>
{pipSupported && (
<>
<kbd className="px-1.5 py-0.5 bg-slate-900 border border-slate-700 rounded text-[10px]">Alt+P</kbd>
<span>pop out</span>
</>
)}
</div>
<a href="/" className="hover:text-amber-400 transition-colors">rNotes.online</a>
</footer>