Update script-terminal-modal.tsx

This commit is contained in:
MacRimi
2025-12-06 23:25:35 +01:00
parent ab421e3184
commit 105c543a98

View File

@@ -56,8 +56,10 @@ export function ScriptTerminalModal({
const [modalHeight, setModalHeight] = useState(80) const [modalHeight, setModalHeight] = useState(80)
const [isResizing, setIsResizing] = useState(false) const [isResizing, setIsResizing] = useState(false)
const startYRef = useRef(0) const resizeHandlersRef = useRef<{
const startHeightRef = useRef(80) handleMove: ((e: MouseEvent | TouchEvent) => void) | null
handleEnd: (() => void) | null
}>({ handleMove: null, handleEnd: null })
const terminalContainerRef = useCallback( const terminalContainerRef = useCallback(
(node: HTMLDivElement | null) => { (node: HTMLDivElement | null) => {
@@ -283,6 +285,16 @@ export function ScriptTerminalModal({
termRef.current.dispose() termRef.current.dispose()
termRef.current = null 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) sessionIdRef.current = Math.random().toString(36).substring(2, 8)
setIsComplete(false) setIsComplete(false)
setExitCode(null) setExitCode(null)
@@ -347,29 +359,73 @@ export function ScriptTerminalModal({
} }
const handleResizeStart = (e: React.MouseEvent | React.TouchEvent) => { const handleResizeStart = (e: React.MouseEvent | React.TouchEvent) => {
e.preventDefault()
e.stopPropagation()
setIsResizing(true) setIsResizing(true)
startYRef.current = "clientY" in e ? e.clientY : e.touches[0].clientY const startY = "clientY" in e ? e.clientY : e.touches[0].clientY
startHeightRef.current = modalHeight const startHeight = modalHeight
document.addEventListener("mousemove", handleResize as any)
document.addEventListener("touchmove", handleResize as any)
document.addEventListener("mouseup", handleResizeEnd)
document.addEventListener("touchend", handleResizeEnd)
}
const handleResize = (e: MouseEvent | TouchEvent) => { const handleMove = (moveEvent: MouseEvent | TouchEvent) => {
if (!isResizing) return const currentY = moveEvent instanceof MouseEvent ? moveEvent.clientY : moveEvent.touches[0].clientY
const currentY = e instanceof MouseEvent ? e.clientY : e.touches[0].clientY const deltaY = currentY - startY
const deltaY = currentY - startYRef.current const deltaPercent = (deltaY / window.innerHeight) * 100
const newHeight = startHeightRef.current + (deltaY / window.innerHeight) * 100 const newHeight = Math.max(50, Math.min(95, startHeight + deltaPercent))
setModalHeight(Math.max(50, Math.min(95, newHeight)))
}
const handleResizeEnd = () => { setModalHeight(newHeight)
setIsResizing(false)
document.removeEventListener("mousemove", handleResize as any) if (fitAddonRef.current && termRef.current && wsRef.current?.readyState === WebSocket.OPEN) {
document.removeEventListener("touchmove", handleResize as any) try {
document.removeEventListener("mouseup", handleResizeEnd) setTimeout(() => {
document.removeEventListener("touchend", handleResizeEnd) 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 ( return (
@@ -411,13 +467,15 @@ export function ScriptTerminalModal({
{!isMobile && ( {!isMobile && (
<div <div
className={`h-2 cursor-ns-resize flex items-center justify-center transition-colors ${ className={`h-2 cursor-ns-resize flex items-center justify-center transition-all duration-150 ${
isResizing ? "bg-blue-500" : "bg-zinc-800 hover:bg-blue-500/50" isResizing ? "bg-blue-500 h-3" : "bg-zinc-800 hover:bg-blue-500/50"
}`} }`}
onMouseDown={handleResizeStart} onMouseDown={handleResizeStart}
onTouchStart={handleResizeStart} onTouchStart={handleResizeStart}
> >
<GripHorizontal className={`h-4 w-4 ${isResizing ? "text-white" : "text-zinc-500"}`} /> <GripHorizontal
className={`h-4 w-4 transition-all duration-150 ${isResizing ? "text-white scale-110" : "text-zinc-500"}`}
/>
</div> </div>
)} )}
@@ -445,7 +503,7 @@ export function ScriptTerminalModal({
{currentInteraction && ( {currentInteraction && (
<Dialog open={true}> <Dialog open={true}>
<DialogContent <DialogContent
className="max-w-4xl max-h-[80vh] overflow-y-auto" className="max-w-4xl max-h-[80vh] overflow-y-auto animate-in fade-in-0 zoom-in-95 duration-100"
onInteractOutside={(e) => e.preventDefault()} onInteractOutside={(e) => e.preventDefault()}
onEscapeKeyDown={(e) => e.preventDefault()} onEscapeKeyDown={(e) => e.preventDefault()}
hideClose hideClose
@@ -458,14 +516,14 @@ export function ScriptTerminalModal({
<div className="flex gap-2"> <div className="flex gap-2">
<Button <Button
onClick={() => handleInteractionResponse("yes")} onClick={() => handleInteractionResponse("yes")}
className="flex-1 bg-blue-600 hover:bg-blue-700 text-white" className="flex-1 bg-blue-600 hover:bg-blue-700 text-white transition-all duration-150"
> >
Yes Yes
</Button> </Button>
<Button <Button
onClick={() => handleInteractionResponse("cancel")} onClick={() => handleInteractionResponse("cancel")}
variant="outline" variant="outline"
className="flex-1 hover:bg-red-600 hover:text-white hover:border-red-600" className="flex-1 hover:bg-red-600 hover:text-white hover:border-red-600 transition-all duration-150"
> >
Cancel Cancel
</Button> </Button>
@@ -474,12 +532,13 @@ export function ScriptTerminalModal({
{currentInteraction.type === "menu" && currentInteraction.options && ( {currentInteraction.type === "menu" && currentInteraction.options && (
<div className="space-y-2"> <div className="space-y-2">
{currentInteraction.options.map((option) => ( {currentInteraction.options.map((option, index) => (
<Button <Button
key={option.value} key={option.value}
onClick={() => handleInteractionResponse(option.value)} onClick={() => handleInteractionResponse(option.value)}
variant="outline" variant="outline"
className="w-full justify-start hover:bg-blue-600 hover:text-white" className="w-full justify-start hover:bg-blue-600 hover:text-white transition-all duration-100 animate-in fade-in-0 slide-in-from-left-2"
style={{ animationDelay: `${index * 30}ms` }}
> >
{option.label} {option.label}
</Button> </Button>
@@ -487,7 +546,7 @@ export function ScriptTerminalModal({
<Button <Button
onClick={() => handleInteractionResponse("cancel")} onClick={() => handleInteractionResponse("cancel")}
variant="outline" variant="outline"
className="w-full hover:bg-red-600 hover:text-white hover:border-red-600" className="w-full hover:bg-red-600 hover:text-white hover:border-red-600 transition-all duration-150"
> >
Cancel Cancel
</Button> </Button>
@@ -506,18 +565,19 @@ export function ScriptTerminalModal({
} }
}} }}
placeholder={currentInteraction.default || ""} placeholder={currentInteraction.default || ""}
className="transition-all duration-150"
/> />
<div className="flex gap-2"> <div className="flex gap-2">
<Button <Button
onClick={() => handleInteractionResponse(interactionInput)} onClick={() => handleInteractionResponse(interactionInput)}
className="flex-1 bg-blue-600 hover:bg-blue-700" className="flex-1 bg-blue-600 hover:bg-blue-700 transition-all duration-150"
> >
Submit Submit
</Button> </Button>
<Button <Button
onClick={() => handleInteractionResponse("cancel")} onClick={() => handleInteractionResponse("cancel")}
variant="outline" variant="outline"
className="flex-1 hover:bg-red-600 hover:text-white hover:border-red-600" className="flex-1 hover:bg-red-600 hover:text-white hover:border-red-600 transition-all duration-150"
> >
Cancel Cancel
</Button> </Button>
@@ -529,14 +589,14 @@ export function ScriptTerminalModal({
<div className="flex gap-2"> <div className="flex gap-2">
<Button <Button
onClick={() => handleInteractionResponse("ok")} onClick={() => handleInteractionResponse("ok")}
className="flex-1 bg-blue-600 hover:bg-blue-700" className="flex-1 bg-blue-600 hover:bg-blue-700 transition-all duration-150"
> >
OK OK
</Button> </Button>
<Button <Button
onClick={() => handleInteractionResponse("cancel")} onClick={() => handleInteractionResponse("cancel")}
variant="outline" variant="outline"
className="flex-1 hover:bg-red-600 hover:text-white hover:border-red-600" className="flex-1 hover:bg-red-600 hover:text-white hover:border-red-600 transition-all duration-150"
> >
Cancel Cancel
</Button> </Button>