Full game
This commit is contained in:
@@ -1,14 +1,26 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useImperativeHandle, forwardRef } from "react";
|
||||
import '@xterm/xterm/css/xterm.css';
|
||||
import {
|
||||
useEffect,
|
||||
useRef,
|
||||
useImperativeHandle,
|
||||
forwardRef,
|
||||
RefObject,
|
||||
} from "react";
|
||||
import "@xterm/xterm/css/xterm.css";
|
||||
|
||||
export interface TerminalRef {
|
||||
export type TerminalRef = {
|
||||
write: (data: string) => void;
|
||||
clear: () => void;
|
||||
}
|
||||
focus: () => void;
|
||||
};
|
||||
|
||||
export const Terminal = forwardRef<TerminalRef, {}>(function Terminal(_props, ref) {
|
||||
export const Terminal = forwardRef<
|
||||
TerminalRef,
|
||||
{
|
||||
onData: (data: String) => void;
|
||||
}
|
||||
>(function Terminal(props, ref) {
|
||||
const terminalRef = useRef<HTMLDivElement>(null);
|
||||
const xtermRef = useRef<any>(null);
|
||||
|
||||
@@ -22,59 +34,34 @@ export const Terminal = forwardRef<TerminalRef, {}>(function Terminal(_props, re
|
||||
if (xtermRef.current) {
|
||||
xtermRef.current.clear();
|
||||
}
|
||||
}
|
||||
},
|
||||
focus: () => {
|
||||
if (xtermRef.current) {
|
||||
xtermRef.current.focus();
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
// Set to false when this component is unmounted.
|
||||
//
|
||||
// Here's what this flag prevents:
|
||||
// - <Terminal> component mounts
|
||||
// - `useEffect` runs, `mounted = true`
|
||||
// - `init_term()` function begins work
|
||||
// - before init_term() finishes, the user navigates away and <Terminal> to unmounts
|
||||
// - `useEffect` cleans up, `mounted = false`
|
||||
// - `init_term()` ccompletes, and we attempt to set `xtermRef.current`, causing issues
|
||||
let mounted = true;
|
||||
|
||||
const initTerminal = async () => {
|
||||
if (!terminalRef.current) return;
|
||||
|
||||
try {
|
||||
const { Terminal } = await import('@xterm/xterm');
|
||||
|
||||
init_term(terminalRef, props.onData, () => mounted)
|
||||
.then((term) => {
|
||||
if (!mounted) return;
|
||||
|
||||
const term = new Terminal({
|
||||
//"fontFamily": "Fantasque",
|
||||
"rows": 24,
|
||||
"fontSize": 16,
|
||||
"tabStopWidth": 8,
|
||||
"cursorBlink": true,
|
||||
"theme": {
|
||||
"background": "#1D1F21",
|
||||
"foreground": "#F8F8F8",
|
||||
"cursor": "#F8F8F2",
|
||||
"black": "#282828",
|
||||
"blue": "#0087AF",
|
||||
"brightBlack": "#555555",
|
||||
"brightBlue": "#87DFFF",
|
||||
"brightCyan": "#28D1E7",
|
||||
"brightGreen": "#A8FF60",
|
||||
"brightMagenta": "#985EFF",
|
||||
"brightRed": "#FFAA00",
|
||||
"brightWhite": "#D0D0D0",
|
||||
"brightYellow": "#F1FF52",
|
||||
"cyan": "#87DFEB",
|
||||
"green": "#B4EC85",
|
||||
"magenta": "#BD99FF",
|
||||
"red": "#FF6600",
|
||||
"white": "#F8F8F8",
|
||||
"yellow": "#FFFFB6"
|
||||
}
|
||||
});
|
||||
|
||||
term.open(terminalRef.current);
|
||||
term.write('Terminal ready.\r\n');
|
||||
|
||||
xtermRef.current = term;
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize terminal:', error);
|
||||
}
|
||||
};
|
||||
|
||||
initTerminal();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Failed to initialize terminal:", err);
|
||||
});
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
@@ -83,7 +70,57 @@ export const Terminal = forwardRef<TerminalRef, {}>(function Terminal(_props, re
|
||||
xtermRef.current = null;
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
}, [props.onData]);
|
||||
|
||||
return <div ref={terminalRef} style={{ height: "100%", width: "100%" }} />;
|
||||
});
|
||||
|
||||
async function init_term(
|
||||
ref: RefObject<HTMLDivElement>,
|
||||
|
||||
// Called when the terminal receives data
|
||||
onData: (data: String) => void,
|
||||
isMounted: () => boolean
|
||||
) {
|
||||
if (!ref.current) return;
|
||||
|
||||
const { Terminal } = await import("@xterm/xterm");
|
||||
if (!isMounted()) return;
|
||||
|
||||
const term = new Terminal({
|
||||
//"fontFamily": "Fantasque",
|
||||
rows: 24,
|
||||
fontSize: 16,
|
||||
tabStopWidth: 8,
|
||||
cursorBlink: false,
|
||||
cursorStyle: "block",
|
||||
cursorInactiveStyle: "none",
|
||||
theme: {
|
||||
background: "#1D1F21",
|
||||
foreground: "#F8F8F8",
|
||||
cursor: "#F8F8F2",
|
||||
black: "#282828",
|
||||
blue: "#0087AF",
|
||||
brightBlack: "#555555",
|
||||
brightBlue: "#87DFFF",
|
||||
brightCyan: "#28D1E7",
|
||||
brightGreen: "#A8FF60",
|
||||
brightMagenta: "#985EFF",
|
||||
brightRed: "#FFAA00",
|
||||
brightWhite: "#D0D0D0",
|
||||
brightYellow: "#F1FF52",
|
||||
cyan: "#87DFEB",
|
||||
green: "#B4EC85",
|
||||
magenta: "#BD99FF",
|
||||
red: "#ff2f00ff",
|
||||
white: "#F8F8F8",
|
||||
yellow: "#FFFFB6",
|
||||
},
|
||||
});
|
||||
|
||||
term.open(ref.current);
|
||||
term.onData(onData);
|
||||
|
||||
console.log("Terminal ready");
|
||||
return term;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user