feat: scaffold HTML v2 — full-width desktop layout, no terminal panel
This commit is contained in:
@@ -0,0 +1,131 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{{TITLE}}</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg: #0a0f0c;
|
||||||
|
--panel-bg: #111a15;
|
||||||
|
--border: #2a3a2e;
|
||||||
|
--text: #aaccaa;
|
||||||
|
--text-dim: #557755;
|
||||||
|
--accent: #33ff66;
|
||||||
|
}
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text);
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 14px;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
#content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
#log-feed {
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
padding: 8px 12px;
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
#log-feed h3 {
|
||||||
|
color: var(--text-dim);
|
||||||
|
font-size: 11px;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.log-entry {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-dim);
|
||||||
|
padding: 2px 0;
|
||||||
|
}
|
||||||
|
.log-entry .log-time {
|
||||||
|
color: var(--accent);
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
#status {
|
||||||
|
background: var(--panel-bg);
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
padding: 4px 12px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-dim);
|
||||||
|
}
|
||||||
|
#status.connected { color: var(--accent); }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="content">
|
||||||
|
<h1 style="color: var(--accent); font-size: 18px;">{{TITLE}}</h1>
|
||||||
|
<p style="color: var(--text-dim); margin-top: 8px;">{{DESCRIPTION}}</p>
|
||||||
|
<p style="color: var(--text-dim); margin-top: 16px;">Waiting for content...</p>
|
||||||
|
</div>
|
||||||
|
<div id="log-feed">
|
||||||
|
<h3>Session Log</h3>
|
||||||
|
<div id="log-entries"></div>
|
||||||
|
</div>
|
||||||
|
<div id="status">Connecting...</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const WS_URL = `ws://${location.host}/ws`;
|
||||||
|
let ws;
|
||||||
|
|
||||||
|
function connect() {
|
||||||
|
ws = new WebSocket(WS_URL);
|
||||||
|
ws.onopen = () => {
|
||||||
|
document.getElementById('status').textContent = 'Connected';
|
||||||
|
document.getElementById('status').className = 'connected';
|
||||||
|
};
|
||||||
|
ws.onclose = () => {
|
||||||
|
document.getElementById('status').textContent = 'Disconnected — reconnecting...';
|
||||||
|
document.getElementById('status').className = '';
|
||||||
|
setTimeout(connect, 2000);
|
||||||
|
};
|
||||||
|
ws.onmessage = (e) => {
|
||||||
|
const msg = JSON.parse(e.data);
|
||||||
|
if (msg.type === 'state') handleState(msg.state);
|
||||||
|
if (msg.type === 'log') handleLog(msg.entry);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleState(state) {
|
||||||
|
if (state.template) {
|
||||||
|
document.getElementById('content').innerHTML = state.template;
|
||||||
|
}
|
||||||
|
if (state.styles) {
|
||||||
|
let el = document.getElementById('dynamic-styles');
|
||||||
|
if (!el) { el = document.createElement('style'); el.id = 'dynamic-styles'; document.head.appendChild(el); }
|
||||||
|
el.textContent = state.styles;
|
||||||
|
}
|
||||||
|
if (state.script) {
|
||||||
|
try { new Function(state.script)(); } catch(e) { console.error('Script error:', e); }
|
||||||
|
}
|
||||||
|
window.__workbench_state = state;
|
||||||
|
try { localStorage.setItem('workbench-state', JSON.stringify(state)); } catch(e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleLog(entry) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.className = 'log-entry';
|
||||||
|
const time = new Date().toLocaleTimeString();
|
||||||
|
div.innerHTML = `<span class="log-time">${time}</span>${entry}`;
|
||||||
|
const feed = document.getElementById('log-entries');
|
||||||
|
feed.appendChild(div);
|
||||||
|
feed.scrollTop = feed.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const saved = JSON.parse(localStorage.getItem('workbench-state'));
|
||||||
|
if (saved) handleState(saved);
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
|
connect();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user