From eb1fbf136dfce5099afbf1a2f1411a672656a59a Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Sat, 27 Jun 2026 16:41:57 +0900 Subject: feat(sidebar-tabs): click tab ID badge to copy conversation id --- src/features/tabs/ui/TabList.svelte | 62 ++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 5 deletions(-) (limited to 'src/features/tabs/ui') diff --git a/src/features/tabs/ui/TabList.svelte b/src/features/tabs/ui/TabList.svelte index efef4fa..40f95cd 100644 --- a/src/features/tabs/ui/TabList.svelte +++ b/src/features/tabs/ui/TabList.svelte @@ -55,6 +55,46 @@ function cancelRename(): void { editingId = null; } + + // Click-to-copy the agent (conversation) id: clicking the ID badge copies the + // FULL conversationId to the clipboard (the stable, useful id — the badge + // only shows a short prefix) and briefly highlights the badge as feedback. + // Clipboard is the edge effect; absent (insecure context) → select the badge + // text so the user can Ctrl+C manually. + let copiedId = $state(null); + let copyTimer: ReturnType | undefined; + + async function copyId(conversationId: string, el: HTMLElement): Promise { + const clipboard = navigator.clipboard; + if (clipboard === undefined) { + selectText(el); + flashCopied(conversationId); + return; + } + try { + await clipboard.writeText(conversationId); + flashCopied(conversationId); + } catch { + selectText(el); + flashCopied(conversationId); + } + } + + function flashCopied(conversationId: string): void { + copiedId = conversationId; + clearTimeout(copyTimer); + copyTimer = setTimeout(() => { + copiedId = null; + }, 1200); + } + + function selectText(el: HTMLElement): void { + const range = document.createRange(); + range.selectNodeContents(el); + const selection = window.getSelection(); + selection?.removeAllRanges(); + selection?.addRange(range); + }
@@ -75,12 +115,24 @@ if (e.key === "Enter") onSelect(tab.conversationId); }} > - { + e.stopPropagation(); + void copyId(tab.conversationId, e.currentTarget); + }} > - {handles.get(tab.conversationId) ?? tab.conversationId} - + {copiedId === tab.conversationId + ? "Copied!" + : (handles.get(tab.conversationId) ?? tab.conversationId)} + {#if editingId === tab.conversationId}