Files
wdmUI/mockups/palette-comparison.html

438 lines
17 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HAI · LCARS Router Console — Palette Variants</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Antonio:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<style>
/* ====== CLASSIC LCARS PALETTE ====== */
:root,
[data-palette="classic"] {
--bg: #000000;
--ink: #FF9966; /* dominant: peach */
--ink-2: #FFCC99;
--wan: #CC6666; /* warning: dim red */
--mgmt: #9999CC; /* lavender */
--cam: #FFCC66; /* yellow */
--hai: #99CC99; /* green */
--iot: #CC99CC; /* purple */
--beige: #FFCC99;
--warn: #FF6666;
--bar: #FF9966;
--bar-dim: #663322;
--cell: #111111;
--cell-2: #1a1a1a;
--hai-text: #000; /* text color when hai is the bg */
}
/* ====== COMPLEMENTARY PALETTE (180° rotated) ====== */
[data-palette="complementary"] {
--bg: #000000;
--ink: #66CCFF; /* dominant: sky cyan */
--ink-2: #99CCFF;
--wan: #66CCCC; /* warning: dim turquoise */
--mgmt: #CCCC99; /* olive-cream */
--cam: #6699FF; /* royal blue */
--hai: #CC99CC; /* mauve */
--iot: #99CC99; /* green (was purple) */
--beige: #99CCFF;
--warn: #99FFFF; /* alarm: bright cyan */
--bar: #66CCFF;
--bar-dim: #224466;
--cell: #0A0E12;
--cell-2: #141a20;
--hai-text: #000;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: var(--bg); color: var(--ink); font-family: 'Antonio', 'Arial Narrow', sans-serif; letter-spacing: 0.02em; transition: background 200ms ease, color 200ms ease; }
body { min-height: 100vh; padding: 24px; }
.mono { font-family: 'JetBrains Mono', monospace; }
button { font-family: inherit; cursor: pointer; }
/* ===== Toolbar ===== */
.toolbar {
display: flex; gap: 24px; align-items: center; margin-bottom: 24px;
flex-wrap: wrap;
}
.toolbar .group {
display: flex; gap: 8px; align-items: center;
}
.toolbar .label {
font-size: 11px; letter-spacing: 0.2em; color: var(--ink-2);
text-transform: uppercase; margin-right: 8px;
}
.toolbar button {
background: var(--bar-dim); color: var(--ink); border: none;
padding: 10px 20px; border-radius: 18px;
font-size: 13px; letter-spacing: 0.15em; text-transform: uppercase;
transition: all 120ms ease;
}
.toolbar button.active { background: var(--ink); color: #000; }
.toolbar button:hover { background: var(--bar); color: #000; }
/* Palette swatch preview */
.palette-preview {
display: flex; gap: 4px; margin-left: 8px;
}
.palette-preview .sw {
width: 18px; height: 18px; border-radius: 3px;
}
/* ===== Console chrome ===== */
.console {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: auto 1fr auto;
gap: 8px;
min-height: 820px;
}
.topbar {
grid-column: 1 / -1;
display: grid;
grid-template-columns: 200px 1fr auto;
gap: 8px;
height: 64px;
}
.topbar .corner {
background: var(--ink);
border-radius: 0 0 0 32px;
display: flex; align-items: flex-end; justify-content: flex-end;
padding: 10px 16px;
color: #000; font-weight: 700; font-size: 12px; letter-spacing: 0.3em;
}
.topbar .title-strip {
background: var(--bg);
border-bottom: 4px solid var(--ink);
display: flex; align-items: flex-end; padding: 0 16px 8px;
gap: 24px;
}
.topbar .sys-title {
font-size: 28px; font-weight: 700; letter-spacing: 0.1em;
color: var(--ink);
}
.topbar .sys-id {
font-size: 12px; color: var(--ink-2); letter-spacing: 0.25em;
margin-bottom: 4px;
}
.topbar .clock {
background: var(--ink); color: #000;
padding: 0 24px;
display: flex; align-items: center;
border-radius: 32px 0 0 0;
font-weight: 700; font-size: 14px; letter-spacing: 0.15em;
}
/* Left rail */
.leftrail {
background: var(--bg);
display: flex; flex-direction: column; gap: 4px;
}
.pill {
background: var(--bar-dim); color: var(--ink);
border: none; padding: 14px 16px; text-align: right;
font-size: 13px; letter-spacing: 0.15em; text-transform: uppercase;
border-radius: 0;
transition: all 100ms ease;
}
.pill.active { background: var(--ink); color: #000; }
.pill:hover { background: var(--bar); color: #000; }
.pill.wan { color: var(--wan); }
.pill.wan.active { background: var(--wan); color: #000; }
.pill.mgmt { color: var(--mgmt); }
.pill.mgmt.active { background: var(--mgmt); color: #000; }
.pill.cam { color: var(--cam); }
.pill.cam.active { background: var(--cam); color: #000; }
.pill.hai { color: var(--hai); }
.pill.hai.active { background: var(--hai); color: var(--hai-text); }
.pill .num {
font-family: 'JetBrains Mono', monospace;
font-size: 10px; opacity: 0.7; margin-right: 6px;
}
/* Bottom bar */
.bottombar {
grid-column: 1 / -1;
display: grid;
grid-template-columns: 200px 1fr;
gap: 8px; height: 56px;
}
.bottombar .corner-bl {
background: var(--ink);
border-radius: 32px 0 0 0;
display: flex; align-items: flex-start; justify-content: flex-end;
padding: 8px 16px; color: #000; font-weight: 700;
font-size: 11px; letter-spacing: 0.25em;
}
.status-strip {
border-top: 4px solid var(--ink);
display: flex; align-items: center; gap: 24px;
padding: 0 16px;
font-size: 12px;
font-family: 'JetBrains Mono', monospace;
}
.status-chip {
display: inline-flex; align-items: center; gap: 8px;
padding: 4px 12px; border-radius: 12px;
background: var(--cell-2);
letter-spacing: 0.1em; color: var(--ink-2);
}
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.dot.ok { background: var(--hai); box-shadow: 0 0 8px var(--hai); }
.dot.warn { background: var(--cam); box-shadow: 0 0 8px var(--cam); }
.dot.err { background: var(--warn); box-shadow: 0 0 8px var(--warn); animation: blink 1.2s infinite; }
@keyframes blink { 50% { opacity: 0.3; } }
/* Main grid */
.main {
background: var(--bg);
padding: 0 8px;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto auto auto;
gap: 12px;
}
.panel {
background: var(--cell);
border-radius: 16px;
padding: 16px 20px;
border-left: 6px solid var(--ink);
}
.panel.wide { grid-column: 1 / -1; }
.panel.wan { border-left-color: var(--wan); }
.panel.mgmt { border-left-color: var(--mgmt); }
.panel.cam { border-left-color: var(--cam); }
.panel.hai { border-left-color: var(--hai); }
.panel.iot { border-left-color: var(--iot); }
.panel h3 {
margin: 0 0 12px 0;
font-size: 13px; letter-spacing: 0.25em;
text-transform: uppercase; color: var(--ink-2);
display: flex; justify-content: space-between; align-items: baseline;
}
.panel h3 .id {
font-family: 'JetBrains Mono', monospace;
font-size: 10px; color: var(--ink);
background: var(--bar-dim);
padding: 2px 8px; border-radius: 8px;
}
.kv { display: grid; grid-template-columns: 110px 1fr; gap: 6px 12px; font-family: 'JetBrains Mono', monospace; font-size: 12px; }
.kv .k { color: var(--ink-2); letter-spacing: 0.1em; }
.kv .v { color: var(--ink); }
.kv .v.green { color: var(--hai); }
.kv .v.red { color: var(--wan); }
.kv .v.blue { color: var(--mgmt); }
.kv .v.yellow { color: var(--cam); }
/* Detail pane */
.detail-pane {
background: var(--cell);
border-radius: 16px;
padding: 16px 20px;
border-left: 6px solid var(--mgmt);
grid-column: 2; grid-row: 1 / span 3;
overflow-y: auto;
}
.detail-pane h2 {
margin: 0 0 16px 0; font-size: 22px;
letter-spacing: 0.15em; color: var(--mgmt);
}
.svclist { display: flex; flex-direction: column; gap: 6px; }
.svc {
display: grid;
grid-template-columns: 1fr auto auto;
gap: 12px; align-items: center;
background: var(--cell-2); padding: 8px 14px; border-radius: 8px;
font-family: 'JetBrains Mono', monospace; font-size: 12px;
}
.svc .name { color: var(--ink); letter-spacing: 0.1em; }
.svc .meta { color: var(--ink-2); font-size: 10px; }
.actionrow { display: flex; gap: 8px; margin-top: 12px; }
.actionrow button {
background: var(--ink); color: #000; border: none;
padding: 10px 20px; border-radius: 18px;
font-size: 12px; letter-spacing: 0.2em; text-transform: uppercase;
font-weight: 700;
}
.actionrow button.secondary { background: var(--bar-dim); color: var(--ink); }
.actionrow button.danger { background: var(--wan); color: #000; }
.notes {
background: var(--cell-2); border-radius: 12px;
padding: 16px 20px; margin-top: 16px;
border-left: 4px solid var(--mgmt);
font-size: 13px; line-height: 1.6; color: var(--ink-2);
}
.notes strong { color: var(--ink); }
@media (max-width: 900px) {
.console { grid-template-columns: 1fr; }
.topbar, .bottombar { grid-template-columns: 1fr; }
.main { grid-template-columns: 1fr; }
.detail-pane { grid-column: 1; grid-row: auto; }
.leftrail { flex-direction: row; flex-wrap: wrap; }
.pill { flex: 1 1 30%; text-align: center; padding: 10px; font-size: 11px; }
}
</style>
</head>
<body data-palette="classic">
<div class="toolbar">
<div class="group">
<span class="label">Palette</span>
<button class="pal-btn active" data-palette="classic">Classic</button>
<button class="pal-btn" data-palette="complementary">Complementary</button>
</div>
<div class="palette-preview" id="preview"></div>
</div>
<div class="console">
<div class="topbar">
<div class="corner">HAI · 47-A</div>
<div class="title-strip">
<div class="sys-id">ROUTER ID 8B-2F-A1 · SITE LAB · OPENWRT 23.05</div>
<div class="sys-title">BRIDGE OPS</div>
</div>
<div class="clock mono" id="clock">2026.05.01 · 19:27:25</div>
</div>
<div class="leftrail">
<button class="pill active"><span class="num">10</span>OVERVIEW</button>
<button class="pill wan"><span class="num">20</span>WAN</button>
<button class="pill"><span class="num">30</span>VLAN-FW</button>
<button class="pill cam"><span class="num">31</span>CAMS</button>
<button class="pill hai"><span class="num">32</span>HAI</button>
<button class="pill mgmt"><span class="num">33</span>MGMT</button>
<button class="pill"><span class="num">40</span>DHCP/DNS</button>
<button class="pill"><span class="num">50</span>WIFI</button>
<button class="pill mgmt"><span class="num">60</span>TAILSCALE</button>
<button class="pill"><span class="num">70</span>MQTT BR</button>
<button class="pill"><span class="num">80</span>SERVICES</button>
<button class="pill"><span class="num">90</span>GITOPS</button>
<button class="pill"><span class="num">99</span>LOGS</button>
</div>
<div class="main">
<div class="panel wan">
<h3>WAN <span class="id">IF-WAN0</span></h3>
<div class="kv">
<span class="k">STATE</span><span class="v red">UP · DHCP</span>
<span class="k">IPv4</span><span class="v">192.0.2.47/24</span>
<span class="k">GW</span><span class="v">192.0.2.1</span>
<span class="k">UPTIME</span><span class="v">14d 03h</span>
<span class="k">FAILOVER</span><span class="v">mwan3 · LTE standby</span>
</div>
</div>
<div class="panel hai">
<h3>HAI DEVICE <span class="id">VLAN-20</span></h3>
<div class="kv">
<span class="k">DEVICE</span><span class="v green">RK3588 · ONLINE</span>
<span class="k">IP</span><span class="v">192.168.20.10</span>
<span class="k">MQTT</span><span class="v green">CONNECTED</span>
<span class="k">FRIGATE</span><span class="v green">RUNNING · NPU</span>
<span class="k">LAST EVT</span><span class="v">12s ago</span>
</div>
</div>
<div class="panel cam wide">
<h3>CAMERAS <span class="id">VLAN-10 · QUARANTINED</span></h3>
<div class="kv" style="grid-template-columns: 80px 1fr 80px 1fr;">
<span class="k">CAM-01</span><span class="v yellow">192.168.10.11 · RTSP OK</span>
<span class="k">CAM-02</span><span class="v yellow">192.168.10.12 · RTSP OK</span>
<span class="k">CAM-03</span><span class="v yellow">192.168.10.13 · RTSP OK</span>
<span class="k">CAM-04</span><span class="v red">192.168.10.14 · OFFLINE</span>
<span class="k">DNS BLOCK</span><span class="v">847 calls today</span>
<span class="k">EGRESS</span><span class="v red">DENIED · ALL</span>
</div>
</div>
<div class="detail-pane">
<h2 class="mono">▸ OVERVIEW</h2>
<div class="kv" style="margin-bottom: 16px;">
<span class="k">SITE</span><span class="v">site-lab</span>
<span class="k">FLEET</span><span class="v">hai-edge / 4 cams · 1 hai</span>
<span class="k">CONFIG REV</span><span class="v">git: a3f8b21 · clean</span>
<span class="k">LAST PUSH</span><span class="v">2h 14m ago by ops</span>
<span class="k">TS NODE</span><span class="v blue">router-site-lab.tail-net.ts</span>
</div>
<h3 style="font-size: 11px; color: var(--ink-2); letter-spacing: 0.25em; margin: 16px 0 8px;">SUBSYSTEMS</h3>
<div class="svclist">
<div class="svc"><span class="name">dnsmasq</span><span class="meta">14d 03h</span><span class="dot ok"></span></div>
<div class="svc"><span class="name">mosquitto</span><span class="meta">14d 03h</span><span class="dot ok"></span></div>
<div class="svc"><span class="name">mqtt-bridge → hub</span><span class="meta">connected · q:0</span><span class="dot ok"></span></div>
<div class="svc"><span class="name">tailscaled</span><span class="meta">peer × 7</span><span class="dot ok"></span></div>
<div class="svc"><span class="name">chrony (ntp)</span><span class="meta">offset ±2ms</span><span class="dot ok"></span></div>
<div class="svc"><span class="name">node_exporter</span><span class="meta">:9100</span><span class="dot ok"></span></div>
<div class="svc"><span class="name">adblock-dns</span><span class="meta">12.4k entries</span><span class="dot warn"></span></div>
</div>
<div class="actionrow">
<button>RECONCILE</button>
<button class="secondary">PULL CONFIG</button>
<button class="danger">REBOOT</button>
</div>
<div class="notes">
<strong>Palette logic preserved:</strong> dominant warm / cool, accent for warnings, distinct hue per VLAN domain. The complementary variant rotates the wheel 180° but keeps the same semantic mappings — cyan replaces peach as the "nominal" color, mauve becomes the HAI compute domain, royal blue marks the camera quarantine. The same panel reads identically in both modes.
</div>
</div>
</div>
<div class="bottombar">
<div class="corner-bl">STATUS · NOMINAL</div>
<div class="status-strip">
<span class="status-chip"><span class="dot ok"></span>WAN UP</span>
<span class="status-chip"><span class="dot ok"></span>MQTT BR</span>
<span class="status-chip"><span class="dot ok"></span>TS PEERS 7</span>
<span class="status-chip"><span class="dot warn"></span>CAM-04 OFFLINE</span>
<span class="status-chip"><span class="dot ok"></span>GIT CLEAN</span>
<span class="status-chip">CPU 18% · MEM 42% · LOAD 0.31</span>
</div>
</div>
</div>
<script>
// Palette swap
const previewEl = document.getElementById('preview');
function renderPreview() {
const cs = getComputedStyle(document.body);
const tokens = ['--ink', '--wan', '--mgmt', '--cam', '--hai', '--iot'];
previewEl.innerHTML = tokens
.map(t => `<div class="sw" style="background:${cs.getPropertyValue(t).trim()}" title="${t}"></div>`)
.join('');
}
document.querySelectorAll('.pal-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.pal-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
document.body.dataset.palette = btn.dataset.palette;
renderPreview();
});
});
renderPreview();
// Live clock
function tick() {
const now = new Date();
const pad = n => String(n).padStart(2, '0');
document.getElementById('clock').textContent =
`${now.getFullYear()}.${pad(now.getMonth()+1)}.${pad(now.getDate())} · ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
}
tick(); setInterval(tick, 1000);
</script>
</body>
</html>