Micro.blog widget
This Bearming add-on for Bear fetches and displays your latest post from a Micro.blog JSON feed. Images are shown as a square thumbnail, book covers keep their natural ratio, and the timestamp links back to the original post.1 2
Want to show a full feed? Check out the Micro.blog feed add-on.
Preview
How to use
Add the markup to your footer or wherever you want the widget to appear, then add the script and styles to your theme. Replace the feed URL with your own Micro.blog JSON feed URL.
Markup
<div class="mb-latest" data-feed="https://yoursite.com/feed.json" hidden></div>
Script
<script>
/* Micro.blog latest post | robertbirming.com */
(async () => {
const root = document.querySelector('.mb-latest');
const feed = root?.getAttribute('data-feed');
if (!feed) return;
const safeUrl = url => /^https?:\/\//.test(url) ? url : '#';
const timeAgo = date => {
const ms = Date.now() - new Date(date).getTime();
if (!Number.isFinite(ms) || ms < 60000) return 'just now';
const mins = ms / 60000 | 0;
const fmt = (n, u) => `${n} ${u}${n === 1 ? '' : 's'} ago`;
if (mins < 60) return fmt(mins, 'minute');
if (mins < 1440) return fmt(mins / 60 | 0, 'hour');
if (mins < 43200) return fmt(mins / 1440 | 0, 'day');
if (mins < 525600) return fmt(mins / 43200 | 0, 'month');
return fmt(mins / 525600 | 0, 'year');
};
try {
const res = await fetch(feed);
if (!res.ok) return;
const { items } = await res.json();
const post = items?.[0];
if (!post) return;
const parser = new DOMParser();
const doc = parser.parseFromString(post.content_html || '', 'text/html');
let thumb = null;
let isBook = false;
let isVideo = false;
const img = doc.querySelector('img');
const vid = doc.querySelector('video');
if (img) {
thumb = img.src;
isBook = img.classList.contains('microblog_book');
img.remove();
} else if (vid) {
thumb = vid.getAttribute('poster');
isVideo = true;
vid.remove();
}
const mapLink = doc.querySelector('a[href*="maps.apple.com"]');
let locationHref = null;
if (mapLink) {
locationHref = safeUrl(mapLink.getAttribute('href').replace(/^http:/, 'https:'));
(mapLink.closest('p') || mapLink).remove();
}
const text = doc.body.innerHTML.trim();
const url = safeUrl(post.url);
const when = timeAgo(post.date_published);
const thumbClass = `mb-latest-thumb${isBook ? ' mb-latest-thumb--book' : ''}${isVideo ? ' mb-latest-thumb--video' : ''}`;
const thumbHtml = thumb
? `<a class="mb-latest-thumb-link${isVideo ? ' mb-latest-thumb-link--video' : ''}" href="${url}" rel="noopener">` +
`<img class="${thumbClass}" src="${thumb}" alt="" loading="lazy" decoding="async"></a>`
: '';
root.innerHTML =
thumbHtml +
`<div class="mb-latest-body">` +
`<div class="mb-latest-text">${text}</div>` +
`<div class="mb-latest-meta">` +
`<a class="mb-latest-time" href="${url}" rel="noopener">${when}</a>` +
(locationHref ? `<a class="mb-latest-location" href="${locationHref}" rel="noopener">📍</a>` : '') +
`</div>` +
`</div>`;
root.removeAttribute('hidden');
} catch {}
})();
</script>
Styles
/* Micro.blog latest post | robertbirming.com */
.mb-latest {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.3em 1.1rem;
align-items: start;
max-inline-size: 34rem;
margin-inline: auto;
margin-block: var(--space-block);
padding: 1rem 1.1rem;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
}
.mb-latest::before {
content: "Latest status";
display: block;
grid-column: 1 / -1;
margin-block-end: 0.5em;
font-size: calc(var(--font-size) * 0.8);
font-weight: 500;
text-transform: uppercase;
color: var(--muted);
}
.mb-latest:not(:has(.mb-latest-thumb-link)) .mb-latest-body {
grid-column: 1 / -1;
}
.mb-latest-thumb-link {
display: block;
position: relative;
margin-block-start: 0.2rem;
}
.mb-latest-thumb-link--video::after {
content: "▶";
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
color: #fff;
background: color-mix(in srgb, var(--text) 25%, transparent);
border-radius: var(--radius);
}
.mb-latest-thumb {
width: 4rem;
height: 4rem;
object-fit: cover;
border-radius: var(--radius);
margin: 0;
}
.mb-latest-thumb--book {
width: auto;
max-width: 3rem;
height: auto;
object-fit: contain;
}
.mb-latest-body {
min-width: 0;
}
.mb-latest-text {
font-size: calc(var(--font-size) * 0.95);
color: color-mix(in srgb, var(--text) 95%, var(--bg));
overflow-wrap: break-word;
}
.mb-latest-text > :first-child { margin-block-start: 0; }
.mb-latest-text > :last-child { margin-block-end: 0; }
.mb-latest-meta {
display: flex;
align-items: center;
gap: 0.6em;
margin-block-start: 0.7em;
}
.mb-latest-time {
font-size: calc(var(--font-size) * 0.8);
color: var(--muted);
text-decoration: none;
}
.mb-latest-time:visited {
color: var(--muted);
}
@media (hover: hover) {
.mb-latest-time:hover {
color: var(--link);
}
}
.mb-latest-location {
margin-inline-start: auto;
font-size: calc(var(--font-size) * 0.8);
line-height: 1;
text-decoration: none;
}
@media (hover: hover) {
.mb-latest-location:hover {
text-decoration: none;
opacity: 0.7;
}
}
footer .mb-latest {
text-align: start;
}
Want more? Check out all available Bearming add-ons.
Happy blogging, and microblogging.
Built for the Bearming theme. Using a different theme? Add the Bearming tokens to make them work with your setup.↩
Requires JavaScript, available on Bear Blog's premium plan.↩