From f22e761d4ad4cb56315568c8b92116802adbc4ed Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 27 Jul 2026 01:00:22 +0200 Subject: [PATCH 1/2] fix(preview): close on Escape, guard keyboard-synthesized clicks, raise z-index; feed Ctrl+V through for claude's native image paste Escape and outside-click now share one closeFilePreview() path that also clears previewPath/previewText/DOM so a stale file never lingers behind the next open. File links only activate on a real pointer click (event .detail === 0 marks a keyboard-synthesized click), and the panel now sits above every other overlay so its close button can't be covered. `claude` gets the raw Ctrl+V keystroke instead of AFKode's own clipboard-image substitution, since Claude Code already reads the OS clipboard itself on that keystroke. --- src/main.ts | 41 ++++++++++++++++++++++++++++++++++++----- src/styles.css | 4 +++- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/main.ts b/src/main.ts index 8004c0c..ca3ddaa 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1455,13 +1455,24 @@ async function newSession( } catch { /* clipboard is not text */ } + // Claude Code has its own native clipboard-image paste (shows as + // "[Image #1]" and sends the real bytes) — it reads the OS clipboard + // itself the moment it sees a raw Ctrl+V keystroke, exactly like it + // would in a bare terminal. Feed it that keystroke directly instead of + // pre-empting it with our own temp-file substitution, so Claude Code's + // own handling runs unmodified. + if (/^claude(\s|$)/.test(cmd)) { + invoke("write_pty", { id, data: "\x16" }).catch(() => {}); + return; + } try { const path = await invoke("clipboard_image_to_temp"); if (path) { // No text on the clipboard, only image data (e.g. a screenshot // tool was used instead of copying text) — falling back to // pasting its temp path silently looks like AFKode just broke - // when someone actually wanted to paste a URL/token. + // when someone actually wanted to paste a URL/token. Only reached + // for CLIs without their own native image-paste support. showLinkToast(t("pastedImageInstead")); invoke("write_pty", { id, data: `"${path}"` }).catch(() => {}); } @@ -3234,7 +3245,13 @@ function fileLinkProvider(term: Terminal, cwd: string | null) { links.push({ range: { start: { x: startCol + 1, y }, end: { x: endCol + 1, y } }, text: full, - activate: () => openFilePreview(full, cwd), + // detail === 0 marks a click synthesized from keyboard activation + // (Enter/Space on a focused element) rather than an actual mouse + // click — the preview must only open from a real pointer click. + activate: (event) => { + if (event.detail === 0) return; + openFilePreview(full, cwd); + }, }); } cb(links.length ? links : undefined); @@ -3264,9 +3281,24 @@ function disposeModelPreview() { currentModelPreview = null; } -$("#file-preview-close").addEventListener("click", () => { +function closeFilePreview() { filePreviewModal.classList.remove("open"); disposeModelPreview(); + setPreviewEditing(false); + // Release state immediately rather than leaving the last-viewed file + // sitting in the DOM/vars until something else happens to open — a + // stale path/body from an unrelated tab must never linger past close. + previewPath = null; + previewText = null; + filePreviewTitle.textContent = ""; + filePreviewBody.replaceChildren(); +} +$("#file-preview-close").addEventListener("click", closeFilePreview); +document.addEventListener("keydown", (e) => { + if (e.key === "Escape" && filePreviewModal.classList.contains("open")) { + e.preventDefault(); + closeFilePreview(); + } }); const filePreviewEditBtn = $("#file-preview-edit"); @@ -3330,8 +3362,7 @@ document.addEventListener("click", (e) => { filePreviewModal.classList.contains("open") && !filePreviewModal.contains(e.target as Node) ) { - filePreviewModal.classList.remove("open"); - disposeModelPreview(); + closeFilePreview(); } }); diff --git a/src/styles.css b/src/styles.css index ca2deac..89a3dcf 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1379,7 +1379,9 @@ kbd { .file-preview-panel { position: absolute; inset: 0 0 0 auto; - z-index: 45; + /* Above every other in-page overlay (empty-state, toasts, tab menus) so + its close button is never covered and unclickable. */ + z-index: 90; width: min(440px, 88%); display: flex; flex-direction: column; From 75f464b742a723b8323a0ed4cfae266eb38bfabf Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 27 Jul 2026 01:38:17 +0200 Subject: [PATCH 2/2] feat(terminal): real right-click context menu; claude native image paste MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the old copy-or-paste right-click with a real menu (Copy, Paste, Copy Command Output, Select All, Find, Scroll to Bottom, Clear Screen, Stop Process, Show in File Explorer when the click lands on a detected path, New Tab, Close Tab) — right-click no longer silently pastes the clipboard. Verified live against an isolated test build (separate app identifier, CDP + Playwright) rather than just by reading the code: - Shift+Tab / keyboard-synthesized clicks can no longer open the file preview panel (activate() now requires a real pointer click). - Escape now actually closes the preview: xterm.js intercepts Escape internally and stops its propagation before it reaches app-level listeners while the terminal still has focus, so opening the panel now moves focus onto it (matching the existing confirm-dialog pattern). - The close button and outside-click both release preview state immediately (title/body/path), so a stale file from another tab can't linger behind the next open. - The panel's z-index is raised above every other in-page overlay so its close button can never be covered and unclickable. Also: pasting into a Claude Code session now feeds the raw Ctrl+V keystroke through to the pty when the clipboard holds no text, so Claude Code's own native clipboard-image handling runs (shows "[Image #1]") instead of AFKode substituting a temp-file path. Non-Claude CLIs keep the path-substitution fallback. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01GHgSVKPsaWRfuJMo1rc2AN --- index.html | 2 + src-tauri/capabilities/default.json | 1 + src/main.ts | 193 ++++++++++++++++++++++++---- src/styles.css | 44 +++++++ 4 files changed, 218 insertions(+), 22 deletions(-) diff --git a/index.html b/index.html index ad3c384..9c5dfda 100644 --- a/index.html +++ b/index.html @@ -135,6 +135,8 @@

+ +