initial: cmd-palette widget, written for Silas
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>cmd</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
html, body { height: 100%; background: #0f1117; color: #e0e0e0; font-family: monospace; }
|
||||
body { padding: 12px; display: flex; flex-direction: column; gap: 8px; }
|
||||
.cmd-row { display: flex; gap: 8px; align-items: flex-start; }
|
||||
.cmd-text { flex: 1; background: #1a1d27; color: #7ec8e3; border: 1px solid #2a2d37;
|
||||
border-radius: 6px; padding: 10px 12px; font-size: 0.78rem; font-family: monospace;
|
||||
white-space: pre-wrap; word-break: break-all; cursor: default; user-select: text; }
|
||||
.cmd-copy { padding: 6px 10px; background: #2a2d37; color: #aaa; border: 1px solid #3a3d47;
|
||||
border-radius: 4px; font-family: monospace; font-size: 0.75rem; cursor: pointer;
|
||||
white-space: nowrap; flex-shrink: 0; }
|
||||
.cmd-copy:hover { background: #3a3d47; color: #e0e0e0; }
|
||||
.cmd-copy.ok { color: #22c55e; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="status-bar" style="font-size:0.7rem;color:#444;margin-bottom:2px">refreshing in 5s</div>
|
||||
<div id="loaded-ts" style="font-size:0.68rem;color:#555;margin-bottom:6px">loaded: —</div>
|
||||
<div id="commands"></div>
|
||||
<script>
|
||||
/* COMMANDS_START */
|
||||
var _ts = "";
|
||||
var _cmds = [
|
||||
"sudo curl -s -u \"admin:Git.jhestyr.net123\" \"https://git.jhestyr.net/api/v1/repos/admin/istrain/raw/sdr/software/analyzer/server.js?ref=e844af2\" -o /mnt/tank/apps/istrain-analyzer/server.js && sudo docker restart istrain-analyzer-1 && echo \"analyzer ok\"",
|
||||
"echo \"[]\" | sudo tee /mnt/tank/apps/istrain/data/train_events.json && echo \"cleared\""
|
||||
];
|
||||
/* COMMANDS_END */
|
||||
function render(cmds) {
|
||||
const el = document.getElementById('commands');
|
||||
el.innerHTML = '';
|
||||
cmds.forEach(cmd => {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'cmd-row';
|
||||
const text = document.createElement('div');
|
||||
text.className = 'cmd-text';
|
||||
text.textContent = cmd;
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'cmd-copy';
|
||||
btn.textContent = 'copy';
|
||||
btn.onclick = () => {
|
||||
navigator.clipboard.writeText(cmd).then(() => {
|
||||
btn.textContent = 'ok'; btn.classList.add('ok');
|
||||
setTimeout(() => { btn.textContent = 'copy'; btn.classList.remove('ok'); }, 1500);
|
||||
});
|
||||
};
|
||||
row.appendChild(text);
|
||||
row.appendChild(btn);
|
||||
el.appendChild(row);
|
||||
});
|
||||
}
|
||||
function timeAgo(tsStr) {
|
||||
if (!tsStr) return '';
|
||||
const d = new Date(tsStr.replace(' ', 'T'));
|
||||
if (isNaN(d)) return '';
|
||||
const secs = Math.floor((Date.now() - d) / 1000);
|
||||
if (secs < 60) return secs + 's ago';
|
||||
if (secs < 3600) return Math.floor(secs / 60) + 'm ago';
|
||||
return Math.floor(secs / 3600) + 'h ' + Math.floor((secs % 3600) / 60) + 'm ago';
|
||||
}
|
||||
function updateTs(ts) {
|
||||
const ago = timeAgo(ts);
|
||||
document.getElementById('loaded-ts').textContent = 'loaded: ' + (ts || '—') + (ago ? ' · ' + ago : '');
|
||||
}
|
||||
render(_cmds);
|
||||
updateTs(_ts);
|
||||
let countdown = 5;
|
||||
let _currentTs = _ts;
|
||||
const bar = document.getElementById('status-bar');
|
||||
setInterval(() => {
|
||||
countdown--;
|
||||
updateTs(_currentTs);
|
||||
bar.textContent = countdown > 0 ? 'refreshing in ' + countdown + 's' : 'refreshing...';
|
||||
if (countdown <= 0) {
|
||||
countdown = 5;
|
||||
fetch(location.href + '?t=' + Date.now()).then(r => r.text()).then(html => {
|
||||
const m = html.match(/\/\* COMMANDS_START \*\/[\s\S]*?var _cmds = (\[[\s\S]*?\]);\s*\/\* COMMANDS_END \*\//);
|
||||
const tm = html.match(/var _ts = "([^"]*)";/);
|
||||
if (m) render(JSON.parse(m[1]));
|
||||
if (tm) { _currentTs = tm[1]; updateTs(_currentTs); }
|
||||
}).catch(() => {});
|
||||
}
|
||||
}, 1000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user