bitburner-src/src/Terminal/ui/TerminalRoot.tsx

118 lines
3.4 KiB
TypeScript
Raw Normal View History

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";
import { ITerminal, Output, Link } from "../ITerminal";
2021-09-17 08:58:02 +02:00
import { IRouter } from "../../ui/Router";
2021-09-16 08:52:45 +02:00
import { IPlayer } from "../../PersonObjects/IPlayer";
import { TerminalInput } from "./TerminalInput";
2021-09-18 21:44:39 +02:00
import { TerminalEvents } from "../TerminalEvents";
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: {
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-18 08:21:48 +02:00
overflowWrap: "anywhere",
margin: theme.spacing(0),
2021-09-16 08:52:45 +02:00
},
2021-09-16 21:04:20 +02:00
list: {
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;
2021-09-17 08:58:02 +02:00
router: IRouter;
2021-09-16 08:52:45 +02:00
player: IPlayer;
}
2021-09-17 08:58:02 +02:00
export function TerminalRoot({ terminal, router, player }: IProps): React.ReactElement {
2021-09-17 02:14:09 +02:00
const scrollHook = useRef<HTMLDivElement>(null);
2021-09-19 06:46:39 +02:00
const setRerender = useState(0)[1];
2021-09-16 08:52:45 +02:00
function rerender(): void {
2021-09-19 06:46:39 +02:00
setRerender((old) => old + 1);
2021-09-16 08:52:45 +02:00
}
useEffect(() => {
2021-09-18 21:44:39 +02:00
return TerminalEvents.subscribe(rerender);
2021-09-16 08:52:45 +02:00
}, []);
2021-09-17 03:49:38 +02:00
function doScroll(): void {
const hook = scrollHook.current;
if (hook !== null) {
setTimeout(() => hook.scrollIntoView(true), 50);
}
2021-09-17 02:14:09 +02:00
}
2021-09-17 03:49:38 +02:00
doScroll();
useEffect(() => {
setTimeout(doScroll, 50);
}, []);
2021-09-16 08:52:45 +02:00
const classes = useStyles();
return (
2021-09-17 02:14:09 +02:00
<>
2021-09-17 08:04:44 +02:00
<Box width="100%" minHeight="100vh" display={"flex"} alignItems={"flex-end"}>
2021-09-17 02:14:09 +02:00
<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)}
>
&gt;&nbsp;{item.hostname}
</MuiLink>
</ListItem>
);
})}
2021-09-17 09:08:15 +02:00
{terminal.action !== null && (
<ListItem classes={{ root: classes.nopadding }}>
<ActionTimer terminal={terminal} />{" "}
</ListItem>
)}
2021-09-17 02:14:09 +02:00
</List>
<div ref={scrollHook}></div>
</Box>
2021-09-17 08:04:44 +02:00
<Box position="sticky" bottom={0} width="100%" px={0}>
2021-09-17 08:58:02 +02:00
<TerminalInput player={player} router={router} terminal={terminal} />
2021-09-17 02:14:09 +02:00
</Box>
</>
2021-09-16 08:52:45 +02:00
);
}