From b0621d15c675b7b8c1615b0699cc85ea1430a728 Mon Sep 17 00:00:00 2001 From: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Date: Mon, 21 Jul 2025 13:50:23 -0400 Subject: hooking clipboard automation button, hide plugin wiki for now (#118) * hooking clipboard automation button, hide plugin wiki for now * add direct copy to clip buttons for patch and unpatch --- src/components/DocumentationButton.tsx | 2 + src/components/FGModInstallerSection.tsx | 17 ++++ src/components/SmartClipboardButton.tsx | 128 +++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 src/components/SmartClipboardButton.tsx (limited to 'src/components') diff --git a/src/components/DocumentationButton.tsx b/src/components/DocumentationButton.tsx index 4125fd3..7069bc2 100644 --- a/src/components/DocumentationButton.tsx +++ b/src/components/DocumentationButton.tsx @@ -12,6 +12,7 @@ export function DocumentationButton() { return ( + {/* + */} ) : null} + + {pathExists === true ? ( + + ) : null} + + {pathExists === true ? ( + + ) : null} ); } diff --git a/src/components/SmartClipboardButton.tsx b/src/components/SmartClipboardButton.tsx new file mode 100644 index 0000000..7d250f5 --- /dev/null +++ b/src/components/SmartClipboardButton.tsx @@ -0,0 +1,128 @@ +import { useState } from "react"; +import { PanelSectionRow, ButtonItem } from "@decky/ui"; +import { FaClipboard } from "react-icons/fa"; +import { toaster } from "@decky/api"; + +interface SmartClipboardButtonProps { + command?: string; + buttonText?: string; + successMessage?: string; +} + +export function SmartClipboardButton({ + command = "~/fgmod/fgmod %command%", + buttonText = "Copy Launch Command", + successMessage = "Launch option ready to paste" +}: SmartClipboardButtonProps) { + const [isLoading, setIsLoading] = useState(false); + + const getLaunchOptionText = (): string => { + return command; + }; + + const copyToClipboard = async () => { + if (isLoading) return; + + setIsLoading(true); + try { + const text = getLaunchOptionText(); + + // Use the proven input simulation method + const tempInput = document.createElement('input'); + tempInput.value = text; + tempInput.style.position = 'absolute'; + tempInput.style.left = '-9999px'; + document.body.appendChild(tempInput); + + // Focus and select the text + tempInput.focus(); + tempInput.select(); + + // Try copying using execCommand first (most reliable in gaming mode) + let copySuccess = false; + try { + if (document.execCommand('copy')) { + copySuccess = true; + } + } catch (e) { + // If execCommand fails, try navigator.clipboard as fallback + try { + await navigator.clipboard.writeText(text); + copySuccess = true; + } catch (clipboardError) { + console.error('Both copy methods failed:', e, clipboardError); + } + } + + // Clean up + document.body.removeChild(tempInput); + + if (copySuccess) { + // Verify the copy worked by reading back + try { + const readBack = await navigator.clipboard.readText(); + if (readBack === text) { + toaster.toast({ + title: "Copied to Clipboard!", + body: successMessage + }); + } else { + // Copy worked but verification failed - still consider it success + toaster.toast({ + title: "Copied to Clipboard!", + body: "Launch option copied (verification unavailable)" + }); + } + } catch (e) { + // Verification failed but copy likely worked + toaster.toast({ + title: "Copied to Clipboard!", + body: "Launch option copied successfully" + }); + } + } else { + toaster.toast({ + title: "Copy Failed", + body: "Unable to copy to clipboard" + }); + } + + } catch (error) { + toaster.toast({ + title: "Copy Failed", + body: `Error: ${String(error)}` + }); + } finally { + setIsLoading(false); + } + }; + + return ( + + + + {isLoading ? ( + + ) : ( + + )} + {isLoading ? "Copying..." : buttonText} + + + + + ); +} -- cgit v1.2.3