socktop-webterm/static/terminal.js

178 lines
4.9 KiB
JavaScript
Raw Permalink Normal View History

// 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");
});
})();