72 lines
1.9 KiB
TypeScript
72 lines
1.9 KiB
TypeScript
import { FitAddon } from "@xterm/addon-fit";
|
|
import { Terminal } from "@xterm/xterm";
|
|
import { useEffect, useRef, useState } from "react";
|
|
|
|
export function TerminalPanel() {
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
const [failed, setFailed] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const container = containerRef.current;
|
|
if (!container) return;
|
|
|
|
let terminal: Terminal | undefined;
|
|
let fitAddon: FitAddon | undefined;
|
|
|
|
try {
|
|
terminal = new Terminal({
|
|
cursorBlink: true,
|
|
convertEol: true,
|
|
fontFamily:
|
|
'Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
|
|
fontSize: 12,
|
|
theme: {
|
|
background: "#171717",
|
|
foreground: "#e5e5e5",
|
|
},
|
|
});
|
|
fitAddon = new FitAddon();
|
|
terminal.loadAddon(fitAddon);
|
|
terminal.open(container);
|
|
terminal.writeln("codespace terminal");
|
|
terminal.writeln("Mock session initialized. No process is attached.");
|
|
terminal.writeln("");
|
|
terminal.writeln("$ pnpm test");
|
|
terminal.writeln("mock: 3 files checked, 0 failures");
|
|
terminal.write("$ ");
|
|
fitAddon.fit();
|
|
} catch {
|
|
setFailed(true);
|
|
terminal?.dispose();
|
|
fitAddon?.dispose();
|
|
return;
|
|
}
|
|
|
|
const handleResize = () => {
|
|
fitAddon?.fit();
|
|
};
|
|
|
|
window.addEventListener("resize", handleResize);
|
|
|
|
return () => {
|
|
window.removeEventListener("resize", handleResize);
|
|
terminal?.dispose();
|
|
fitAddon?.dispose();
|
|
};
|
|
}, []);
|
|
|
|
if (failed) {
|
|
return (
|
|
<section className="flex h-full w-full items-center justify-center bg-background text-sm text-muted-foreground">
|
|
Terminal failed to initialize
|
|
</section>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<section className="h-full w-full overflow-hidden bg-[#171717] p-2">
|
|
<div ref={containerRef} className="h-full w-full" />
|
|
</section>
|
|
);
|
|
}
|