feat: add ActivityPub badge and platform detection for interactions

- Add ActivityPub/Fediverse platform badge (purple, network icon) to
  interactions page alongside existing Mastodon and Bluesky badges
- Detect platform from Bridgy source URLs and author URLs for
  webmention.io items that lack a platform field
- Filter self-referencing syndication URLs from "Also on" footer so
  self-hosted AP posts don't show a redundant link back to the site
This commit is contained in:
Ricardo
2026-02-19 16:52:44 +01:00
parent cb68b7be00
commit 03ace58be5
2 changed files with 31 additions and 1 deletions
+10 -1
View File
@@ -72,12 +72,21 @@ withBlogSidebar: true
{% endif %}
{# Syndication Footer - shows where this post was also published #}
{# Skip syndication URLs that point back to our own site (self-hosted AP) #}
{% set externalSyndication = [] %}
{% if syndication %}
{% for url in syndication %}
{% if url.indexOf(site.url) != 0 %}
{% set externalSyndication = (externalSyndication.push(url), externalSyndication) %}
{% endif %}
{% endfor %}
{% endif %}
{% if externalSyndication.length %}
<footer class="post-footer mt-8 pt-6 border-t border-surface-200 dark:border-surface-700">
<div class="flex flex-wrap items-center gap-4">
<span class="text-sm text-surface-500 dark:text-surface-400">Also on:</span>
<div class="flex flex-wrap gap-3">
{% for url in syndication %}
{% for url in externalSyndication %}
{% if "bsky.app" in url or "bluesky" in url %}
<a class="u-syndication inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-[#0085ff]/10 text-[#0085ff] hover:bg-[#0085ff]/20 transition-colors text-sm font-medium" href="{{ url }}" target="_blank" rel="noopener syndication" title="View on Bluesky">
<svg class="w-4 h-4" viewBox="0 0 568 501" fill="currentColor" aria-hidden="true">
+21
View File
@@ -250,6 +250,9 @@ permalink: /interactions/
<span x-show="wm.platform === 'bluesky'" class="inline-flex items-center gap-1 px-1.5 py-0.5 text-xs bg-sky-100 dark:bg-sky-900/30 text-sky-600 dark:text-sky-400 rounded-full" title="Bluesky">
<svg class="w-3 h-3" viewBox="0 0 568 501" fill="currentColor"><path d="M123.121 33.664C188.241 82.553 258.281 181.68 284 234.873c25.719-53.192 95.759-152.32 160.879-201.21C491.866-1.611 568-28.906 568 57.947c0 17.346-9.945 145.713-15.778 166.555-20.275 72.453-94.155 90.933-159.875 79.748C507.222 323.8 536.444 388.56 473.333 453.32c-119.86 122.992-172.272-30.859-185.702-70.281-2.462-7.227-3.614-10.608-3.631-7.733-.017-2.875-1.169.506-3.631 7.733-13.43 39.422-65.842 193.273-185.702 70.281-63.111-64.76-33.89-129.52 80.986-149.071-65.72 11.185-139.6-7.295-159.875-79.748C9.945 203.659 0 75.291 0 57.946 0-28.906 76.135-1.612 123.121 33.664Z"/></svg>
</span>
<span x-show="wm.platform === 'activitypub'" class="inline-flex items-center gap-1 px-1.5 py-0.5 text-xs bg-purple-100 dark:bg-purple-900/30 text-purple-600 dark:text-purple-400 rounded-full" title="Fediverse (ActivityPub)">
<svg class="w-3 h-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="5" r="2.5"/><circle cx="6" cy="12" r="2.5"/><circle cx="18" cy="19" r="2.5"/><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/></svg>
</span>
<a :href="wm.url || '#'" target="_blank" rel="noopener" class="text-xs text-surface-500 hover:underline">
<time :datetime="wm.published || wm['wm-received']" x-text="formatDate(wm.published || wm['wm-received'])"></time>
@@ -414,6 +417,18 @@ function interactionsApp() {
}
},
detectPlatform(item) {
const source = item['wm-source'] || '';
const authorUrl = item.author?.url || '';
// Bridgy source URLs: brid.gy/{action}/{platform}/...
if (source.includes('brid.gy/') && source.includes('/mastodon/')) return 'mastodon';
if (source.includes('brid.gy/') && source.includes('/bluesky/')) return 'bluesky';
// Author URL heuristics
if (authorUrl.includes('bsky.app')) return 'bluesky';
if (authorUrl.includes('mstdn') || authorUrl.includes('mastodon') || authorUrl.includes('social.')) return 'mastodon';
return null;
},
mergeAndDeduplicate(wmItems, convItems) {
// Build a Set of source URLs from conversations for dedup
const convUrls = new Set(convItems.map(c => c.url).filter(Boolean));
@@ -438,6 +453,12 @@ function interactionsApp() {
// (same interaction from Bridgy webmention AND direct poll)
if (item.url && convUrls.has(item.url)) continue;
// Infer platform from Bridgy source URL or author URL
if (!item.platform) {
const detected = this.detectPlatform(item);
if (detected) item.platform = detected;
}
seen.add(wmKey);
result.push(item);
}