2021-09-17 02:14:09 +02:00
|
|
|
import React, { useState, useEffect, useRef } from "react";
|
2021-09-17 01:23:03 +02:00
|
|
|
import Typography from "@mui/material/Typography";
|
|
|
|
import List from "@mui/material/List";
|
|
|
|
import ListItem from "@mui/material/ListItem";
|
|
|
|
import { Link as MuiLink } from "@mui/material";
|
|
|
|
import { Theme } from "@mui/material/styles";
|
2021-09-17 02:14:09 +02:00
|
|
|
import makeStyles from "@mui/styles/makeStyles";
|
|
|
|
import createStyles from "@mui/styles/createStyles";
|
2021-09-17 01:23:03 +02:00
|
|
|
import Box from "@mui/material/Box";
|
2021-09-16 21:37:01 +02:00
|
|
|
import { ITerminal, Output, Link } from "../ITerminal";
|
2021-09-16 08:52:45 +02:00
|
|
|
import { IEngine } from "../../IEngine";
|
|
|
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
2021-09-16 21:37:01 +02:00
|
|
|
import { TerminalInput } from "./TerminalInput";
|
2021-09-16 20:43:39 +02:00
|
|
|
|
|
|
|
interface IActionTimerProps {
|
|
|
|
terminal: ITerminal;
|
|
|
|
}
|
|
|
|
|
|
|
|
function ActionTimer({ terminal }: IActionTimerProps): React.ReactElement {
|
|
|
|
return (
|
|
|
|
<Typography color={"primary"} paragraph={false}>
|
|
|
|
{terminal.getProgressText()}
|
|
|
|
</Typography>
|
|
|
|
);
|
|
|
|
}
|
2021-09-16 08:52:45 +02:00
|
|
|
|
|
|
|
const useStyles = makeStyles((theme: Theme) =>
|
|
|
|
createStyles({
|
|
|
|
nopadding: {
|
2021-09-16 21:37:01 +02:00
|
|
|
padding: theme.spacing(0),
|
2021-09-16 08:52:45 +02:00
|
|
|
},
|
|
|
|
preformatted: {
|
2021-09-16 20:55:55 +02:00
|
|
|
whiteSpace: "pre-wrap",
|
2021-09-16 21:37:01 +02:00
|
|
|
margin: theme.spacing(0),
|
2021-09-16 08:52:45 +02:00
|
|
|
},
|
2021-09-16 21:04:20 +02:00
|
|
|
list: {
|
2021-09-16 21:37:01 +02:00
|
|
|
padding: theme.spacing(0),
|
2021-09-16 21:04:20 +02:00
|
|
|
height: "100%",
|
|
|
|
},
|
2021-09-16 08:52:45 +02:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
|
|
|
|
interface IProps {
|
|
|
|
terminal: ITerminal;
|
|
|
|
engine: IEngine;
|
|
|
|
player: IPlayer;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function TerminalRoot({ terminal, engine, player }: IProps): React.ReactElement {
|
2021-09-17 02:14:09 +02:00
|
|
|
const scrollHook = useRef<HTMLDivElement>(null);
|
2021-09-16 08:52:45 +02:00
|
|
|
const setRerender = useState(false)[1];
|
|
|
|
function rerender(): void {
|
|
|
|
setRerender((old) => !old);
|
|
|
|
}
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const id = setInterval(() => {
|
|
|
|
if (terminal.pollChanges()) rerender();
|
|
|
|
}, 100);
|
|
|
|
return () => clearInterval(id);
|
|
|
|
}, []);
|
|
|
|
|
2021-09-17 02:14:09 +02:00
|
|
|
const hook = scrollHook.current;
|
|
|
|
if (hook !== null) {
|
|
|
|
setTimeout(() => hook.scrollIntoView(true), 10);
|
|
|
|
}
|
|
|
|
|
2021-09-16 08:52:45 +02:00
|
|
|
const classes = useStyles();
|
|
|
|
return (
|
2021-09-17 02:14:09 +02:00
|
|
|
<>
|
|
|
|
<Box width="100%" minHeight="100vh" px={1}>
|
|
|
|
<List classes={{ root: classes.list }}>
|
|
|
|
{terminal.outputHistory.map((item, i) => {
|
|
|
|
if (item instanceof Output)
|
|
|
|
return (
|
|
|
|
<ListItem key={i} classes={{ root: classes.nopadding }}>
|
|
|
|
<Typography classes={{ root: classes.preformatted }} color={item.color} paragraph={false}>
|
|
|
|
{item.text}
|
|
|
|
</Typography>
|
|
|
|
</ListItem>
|
|
|
|
);
|
|
|
|
if (item instanceof Link)
|
|
|
|
return (
|
|
|
|
<ListItem key={i} classes={{ root: classes.nopadding }}>
|
|
|
|
<MuiLink
|
|
|
|
classes={{ root: classes.preformatted }}
|
|
|
|
color={"secondary"}
|
|
|
|
paragraph={false}
|
|
|
|
onClick={() => terminal.connectToServer(player, item.hostname)}
|
|
|
|
>
|
|
|
|
> {item.hostname}
|
|
|
|
</MuiLink>
|
|
|
|
</ListItem>
|
|
|
|
);
|
|
|
|
})}
|
|
|
|
</List>
|
|
|
|
{terminal.action !== null && <ActionTimer terminal={terminal} />}
|
|
|
|
<div ref={scrollHook}></div>
|
|
|
|
</Box>
|
|
|
|
<Box position="sticky" bottom={0} width="100%" px={1}>
|
|
|
|
<TerminalInput player={player} engine={engine} terminal={terminal} />
|
|
|
|
</Box>
|
|
|
|
</>
|
2021-09-16 08:52:45 +02:00
|
|
|
);
|
|
|
|
}
|