// Terminal Initialization Script for socktop webterm // Catppuccin Frappe theme with transparency (function() { 'use strict'; // Catppuccin Frappe theme for xterm var term = new Terminal({ allowTransparency: true, fontFamily: '"JetBrains Mono", "Fira Code", "Cascadia Code", Consolas, monospace', fontSize: 14, lineHeight: 1.2, cursorBlink: true, cursorStyle: "block", theme: { background: "rgba(48, 52, 70, 0.75)", foreground: "#c6d0f5", cursor: "#f2d5cf", cursorAccent: "#303446", selectionBackground: "rgba(202, 158, 230, 0.3)", // ANSI colors black: "#51576d", red: "#e78284", green: "#a6d189", yellow: "#e5c890", blue: "#8caaee", magenta: "#f4b8e4", cyan: "#81c8be", white: "#b5bfe2", // Bright ANSI colors brightBlack: "#626880", brightRed: "#e78284", brightGreen: "#a6d189", brightYellow: "#e5c890", brightBlue: "#8caaee", brightMagenta: "#f4b8e4", brightCyan: "#81c8be", brightWhite: "#a5adce", }, }); // Create and load the FitAddon var fitAddon = new FitAddon.FitAddon(); term.loadAddon(fitAddon); // Create and load the TerminadoAddon var terminadoAddon = new TerminadoAddon(); term.loadAddon(terminadoAddon); // Open terminal in the container var terminalContainer = document.getElementById("terminal"); term.open(terminalContainer); // Build websocket URL var protocol = location.protocol === "https:" ? "wss://" : "ws://"; var socketURL = protocol + location.hostname + (location.port ? ":" + location.port : "") + window.WEBSOCKET_PATH; var sock = new WebSocket(socketURL); // Fit-once strategy var fitDone = false; function fitOnceIfReady() { if (fitDone) return; if (!terminalContainer) return; var w = terminalContainer.clientWidth; var h = terminalContainer.clientHeight; if (!w || !h) return; try { fitAddon.fit(); fitDone = true; } catch (e) { console.error("Fit error:", e); } } // Schedule fit if ( document.readyState === "complete" || document.readyState === "interactive" ) { requestAnimationFrame(fitOnceIfReady); } else { window.addEventListener( "DOMContentLoaded", function () { requestAnimationFrame(fitOnceIfReady); }, { once: true }, ); } window.addEventListener( "load", function () { requestAnimationFrame(fitOnceIfReady); setTimeout(fitOnceIfReady, 150); }, { once: true }, ); // Send size and auto-launch command var autoSent = false; function sendSizeAndCommandOnce() { if (autoSent) return; if (!sock || sock.readyState !== WebSocket.OPEN) return; if (!fitDone) return; var rows = term.rows || 0; var cols = term.cols || 0; if (!rows || !cols) { var approxCharW = 9; var approxCharH = 18; cols = Math.max( 1, Math.floor(terminalContainer.clientWidth / approxCharW), ); rows = Math.max( 1, Math.floor( terminalContainer.clientHeight / approxCharH, ), ); } if (rows > 0 && cols > 0) { try { terminadoAddon.sendSize(rows, cols); terminadoAddon.sendCommand("socktop -P local\r"); autoSent = true; } catch (e) { console.error("Failed to send initial commands:", e); } } } // WebSocket event handlers sock.addEventListener("open", function () { terminadoAddon.attach(sock, true, true); requestAnimationFrame(function () { fitOnceIfReady(); setTimeout(sendSizeAndCommandOnce, 120); }); }); function onFirstMessage() { fitOnceIfReady(); try { sock.removeEventListener("message", onFirstMessage); } catch (e) {} setTimeout(sendSizeAndCommandOnce, 40); } sock.addEventListener("message", onFirstMessage); // Handle window resize window.addEventListener("resize", function () { try { fitAddon.fit(); } catch (e) { console.error("Resize fit error:", e); } }); sock.addEventListener("error", function (err) { console.error("WebSocket error:", err); }); sock.addEventListener("close", function () { console.log("WebSocket closed"); }); })();