| 1 | import { useEffect, useState } from "react"; |
| 2 | |
| 3 | import { isMacPlatform } from "../lib/utils"; |
| 4 | |
| 5 | // A released hold hint lingers for the original hold duration. Double-press |
| 6 | // hints disappear as soon as their acceptance window closes. |
| 7 | const HOLD_HINT_LINGER_MS = 1200; |
| 8 | |
| 9 | /** |
| 10 | * The desktop main process intercepts the quit accelerator and pushes |
| 11 | * press/release states while it waits for a hold or second press. |
| 12 | */ |
| 13 | export function QuitHoldOverlay() { |
| 14 | const [visibleMode, setVisibleMode] = useState<"hold" | "double-click" | null>(null); |
| 15 | |
| 16 | useEffect(() => { |
| 17 | const subscribe = window.desktopBridge?.onQuitShortcut; |
| 18 | if (!subscribe) return; |
| 19 | let hideTimer: number | undefined; |
| 20 | let pressedMode: "hold" | "double-click" = "hold"; |
| 21 | const unsubscribe = subscribe((hint) => { |
| 22 | window.clearTimeout(hideTimer); |
| 23 | if (hint.state === "down") { |
| 24 | pressedMode = hint.mode; |
| 25 | setVisibleMode(hint.mode); |
| 26 | return; |
| 27 | } |
| 28 | if (pressedMode === "double-click") { |
| 29 | setVisibleMode(null); |
| 30 | return; |
| 31 | } |
| 32 | hideTimer = window.setTimeout(() => setVisibleMode(null), HOLD_HINT_LINGER_MS); |
| 33 | }); |
| 34 | return () => { |
| 35 | window.clearTimeout(hideTimer); |
| 36 | unsubscribe(); |
| 37 | }; |
| 38 | }, []); |
| 39 | |
| 40 | if (!visibleMode) return null; |
| 41 | const shortcut = isMacPlatform(navigator.platform) ? "⌘Q" : "Ctrl+Q"; |
| 42 | const message = |
| 43 | visibleMode === "hold" |
| 44 | ? `Hold ${shortcut} or press twice to quit` |
| 45 | : `Press ${shortcut} again to quit`; |
| 46 | return ( |
| 47 | <div |
| 48 | role="status" |
| 49 | className="pointer-events-none fixed inset-x-0 top-[22%] z-100 flex justify-center" |
| 50 | > |
| 51 | <div className="rounded-full bg-foreground/95 px-8 py-4 text-2xl font-bold text-background shadow-xl"> |
| 52 | {message} |
| 53 | </div> |
| 54 | </div> |
| 55 | ); |
| 56 | } |