diff --git a/src/App.svelte b/src/App.svelte index 21f9957..47df8d8 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -34,7 +34,12 @@ systemPrefersDark = media.matches; const onSystemThemeChange = (e: MediaQueryListEvent) => (systemPrefersDark = e.matches); media.addEventListener("change", onSystemThemeChange); - return () => media.removeEventListener("change", onSystemThemeChange); + + window.addEventListener("keydown", onGlobalKeydown); + return () => { + media.removeEventListener("change", onSystemThemeChange); + window.removeEventListener("keydown", onGlobalKeydown); + }; }); function startRecording() { @@ -42,6 +47,39 @@ recording.start(undefined, settings.settings.default_record); } + function toggleRecording() { + if (recording.state === "idle") startRecording(); + else recording.stop(); + } + + // Global shortcuts (T7.4, FR-UX-3): record start/stop, view toggles. + // "Template apply" isn't included — there's no template UI yet (Phase 8, T8.1). + function isEditableTarget(target: EventTarget | null): boolean { + if (!(target instanceof HTMLElement)) return false; + return ( + target.tagName === "INPUT" || + target.tagName === "TEXTAREA" || + target.tagName === "SELECT" || + target.isContentEditable + ); + } + + function onGlobalKeydown(e: KeyboardEvent) { + if (e.key === "Escape") { + if (showConsent) showConsent = false; + else if (showSettings) showSettings = false; + return; + } + if (isEditableTarget(e.target)) return; // never hijack typing in a field + if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === "r") { + e.preventDefault(); + toggleRecording(); + } else if (e.ctrlKey && e.key === ",") { + e.preventDefault(); + showSettings = !showSettings; + } + } + // Mid-meeting retention toggle (FR-REC-1); gates on the same one-time // consent notice as the Settings default-record toggle (FR-REC-2). function onToggleRetention(e: Event) { @@ -67,9 +105,17 @@ local · private
{#if recording.state === "idle"} - + {:else} - + Recording…