// ─── Shared UI Primitives ─────────────────────────────────────────────────── // Exports: Panel, HexKPI, StatusBadge, SCPButton, Modal, DataTable, // CornerFrame, GlowDot, SectionLabel, InputField, Toggle, CodeEditor const uiStyles = ` .panel { background: rgba(0, 15, 35, 0.85); border: 1px solid rgba(0, 180, 255, 0.2); position: relative; overflow: hidden; } .panel::before { content: ''; position: absolute; inset: 0; background: linear-gradient(135deg, rgba(0,200,255,0.03) 0%, transparent 60%); pointer-events: none; } .panel-corner { position: absolute; width: 10px; height: 10px; border-color: rgba(0,200,255,0.7); border-style: solid; } .panel-corner.tl { top: 0; left: 0; border-width: 2px 0 0 2px; } .panel-corner.tr { top: 0; right: 0; border-width: 2px 2px 0 0; } .panel-corner.bl { bottom: 0; left: 0; border-width: 0 0 2px 2px; } .panel-corner.br { bottom: 0; right: 0; border-width: 0 2px 2px 0; } .scp-btn { background: transparent; border: 1px solid currentColor; color: inherit; font-family: 'Share Tech Mono', monospace; font-size: 14px; letter-spacing: 0.12em; text-transform: uppercase; cursor: pointer; padding: 6px 13px; transition: all 0.15s; position: relative; overflow: hidden; } .scp-btn::before { content: ''; position: absolute; inset: 0; background: currentColor; opacity: 0; transition: opacity 0.15s; } .scp-btn:hover::before { opacity: 0.12; } .scp-btn:active::before { opacity: 0.25; } .scp-btn:disabled { opacity: 0.35; cursor: not-allowed; } .modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.7); backdrop-filter: blur(4px); z-index: 1000; display: flex; align-items: center; justify-content: center; } .modal-box { background: #020c1e; border: 1px solid rgba(0,200,255,0.4); box-shadow: 0 0 40px rgba(0,200,255,0.15), 0 0 80px rgba(0,0,0,0.8); min-width: 500px; max-width: 90vw; max-height: 85vh; display: flex; flex-direction: column; position: relative; } .modal-header { padding: 14px 20px; border-bottom: 1px solid rgba(0,200,255,0.2); display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; font-size: 14px; } .modal-body { padding: 20px; overflow-y: auto; flex: 1; } .code-editor { width: 100%; background: rgba(0,5,15,0.9); border: 1px solid rgba(0,200,255,0.2); color: #00ff88; font-family: 'Share Tech Mono', monospace; font-size: 14px; line-height: 1.6; padding: 12px; resize: vertical; outline: none; box-sizing: border-box; } .code-editor:focus { border-color: rgba(0,200,255,0.5); } .scp-input { background: rgba(0,10,25,0.8); border: 1px solid rgba(0,180,255,0.25); color: #e0f4ff; font-family: 'Share Tech Mono', monospace; font-size: 14px; padding: 8px 10px; outline: none; width: 100%; box-sizing: border-box; transition: border-color 0.2s; } .scp-input:focus { border-color: rgba(0,200,255,0.6); } .scp-select { background: rgba(0,10,25,0.8); border: 1px solid rgba(0,180,255,0.25); color: #e0f4ff; font-family: 'Share Tech Mono', monospace; font-size: 14px; padding: 8px 10px; outline: none; width: 100%; box-sizing: border-box; cursor: pointer; } .data-table { width: 100%; border-collapse: collapse; } .data-table th { font-size: 14px; letter-spacing: 0.12em; color: rgba(0,200,255,0.6); text-transform: uppercase; padding: 7px 10px; border-bottom: 1px solid rgba(0,200,255,0.15); text-align: left; font-weight: 400; } .data-table td { font-size: 14px; padding: 9px 10px; border-bottom: 1px solid rgba(0,200,255,0.06); color: rgba(220,240,255,0.85); font-family: 'Share Tech Mono', monospace; } .data-table tr:hover td { background: rgba(0,200,255,0.04); } .toggle-switch { display: flex; align-items: center; gap: 8px; cursor: pointer; } .toggle-track { width: 32px; height: 16px; border-radius: 8px; border: 1px solid rgba(0,200,255,0.4); position: relative; background: rgba(0,10,25,0.8); transition: all 0.2s; flex-shrink: 0; } .toggle-track.on { background: rgba(0,200,100,0.25); border-color: rgba(0,255,140,0.6); } .toggle-thumb { position: absolute; top: 2px; left: 2px; width: 10px; height: 10px; border-radius: 50%; background: rgba(0,200,255,0.5); transition: all 0.2s; } .toggle-track { width: 36px; height: 18px; border-radius: 9px; border: 1px solid rgba(0,200,255,0.4); position: relative; background: rgba(0,10,25,0.8); transition: all 0.2s; flex-shrink: 0; } .toggle-track.on { background: rgba(0,200,100,0.25); border-color: rgba(0,255,140,0.6); } .toggle-thumb { position: absolute; top: 3px; left: 3px; width: 10px; height: 10px; border-radius: 50%; background: rgba(0,200,255,0.5); transition: all 0.2s; } .toggle-track.on .toggle-thumb { left: 21px; background: #00ff88; box-shadow: 0 0 6px #00ff88; } .section-label { font-size: 14px; letter-spacing: 0.15em; text-transform: uppercase; color: rgba(0,200,255,0.5); font-family: 'Share Tech Mono', monospace; margin-bottom: 2px; } .glow-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; } @keyframes blink { 0%,100%{opacity:1} 50%{opacity:0.3} } .blink { animation: blink 1.4s infinite; } @keyframes scanline { 0% { transform: translateY(-100%); } 100% { transform: translateY(100vh); } } `; // Inject styles once if (!document.getElementById('scp-ui-styles')) { const s = document.createElement('style'); s.id = 'scp-ui-styles'; s.textContent = uiStyles; document.head.appendChild(s); } // ─── Panel ────────────────────────────────────────────────────────────────── function Panel({ children, style, className = '', title, accent = '#00c8ff', headerRight }) { return (
| {c.label} | )}
|---|
| {c.render ? c.render(r) : r[c.key]} | )}