Robert Birming

Latest photo widget

A widget that pulls your latest photo from a feed and displays it as a card on your blog. Works with Micro.blog and (most) other JSON feeds that include images in their content.1

Preview

Loading...

How to use

  1. Copy the snippet below and add it where you want the widget to appear.
  2. Replace the data-feed URL with your own JSON feed. On Micro.blog, a category feed looks like https://yourblog.com/categories/photos/feed.json.
  3. Copy the styles and add them to your theme.

Snippet

<div id="photo-latest" data-feed="https://yourblog.com/categories/photos/feed.json">Loading...</div>

<script>
(function(){
  var c = document.getElementById('photo-latest');
  if (!c) return;
  var feedUrl = c.getAttribute('data-feed');
  if (!feedUrl) return;

  fetch(feedUrl)
    .then(function(r) { if (!r.ok) throw new Error(r.status); return r.json(); })
    .then(function(data) {
      if (!data.items || !data.items.length) { c.textContent = 'No photos found.'; return; }

      var item = data.items.sort(function(a, b) {
        return new Date(b.date_published || 0) - new Date(a.date_published || 0);
      }).find(function(it) {
        var tmp = document.createElement('div');
        tmp.innerHTML = it.content_html || '';
        return tmp.querySelector('img');
      });

      if (!item) { c.textContent = 'No photos found.'; return; }

      var tmp = document.createElement('div');
      tmp.innerHTML = item.content_html || '';
      var imgEl = tmp.querySelector('img');
      var src = imgEl.getAttribute('src');
      var permalink = item.url || '#';

      var date = '';
      if (item.date_published) {
        var d = new Date(item.date_published);
        date = d.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });
      }

      var caption = '';
      if (tmp.textContent) {
        caption = tmp.textContent.trim().slice(0, 180);
      }

      c.textContent = '';
      var card = document.createElement('div');
      card.className = 'photo-latest-card';

      var photo = document.createElement('a');
      photo.className = 'photo-latest-img-link';
      photo.href = permalink;
      photo.target = '_blank';
      photo.rel = 'noopener';
      var img = document.createElement('img');
      img.className = 'photo-latest-img';
      img.src = src;
      img.alt = caption || 'Photo';
      img.loading = 'lazy';
      photo.appendChild(img);
      card.appendChild(photo);

      if (date) {
        var dateEl = document.createElement('a');
        dateEl.className = 'photo-latest-date';
        dateEl.href = permalink;
        dateEl.target = '_blank';
        dateEl.rel = 'noopener';
        dateEl.textContent = date;
        card.appendChild(dateEl);
      }

      if (caption) {
        var text = document.createElement('p');
        text.className = 'photo-latest-caption';
        text.textContent = caption;
        card.appendChild(text);
      }

      c.appendChild(card);
    })
    .catch(function(e) { c.textContent = 'Could not load photo. (' + e.message + ')'; });
})();
</script>

Styles

/* Latest photo widget | robertbirming.com */
#photo-latest {
  max-inline-size: 34rem;
  margin-block: var(--space-block);
  margin-inline: auto;
}

.photo-latest-card {
  padding-block: 1rem;
  padding-inline: 1.1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.photo-latest-img-link {
  display: block;
  border-radius: var(--radius);
  overflow: hidden;
}

.photo-latest-img {
  display: block;
  inline-size: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  margin: 0;
  border-radius: 0;
}

.photo-latest-date {
  display: block;
  margin-block-start: 1em;
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--text);
}

.photo-latest-date:visited {
  color: var(--text);
}

@media (hover: hover) {
  .photo-latest-date:hover {
    color: var(--link) !important;
  }
}

.photo-latest-caption {
  margin-block: 0.7em 0;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--muted);
}

Want more? Check out the Bear library.

Happy blogging, and happy shooting.

  1. This add-on is built for Bearming. Using a different theme? Add the Bearming tokens to make it work with your setup.