diff --git a/src/components/Btop.tsx b/src/components/Btop.tsx new file mode 100644 index 0000000..a8c1727 --- /dev/null +++ b/src/components/Btop.tsx @@ -0,0 +1,247 @@ +import { createSignal, onMount, onCleanup, Show } from "solid-js"; + +interface BtopProps { + onClose: () => void; +} + +export function Btop(props: BtopProps) { + const [cpuUsage, setCpuUsage] = createSignal(64); + const [memUsage, setMemUsage] = createSignal(80); + const [netDown, setNetDown] = createSignal(404); + const [netUp, setNetUp] = createSignal(0); + const [processes, setProcesses] = createSignal([ + { + pid: 404, + name: "error-handler", + cpu: 32.0, + mem: 15.2, + status: "Running" + }, + { + pid: 128, + name: "glitch-generator", + cpu: 18.4, + mem: 8.7, + status: "Running" + }, + { pid: 256, name: "terminal-shell", cpu: 8.2, mem: 4.1, status: "Running" }, + { + pid: 512, + name: "random-process", + cpu: 5.4, + mem: 2.3, + status: "Sleeping" + }, + { pid: 1024, name: "mystery-daemon", cpu: 0.0, mem: 0.0, status: "???" } + ]); + const [isMobile, setIsMobile] = createSignal(false); + + onMount(() => { + // Check if mobile + if (typeof window !== "undefined") { + setIsMobile(window.innerWidth < 768); + + const handleResize = () => { + setIsMobile(window.innerWidth < 768); + }; + window.addEventListener("resize", handleResize); + onCleanup(() => window.removeEventListener("resize", handleResize)); + } + + // Animate CPU usage + const cpuInterval = setInterval(() => { + setCpuUsage((prev) => { + const change = (Math.random() - 0.5) * 10; + const newVal = Math.max(30, Math.min(95, prev + change)); + return Math.round(newVal); + }); + }, 1000); + + // Animate memory usage + const memInterval = setInterval(() => { + setMemUsage((prev) => { + const change = (Math.random() - 0.5) * 5; + const newVal = Math.max(60, Math.min(90, prev + change)); + return Math.round(newVal); + }); + }, 1500); + + // Animate network + const netInterval = setInterval(() => { + setNetDown(Math.floor(Math.random() * 1000)); + setNetUp(Math.floor(Math.random() * 100)); + }, 800); + + // Animate processes + const procInterval = setInterval(() => { + setProcesses((prev) => + prev.map((proc) => ({ + ...proc, + cpu: + proc.name === "mystery-daemon" + ? 0.0 + : Math.max(0, proc.cpu + (Math.random() - 0.5) * 5), + mem: + proc.name === "mystery-daemon" + ? 0.0 + : Math.max(0, proc.mem + (Math.random() - 0.5) * 2) + })) + ); + }, 2000); + + // Keyboard handler for :q + const handleKeyPress = (e: KeyboardEvent) => { + if (!isMobile() && e.key === "q" && e.shiftKey && e.key === ":") { + props.onClose(); + } + // Simple 'q' press to quit + if (!isMobile() && e.key === "q") { + props.onClose(); + } + }; + + window.addEventListener("keydown", handleKeyPress); + + onCleanup(() => { + clearInterval(cpuInterval); + clearInterval(memInterval); + clearInterval(netInterval); + clearInterval(procInterval); + window.removeEventListener("keydown", handleKeyPress); + }); + }); + + const createBar = (percentage: number, width: number = 30) => { + const filled = Math.round((percentage / 100) * width); + const empty = width - filled; + return "█".repeat(filled) + "░".repeat(empty); + }; + + return ( +
| PID | +Name | +CPU% | +MEM% | +Status | +
|---|---|---|---|---|
| {proc.pid} | ++ {proc.name} + | ++ {proc.cpu.toFixed(1)} + | ++ {proc.mem.toFixed(1)} + | ++ {proc.status} + | +