From c243b70629c91861efaa37e9613af708cd54e716 Mon Sep 17 00:00:00 2001 From: Ricardo Date: Tue, 3 Mar 2026 13:46:58 +0100 Subject: [PATCH] feat: enriched media model with ALT badges (Release 3+4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change photo storage from bare URL strings to objects with url, alt, width, height (AP) plus blurhash and focus (Mastodon API). Templates handle both old string and new object format for backward compat. Add ALT text badges on gallery images — click to expand the full alt text in an overlay. Renders in both reader and explore views. Also pass alt text through to lightbox and quote embed photos. Bump version to 2.5.3. Confab-Link: http://localhost:8080/sessions/e9d666ac-3c90-4298-9e92-9ac9d142bc06 --- assets/reader.css | 42 +++++++++++++++++++++++++++++++ lib/controllers/explore-utils.js | 16 ++++++++++-- lib/timeline-store.js | 7 +++++- package.json | 2 +- views/partials/ap-item-media.njk | 25 ++++++++++++------ views/partials/ap-quote-embed.njk | 3 ++- 6 files changed, 83 insertions(+), 12 deletions(-) diff --git a/assets/reader.css b/assets/reader.css index 2e11659..432882c 100644 --- a/assets/reader.css +++ b/assets/reader.css @@ -2537,3 +2537,45 @@ margin: 0 0.05em; } +/* Gallery items — positioned for ALT badge overlay */ +.ap-card__gallery-item { + position: relative; +} + +/* ALT text badges */ +.ap-media__alt-badge { + position: absolute; + bottom: 0.5rem; + left: 0.5rem; + background: rgba(0, 0, 0, 0.7); + color: white; + font-size: 0.65rem; + font-weight: 700; + padding: 0.15rem 0.35rem; + border-radius: var(--border-radius-small); + border: none; + cursor: pointer; + text-transform: uppercase; + letter-spacing: 0.03em; + z-index: 1; +} + +.ap-media__alt-badge:hover { + background: rgba(0, 0, 0, 0.9); +} + +.ap-media__alt-text { + position: absolute; + bottom: 2.2rem; + left: 0.5rem; + right: 0.5rem; + background: rgba(0, 0, 0, 0.85); + color: white; + font-size: var(--font-size-s); + padding: 0.5rem; + border-radius: var(--border-radius-small); + max-height: 8rem; + overflow-y: auto; + z-index: 2; +} + diff --git a/lib/controllers/explore-utils.js b/lib/controllers/explore-utils.js index 03a95a6..197ee94 100644 --- a/lib/controllers/explore-utils.js +++ b/lib/controllers/explore-utils.js @@ -84,7 +84,14 @@ export function mapMastodonStatusToItem(status, instance) { const url = att.url || att.remote_url || ""; if (!url) continue; if (att.type === "image" || att.type === "gifv") { - photo.push(url); + photo.push({ + url, + alt: att.description || "", + width: att.meta?.original?.width || null, + height: att.meta?.original?.height || null, + blurhash: att.blurhash || "", + focus: att.meta?.focus || null, + }); } else if (att.type === "video") { video.push(url); } else if (att.type === "audio") { @@ -144,7 +151,12 @@ export function mapMastodonStatusToItem(status, instance) { for (const att of q.media_attachments || []) { const attUrl = att.url || att.remote_url || ""; if (attUrl && (att.type === "image" || att.type === "gifv")) { - qPhoto.push(attUrl); + qPhoto.push({ + url: attUrl, + alt: att.description || "", + width: att.meta?.original?.width || null, + height: att.meta?.original?.height || null, + }); } } diff --git a/lib/timeline-store.js b/lib/timeline-store.js index 714de76..e843ccb 100644 --- a/lib/timeline-store.js +++ b/lib/timeline-store.js @@ -256,7 +256,12 @@ export async function extractObjectData(object, options = {}) { const mediaType = att.mediaType?.toLowerCase() || ""; if (mediaType.startsWith("image/")) { - photo.push(mediaUrl); + photo.push({ + url: mediaUrl, + alt: att.name?.toString() || "", + width: att.width || null, + height: att.height || null, + }); } else if (mediaType.startsWith("video/")) { video.push(mediaUrl); } else if (mediaType.startsWith("audio/")) { diff --git a/package.json b/package.json index cc32142..e84f176 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rmdes/indiekit-endpoint-activitypub", - "version": "2.5.2", + "version": "2.5.3", "description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.", "keywords": [ "indiekit", diff --git a/views/partials/ap-item-media.njk b/views/partials/ap-item-media.njk index 33adefd..c19def0 100644 --- a/views/partials/ap-item-media.njk +++ b/views/partials/ap-item-media.njk @@ -6,14 +6,23 @@ {% set extraCount = item.photo.length - 4 %} {% set totalPhotos = item.photo.length %} {% endif %} {% endfor %} @@ -24,7 +33,9 @@ {% if totalPhotos > 1 %} {% endif %} - + {% if totalPhotos > 1 %}
diff --git a/views/partials/ap-quote-embed.njk b/views/partials/ap-quote-embed.njk index 15d1a24..66466ef 100644 --- a/views/partials/ap-quote-embed.njk +++ b/views/partials/ap-quote-embed.njk @@ -25,8 +25,9 @@
{{ item.quote.content.html | safe }}
{% endif %} {% if item.quote.photo and item.quote.photo.length > 0 %} + {% set qPhoto = item.quote.photo[0] %}
- + {{ qPhoto.alt if qPhoto.alt else '' }}
{% endif %}