···
2
-
<span><a href="https://bsky.app/@doing.dunkirk.sh" id="verb-link">Kieran is</a> <i id="status-text">"doing smthing interesting"</i> - <span id="time-ago"></span></span>
1
+
<div class="bubble" style="visibility: hidden; opacity: 0;">
2
+
<span><a href="https://bsky.app/@doing.dunkirk.sh" id="verb-link">Kieran is</a> <i id="status-text"></i> - <span id="time-ago"></span></span>
document.addEventListener("DOMContentLoaded", () => {
7
+
// Initialize RelativeTimeFormat with user's locale
8
+
const rtf = new Intl.RelativeTimeFormat(navigator.language, {
"https://bsky.social/xrpc/com.atproto.repo.listRecords?repo=dunkirk.sh&collection=a.status.update",
···
if (statusData.records && statusData.records.length > 0) {
18
-
const latestStatus = `"${statusData.records[0].value.text}"`;
19
-
document.getElementById("status-text").textContent = latestStatus;
21
-
// Calculate and display time ago
24
+
// Calculate time difference
if (statusData.records[0].value.createdAt) {
const createdDate = new Date(statusData.records[0].value.createdAt);
···
const diffInHours = Math.floor(diffInMs / (1000 * 60 * 60));
const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24));
33
+
// Ignore if older than 12 hours
34
+
if (diffInHours > 12) {
38
+
const latestStatus = `"${statusData.records[0].value.text}"`;
39
+
document.getElementById("status-text").textContent = latestStatus;
41
+
// Format time contextually using Intl.RelativeTimeFormat
43
+
const createdHour = createdDate.getHours();
44
+
const isToday = diffInHours < 24 && now.getDate() === createdDate.getDate();
45
+
const isYesterday = diffInHours >= 24 && diffInHours < 48 &&
46
+
(now.getDate() - createdDate.getDate() === 1 ||
47
+
(now.getDate() === 1 && new Date(now.getFullYear(), now.getMonth(), 0).getDate() === createdDate.getDate()));
32
-
timeAgoText = "just now";
33
-
} else if (diffInMins < 30) {
34
-
timeAgoText = `in the last ${diffInMins} minute${diffInMins === 1 ? '' : 's'}`;
50
+
timeAgoText = rtf.format(0, "minute"); // "now" in the user's language
51
+
} else if (diffInMins < 5) {
52
+
timeAgoText = rtf.format(-1, "minute"); // "1 minute ago" in the user's language
} else if (diffInMins < 60) {
36
-
timeAgoText = `${diffInMins} minute${diffInMins === 1 ? '' : 's'} ago`;
37
-
} else if (diffInHours < 24) {
38
-
timeAgoText = `${diffInHours} hour${diffInHours === 1 ? '' : 's'} ago`;
54
+
timeAgoText = rtf.format(-diffInMins, "minute");
55
+
} else if (diffInHours < 3) {
56
+
timeAgoText = rtf.format(-diffInHours, "hour");
57
+
} else if (isToday) {
58
+
// Time of day context, but still localized
59
+
if (createdHour < 12) {
60
+
timeAgoText = "this morning";
61
+
} else if (createdHour < 17) {
62
+
timeAgoText = "this afternoon";
64
+
timeAgoText = "this evening";
66
+
} else if (isYesterday) {
67
+
timeAgoText = rtf.format(-1, "day"); // "yesterday" in the user's language
68
+
} else if (diffInDays < 7) {
69
+
timeAgoText = rtf.format(-diffInDays, "day");
40
-
timeAgoText = `${diffInDays} day${diffInDays === 1 ? '' : 's'} ago`;
71
+
// For older posts, use a date formatter
72
+
const dateFormatter = new Intl.DateTimeFormat(navigator.language, {
76
+
timeAgoText = `on ${dateFormatter.format(createdDate)}`;
document.getElementById("time-ago").textContent = timeAgoText;
45
-
// Change "is" to "was" if more than 30 minutes old
81
+
// Change "is" to "was" based on recency
const verbLink = document.getElementById("verb-link");
verbLink.textContent = "Kieran was";
87
+
// Show and animate the bubble since we have a valid status
88
+
const bubble = document.querySelector(".bubble");
89
+
bubble.style.visibility = "visible";
90
+
bubble.classList.add("animate-in");
92
+
// For reduced motion preferences, ensure the bubble is always visible
93
+
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
94
+
bubble.style.transform = "none"; // Ensure no transform is applied
95
+
bubble.style.opacity = "1"; // Ensure content is visible