orchard
mirrorEvery site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.
blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics
1// The clock ticks without the server, since a second hand over a stream would
2// be a frame a second for something the browser already knows. UTC sits beside
3// local because every timestamp the server logs is UTC.
4const utc = document.querySelector("[data-clock-utc]");
5const zone = document.querySelector("[data-clock-zone]");
6const local = document.querySelector("[data-clock-local]");
7const date = document.querySelector("[data-clock-date]");
8
9if (utc && local && date) {
10 const hms = (tz) =>
11 new Intl.DateTimeFormat("en-GB", {
12 hour: "2-digit",
13 minute: "2-digit",
14 second: "2-digit",
15 hour12: false,
16 ...(tz ? { timeZone: tz } : {}),
17 });
18
19 const utcFmt = hms("UTC");
20 const localFmt = hms(null);
21 const dateFmt = new Intl.DateTimeFormat("en-GB", {
22 weekday: "short",
23 day: "2-digit",
24 month: "short",
25 });
26
27 // "LOCAL" on its own does not say local to what, and the answer differs per
28 // viewer, so the label carries the browser's actual zone abbreviation. Intl
29 // gives the short name for today, which is what handles daylight saving
30 // without a table.
31 if (zone) {
32 const now = new Date();
33 const parts = new Intl.DateTimeFormat("en-US", {
34 timeZoneName: "short",
35 }).formatToParts(now);
36 const named = parts.find((p) => p.type === "timeZoneName");
37 zone.textContent = named ? named.value.toUpperCase() : "LOCAL";
38 zone.title = Intl.DateTimeFormat().resolvedOptions().timeZone || "";
39 }
40
41 const tick = () => {
42 const now = new Date();
43 utc.textContent = utcFmt.format(now);
44 local.textContent = localFmt.format(now);
45 date.textContent = dateFmt.format(now).toUpperCase();
46 };
47
48 tick();
49 setInterval(tick, 1000);
50}