forked from forthfate/openorbit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathassistant-terminal.tsx
More file actions
25 lines (24 loc) · 1.68 KB
/
Copy pathassistant-terminal.tsx
File metadata and controls
25 lines (24 loc) · 1.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { FitAddon } from '@xterm/addon-fit'
import { Terminal } from '@xterm/xterm'
import '@xterm/xterm/css/xterm.css'
import { useEffect, useRef } from 'react'
export function AssistantTerminal({active}:{active:boolean}){
const host=useRef<HTMLDivElement>(null)
const resizeTerminal=useRef<()=>void>(()=>undefined)
useEffect(()=>{
if(!host.current)return
const terminal=new Terminal({cursorBlink:true,fontSize:12,theme:{background:'#101614',foreground:'#e9eee9'}})
const fit=new FitAddon();terminal.loadAddon(fit);terminal.open(host.current);fit.fit()
const socket=new WebSocket(`${location.protocol==='https:'?'wss':'ws'}://${location.host}/api/terminal`)
socket.onopen=()=>{terminal.focus();socket.send(JSON.stringify({type:'resize',cols:terminal.cols,rows:terminal.rows}))}
socket.onmessage=event=>terminal.write(event.data)
socket.onclose=()=>terminal.write('\r\n[Terminal session ended]')
const input=terminal.onData(data=>socket.readyState===WebSocket.OPEN&&socket.send(JSON.stringify({type:'input',data})))
const resize=()=>{fit.fit();if(socket.readyState===WebSocket.OPEN)socket.send(JSON.stringify({type:'resize',cols:terminal.cols,rows:terminal.rows}))}
resizeTerminal.current=resize
window.addEventListener('resize',resize)
return()=>{resizeTerminal.current=()=>undefined;input.dispose();window.removeEventListener('resize',resize);socket.close();terminal.dispose()}
},[])
useEffect(()=>{if(active)requestAnimationFrame(()=>{resizeTerminal.current();host.current?.querySelector<HTMLTextAreaElement>('.xterm-helper-textarea')?.focus()})},[active])
return <div className={`assistant-terminal ${active?'assistant-terminal--active':''}`} ref={host}/>
}