logs-test / public /index.html
ulduldp's picture
Update public/index.html
dbe47f5 verified
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Live Logs</title>
<style>
body {
margin: 0;
background: #0b1020;
color: #e2e8f0;
font-family: monospace;
display: flex;
flex-direction: column;
height: 90vh;
}
header {
padding: 10px;
background: #111827;
border-bottom: 1px solid #1f2937;
}
#logs {
flex: 1;
overflow-y: auto;
padding: 10px;
font-size: 13px;
}
.log {
margin-bottom: 6px;
word-break: break-word;
}
.time {
color: #64748b;
margin-right: 6px;
}
footer {
position: relative;
display: flex;
padding: 8px;
background: #111827;
border-top: 1px solid #1f2937;
}
input {
flex: 1;
padding: 10px;
background: #0b1020;
border: none;
color: white;
border-radius: 6px;
outline: none;
}
button {
margin-left: 8px;
padding: 10px 14px;
background: #2563eb;
border: none;
color: white;
border-radius: 6px;
}
#suggestions {
position: absolute;
bottom: 60px;
left: 10px;
right: 10px;
background: #111827;
border: 1px solid #1f2937;
border-radius: 6px;
max-height: 150px;
overflow-y: auto;
display: none;
z-index: 10;
}
.suggestion-item {
padding: 8px;
cursor: pointer;
}
.suggestion-item:hover {
background: #1f2937;
}
</style>
</head>
<body>
<header>📡 Live Logs Terminal</header>
<div id="logs"></div>
<footer>
<input id="cmd" placeholder="Enter command..." autocomplete="off" />
<button onclick="sendCmd()">Send</button>
<div id="suggestions"></div>
</footer>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
const logsDiv = document.getElementById('logs');
const input = document.getElementById('cmd');
const suggestionBox = document.getElementById('suggestions');
// ===== CONFIG =====
const LIMIT = 50;
const MAX_DOM_LOGS = 200;
let offset = 0;
let loading = false;
let hasMore = true;
// ===== TIME =====
function formatTime(ts) {
return new Date(ts).toLocaleString('en-IN', {
timeZone: 'Asia/Kolkata',
hour12: false
});
}
// ===== CREATE LOG ELEMENT =====
function createLogElement(log) {
const div = document.createElement('div');
div.className = 'log';
div.innerHTML = `
<span class="time">[${formatTime(log.timestamp)}]</span>
${log.html}
`;
return div;
}
// ===== LIVE LOG ADD =====
function addLog(log) {
const div = createLogElement(log);
const isNearBottom =
logsDiv.scrollHeight - logsDiv.scrollTop <= logsDiv.clientHeight + 50;
logsDiv.appendChild(div);
// 🧹 DOM cleanup
if (logsDiv.children.length > MAX_DOM_LOGS) {
logsDiv.removeChild(logsDiv.firstChild);
}
if (isNearBottom) {
logsDiv.scrollTop = logsDiv.scrollHeight;
}
}
// ===== LOAD OLD LOGS (PAGINATION) =====
async function loadLogs() {
if (loading || !hasMore) return;
loading = true;
const res = await fetch(`/api/logs?limit=${LIMIT}&offset=${offset}`);
const data = await res.json();
hasMore = data.hasMore;
const prevHeight = logsDiv.scrollHeight;
data.logs.reverse().forEach(log => {
logsDiv.prepend(createLogElement(log));
});
offset += data.logs.length;
// maintain scroll position
logsDiv.scrollTop = logsDiv.scrollHeight - prevHeight;
loading = false;
}
// ===== HISTORY =====
function getHistory() {
return JSON.parse(localStorage.getItem('cmd_history') || '[]');
}
function saveToHistory(cmd) {
let history = getHistory();
history = history.filter(c => c !== cmd);
history.unshift(cmd);
if (history.length > 50) history.pop();
localStorage.setItem('cmd_history', JSON.stringify(history));
}
// ===== SUGGESTIONS =====
function showSuggestions(value) {
const history = getHistory();
const filtered = history.filter(cmd =>
cmd.toLowerCase().includes(value.toLowerCase())
);
if (!value || filtered.length === 0) {
suggestionBox.style.display = 'none';
return;
}
suggestionBox.innerHTML = '';
filtered.slice(0, 5).forEach(cmd => {
const div = document.createElement('div');
div.className = 'suggestion-item';
div.textContent = cmd;
div.onclick = () => {
input.value = cmd;
suggestionBox.style.display = 'none';
};
suggestionBox.appendChild(div);
});
suggestionBox.style.display = 'block';
}
// ===== EVENTS =====
input.addEventListener('input', () => {
showSuggestions(input.value);
});
input.addEventListener('keypress', e => {
if (e.key === 'Enter') sendCmd();
});
// ===== SEND COMMAND =====
function sendCmd() {
const val = input.value.trim();
if (!val) return;
socket.emit('command', { command: val });
saveToHistory(val);
input.value = '';
suggestionBox.style.display = 'none';
if (val === "clear") {
logsDiv.innerHTML = "";
offset = 0;
hasMore = true;
return;
}
}
// ===== SCROLL LOAD =====
logsDiv.addEventListener('scroll', () => {
if (logsDiv.scrollTop < 50) {
loadLogs();
}
});
// ===== INIT =====
loadLogs();
// ===== LIVE SOCKET =====
socket.on('log', addLog);
</script>
</body>
</html>