Files
MyClub/scripts/templates/terminal.html
T
Tomas Dvorak dfc079288f hot fix #1
2026-01-26 08:13:18 +01:00

336 lines
9.9 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Terminal Tamagotchi</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #000;
font-family: 'Courier New', 'Monaco', 'Menlo', monospace;
color: #00ff00;
overflow: hidden;
height: 100vh;
display: flex;
flex-direction: column;
}
.terminal-header {
background: #333;
padding: 8px;
border-bottom: 2px solid #666;
display: flex;
align-items: center;
gap: 8px;
}
.terminal-button {
width: 12px;
height: 12px;
border-radius: 50%;
border: none;
}
.terminal-button.close { background: #ff5f56; }
.terminal-button.minimize { background: #ffbd2e; }
.terminal-button.maximize { background: #27c93f; }
.terminal-title {
color: #fff;
font-size: 14px;
flex: 1;
text-align: center;
}
.terminal-body {
flex: 1;
padding: 25px;
overflow: hidden; /* No scrolling at all */
font-size: 18px; /* Much bigger font */
line-height: 1.5; /* More spacing */
white-space: pre-wrap;
background: #0a0a0a;
max-height: calc(100vh - 120px); /* More height */
box-sizing: border-box;
}
.terminal-body::-webkit-scrollbar {
width: 8px;
}
.terminal-body::-webkit-scrollbar-track {
background: #1a1a1a;
}
.terminal-body::-webkit-scrollbar-thumb {
background: #333;
border-radius: 4px;
}
.terminal-body::-webkit-scrollbar-thumb:hover {
background: #555;
}
.terminal-input {
background: #0a0a0a;
border: none;
color: #00ff00;
font-family: 'Courier New', 'Monaco', 'Menlo', monospace;
font-size: 18px; /* Match terminal body */
padding: 12px 25px; /* Bigger padding */
outline: none;
width: 100%;
border-top: 1px solid #333;
box-sizing: border-box;
}
.terminal-input::placeholder {
color: #666;
}
.typing-indicator {
color: #ffff00;
animation: blink 1s infinite;
}
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
.cursor {
display: inline-block;
width: 8px;
height: 16px;
background: #00ff00;
animation: cursor-blink 1s infinite;
vertical-align: text-bottom;
}
@keyframes cursor-blink {
0%, 49% { opacity: 1; }
50%, 100% { opacity: 0; }
}
.status-bar {
background: #333;
color: #00ff00;
padding: 8px 25px; /* Bigger padding */
font-size: 14px; /* Bigger status bar */
border-top: 1px solid #666;
display: flex;
justify-content: space-between;
align-items: center;
}
.status-bar > div {
flex: 1;
text-align: center;
}
.status-bar > div:first-child {
text-align: left;
}
.status-bar > div:last-child {
text-align: right;
}
.activity-detected {
color: #ff6b6b;
font-weight: bold;
}
/* Scanlines effect */
.terminal-body::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
transparent 50%,
rgba(0, 255, 0, 0.03) 50%
);
background-size: 100% 4px;
pointer-events: none;
z-index: 1;
}
.terminal-wrapper {
position: relative;
flex: 1;
display: flex;
flex-direction: column;
}
.terminal-content {
position: relative;
z-index: 2;
}
</style>
</head>
<body>
<div class="terminal-header">
<button class="terminal-button close"></button>
<button class="terminal-button minimize"></button>
<button class="terminal-button maximize"></button>
<div class="terminal-title">terminal-tamagotchi@myclub: ~$</div>
</div>
<div class="terminal-wrapper">
<div class="terminal-body" id="terminal">
<div class="terminal-content" id="terminalContent">
Initializing terminal monitor...
Scanning project files...
</div>
</div>
</div>
<input type="text" class="terminal-input" id="terminalInput" placeholder="Enter command (f=feed, p=play, r=refresh, q=quit)..." autocomplete="off">
<div class="status-bar">
<div id="statusLeft">Ready</div>
<div id="statusCenter">No activity</div>
<div id="statusRight">Connected</div>
</div>
<script>
const socket = io();
let commandHistory = [];
let historyIndex = -1;
const terminal = document.getElementById('terminalContent');
const input = document.getElementById('terminalInput');
const statusLeft = document.getElementById('statusLeft');
const statusCenter = document.getElementById('statusCenter');
const statusRight = document.getElementById('statusRight');
function updateTerminal(data) {
terminal.textContent = data.output;
// Update status - simplified to avoid conflicts
if (data.typing_detected) {
statusLeft.textContent = `ACTIVITY: ${data.recent_changes} files`;
statusLeft.className = 'activity-detected';
// Extract current file info from terminal output
const lines = data.output.split('\n');
const currentFileLine = lines.find(line => line.includes('File:'));
if (currentFileLine) {
const fileName = currentFileLine.split('File:')[1]?.trim();
statusCenter.textContent = `Editing: ${fileName}`;
} else {
statusCenter.textContent = 'Files being modified...';
}
} else {
statusLeft.textContent = 'Monitoring...';
statusLeft.className = '';
statusCenter.textContent = 'No activity';
}
// Auto-scroll to bottom
const terminalBody = document.getElementById('terminal');
terminalBody.scrollTop = terminalBody.scrollHeight;
}
function sendCommand(cmd) {
if (!cmd.trim()) return;
// Add to history
commandHistory.push(cmd);
historyIndex = commandHistory.length;
// Show command in terminal
terminal.textContent += `\n$ ${cmd}\n`;
// Send to server
console.log("Sending command:", cmd); // Debug log
socket.emit('command', { command: cmd });
// Clear input
input.value = '';
}
// Socket events
socket.on('connect', () => {
statusRight.textContent = 'Connected';
statusRight.style.color = '#00ff00';
});
socket.on('disconnect', () => {
statusRight.textContent = 'Disconnected';
statusRight.style.color = '#ff0000';
});
socket.on('terminal_update', (data) => {
updateTerminal(data);
});
socket.on('quit', (data) => {
terminal.textContent += `\n${data.message}\nConnection closed.\n`;
input.disabled = true;
input.placeholder = 'Session ended';
});
// Input handling
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
sendCommand(input.value);
} else if (e.key === 'ArrowUp') {
e.preventDefault();
if (historyIndex > 0) {
historyIndex--;
input.value = commandHistory[historyIndex];
}
} else if (e.key === 'ArrowDown') {
e.preventDefault();
if (historyIndex < commandHistory.length - 1) {
historyIndex++;
input.value = commandHistory[historyIndex];
} else {
historyIndex = commandHistory.length;
input.value = '';
}
}
});
// Focus input on page load
window.addEventListener('load', () => {
input.focus();
// Load initial data
fetch('/api/terminal-data')
.then(response => response.json())
.then(data => updateTerminal(data))
.catch(error => {
terminal.textContent += `Error loading data: ${error}\n`;
});
});
// Keep focus on terminal
document.addEventListener('click', () => {
input.focus();
});
// Add some terminal-like effects
setInterval(() => {
if (Math.random() < 0.01) { // 1% chance of flicker
terminal.style.opacity = '0.9';
setTimeout(() => {
terminal.style.opacity = '1';
}, 50);
}
}, 1000);
</script>
</body>
</html>