100 lines
2.7 KiB
TypeScript
100 lines
2.7 KiB
TypeScript
import { IS_BROWSER } from "$fresh/runtime.ts";
|
|
import { useEffect, useRef, useState } from "preact/hooks";
|
|
import { JSX } from "preact/jsx-runtime";
|
|
import { Sockpuppet } from "puppet/client";
|
|
|
|
export function Terminal(props: { channelId: string }) {
|
|
const puppet = useRef(new Sockpuppet("ws://sockpuppet.cyborggrizzly.com"));
|
|
const [lines, setLines] = useState<string[]>([]);
|
|
const divRef = useRef<HTMLDivElement>(null);
|
|
const storeKey = "commandHistory";
|
|
const [commandHistory, setCommandHistory] = useState<string[]>(
|
|
JSON.parse(localStorage.getItem(storeKey) || "[]"),
|
|
);
|
|
const [historyIndex, setHistoryIndex] = useState(commandHistory.length);
|
|
|
|
const [command, setCommand] = useState("");
|
|
|
|
const changeHistoryIndex = (by: number) => setHistoryIndex((i) => i + by);
|
|
|
|
useEffect(() => {
|
|
if (!IS_BROWSER) return;
|
|
puppet.current.joinChannel(props.channelId, (line) => {
|
|
setLines((l) => [...l, line]);
|
|
});
|
|
setTimeout(() => {
|
|
const channel = puppet.current.getChannel(props.channelId)
|
|
// console.log(channel)
|
|
channel?.send("log");
|
|
}, 200);
|
|
|
|
document.addEventListener("keyup", (e) => {
|
|
switch (e.key) {
|
|
case "Up":
|
|
case "ArrowUp":
|
|
changeHistoryIndex(-1);
|
|
break;
|
|
case "Down":
|
|
case "ArrowDown":
|
|
changeHistoryIndex(1);
|
|
break;
|
|
}
|
|
});
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (divRef.current) {
|
|
divRef.current.scrollTop = divRef.current.scrollHeight;
|
|
}
|
|
}, [lines]);
|
|
|
|
const sendCommand = (e: Event) => {
|
|
e.preventDefault();
|
|
puppet.current.getChannel(props.channelId)?.send(
|
|
historyIndex === commandHistory.length
|
|
? command
|
|
: commandHistory[historyIndex],
|
|
);
|
|
setCommandHistory((c) => [...c, command]);
|
|
setHistoryIndex(commandHistory.length + 1);
|
|
setCommand("");
|
|
};
|
|
|
|
const handleCommandUpdate = (
|
|
e: JSX.TargetedEvent<HTMLInputElement, Event>,
|
|
) => {
|
|
const value = e.currentTarget.value;
|
|
|
|
if (historyIndex !== commandHistory.length) {
|
|
setHistoryIndex(commandHistory.length);
|
|
}
|
|
|
|
setCommand(value || "");
|
|
};
|
|
|
|
useEffect(() => {
|
|
localStorage.setItem(
|
|
storeKey,
|
|
JSON.stringify(commandHistory.slice(0, 100)),
|
|
);
|
|
}, [commandHistory]);
|
|
|
|
return (
|
|
<div>
|
|
<div ref={divRef} class="flex flex-col h-[600px] w-full overflow-auto">
|
|
{lines.map((l) => <pre class="font-mono w-full">{l}</pre>)}
|
|
</div>
|
|
<div class="mt-4">
|
|
<form onSubmit={sendCommand}>
|
|
<input
|
|
type="text"
|
|
class="w-full bg-smoke-600 text-white"
|
|
value={commandHistory[historyIndex] || command}
|
|
onInput={handleCommandUpdate}
|
|
/>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|