···
+
{% set api_url = "https://bsky.social/xrpc/com.atproto.repo.listRecords?repo=dunkirk.sh&collection=a.status.update&limit=50" %}
+
{% set response = load_data(url=api_url, format="json") %}
+
#status-updates-container {
+
flex-direction: column;
+
border-left: 0.375rem solid var(--accent);
+
background-color: var(--bg-light);
+
border-radius: 0.375rem;
+
margin-bottom: 0.75rem;
+
justify-content: space-between;
+
color: var(--text-light);
+
.bsky-post-footer cite {
+
color: var(--text-light);
+
<div id="status-updates-container">
+
{% if response.records %}
+
{% for record in response.records | sort(attribute="value.createdAt") | reverse %}
+
{% set created_at = record.value.createdAt %}
+
{% set status_text = record.value.text %}
+
<div class="bsky-post" data-cid="{{ record.cid }}" data-created="{{ created_at }}">
+
<div class="bsky-post-content">{{ status_text }}</div>
+
<div class="bsky-post-footer">
+
src="https://cdn.bsky.app/img/avatar_thumbnail/plain/did:plc:3h24oe2owgmqpulq6dwwnsph/bafkreiaosnd5uyvwfii4ecb7zks67vwdiovnulsjnr6kb3azbfigjcaw5u@jpeg"
+
<a href="https://bsky.app/@doing.dunkirk.sh" target="_blank" rel="noopener">@doing.dunkirk.sh</a>
+
<span class="bsky-post-time">
+
{{ record.value.createdAt | date(format="%b %d, %Y") }}
+
<div class="bsky-post">
+
<div class="bsky-post-content">No status updates found.</div>
+
document.addEventListener("DOMContentLoaded", () => {
+
const container = document.getElementById("status-updates-container");
+
const API_URL = "https://bsky.social/xrpc/com.atproto.repo.listRecords?repo=dunkirk.sh&collection=a.status.update&limit=50";
+
const existingPosts = new Map();
+
// Collect existing posts by CID
+
document.querySelectorAll('.bsky-post[data-cid]').forEach(post => {
+
existingPosts.set(post.dataset.cid, {
+
created: new Date(post.dataset.created)
+
// Format time relative to now
+
function formatTimeAgo(date) {
+
const now = new Date();
+
const diffInMs = now - date;
+
const diffInMins = Math.floor(diffInMs / (1000 * 60));
+
const diffInHours = Math.floor(diffInMs / (1000 * 60 * 60));
+
if (diffInMins < 1) return "just now";
+
if (diffInMins < 60) return `${Math.round(diffInMins)}m`;
+
if (diffInHours < 24) return `${Math.round(diffInHours)}h`;
+
return new Intl.DateTimeFormat("en", {
+
// Update timestamps on existing posts
+
function updateTimestamps() {
+
existingPosts.forEach((post) => {
+
const timeElement = post.element.querySelector('.bsky-post-time');
+
timeElement.textContent = formatTimeAgo(post.created);
+
// Create a new post element
+
function createPostElement(record) {
+
const createdDate = new Date(record.value.createdAt);
+
const postElement = document.createElement('div');
+
postElement.className = 'bsky-post';
+
postElement.dataset.cid = record.cid;
+
postElement.dataset.created = record.value.createdAt;
+
postElement.innerHTML = `
+
<div class="bsky-post-content">${record.value.text}</div>
+
<div class="bsky-post-footer">
+
<img src="https://cdn.bsky.app/img/avatar_thumbnail/plain/did:plc:3h24oe2owgmqpulq6dwwnsph/bafkreiaosnd5uyvwfii4ecb7zks67vwdiovnulsjnr6kb3azbfigjcaw5u@jpeg" alt="Kieran's avatar" class="avatar" />
+
<a href="https://bsky.app/@doing.dunkirk.sh" target="_blank" rel="noopener">@doing.dunkirk.sh</a>
+
<span class="bsky-post-time">${formatTimeAgo(createdDate)}</span>
+
// Fetch and update posts
+
function fetchAndUpdatePosts() {
+
.then(response => response.json())
+
if (!data.records || data.records.length === 0) {
+
if (existingPosts.size === 0) {
+
container.innerHTML = '<div class="bsky-post"><div class="bsky-post-content">No status updates found.</div></div>';
+
const sortedRecords = data.records.sort((a, b) => {
+
return new Date(b.value.createdAt) - new Date(a.value.createdAt);
+
// Track if we need to reorder
+
let needsReordering = false;
+
for (const record of sortedRecords) {
+
if (!existingPosts.has(record.cid)) {
+
const newPostElement = createPostElement(record);
+
// Always insert at the beginning for now (we'll reorder if needed)
+
container.insertBefore(newPostElement, container.firstChild);
+
existingPosts.set(record.cid, {
+
element: newPostElement,
+
created: new Date(record.value.createdAt)
+
needsReordering = true;
+
// If we added new posts, reorder everything
+
const sortedElements = [...existingPosts.entries()]
+
.sort((a, b) => b[1].created - a[1].created)
+
.map(entry => entry[1].element);
+
// Reattach in correct order
+
sortedElements.forEach(element => {
+
container.appendChild(element);
+
// Update all timestamps
+
console.error("Error fetching status updates:", error);
+
// Update timestamps every minute
+
setInterval(updateTimestamps, 60000);
+
// Fetch new posts every 5 minutes
+
setInterval(fetchAndUpdatePosts, 300000);