Ub / index.html
jyujiaf's picture
Create index.html
5f93257 verified
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HF Space Terminal</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.min.css" />
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.min.js"></script>
<style>
body { margin: 0; background: #1e1e1e; overflow: hidden; }
#terminal { height: 100vh; width: 100vw; }
#status { position: absolute; top: 10px; right: 10px; color: #0f0; background: rgba(0,0,0,0.7); padding: 5px 10px; border-radius: 4px; font-family: sans-serif; font-size: 12px; z-index: 999; pointer-events: none; }
</style>
</head>
<body>
<div id="status">Connecting...</div>
<div id="terminal"></div>
<script>
const term = new Terminal({
cursorBlink: true,
theme: { background: '#1e1e1e', foreground: '#ffffff' },
fontSize: 14,
fontFamily: 'Menlo, Monaco, "Courier New", monospace'
});
const fitAddon = new FitAddon.FitAddon();
term.loadAddon(fitAddon);
term.open(document.getElementById('terminal'));
fitAddon.fit();
// 直接连接当前域名的 /ws 路径 (Nginx 会转发给 ttyd)
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${protocol}//${window.location.host}/ws`;
let sock = null;
let reconnectTimer = null;
function connect() {
if (reconnectTimer) clearTimeout(reconnectTimer);
document.getElementById('status').innerText = "Connecting...";
try {
sock = new WebSocket(wsUrl);
sock.onopen = () => {
document.getElementById('status').innerText = "Connected (Ready)";
document.getElementById('status').style.color = "#0f0";
term.write('\\r\\n\\x1b[32m>>> HF Space Ubuntu Terminal Ready <<<\\x1b[0m\\r\\n');
term.write('\\r\\nType commands (e.g., ls, g++, vim)...\\r\\n\\r\\n');
// 发送初始窗口大小
fitAddon.fit();
const dims = { cols: term.cols, rows: term.rows };
sock.send(JSON.stringify({ resize: dims }));
};
term.onData(data => {
if (sock && sock.readyState === WebSocket.OPEN) {
sock.send(data);
}
});
sock.onmessage = event => {
if (event.data instanceof ArrayBuffer) {
term.write(new Uint8Array(event.data));
} else {
term.write(event.data);
}
};
sock.onclose = () => {
document.getElementById('status').innerText = "Disconnected. Reconnecting...";
document.getElementById('status').style.color = "#ffa500";
reconnectTimer = setTimeout(connect, 2000);
};
sock.onerror = () => {
document.getElementById('status').innerText = "Error";
document.getElementById('status').style.color = "#ff0000";
};
} catch (e) {
document.getElementById('status').innerText = "Error: " + e.message;
}
}
connect();
window.addEventListener('resize', () => {
fitAddon.fit();
if (sock && sock.readyState === WebSocket.OPEN) {
sock.send(JSON.stringify({ resize: { cols: term.cols, rows: term.rows } }));
}
});
</script>
</body>
</html>