479 lines
14 KiB
HTML
479 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
NEXUS COMPONENT PROTOTYPE: Portal Status Wall
|
|
Refs: #749 (Vibe Code prototype), #714 (portal status)
|
|
Design: dark space / holographic — matches Nexus design system
|
|
-->
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Portal Status Wall — Nexus Component</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600&family=Orbitron:wght@400;600;700&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root {
|
|
--color-bg: #050510;
|
|
--color-surface: rgba(10, 15, 40, 0.85);
|
|
--color-border: rgba(74, 240, 192, 0.2);
|
|
--color-border-bright:rgba(74, 240, 192, 0.5);
|
|
--color-text: #e0f0ff;
|
|
--color-text-muted: #8a9ab8;
|
|
--color-primary: #4af0c0;
|
|
--color-primary-dim: rgba(74, 240, 192, 0.15);
|
|
--color-secondary: #7b5cff;
|
|
--color-danger: #ff4466;
|
|
--color-warning: #ffaa22;
|
|
--color-gold: #ffd700;
|
|
--font-display: 'Orbitron', sans-serif;
|
|
--font-body: 'JetBrains Mono', monospace;
|
|
--panel-blur: 16px;
|
|
--panel-radius: 8px;
|
|
--transition: 200ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
}
|
|
|
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
|
|
body {
|
|
background: var(--color-bg);
|
|
font-family: var(--font-body);
|
|
color: var(--color-text);
|
|
min-height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 24px;
|
|
}
|
|
|
|
/* === PORTAL STATUS WALL === */
|
|
.portal-wall {
|
|
width: 100%;
|
|
max-width: 900px;
|
|
}
|
|
|
|
.panel-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.panel-title {
|
|
font-family: var(--font-display);
|
|
font-size: 13px;
|
|
letter-spacing: 0.15em;
|
|
text-transform: uppercase;
|
|
color: var(--color-primary);
|
|
}
|
|
|
|
.panel-title-bar {
|
|
flex: 1;
|
|
height: 1px;
|
|
background: linear-gradient(90deg, var(--color-border-bright) 0%, transparent 100%);
|
|
}
|
|
|
|
.pulse-dot {
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
background: var(--color-primary);
|
|
animation: pulse 2s ease-in-out infinite;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0%, 100% { opacity: 1; box-shadow: 0 0 6px var(--color-primary); }
|
|
50% { opacity: 0.4; box-shadow: none; }
|
|
}
|
|
|
|
/* Portal Grid */
|
|
.portal-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
|
gap: 12px;
|
|
}
|
|
|
|
.portal-card {
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--panel-radius);
|
|
padding: 16px;
|
|
backdrop-filter: blur(var(--panel-blur));
|
|
position: relative;
|
|
overflow: hidden;
|
|
transition: border-color var(--transition), box-shadow var(--transition);
|
|
cursor: default;
|
|
}
|
|
|
|
.portal-card:hover {
|
|
border-color: var(--color-border-bright);
|
|
box-shadow: 0 0 20px rgba(74, 240, 192, 0.08);
|
|
}
|
|
|
|
/* Status indicator stripe */
|
|
.portal-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0; left: 0;
|
|
width: 3px; height: 100%;
|
|
border-radius: var(--panel-radius) 0 0 var(--panel-radius);
|
|
}
|
|
|
|
.portal-card.status-online::before { background: var(--color-primary); }
|
|
.portal-card.status-warning::before { background: var(--color-warning); }
|
|
.portal-card.status-offline::before { background: var(--color-danger); }
|
|
.portal-card.status-locked::before { background: var(--color-secondary); }
|
|
|
|
.portal-header {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
margin-bottom: 10px;
|
|
padding-left: 8px;
|
|
}
|
|
|
|
.portal-name {
|
|
font-family: var(--font-display);
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
letter-spacing: 0.1em;
|
|
color: var(--color-text);
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.portal-id {
|
|
font-size: 10px;
|
|
color: var(--color-text-muted);
|
|
margin-top: 2px;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
|
|
.status-badge {
|
|
font-size: 10px;
|
|
letter-spacing: 0.1em;
|
|
text-transform: uppercase;
|
|
padding: 3px 8px;
|
|
border-radius: 3px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.status-badge.online { color: var(--color-primary); background: rgba(74, 240, 192, 0.12); }
|
|
.status-badge.warning { color: var(--color-warning); background: rgba(255, 170, 34, 0.12); }
|
|
.status-badge.offline { color: var(--color-danger); background: rgba(255, 68, 102, 0.12); }
|
|
.status-badge.locked { color: var(--color-secondary); background: rgba(123, 92, 255, 0.12); }
|
|
|
|
.portal-meta {
|
|
padding-left: 8px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
}
|
|
|
|
.meta-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
font-size: 11px;
|
|
}
|
|
|
|
.meta-label { color: var(--color-text-muted); }
|
|
.meta-value { color: var(--color-text); }
|
|
.meta-value.highlight { color: var(--color-primary); }
|
|
|
|
.portal-latency-bar {
|
|
margin-top: 12px;
|
|
padding-left: 8px;
|
|
}
|
|
|
|
.latency-track {
|
|
height: 3px;
|
|
background: rgba(255,255,255,0.06);
|
|
border-radius: 2px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.latency-fill {
|
|
height: 100%;
|
|
border-radius: 2px;
|
|
transition: width 0.5s ease;
|
|
}
|
|
|
|
.latency-fill.good { background: var(--color-primary); }
|
|
.latency-fill.fair { background: var(--color-warning); }
|
|
.latency-fill.poor { background: var(--color-danger); }
|
|
|
|
.latency-label {
|
|
font-size: 10px;
|
|
color: var(--color-text-muted);
|
|
margin-top: 4px;
|
|
}
|
|
|
|
/* Summary bar */
|
|
.summary-bar {
|
|
display: flex;
|
|
gap: 24px;
|
|
margin-top: 16px;
|
|
padding: 12px 16px;
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--panel-radius);
|
|
backdrop-filter: blur(var(--panel-blur));
|
|
}
|
|
|
|
.summary-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.summary-count {
|
|
font-family: var(--font-display);
|
|
font-size: 20px;
|
|
font-weight: 700;
|
|
line-height: 1;
|
|
}
|
|
|
|
.summary-label {
|
|
color: var(--color-text-muted);
|
|
font-size: 10px;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="portal-wall">
|
|
|
|
<div class="panel-header">
|
|
<div class="pulse-dot"></div>
|
|
<span class="panel-title">Portal Status Wall</span>
|
|
<div class="panel-title-bar"></div>
|
|
<span style="font-size:11px;color:var(--color-text-muted)">LIVE</span>
|
|
</div>
|
|
|
|
<div class="portal-grid">
|
|
|
|
<!-- Portal: Hermes -->
|
|
<div class="portal-card status-online">
|
|
<div class="portal-header">
|
|
<div>
|
|
<div class="portal-name">Hermes</div>
|
|
<div class="portal-id">portal://hermes.nexus</div>
|
|
</div>
|
|
<span class="status-badge online">online</span>
|
|
</div>
|
|
<div class="portal-meta">
|
|
<div class="meta-row">
|
|
<span class="meta-label">Type</span>
|
|
<span class="meta-value">Comm Bridge</span>
|
|
</div>
|
|
<div class="meta-row">
|
|
<span class="meta-label">Agents</span>
|
|
<span class="meta-value highlight">3 active</span>
|
|
</div>
|
|
<div class="meta-row">
|
|
<span class="meta-label">Last beat</span>
|
|
<span class="meta-value">2s ago</span>
|
|
</div>
|
|
</div>
|
|
<div class="portal-latency-bar">
|
|
<div class="latency-track">
|
|
<div class="latency-fill good" style="width:22%"></div>
|
|
</div>
|
|
<div class="latency-label">22ms latency</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Portal: Archive -->
|
|
<div class="portal-card status-online">
|
|
<div class="portal-header">
|
|
<div>
|
|
<div class="portal-name">Archive</div>
|
|
<div class="portal-id">portal://archive.nexus</div>
|
|
</div>
|
|
<span class="status-badge online">online</span>
|
|
</div>
|
|
<div class="portal-meta">
|
|
<div class="meta-row">
|
|
<span class="meta-label">Type</span>
|
|
<span class="meta-value">Memory Store</span>
|
|
</div>
|
|
<div class="meta-row">
|
|
<span class="meta-label">Records</span>
|
|
<span class="meta-value highlight">14,822</span>
|
|
</div>
|
|
<div class="meta-row">
|
|
<span class="meta-label">Last write</span>
|
|
<span class="meta-value">41s ago</span>
|
|
</div>
|
|
</div>
|
|
<div class="portal-latency-bar">
|
|
<div class="latency-track">
|
|
<div class="latency-fill good" style="width:8%"></div>
|
|
</div>
|
|
<div class="latency-label">8ms latency</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Portal: Satflow -->
|
|
<div class="portal-card status-warning">
|
|
<div class="portal-header">
|
|
<div>
|
|
<div class="portal-name">Satflow</div>
|
|
<div class="portal-id">portal://satflow.nexus</div>
|
|
</div>
|
|
<span class="status-badge warning">degraded</span>
|
|
</div>
|
|
<div class="portal-meta">
|
|
<div class="meta-row">
|
|
<span class="meta-label">Type</span>
|
|
<span class="meta-value">Economy</span>
|
|
</div>
|
|
<div class="meta-row">
|
|
<span class="meta-label">Queue</span>
|
|
<span class="meta-value" style="color:var(--color-warning)">87 pending</span>
|
|
</div>
|
|
<div class="meta-row">
|
|
<span class="meta-label">Last beat</span>
|
|
<span class="meta-value">18s ago</span>
|
|
</div>
|
|
</div>
|
|
<div class="portal-latency-bar">
|
|
<div class="latency-track">
|
|
<div class="latency-fill fair" style="width:61%"></div>
|
|
</div>
|
|
<div class="latency-label">610ms latency</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Portal: Evennia -->
|
|
<div class="portal-card status-online">
|
|
<div class="portal-header">
|
|
<div>
|
|
<div class="portal-name">Evennia</div>
|
|
<div class="portal-id">portal://evennia.nexus</div>
|
|
</div>
|
|
<span class="status-badge online">online</span>
|
|
</div>
|
|
<div class="portal-meta">
|
|
<div class="meta-row">
|
|
<span class="meta-label">Type</span>
|
|
<span class="meta-value">World Engine</span>
|
|
</div>
|
|
<div class="meta-row">
|
|
<span class="meta-label">Players</span>
|
|
<span class="meta-value highlight">1 online</span>
|
|
</div>
|
|
<div class="meta-row">
|
|
<span class="meta-label">Uptime</span>
|
|
<span class="meta-value">6h 14m</span>
|
|
</div>
|
|
</div>
|
|
<div class="portal-latency-bar">
|
|
<div class="latency-track">
|
|
<div class="latency-fill good" style="width:15%"></div>
|
|
</div>
|
|
<div class="latency-label">15ms latency</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Portal: Bannerlord -->
|
|
<div class="portal-card status-offline">
|
|
<div class="portal-header">
|
|
<div>
|
|
<div class="portal-name">Bannerlord</div>
|
|
<div class="portal-id">portal://bannerlord.nexus</div>
|
|
</div>
|
|
<span class="status-badge offline">offline</span>
|
|
</div>
|
|
<div class="portal-meta">
|
|
<div class="meta-row">
|
|
<span class="meta-label">Type</span>
|
|
<span class="meta-value">Game MCP</span>
|
|
</div>
|
|
<div class="meta-row">
|
|
<span class="meta-label">Last seen</span>
|
|
<span class="meta-value" style="color:var(--color-danger)">2h ago</span>
|
|
</div>
|
|
<div class="meta-row">
|
|
<span class="meta-label">Error</span>
|
|
<span class="meta-value" style="color:var(--color-danger)">connection reset</span>
|
|
</div>
|
|
</div>
|
|
<div class="portal-latency-bar">
|
|
<div class="latency-track">
|
|
<div class="latency-fill poor" style="width:100%"></div>
|
|
</div>
|
|
<div class="latency-label">timeout</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Portal: OpenClaw -->
|
|
<div class="portal-card status-locked">
|
|
<div class="portal-header">
|
|
<div>
|
|
<div class="portal-name">OpenClaw</div>
|
|
<div class="portal-id">portal://openclaw.nexus</div>
|
|
</div>
|
|
<span class="status-badge locked">locked</span>
|
|
</div>
|
|
<div class="portal-meta">
|
|
<div class="meta-row">
|
|
<span class="meta-label">Type</span>
|
|
<span class="meta-value">Sidecar AI</span>
|
|
</div>
|
|
<div class="meta-row">
|
|
<span class="meta-label">Role</span>
|
|
<span class="meta-value" style="color:var(--color-secondary)">observer only</span>
|
|
</div>
|
|
<div class="meta-row">
|
|
<span class="meta-label">Auth</span>
|
|
<span class="meta-value">requires token</span>
|
|
</div>
|
|
</div>
|
|
<div class="portal-latency-bar">
|
|
<div class="latency-track">
|
|
<div class="latency-fill" style="width:0%;background:var(--color-secondary)"></div>
|
|
</div>
|
|
<div class="latency-label">access gated</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- /portal-grid -->
|
|
|
|
<!-- Summary Bar -->
|
|
<div class="summary-bar">
|
|
<div class="summary-item">
|
|
<div>
|
|
<div class="summary-count" style="color:var(--color-primary)">4</div>
|
|
<div class="summary-label">Online</div>
|
|
</div>
|
|
</div>
|
|
<div class="summary-item">
|
|
<div>
|
|
<div class="summary-count" style="color:var(--color-warning)">1</div>
|
|
<div class="summary-label">Degraded</div>
|
|
</div>
|
|
</div>
|
|
<div class="summary-item">
|
|
<div>
|
|
<div class="summary-count" style="color:var(--color-danger)">1</div>
|
|
<div class="summary-label">Offline</div>
|
|
</div>
|
|
</div>
|
|
<div class="summary-item">
|
|
<div>
|
|
<div class="summary-count" style="color:var(--color-secondary)">1</div>
|
|
<div class="summary-label">Locked</div>
|
|
</div>
|
|
</div>
|
|
<div style="margin-left:auto;align-self:center;font-size:10px;color:var(--color-text-muted)">
|
|
LAST SYNC: <span style="color:var(--color-text)">04:20:07 UTC</span>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</body>
|
|
</html>
|