wa-dev-tools/public/status.html
treamz 27ad078e07 Unified header: same top-header across landing, login, register, status
- Landing: replaced custom landing-nav with standard top-header
- Removed scroll listener for nav (no longer needed)
- Header CSS moved to shared.css (single source)
- Removed duplicate header CSS from login, register, status
- All 4 public pages now have identical header with theme toggle
2026-03-22 00:49:52 +03:00

131 lines
7.1 KiB
HTML

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Status — WA Dev Tools</title>
<script src="/vendor/tailwind.js"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: { extend: {
fontFamily: { mono: ['JetBrains Mono', 'monospace'], sans: ['Manrope', 'sans-serif'] },
colors: { surface: { 900: '#060c18', 800: '#091020', 700: '#0d1828', 600: '#162040' }, accent: { DEFAULT: '#0054e6', dim: '#0043b8', bright: '#6b9fff' } }
}}
};
</script>
<link href="/vendor/fonts.css" rel="stylesheet">
<link href="/shared.css" rel="stylesheet">
<style>
.status-page { padding-top:80px; max-width:680px; margin:0 auto; padding-left:20px; padding-right:20px; padding-bottom:60px; }
.overall-banner { border-radius:12px; padding:24px 28px; margin-bottom:32px; display:flex; align-items:center; gap:14px; }
.overall-banner.operational { background:rgba(34,197,94,.08); border:1px solid rgba(34,197,94,.2); }
.overall-banner.degraded { background:rgba(234,179,8,.08); border:1px solid rgba(234,179,8,.2); }
.overall-banner.outage { background:rgba(239,68,68,.08); border:1px solid rgba(239,68,68,.2); }
.overall-dot { width:10px; height:10px; border-radius:50%; flex-shrink:0; }
.overall-dot.operational { background:#22c55e; }
.overall-dot.degraded { background:#eab308; }
.overall-dot.outage { background:#ef4444; }
.overall-text { font-size:16px; font-weight:700; color:var(--text-primary); }
.service-list { display:flex; flex-direction:column; }
.service-row { display:flex; align-items:center; justify-content:space-between; padding:16px 0; border-bottom:1px solid var(--surface-600); }
.service-row:last-child { border-bottom:none; }
.service-name { font-size:15px; font-weight:500; color:var(--text-primary); }
.service-badge { display:flex; align-items:center; gap:8px; font-size:13px; font-weight:500; }
.service-badge .dot { width:8px; height:8px; border-radius:50%; }
.service-badge .dot.operational { background:#22c55e; }
.service-badge .dot.degraded { background:#eab308; }
.service-badge .dot.outage { background:#ef4444; }
.service-badge .label { color:var(--text-muted); }
.uptime-footer { margin-top:32px; text-align:center; color:var(--text-muted); font-size:12px; font-family:'JetBrains Mono',monospace; }
.uptime-footer .uptime-val { font-size:14px; color:var(--text-secondary); font-weight:600; margin-bottom:4px; }
</style>
<script>
(function(){ if (localStorage.getItem('theme') === 'dark') document.documentElement.classList.add('dark'); })();
</script>
</head>
<body>
<header class="top-header">
<a href="/" class="top-logo">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="color:var(--accent)"><path stroke-linecap="round" stroke-linejoin="round" d="M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5"/></svg>
WA Dev <span>Tools</span>
</a>
<nav class="top-nav">
<a href="/">Главная</a>
<a href="/#tools">Инструменты</a>
<a href="/#features">Возможности</a>
</nav>
<div class="top-right">
<button class="theme-btn" id="themeBtn" title="Переключить тему">
<svg class="sun-i" width="16" height="16" fill="currentColor" viewBox="0 0 20 20"><path d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"/></svg>
<svg class="moon-i" width="16" height="16" fill="currentColor" viewBox="0 0 20 20"><path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"/></svg>
</button>
<a href="/auth/login" class="btn-ghost">Войти</a>
<a href="/auth/register" class="btn-primary-sm">Регистрация</a>
</div>
</header>
<div class="status-page">
<div id="banner" class="overall-banner operational">
<div class="overall-dot operational" id="bannerDot"></div>
<div class="overall-text" id="bannerText">All systems operational</div>
</div>
<div class="service-list" id="serviceList">
<div style="text-align:center;padding:40px 0;color:var(--text-muted);font-size:13px;">Loading...</div>
</div>
<div class="uptime-footer">
<div class="uptime-val" id="uptimeVal"></div>
<div id="lastCheck"></div>
</div>
</div>
<script>
const OVERALL = { operational: 'All systems operational', degraded: 'Partial system outage', outage: 'Major system outage' };
const STATUS = { operational: 'Operational', degraded: 'Degraded', outage: 'Outage' };
function fmtUptime(s) {
const d = Math.floor(s / 86400), h = Math.floor((s % 86400) / 3600), m = Math.floor((s % 3600) / 60);
const p = [];
if (d) p.push(d + 'd');
if (h) p.push(h + 'h');
p.push(m + 'm');
return 'Uptime: ' + p.join(' ');
}
function render(data) {
const b = document.getElementById('banner');
b.className = 'overall-banner ' + data.overall;
document.getElementById('bannerDot').className = 'overall-dot ' + data.overall;
document.getElementById('bannerText').textContent = OVERALL[data.overall] || data.overall;
document.getElementById('serviceList').innerHTML = data.services.map(s =>
'<div class="service-row"><div class="service-name">' + s.name + '</div>' +
'<div class="service-badge"><span class="dot ' + s.status + '"></span>' +
'<span class="label">' + (STATUS[s.status] || s.status) + '</span></div></div>'
).join('');
document.getElementById('uptimeVal').textContent = fmtUptime(data.uptime);
document.getElementById('lastCheck').textContent = 'Last checked: ' + new Date(data.timestamp).toLocaleTimeString();
}
async function poll() { try { const r = await fetch('/status/api'); if (r.ok) render(await r.json()); } catch {} }
poll();
setInterval(poll, 30000);
// Theme
const tb = document.getElementById('themeBtn');
function ut() {
const d = document.documentElement.classList.contains('dark');
document.querySelectorAll('.sun-i').forEach(e => e.style.display = d ? 'none' : 'block');
document.querySelectorAll('.moon-i').forEach(e => e.style.display = d ? 'block' : 'none');
}
ut();
tb.addEventListener('click', () => { const d = document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', d ? 'dark' : ''); ut(); });
</script>
</body>
</html>