Files
dyndns-updater/web/index.html
T
2026-04-11 20:55:47 +02:00

125 lines
4.7 KiB
HTML

<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DynDns Updater</title>
<link rel="stylesheet" href="beer.min.css">
<script src="beer.min.js" defer></script>
<script src="alpine.min.js" defer></script>
</head>
<body>
<main x-data="data" class="responsive">
<h1>DynDns Updater</h1>
<table>
<tbody>
<tr>
<th>IPv4</td>
<td><span x-text="addrs.ipv4"></span></td>
</tr>
<tr>
<th>IPv6</td>
<td><span x-text="addrs.ipv6"></span></td>
</tr>
<tr>
<th>Last Update</td>
<td><span x-text="niceTime(lastUpdate)"></span></td>
</tr>
</tbody>
</table>
<button x-on:click="update">Update</button>
<template x-for="domain in domains">
<article>
<h5>
<span x-text="domain.success ? '✅' : '❌'"></span>
<span x-text="domain.name"></span>
</h5>
<table>
<tbody>
<tr>
<th>IPv4</td>
<td><span x-text="domain.addrs.ipv4"></span></td>
</tr>
<tr>
<th>IPv6</td>
<td><span x-text="domain.addrs.ipv6"></span></td>
</tr>
<tr>
<th>Last Update</td>
<td><span x-text="niceTime(domain.lastUpdate)"></span></td>
</tr>
</tbody>
</table>
<ul class="list border">
<template x-for="update in domain.history">
<li>
<i>home</i>
<div class="max">
<h6 class="small" x-text="update.response_text"></h6>
<div>
<button class="chip">IPv4</button><span x-text="update.addrs.ipv4"></span>
<button class="chip">IPv6</button><span x-text="update.addrs.ipv6"></span>
</div>
</div>
<label><span x-text="niceTime(update.timestamp)"></span></label>
</li>
</template>
</ul>
</article>
</template>
</main>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('data', () => ({
addrs: { ipv4: null, ipv6: null },
lastUpdate: null,
domains: [],
niceTime(time) {
if (!time) return '';
const diff = new Date() - time;
if (diff < 1000) {
return 'just now';
} else if (diff < 60000) {
return `${Math.round(diff / 1000)} seconds ago`;
} else if (diff < 3600000) {
return `${Math.round(diff / 60000)} minutes ago`;
} else {
return time.toISOString();
}
},
async update() {
const res = await fetch('http://localhost:8080/state');
const data = await res.json();
this.addrs = data.addrs;
this.lastUpdate = new Date(data.timestamp * 1000);
this.domains = Object.entries(data.domains).map(([domain, history]) => ({
name: domain,
success: history[history.length - 1].success,
lastUpdate: new Date(history[history.length - 1].timestamp * 1000),
addrs: history[history.length - 1].addrs,
history: history.reverse().map(h => ({
timestamp: new Date(h.timestamp * 1000),
addrs: h.addrs,
success: h.success,
response_text: h.response_text
}))
}));
},
async init() {
await this.update();
window.setInterval(() => {
this.update();
}, 10000);
},
}))
});
</script>
<style>
main {
overflow: auto;
}
</style>
</body>
</html>