Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
5.1 kB · 166 lines
HTML
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Aesthetic Computer Shell</title> <link rel="stylesheet" href="../node_modules/@xterm/xterm/css/xterm.css"> <style> * { margin: 0; padding: 0; box-sizing: border-box; } html, body { width: 100%; height: 100%; overflow: hidden; background: #0a0a12; } #terminal-container { width: 100%; height: calc(100% - 64px); /* Leave space at top */ margin-top: 64px; /* Push terminal down */ padding: 8px; } .xterm { height: 100%; } .xterm-viewport { padding-top: 0 !important; } </style></head><body> <div id="terminal-container"></div>
<script> // With nodeIntegration enabled, we can use require() directly const { Terminal } = require('@xterm/xterm'); const { FitAddon } = require('@xterm/addon-fit'); const { WebglAddon } = require('@xterm/addon-webgl'); const { ipcRenderer } = require('electron');
const terminalContainer = document.getElementById('terminal-container');
// Initialize terminal with performance optimizations const term = new Terminal({ cursorBlink: true, cursorStyle: 'block', fontSize: 14, fontFamily: "'SF Mono', 'Fira Code', 'Cascadia Code', monospace", theme: { background: '#0a0a12', foreground: '#eee', cursor: '#f0f', cursorAccent: '#0a0a12', selectionBackground: 'rgba(255, 0, 255, 0.3)', black: '#1a1a2e', red: '#ff5555', green: '#50fa7b', yellow: '#f1fa8c', blue: '#6272a4', magenta: '#ff79c6', cyan: '#8be9fd', white: '#f8f8f2', }, allowTransparency: false, // Disabled for WebGL performance scrollback: 5000, fastScrollModifier: 'alt', fastScrollSensitivity: 5, });
const fitAddon = new FitAddon(); term.loadAddon(fitAddon); term.open(terminalContainer); // Load WebGL addon for GPU-accelerated rendering try { const webglAddon = new WebglAddon(); webglAddon.onContextLoss(() => { webglAddon.dispose(); }); term.loadAddon(webglAddon); console.log('[shell] WebGL renderer enabled'); } catch (e) { console.warn('[shell] WebGL not available, using canvas renderer'); } // Fit after a short delay to ensure container is sized setTimeout(() => fitAddon.fit(), 50);
// Resize handling const resizeObserver = new ResizeObserver(() => { fitAddon.fit(); ipcRenderer.send('pty-resize', term.cols, term.rows); }); resizeObserver.observe(terminalContainer);
// Connect to PTY async function initShell() { try { // Check Docker const dockerOk = await ipcRenderer.invoke('check-docker'); if (!dockerOk) { term.writeln('\x1b[31mError: Docker not running\x1b[0m'); return; }
// Check if container is running const containerRunning = await ipcRenderer.invoke('check-container'); if (!containerRunning) { // Check if container exists but is stopped const containerExists = await ipcRenderer.invoke('check-container-exists'); if (containerExists) { term.writeln('\x1b[33mStarting existing container...\x1b[0m'); await ipcRenderer.invoke('start-existing-container'); } else { term.writeln('\x1b[33mCreating devcontainer...\x1b[0m'); await ipcRenderer.invoke('start-container'); } }
// Connect PTY const connected = await ipcRenderer.invoke('connect-pty'); if (!connected) { term.writeln('\x1b[31mFailed to connect to shell\x1b[0m'); return; }
// PTY data → terminal ipcRenderer.on('pty-data', (event, data) => { term.write(data); });
// Terminal input → PTY term.onData((data) => { ipcRenderer.send('pty-input', data); });
// PTY exit ipcRenderer.on('pty-exit', (event, code) => { term.writeln(`\r\n\x1b[33mShell exited with code ${code}\x1b[0m`); });
// Send initial resize ipcRenderer.send('pty-resize', term.cols, term.rows); // Auto-start emacs after a brief delay for shell to initialize setTimeout(() => { ipcRenderer.send('pty-input', 'ac-aesthetic\n'); }, 500);
} catch (err) { term.writeln(`\x1b[31mError: ${err.message}\x1b[0m`); } }
// Expose reboot function globally for easy access window.rebootApp = async () => { console.log('Requesting app reboot...'); try { const result = await ipcRenderer.invoke('app-reboot'); console.log('Reboot initiated:', result); return result; } catch (err) { console.error('Reboot failed:', err); throw err; } };
initShell(); </script></body></html>