mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-04-18 10:02:16 +00:00
Update terminal-panel.tsx
This commit is contained in:
@@ -16,7 +16,6 @@ import {
|
|||||||
Grid2X2,
|
Grid2X2,
|
||||||
GripHorizontal,
|
GripHorizontal,
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
Clipboard,
|
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
@@ -493,6 +492,8 @@ export const TerminalPanel: React.FC<TerminalPanelProps> = ({ websocketUrl, onCl
|
|||||||
customGlyphs: true,
|
customGlyphs: true,
|
||||||
fontWeight: "500",
|
fontWeight: "500",
|
||||||
fontWeightBold: "700",
|
fontWeightBold: "700",
|
||||||
|
rightClickSelectsWord: true,
|
||||||
|
allowProposedApi: true,
|
||||||
theme: {
|
theme: {
|
||||||
background: "#000000",
|
background: "#000000",
|
||||||
foreground: "#ffffff",
|
foreground: "#ffffff",
|
||||||
@@ -523,6 +524,20 @@ export const TerminalPanel: React.FC<TerminalPanelProps> = ({ websocketUrl, onCl
|
|||||||
term.open(container)
|
term.open(container)
|
||||||
|
|
||||||
fitAddon.fit()
|
fitAddon.fit()
|
||||||
|
|
||||||
|
// Enable native paste on mobile - handle paste event from clipboard
|
||||||
|
const handlePaste = (e: ClipboardEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
const text = e.clipboardData?.getData('text')
|
||||||
|
if (text) {
|
||||||
|
// Will be sent through WebSocket once connected
|
||||||
|
const currentTerminal = terminals.find(t => t.id === terminal.id)
|
||||||
|
if (currentTerminal?.ws && currentTerminal.ws.readyState === WebSocket.OPEN) {
|
||||||
|
currentTerminal.ws.send(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
container.addEventListener('paste', handlePaste)
|
||||||
|
|
||||||
const wsUrl = websocketUrl || getWebSocketUrl()
|
const wsUrl = websocketUrl || getWebSocketUrl()
|
||||||
|
|
||||||
@@ -580,17 +595,14 @@ export const TerminalPanel: React.FC<TerminalPanelProps> = ({ websocketUrl, onCl
|
|||||||
)
|
)
|
||||||
syncSizeWithBackend()
|
syncSizeWithBackend()
|
||||||
|
|
||||||
// Auto-refresh for mobile/VPN: send a newline after 1 second to ensure connection is active
|
// Mobile fix: additional fit after short delay to ensure proper rendering
|
||||||
// This fixes the issue where mobile connections sometimes don't fully initialize
|
// This helps with VPN/slow connections where initial render may not complete
|
||||||
const isMobileDevice = window.innerWidth < 768 ||
|
const isMobileDevice = window.innerWidth < 768 ||
|
||||||
('ontouchstart' in window && navigator.maxTouchPoints > 0)
|
('ontouchstart' in window && navigator.maxTouchPoints > 0)
|
||||||
if (isMobileDevice) {
|
if (isMobileDevice) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (ws.readyState === WebSocket.OPEN) {
|
syncSizeWithBackend()
|
||||||
// Send empty string to trigger a refresh without executing any command
|
}, 500)
|
||||||
ws.send('\n')
|
|
||||||
}
|
|
||||||
}, 1000)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,32 +757,6 @@ const handleClose = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paste from clipboard - essential for mobile devices
|
|
||||||
const handlePaste = async (e?: React.MouseEvent | React.TouchEvent) => {
|
|
||||||
if (e) {
|
|
||||||
e.preventDefault()
|
|
||||||
e.stopPropagation()
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const text = await navigator.clipboard.readText()
|
|
||||||
if (text) {
|
|
||||||
const activeTerminal = terminals.find((t) => t.id === activeTerminalId)
|
|
||||||
if (activeTerminal?.ws && activeTerminal.ws.readyState === WebSocket.OPEN) {
|
|
||||||
// Send text character by character to handle special characters properly
|
|
||||||
activeTerminal.ws.send(text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.warn('[Terminal] Clipboard access denied:', err)
|
|
||||||
// Fallback: show a message in terminal
|
|
||||||
const activeTerminal = terminals.find((t) => t.id === activeTerminalId)
|
|
||||||
if (activeTerminal?.term) {
|
|
||||||
activeTerminal.term.writeln('\r\n\x1b[33m[INFO] Clipboard access denied. Please allow clipboard permissions.\x1b[0m')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getLayoutClass = () => {
|
const getLayoutClass = () => {
|
||||||
const count = terminals.length
|
const count = terminals.length
|
||||||
if (isMobile || count === 1) return "grid grid-cols-1"
|
if (isMobile || count === 1) return "grid grid-cols-1"
|
||||||
@@ -1072,16 +1058,6 @@ const handleClose = () => {
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
<Button
|
|
||||||
onPointerDown={(e) => handlePaste(e)}
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
className="h-8 px-2 text-xs gap-1 bg-green-600/20 hover:bg-green-600/30 border-green-600/50 text-green-400"
|
|
||||||
title="Paste from clipboard"
|
|
||||||
>
|
|
||||||
<Clipboard className="h-3.5 w-3.5" />
|
|
||||||
Paste
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user