diff --git a/apps/extension/src/entrypoints/popup/App.test.tsx b/apps/extension/src/entrypoints/popup/App.test.tsx index 54062f0..155e7b6 100644 --- a/apps/extension/src/entrypoints/popup/App.test.tsx +++ b/apps/extension/src/entrypoints/popup/App.test.tsx @@ -199,7 +199,9 @@ describe("App", () => { expect(copied).toContain("--browser 03c3e47f"); expect(copied).toContain('--purpose "发布 wiki 文档"'); expect(copied).not.toMatch(/bsk record start[^\n]*--url/); - await waitFor(() => expect(copyButton.textContent).toContain("已复制")); + // Button label stays static; a transient toast confirms the copy. + expect(copyButton.textContent).toContain("复制录制指令"); + await waitFor(() => expect(screen.getByRole("status").textContent).toContain("已复制")); }); it("includes --url in record prompt when a start URL is provided", async () => { diff --git a/apps/extension/src/entrypoints/popup/App.tsx b/apps/extension/src/entrypoints/popup/App.tsx index 84166bb..6aee921 100644 --- a/apps/extension/src/entrypoints/popup/App.tsx +++ b/apps/extension/src/entrypoints/popup/App.tsx @@ -41,7 +41,10 @@ export function App() { const [copiedInstanceId, setCopiedInstanceId] = useState(false); const [purposeDraft, setPurposeDraft] = useState(""); const [startUrlDraft, setStartUrlDraft] = useState(""); - const [copiedPrompt, setCopiedPrompt] = useState(false); + // Bumped on every successful copy so the "copied" toast re-shows (and its + // auto-hide timer restarts) even when the copied content is unchanged. + const [copiedTick, setCopiedTick] = useState(0); + const showCopiedToast = copiedTick > 0; useEffect(() => { const query = window.matchMedia("(prefers-color-scheme: dark)"); @@ -56,9 +59,21 @@ export function App() { useEffect(() => { setCopiedInstanceId(false); - setCopiedPrompt(false); + setCopiedTick(0); }, [snapshot.instanceId]); + // Hide the copied toast when the command changes (topic / start URL edits). + useEffect(() => { + setCopiedTick(0); + }, [purposeDraft, startUrlDraft]); + + // Auto-hide the copied toast shortly after it appears. + useEffect(() => { + if (copiedTick === 0) return; + const timer = window.setTimeout(() => setCopiedTick(0), 1500); + return () => window.clearTimeout(timer); + }, [copiedTick]); + const isSkewed = statusState === "version_skew"; const daemonVersion = snapshot.handshake?.version ?? "—"; const daemonProtocol = snapshot.handshake?.protocol_version ?? "—"; @@ -92,7 +107,7 @@ export function App() { const copyRecordPrompt = async () => { if (!recordReady || !navigator.clipboard?.writeText) return; await navigator.clipboard.writeText(recordPrompt); - setCopiedPrompt(true); + setCopiedTick((tick) => tick + 1); }; const headerTitle = @@ -338,29 +353,32 @@ export function App() { {t("popup.record.hintDisconnected")}

)} - + + )}