From 2e65d0ef4ac31fa58935d2f20fab023d94a2e8a8 Mon Sep 17 00:00:00 2001 From: Jake Jarvis Date: Mon, 31 Jan 2022 15:47:54 -0500 Subject: [PATCH] extract fake DOS terminal into a separate component --- components/Terminal/Terminal.module.css | 28 ++++++++++++++ components/Terminal/Terminal.tsx | 18 +++++++++ components/VNC/VNC.module.css | 24 +----------- components/VNC/VNC.tsx | 47 +++++++++++++---------- components/Wallpaper/Wallpaper.module.css | 1 - 5 files changed, 74 insertions(+), 44 deletions(-) create mode 100644 components/Terminal/Terminal.module.css create mode 100644 components/Terminal/Terminal.tsx diff --git a/components/Terminal/Terminal.module.css b/components/Terminal/Terminal.module.css new file mode 100644 index 00000000..5837b4a3 --- /dev/null +++ b/components/Terminal/Terminal.module.css @@ -0,0 +1,28 @@ +.terminal { + width: 100%; + height: 100%; + padding: 1em; + + background-color: #000000; + color: #cccccc; + + font-size: 0.925em; + font-weight: 500; + line-height: 2; + white-space: pre-wrap; + user-select: none; +} + +.blink { + display: inline-block; + vertical-align: text-bottom; + width: 10px; + border-bottom: 2px solid #cccccc; + animation: blink 1s step-end infinite; +} + +@keyframes blink { + 50% { + opacity: 0; + } +} diff --git a/components/Terminal/Terminal.tsx b/components/Terminal/Terminal.tsx new file mode 100644 index 00000000..5b81a52d --- /dev/null +++ b/components/Terminal/Terminal.tsx @@ -0,0 +1,18 @@ +import { forwardRef } from "react"; +import classNames from "classnames"; +import type { Ref, HTMLAttributes } from "react"; + +import styles from "./Terminal.module.css"; + +type Props = HTMLAttributes; + +// a DOS-style terminal box with dynamic text +const Terminal = forwardRef(function Terminal({ className, ...rest }: Props, ref: Ref) { + return ( +
+ +
+ ); +}); + +export default Terminal; diff --git a/components/VNC/VNC.module.css b/components/VNC/VNC.module.css index d3a07daf..7f0b591f 100644 --- a/components/VNC/VNC.module.css +++ b/components/VNC/VNC.module.css @@ -19,28 +19,8 @@ cursor: default !important; } -.cmd { +.terminal { + height: 400px; width: 100%; max-width: 700px; - min-height: 400px; - padding: 1em; - - background-color: #000000; - color: #cccccc; - - font-size: 0.925em; - font-weight: 500; - line-height: 2; - white-space: pre-wrap; - user-select: none; -} - -.blink { - animation: blink 1s step-end infinite; -} - -@keyframes blink { - 50% { - opacity: 0; - } } diff --git a/components/VNC/VNC.tsx b/components/VNC/VNC.tsx index df553569..c2ae43f5 100644 --- a/components/VNC/VNC.tsx +++ b/components/VNC/VNC.tsx @@ -1,7 +1,7 @@ import { useRef, useEffect, useState, memo } from "react"; import { useRouter } from "next/router"; -import classNames from "classnames"; import RFB from "@novnc/novnc/core/rfb.js"; +import Terminal from "../Terminal/Terminal"; import styles from "./VNC.module.css"; @@ -16,8 +16,7 @@ const VNC = ({ server }: Props) => { const [loaded, setLoaded] = useState(false); // DOS-style box for text - const terminalRef = useRef(null); - const terminalMessageRef = useRef(null); + const terminalRef = useRef(null); // the actual connection and virtual screen (injected by noVNC when it's ready) const rfbRef = useRef(null); @@ -25,28 +24,30 @@ const VNC = ({ server }: Props) => { // makes the console reappear with the given message if there's an error loading, or if the VM has gone poof for // whatever reason (doesn't really matter). - const showTerminalMessage = (message = "") => { + const showTerminalMessage = ({ message, anyKey = false }) => { try { screenRef.current.style.display = "none"; - terminalRef.current.style.display = null; - terminalMessageRef.current.textContent = `${message}\n\nPress the Any key or refresh the page to continue.`; + terminalRef.current.parentElement.style.display = null; + terminalRef.current.textContent = `${message}${ + anyKey ? "\n\nPress the Any key or refresh the page to continue." : "" + }`; } catch (e) {} // eslint-disable-line no-empty }; - // hide the console when VM connects and show the screen + // hides the console and show the screen when VM connects const showScreen = () => { - terminalRef.current.style.display = "none"; + terminalRef.current.parentElement.style.display = "none"; screenRef.current.style.display = null; }; - // end the session forcefully + // ends the session forcefully const disconnectVM = () => { try { rfbRef.current.disconnect(); } catch (e) {} // eslint-disable-line no-empty }; - // prepare for possible navigation away from this page, and disconnect when it happens + // prepare for possible navigation away from this page, and disconnect if/when it happens useEffect(() => { router.events.on("routeChangeStart", disconnectVM); @@ -58,13 +59,16 @@ const VNC = ({ server }: Props) => { useEffect(() => { if (loaded) { - // don't do any of this more than once and overwhelm the fragile backend + // don't do any of this more than once, the backend is pretty fragile return; + } else { + // show loading indicator and continue + showTerminalMessage({ message: "Spinning up your very own personal computer, please wait!" }); } if (!window.WebSocket) { // browser doesn't support websockets - showTerminalMessage("WebSockets must be enabled to begin!"); + showTerminalMessage({ message: "WebSockets must be enabled to begin!", anyKey: true }); return; } @@ -76,30 +80,31 @@ const VNC = ({ server }: Props) => { // scale screen to make it kinda "responsive" rfbRef.current.scaleViewport = true; - // this is the one and only time we're spinning up a VM (hopefully) - setLoaded(true); - // VM connected rfbRef.current.addEventListener("connect", () => { console.log("successfully connected to VM socket!"); + // finally hide the terminal and show the VNC canvas showScreen(); + + // this is the one and only time we're spinning up a VM (hopefully) + setLoaded(true); }); - // VM disconnected + // VM disconnected (on either end) rfbRef.current.addEventListener("disconnect", (detail: unknown) => { console.warn("VM ended session remotely:", detail); - showTerminalMessage("Oh dear, it looks like something's gone very wrong. Sorry about that."); + showTerminalMessage({ + message: "Oh dear, it looks like something's gone very wrong. Sorry about that.", + anyKey: true, + }); }); }, [loaded, server]); return ( <> -
- Spinning up your very own personal computer, please wait!{" "} - _ -
+ {/* the VNC canvas is hidden until we've successfully connected to the socket */}
diff --git a/components/Wallpaper/Wallpaper.module.css b/components/Wallpaper/Wallpaper.module.css index 63921555..92942b3c 100644 --- a/components/Wallpaper/Wallpaper.module.css +++ b/components/Wallpaper/Wallpaper.module.css @@ -5,7 +5,6 @@ padding: 1.5em 0; width: 100%; min-height: 400px; - box-sizing: content-box; } .tile {