fa317a3b78
Theme preference stored in localStorage (auto follows the OS setting). The chosen data-theme attribute is applied synchronously in <head> to avoid any flash of unstyled content. CSS custom properties handle all surface, text, border and input colours across every page. The Appearance section on the profile page lets each user switch modes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
213 lines
5.8 KiB
HTML
213 lines
5.8 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
{% include 'head.html' %}
|
|
|
|
<style>
|
|
html, body { overflow: visible; }
|
|
|
|
.container {
|
|
max-width: 700px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
h1 {
|
|
color: #333;
|
|
margin-bottom: 4px;
|
|
font-size: 1.5em;
|
|
}
|
|
|
|
.subtitle {
|
|
color: #666;
|
|
margin-bottom: 24px;
|
|
font-size: 0.9em;
|
|
}
|
|
|
|
.section {
|
|
background: #fff;
|
|
border-radius: 8px;
|
|
box-shadow: 0 1px 6px rgba(0,0,0,0.1);
|
|
padding: 20px 24px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.section h2 {
|
|
font-size: 1em;
|
|
font-weight: 700;
|
|
color: #333;
|
|
margin: 0 0 16px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 1px solid #eee;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
.info-row {
|
|
display: flex;
|
|
align-items: baseline;
|
|
padding: 8px 0;
|
|
border-bottom: 1px solid #f5f5f5;
|
|
font-size: 0.9em;
|
|
}
|
|
.info-row:last-child { border-bottom: none; }
|
|
|
|
.info-label {
|
|
width: 160px;
|
|
flex-shrink: 0;
|
|
color: #666;
|
|
font-size: 0.88em;
|
|
}
|
|
|
|
.info-value {
|
|
color: #222;
|
|
word-break: break-all;
|
|
}
|
|
|
|
.info-value a {
|
|
color: #0066cc;
|
|
text-decoration: none;
|
|
}
|
|
.info-value a:hover { text-decoration: underline; }
|
|
|
|
.version-badge {
|
|
display: inline-block;
|
|
padding: 3px 12px;
|
|
background: #e8f0fe;
|
|
color: #1a73e8;
|
|
border-radius: 12px;
|
|
font-size: 1.00em;
|
|
font-weight: 600;
|
|
font-family: monospace;
|
|
}
|
|
|
|
.hb-logo {
|
|
font-size: 2.5em;
|
|
font-weight: 700;
|
|
color: #0066cc;
|
|
letter-spacing: -1px;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.hb-tagline {
|
|
color: #555;
|
|
font-size: 0.95em;
|
|
}
|
|
|
|
.logo-section {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 20px;
|
|
padding: 8px 0 4px;
|
|
}
|
|
|
|
.logo-text { flex: 1; }
|
|
|
|
/* ── Dark mode ── */
|
|
html[data-theme="dark"] h1 { color: var(--text); }
|
|
html[data-theme="dark"] .subtitle { color: var(--text-sec); }
|
|
html[data-theme="dark"] .section { background: var(--surface); box-shadow: 0 1px 6px var(--shadow); }
|
|
html[data-theme="dark"] .section h2 { color: var(--text); border-bottom-color: var(--border); }
|
|
html[data-theme="dark"] .info-row { border-bottom-color: var(--border-4); }
|
|
html[data-theme="dark"] .info-label { color: var(--text-sec); }
|
|
html[data-theme="dark"] .info-value { color: var(--text); }
|
|
html[data-theme="dark"] .info-value a { color: var(--link); }
|
|
html[data-theme="dark"] .hb-logo { color: var(--link); }
|
|
html[data-theme="dark"] .hb-tagline { color: var(--text-sec); }
|
|
html[data-theme="dark"] .version-badge { background: #1a3255; color: #60a5fa; }
|
|
</style>
|
|
|
|
<body>
|
|
{% include 'nav.html' %}
|
|
|
|
<div class="container">
|
|
<h1>{{ header }}</h1>
|
|
<p class="subtitle">Heartbeat monitoring system</p>
|
|
|
|
<div class="section">
|
|
<div class="logo-section">
|
|
<div class="logo-text">
|
|
<div class="hb-logo">Heartbeat</div>
|
|
<div class="hb-tagline">Lightweight host monitoring over UDP</div>
|
|
</div>
|
|
<span class="version-badge">v{{ hbd_version }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Version</h2>
|
|
<div class="info-row">
|
|
<span class="info-label">Server version</span>
|
|
<span class="info-value">{{ hbd_version }}</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="info-label">Python</span>
|
|
<span class="info-value">{{ python_version }}</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="info-label">License</span>
|
|
<span class="info-value">MIT</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Runtime</h2>
|
|
<div class="info-row">
|
|
<span class="info-label">Host</span>
|
|
<span class="info-value">{{ server_hostname }}</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="info-label">Started</span>
|
|
<span class="info-value">{{ start_time_str }}</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="info-label">Uptime</span>
|
|
<span class="info-value" id="uptime-value">{{ uptime_str }}</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="info-label">Hosts monitored</span>
|
|
<span class="info-value">{{ host_count }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Contact & Source</h2>
|
|
<div class="info-row">
|
|
<span class="info-label">Author</span>
|
|
<span class="info-value">Andreas Wrede</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="info-label">Email</span>
|
|
<span class="info-value"><a href="mailto:aew.hbd@wrede.ca">aew.hbd@wrede.ca</a></span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="info-label">Repository</span>
|
|
<span class="info-value"><a href="https://git.wrede.ca/andreas/heartbeat" target="_blank" rel="noopener">git.wrede.ca/andreas/heartbeat</a></span>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
(function() {
|
|
var startEpoch = {{ start_epoch }};
|
|
var el = document.getElementById('uptime-value');
|
|
if (!el) return;
|
|
function fmt(s) {
|
|
var d = Math.floor(s / 86400);
|
|
var h = Math.floor((s % 86400) / 3600);
|
|
var m = Math.floor((s % 3600) / 60);
|
|
var sec = s % 60;
|
|
if (d > 0) return d + 'd ' + h + 'h ' + m + 'm';
|
|
if (h > 0) return h + 'h ' + m + 'm ' + sec + 's';
|
|
return m + 'm ' + sec + 's';
|
|
}
|
|
function tick() {
|
|
var up = Math.floor(Date.now() / 1000 - startEpoch);
|
|
el.textContent = fmt(up);
|
|
}
|
|
tick();
|
|
setInterval(tick, 1000);
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|