Files
PiAgentUI/src/utils/clipboard.ts
T
Evandro b3489e1ede
Build & Push Frontend Docker Image / build-and-push (push) Canceled after 0s
Build Validation / validate (push) Canceled after 6s
Build & Push Backend Docker Image / build-and-push (push) Failing after 10m10s
Build & Push Gateway Docker Image / build-and-push (push) Failing after 10m9s
🎉 Initial commit: PiAgentUI — AI Agent Desktop & Web UI
A professional workspace for AI coding agents with:
- Real-time streaming chat with SSE
- Session management (fork, clone, tree navigation)
- MCP tools browser & metadata panel
- Skills browser (global, project, package sources)
- Voice input & STT provider configuration
- Integrated terminal & file explorer
- Model selector with capability metadata
- Keyboard-first UI with command palette
- 8 languages (en, pt-BR, es, ja, zh-CN, ar, bn, hi)
- Tauri 2 desktop app
- React 19 + TypeScript + Vite 8 + Tailwind CSS 4
- Pi Agent extension runtime

Originally forked from OpenCodeUI, now an independent project.
License: GPL-3.0-only
2026-06-01 00:50:06 -03:00

66 lines
1.8 KiB
TypeScript

function fallbackCopyText(text: string): boolean {
if (typeof document === 'undefined' || !document.body) {
return false
}
const textArea = document.createElement('textarea')
textArea.value = text
textArea.setAttribute('readonly', '')
textArea.setAttribute('aria-hidden', 'true')
textArea.style.position = 'fixed'
textArea.style.top = '0'
textArea.style.left = '-9999px'
textArea.style.opacity = '0'
textArea.style.pointerEvents = 'none'
const selection = document.getSelection()
const savedRanges = selection
? Array.from({ length: selection.rangeCount }, (_, index) => selection.getRangeAt(index).cloneRange())
: []
const activeElement = document.activeElement instanceof HTMLElement ? document.activeElement : null
document.body.appendChild(textArea)
textArea.focus()
textArea.select()
textArea.setSelectionRange(0, text.length)
const copied = typeof document.execCommand === 'function' && document.execCommand('copy')
document.body.removeChild(textArea)
if (selection) {
selection.removeAllRanges()
savedRanges.forEach(range => selection.addRange(range))
}
activeElement?.focus()
return copied
}
export async function copyTextToClipboard(text: string): Promise<void> {
let clipboardError: unknown
if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {
try {
await navigator.clipboard.writeText(text)
return
} catch (error) {
clipboardError = error
}
}
if (fallbackCopyText(text)) {
return
}
throw clipboardError instanceof Error ? clipboardError : new Error('Failed to copy text to clipboard')
}
export async function readTextFromClipboard(): Promise<string> {
if (typeof navigator !== 'undefined' && navigator.clipboard?.readText) {
return navigator.clipboard.readText()
}
throw new Error('Clipboard read API is not available')
}