"use client" import { FitAddon } from "@xterm/addon-fit" import { Terminal } from "@xterm/xterm" import "./xterm.css" import { Loader2 } from "lucide-react" import { useEffect, useRef } from "react" import { Socket } from "socket.io-client" export default function EditorTerminal({ socket, id, term, setTerm, visible, }: { socket: Socket id: string term: Terminal | null setTerm: (term: Terminal) => void visible: boolean }) { const terminalRef = useRef(null) useEffect(() => { if (!terminalRef.current) return // console.log("new terminal", id, term ? "reusing" : "creating"); const terminal = new Terminal({ cursorBlink: true, theme: { background: "#262626", }, fontFamily: "var(--font-geist-mono)", fontSize: 14, lineHeight: 1.5, letterSpacing: 0, }) setTerm(terminal) return () => { if (terminal) terminal.dispose() } }, []) useEffect(() => { if (!term) return if (!terminalRef.current) return const fitAddon = new FitAddon() term.loadAddon(fitAddon) term.open(terminalRef.current) fitAddon.fit() const disposableOnData = term.onData((data) => { socket.emit("terminalData", id, data) }) const disposableOnResize = term.onResize((dimensions) => { // const terminal_size = { // width: dimensions.cols, // height: dimensions.rows, // }; fitAddon.fit() socket.emit("terminalResize", dimensions) }) return () => { disposableOnData.dispose() disposableOnResize.dispose() } }, [term, terminalRef.current]) useEffect(() => { if (!term) return const handleTerminalResponse = (response: { id: string; data: string }) => { if (response.id === id) { term.write(response.data) } } socket.on("terminalResponse", handleTerminalResponse) return () => { socket.off("terminalResponse", handleTerminalResponse) } }, [term, id, socket]) return ( <>
{term === null ? (
Connecting to terminal...
) : null}
) }