diff --git a/AppImage/components/script-terminal-modal.tsx b/AppImage/components/script-terminal-modal.tsx index e28890f..5271266 100644 --- a/AppImage/components/script-terminal-modal.tsx +++ b/AppImage/components/script-terminal-modal.tsx @@ -56,8 +56,10 @@ export function ScriptTerminalModal({ const [modalHeight, setModalHeight] = useState(80) const [isResizing, setIsResizing] = useState(false) - const startYRef = useRef(0) - const startHeightRef = useRef(80) + const resizeHandlersRef = useRef<{ + handleMove: ((e: MouseEvent | TouchEvent) => void) | null + handleEnd: (() => void) | null + }>({ handleMove: null, handleEnd: null }) const terminalContainerRef = useCallback( (node: HTMLDivElement | null) => { @@ -283,6 +285,16 @@ export function ScriptTerminalModal({ termRef.current.dispose() termRef.current = null } + if (resizeHandlersRef.current.handleMove) { + document.removeEventListener("mousemove", resizeHandlersRef.current.handleMove as any) + document.removeEventListener("touchmove", resizeHandlersRef.current.handleMove as any) + } + if (resizeHandlersRef.current.handleEnd) { + document.removeEventListener("mouseup", resizeHandlersRef.current.handleEnd) + document.removeEventListener("touchend", resizeHandlersRef.current.handleEnd) + } + resizeHandlersRef.current = { handleMove: null, handleEnd: null } + sessionIdRef.current = Math.random().toString(36).substring(2, 8) setIsComplete(false) setExitCode(null) @@ -347,29 +359,73 @@ export function ScriptTerminalModal({ } const handleResizeStart = (e: React.MouseEvent | React.TouchEvent) => { + e.preventDefault() + e.stopPropagation() + setIsResizing(true) - startYRef.current = "clientY" in e ? e.clientY : e.touches[0].clientY - startHeightRef.current = modalHeight - document.addEventListener("mousemove", handleResize as any) - document.addEventListener("touchmove", handleResize as any) - document.addEventListener("mouseup", handleResizeEnd) - document.addEventListener("touchend", handleResizeEnd) - } + const startY = "clientY" in e ? e.clientY : e.touches[0].clientY + const startHeight = modalHeight - const handleResize = (e: MouseEvent | TouchEvent) => { - if (!isResizing) return - const currentY = e instanceof MouseEvent ? e.clientY : e.touches[0].clientY - const deltaY = currentY - startYRef.current - const newHeight = startHeightRef.current + (deltaY / window.innerHeight) * 100 - setModalHeight(Math.max(50, Math.min(95, newHeight))) - } + const handleMove = (moveEvent: MouseEvent | TouchEvent) => { + const currentY = moveEvent instanceof MouseEvent ? moveEvent.clientY : moveEvent.touches[0].clientY + const deltaY = currentY - startY + const deltaPercent = (deltaY / window.innerHeight) * 100 + const newHeight = Math.max(50, Math.min(95, startHeight + deltaPercent)) - const handleResizeEnd = () => { - setIsResizing(false) - document.removeEventListener("mousemove", handleResize as any) - document.removeEventListener("touchmove", handleResize as any) - document.removeEventListener("mouseup", handleResizeEnd) - document.removeEventListener("touchend", handleResizeEnd) + setModalHeight(newHeight) + + if (fitAddonRef.current && termRef.current && wsRef.current?.readyState === WebSocket.OPEN) { + try { + setTimeout(() => { + fitAddonRef.current.fit() + wsRef.current?.send( + JSON.stringify({ + type: "resize", + cols: termRef.current.cols, + rows: termRef.current.rows, + }), + ) + }, 10) + } catch (err) { + // Ignore + } + } + } + + const handleEnd = () => { + setIsResizing(false) + + if (fitAddonRef.current && termRef.current && wsRef.current?.readyState === WebSocket.OPEN) { + try { + setTimeout(() => { + fitAddonRef.current.fit() + wsRef.current?.send( + JSON.stringify({ + type: "resize", + cols: termRef.current.cols, + rows: termRef.current.rows, + }), + ) + }, 50) + } catch (err) { + // Ignore + } + } + + document.removeEventListener("mousemove", handleMove as any) + document.removeEventListener("touchmove", handleMove as any) + document.removeEventListener("mouseup", handleEnd) + document.removeEventListener("touchend", handleEnd) + + resizeHandlersRef.current = { handleMove: null, handleEnd: null } + } + + resizeHandlersRef.current = { handleMove, handleEnd } + + document.addEventListener("mousemove", handleMove as any) + document.addEventListener("touchmove", handleMove as any, { passive: false }) + document.addEventListener("mouseup", handleEnd) + document.addEventListener("touchend", handleEnd) } return ( @@ -411,13 +467,15 @@ export function ScriptTerminalModal({ {!isMobile && (
- +
)} @@ -445,7 +503,7 @@ export function ScriptTerminalModal({ {currentInteraction && ( e.preventDefault()} onEscapeKeyDown={(e) => e.preventDefault()} hideClose @@ -458,14 +516,14 @@ export function ScriptTerminalModal({
@@ -474,12 +532,13 @@ export function ScriptTerminalModal({ {currentInteraction.type === "menu" && currentInteraction.options && (
- {currentInteraction.options.map((option) => ( + {currentInteraction.options.map((option, index) => ( @@ -487,7 +546,7 @@ export function ScriptTerminalModal({ @@ -506,18 +565,19 @@ export function ScriptTerminalModal({ } }} placeholder={currentInteraction.default || ""} + className="transition-all duration-150" />
@@ -529,14 +589,14 @@ export function ScriptTerminalModal({