clavitor/clavitor.com/templates/glass.tmpl

122 lines
4.7 KiB
Cheetah

{{define "glass"}}
<div class="hero container">
<p class="label accent mb-4">Network</p>
<h1 class="mb-4">Looking Glass</h1>
<p class="lead">{{len .Pops}} points of presence. Real-time status.</p>
</div>
<hr class="divider">
<div class="section container">
<div class="glass-grid">
{{range .Pops}}
<div class="glass-pop {{if eq .Status "live"}}glass-live{{else}}glass-planned{{end}}">
<div class="glass-header">
<span class="glass-city">{{.City}}</span>
<span class="glass-status {{if eq .Status "live"}}glass-status-live{{else}}glass-status-planned{{end}}">{{.Status}}</span>
</div>
<div class="glass-details">
<div class="glass-row">
<span class="glass-key">Region</span>
<span class="glass-val mono">{{.RegionName}}</span>
</div>
<div class="glass-row">
<span class="glass-key">Provider</span>
<span class="glass-val">{{.Provider}}</span>
</div>
{{if .IP}}<div class="glass-row">
<span class="glass-key">IPv4</span>
<span class="glass-val mono">{{.IP}}</span>
</div>{{end}}
{{if .DNS}}<div class="glass-row">
<span class="glass-key">DNS</span>
<span class="glass-val mono">{{.DNS}}</span>
</div>{{end}}
<div class="glass-row">
<span class="glass-key">Latency</span>
<span class="glass-val glass-latency" data-dns="{{.DNS}}" data-status="{{.Status}}">{{if eq .Status "live"}}—{{else}}<span class="glass-muted">Q2 2026</span>{{end}}</span>
</div>
</div>
</div>
{{end}}
</div>
</div>
{{end}}
{{define "glass-script"}}
<script>
(function() {
const grid = document.querySelector('.glass-grid');
let pending = 0;
const pops = grid.querySelectorAll('.glass-pop');
document.querySelectorAll('.glass-latency[data-status="live"][data-dns]').forEach(el => {
const dns = el.dataset.dns;
if (!dns) { el.textContent = '—'; return; }
pending++;
const t0 = performance.now();
const t0 = performance.now();
fetch('https://' + dns + ':1984/ping').then(() => {
const ms = Math.round(performance.now() - t0);
el.textContent = ms + ' ms';
el.dataset.ms = ms;
el.classList.add(ms < 100 ? 'glass-fast' : ms < 250 ? 'glass-ok' : 'glass-slow');
if (--pending === 0) sortGrid();
}).catch(() => {
const ms = Math.round(performance.now() - t0);
if (ms < 4900) {
el.textContent = ms + ' ms';
el.dataset.ms = ms;
el.classList.add(ms < 100 ? 'glass-fast' : ms < 250 ? 'glass-ok' : 'glass-slow');
} else {
el.textContent = 'down';
el.dataset.ms = 99999;
el.classList.add('glass-slow');
}
if (--pending === 0) sortGrid();
});
});
function sortGrid() {
const arr = Array.from(grid.querySelectorAll('.glass-pop'));
arr.sort((a, b) => {
const aMs = parseInt(a.querySelector('.glass-latency')?.dataset.ms || 99998);
const bMs = parseInt(b.querySelector('.glass-latency')?.dataset.ms || 99998);
return aMs - bMs;
});
arr.forEach(el => grid.appendChild(el));
}
function pingAll() {
document.querySelectorAll('.glass-latency[data-status="live"][data-dns]').forEach(el => {
const dns = el.dataset.dns;
if (!dns) return;
el.textContent = '...';
el.className = 'glass-val glass-latency';
const t0 = performance.now();
fetch('https://' + dns + ':1984/ping').then(() => {
const ms = Math.round(performance.now() - t0);
el.textContent = ms + ' ms';
el.dataset.ms = ms;
el.classList.add(ms < 100 ? 'glass-fast' : ms < 250 ? 'glass-ok' : 'glass-slow');
}).catch(() => {
const ms = Math.round(performance.now() - t0);
if (ms < 4900) {
el.textContent = ms + ' ms';
el.dataset.ms = ms;
el.classList.add(ms < 100 ? 'glass-fast' : ms < 250 ? 'glass-ok' : 'glass-slow');
} else {
el.textContent = 'down';
el.dataset.ms = 99999;
el.classList.add('glass-slow');
}
});
});
setTimeout(sortGrid, 6000);
}
setInterval(pingAll, 60000);
})();
</script>
{{end}}