From a6417c650f83b3bc3a639cd66bc2c6b5b95e0c4a Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Wed, 31 Dec 2025 12:52:26 -0500 Subject: [PATCH] btop and reactive theme in neofetch --- src/components/Btop.tsx | 247 +++++++++++++++++++++++ src/components/ErrorBoundaryFallback.tsx | 7 +- src/components/TerminalErrorPage.tsx | 11 +- src/lib/terminal-commands.ts | 19 +- src/routes/[...404].tsx | 2 +- 5 files changed, 279 insertions(+), 7 deletions(-) create mode 100644 src/components/Btop.tsx 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 ( +
+ {/* Main btop container */} +
+ {/* Header */} +
+
+ + btop v1.404.0 - ErrorOS System + Monitor + + + Close + + } + > + Press 'q' to quit + +
+
+ + {/* Content */} +
+ {/* System Stats */} +
+
System Resources
+
+ {/* CPU */} +
+ CPU + [{createBar(cpuUsage())}] + {cpuUsage()}% + 2.4 GHz +
+ + {/* Memory */} +
+ MEM + [{createBar(memUsage())}] + {memUsage()}% + + {((memUsage() / 100) * 16).toFixed(1)}/16 GB + +
+ + {/* Network */} +
+ NET + ↓ {netDown()} KB/s + ↑ {netUp()} KB/s +
+
+
+ + {/* Process List */} +
+
+ Processes +
+
+ + + + + + + + + + + + {processes().map((proc) => ( + + + + + + + + ))} + +
PIDNameCPU%MEM%Status
{proc.pid} + {proc.name} + + {proc.cpu.toFixed(1)} + + {proc.mem.toFixed(1)} + + {proc.status} +
+
+
+ + {/* Footer info */} +
+ Tap the Close button above to exit} + > + + Type q to quit btop + + +
+
+
+ + {/* Overlay background */} +
+
+ ); +} diff --git a/src/components/ErrorBoundaryFallback.tsx b/src/components/ErrorBoundaryFallback.tsx index 7662394..0ac8ea5 100644 --- a/src/components/ErrorBoundaryFallback.tsx +++ b/src/components/ErrorBoundaryFallback.tsx @@ -20,13 +20,14 @@ export default function ErrorBoundaryFallback( }; } - // Try to get dark mode, fallback to true (dark) if context unavailable - let isDark = true; + // Try to get dark mode, fallback to a function returning true (dark) if context unavailable + let isDark: () => boolean; try { const darkMode = useDarkMode(); - isDark = darkMode.isDark(); + isDark = darkMode.isDark; } catch (e) { // Context not available, use default + isDark = () => true; } const [glitchText, setGlitchText] = createSignal("ERROR"); diff --git a/src/components/TerminalErrorPage.tsx b/src/components/TerminalErrorPage.tsx index 1da4b61..ca7166f 100644 --- a/src/components/TerminalErrorPage.tsx +++ b/src/components/TerminalErrorPage.tsx @@ -13,6 +13,7 @@ import { executeTerminalCommand, CommandContext } from "~/lib/terminal-commands"; +import { Btop } from "~/components/Btop"; interface TerminalErrorPageProps { glitchText: string; @@ -34,6 +35,7 @@ export function TerminalErrorPage(props: TerminalErrorPageProps) { const [command, setCommand] = createSignal(""); const [history, setHistory] = createSignal([]); const [historyIndex, setHistoryIndex] = createSignal(-1); + const [btopOpen, setBtopOpen] = createSignal(false); let inputRef: HTMLInputElement | undefined; let footerRef: HTMLDivElement | undefined; @@ -62,6 +64,7 @@ export function TerminalErrorPage(props: TerminalErrorPageProps) { navigate: props.navigate, location: props.location, addToHistory, + openBtop: () => setBtopOpen(true), ...props.commandContext }); @@ -159,7 +162,7 @@ export function TerminalErrorPage(props: TerminalErrorPageProps) {
{/* Main content */} -
+
{/* Terminal header */}
@@ -220,6 +223,7 @@ export function TerminalErrorPage(props: TerminalErrorPageProps) { onKeyDown={handleKeyDown} class="text-text caret-text ml-1 flex-1 border-none bg-transparent outline-none" autocomplete="off" + autocapitalize="off" spellcheck={false} />
@@ -234,6 +238,11 @@ export function TerminalErrorPage(props: TerminalErrorPageProps) {
+ {/* Btop overlay */} + + setBtopOpen(false)} /> + + {/* Custom styles */}