mirror of
https://github.com/svemagie/indiekit-endpoint-microsub.git
synced 2026-04-02 15:35:00 +02:00
feat: add CSS stacking avatar fallback to all templates (v1.0.49)
Phase 3 frontend harmonization: apply the same avatar fallback pattern used in ActivityPub to all Microsub templates. A fallback initials span is always rendered; when the <img> loads, it covers the fallback via absolute positioning. Broken images are removed by event delegation, revealing the initials underneath. Templates updated: item-card, item, actor, author (3 avatar sizes: 40px card, 48px detail, 80px profile). Error delegation script added to reader layout. Confab-Link: http://localhost:8080/sessions/bb4a6ec4-b711-48cd-b3d7-942ec2a9851d
This commit is contained in:
@@ -154,15 +154,40 @@
|
|||||||
margin-bottom: var(--space-s);
|
margin-bottom: var(--space-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ms-item-card__avatar-wrap {
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 40px;
|
||||||
|
position: relative;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-item-card__avatar-wrap > img {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.ms-item-card__author-photo {
|
.ms-item-card__author-photo {
|
||||||
border: var(--border-width-thin) solid var(--color-offset);
|
border: var(--border-width-thin) solid var(--color-offset);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
flex-shrink: 0;
|
|
||||||
height: 40px;
|
height: 40px;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ms-item-card__author-photo--default {
|
||||||
|
align-items: center;
|
||||||
|
background: var(--color-offset);
|
||||||
|
border-radius: 50%;
|
||||||
|
color: var(--color-on-offset);
|
||||||
|
display: flex;
|
||||||
|
font-size: var(--font-size-s);
|
||||||
|
font-weight: 600;
|
||||||
|
height: 40px;
|
||||||
|
justify-content: center;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
.ms-item-card__author-info {
|
.ms-item-card__author-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -496,6 +521,19 @@
|
|||||||
margin-bottom: var(--space-m);
|
margin-bottom: var(--space-m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ms-item__avatar-wrap {
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 48px;
|
||||||
|
position: relative;
|
||||||
|
width: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-item__avatar-wrap > img {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.ms-item__author-photo {
|
.ms-item__author-photo {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
@@ -503,6 +541,19 @@
|
|||||||
width: 48px;
|
width: 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ms-item__author-photo--default {
|
||||||
|
align-items: center;
|
||||||
|
background: var(--color-offset);
|
||||||
|
border-radius: 50%;
|
||||||
|
color: var(--color-on-offset);
|
||||||
|
display: flex;
|
||||||
|
font-size: var(--font-size-m);
|
||||||
|
font-weight: 600;
|
||||||
|
height: 48px;
|
||||||
|
justify-content: center;
|
||||||
|
width: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
.ms-item__author-info {
|
.ms-item__author-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -1010,12 +1061,37 @@
|
|||||||
gap: var(--space-m);
|
gap: var(--space-m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ms-actor-profile__avatar-wrap {
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 80px;
|
||||||
|
position: relative;
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-actor-profile__avatar-wrap > img {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.ms-actor-profile__avatar {
|
.ms-actor-profile__avatar {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
flex-shrink: 0;
|
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ms-actor-profile__avatar--default {
|
||||||
|
align-items: center;
|
||||||
|
background: var(--color-offset);
|
||||||
|
border-radius: 50%;
|
||||||
|
color: var(--color-on-offset);
|
||||||
|
display: flex;
|
||||||
|
font-size: var(--font-size-xl);
|
||||||
|
font-weight: 600;
|
||||||
|
height: 80px;
|
||||||
|
justify-content: center;
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
.ms-actor-profile__info {
|
.ms-actor-profile__info {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rmdes/indiekit-endpoint-microsub",
|
"name": "@rmdes/indiekit-endpoint-microsub",
|
||||||
"version": "1.0.48",
|
"version": "1.0.49",
|
||||||
"description": "Microsub endpoint for Indiekit. Enables subscribing to feeds and reading content using the Microsub protocol.",
|
"description": "Microsub endpoint for Indiekit. Enables subscribing to feeds and reading content using the Microsub protocol.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"indiekit",
|
"indiekit",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
{# Actor profile card #}
|
{# Actor profile card #}
|
||||||
<div class="ms-actor-profile">
|
<div class="ms-actor-profile">
|
||||||
<div class="ms-actor-profile__header">
|
<div class="ms-actor-profile__header">
|
||||||
|
<div class="ms-actor-profile__avatar-wrap" data-avatar-fallback>
|
||||||
{% if actor.photo %}
|
{% if actor.photo %}
|
||||||
<img src="{{ actor.photo }}"
|
<img src="{{ actor.photo }}"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -18,6 +19,8 @@
|
|||||||
width="80"
|
width="80"
|
||||||
height="80">
|
height="80">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<span class="ms-actor-profile__avatar ms-actor-profile__avatar--default" aria-hidden="true">{{ actor.name[0] | upper if actor.name else "?" }}</span>
|
||||||
|
</div>
|
||||||
<div class="ms-actor-profile__info">
|
<div class="ms-actor-profile__info">
|
||||||
<h2 class="ms-actor-profile__name">{{ actor.name }}</h2>
|
<h2 class="ms-actor-profile__name">{{ actor.name }}</h2>
|
||||||
{% if actor.handle %}
|
{% if actor.handle %}
|
||||||
@@ -73,6 +76,7 @@
|
|||||||
{# Author #}
|
{# Author #}
|
||||||
{% if item.author %}
|
{% if item.author %}
|
||||||
<div class="ms-item-card__author" style="padding: 12px 16px 0;">
|
<div class="ms-item-card__author" style="padding: 12px 16px 0;">
|
||||||
|
<div class="ms-item-card__avatar-wrap" data-avatar-fallback>
|
||||||
{% if item.author.photo %}
|
{% if item.author.photo %}
|
||||||
<img src="{{ item.author.photo }}"
|
<img src="{{ item.author.photo }}"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -81,6 +85,8 @@
|
|||||||
height="40"
|
height="40"
|
||||||
loading="lazy">
|
loading="lazy">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<span class="ms-item-card__author-photo ms-item-card__author-photo--default" aria-hidden="true">{{ item.author.name[0] | upper if item.author.name else "?" }}</span>
|
||||||
|
</div>
|
||||||
<div class="ms-item-card__author-info">
|
<div class="ms-item-card__author-info">
|
||||||
<span class="ms-item-card__author-name">{{ item.author.name or "Unknown" }}</span>
|
<span class="ms-item-card__author-name">{{ item.author.name or "Unknown" }}</span>
|
||||||
{% if item.author.url %}
|
{% if item.author.url %}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
{% if item.author %}
|
{% if item.author %}
|
||||||
<header class="ms-item__author">
|
<header class="ms-item__author">
|
||||||
|
<div class="ms-item__avatar-wrap" data-avatar-fallback>
|
||||||
{% if item.author.photo %}
|
{% if item.author.photo %}
|
||||||
<img src="{{ item.author.photo }}"
|
<img src="{{ item.author.photo }}"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -16,6 +17,8 @@
|
|||||||
height="48"
|
height="48"
|
||||||
loading="lazy">
|
loading="lazy">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<span class="ms-item__author-photo ms-item__author-photo--default" aria-hidden="true">{{ item.author.name[0] | upper if item.author.name else "?" }}</span>
|
||||||
|
</div>
|
||||||
<div class="ms-item__author-info">
|
<div class="ms-item__author-info">
|
||||||
<span class="ms-item__author-name">
|
<span class="ms-item__author-name">
|
||||||
{% if item.author.url %}
|
{% if item.author.url %}
|
||||||
|
|||||||
@@ -9,4 +9,6 @@
|
|||||||
{% include "partials/breadcrumbs.njk" %}
|
{% include "partials/breadcrumbs.njk" %}
|
||||||
{% include "partials/view-switcher.njk" %}
|
{% include "partials/view-switcher.njk" %}
|
||||||
{% block reader %}{% endblock %}
|
{% block reader %}{% endblock %}
|
||||||
|
{# Avatar fallback — remove broken images to reveal initials fallback underneath #}
|
||||||
|
<script>document.addEventListener("error",function(e){var t=e.target;if(t.tagName==="IMG"&&t.closest("[data-avatar-fallback]"))t.remove()},true)</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
{# Author display #}
|
{# Author display #}
|
||||||
{% if author %}
|
{% if author %}
|
||||||
<div class="author">
|
<div class="author">
|
||||||
|
<div class="ms-item__avatar-wrap" data-avatar-fallback>
|
||||||
{% if author.photo %}
|
{% if author.photo %}
|
||||||
<img src="{{ author.photo }}" alt="" class="author__photo" width="48" height="48" loading="lazy">
|
<img src="{{ author.photo }}" alt="" class="author__photo" width="48" height="48" loading="lazy">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<span class="ms-item__author-photo ms-item__author-photo--default" aria-hidden="true">{{ author.name[0] | upper if author.name else "?" }}</span>
|
||||||
|
</div>
|
||||||
<div class="author__info">
|
<div class="author__info">
|
||||||
<span class="author__name">
|
<span class="author__name">
|
||||||
{% if author.url %}
|
{% if author.url %}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
{# Author #}
|
{# Author #}
|
||||||
{% if item.author %}
|
{% if item.author %}
|
||||||
<div class="ms-item-card__author">
|
<div class="ms-item-card__author">
|
||||||
|
<div class="ms-item-card__avatar-wrap" data-avatar-fallback>
|
||||||
{% if item.author.photo %}
|
{% if item.author.photo %}
|
||||||
<img src="{{ item.author.photo }}"
|
<img src="{{ item.author.photo }}"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -61,6 +62,8 @@
|
|||||||
height="40"
|
height="40"
|
||||||
loading="lazy">
|
loading="lazy">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<span class="ms-item-card__author-photo ms-item-card__author-photo--default" aria-hidden="true">{{ item.author.name[0] | upper if item.author.name else "?" }}</span>
|
||||||
|
</div>
|
||||||
<div class="ms-item-card__author-info">
|
<div class="ms-item-card__author-info">
|
||||||
<span class="ms-item-card__author-name">{{ item.author.name or "Unknown" }}</span>
|
<span class="ms-item-card__author-name">{{ item.author.name or "Unknown" }}</span>
|
||||||
{% if item._source %}
|
{% if item._source %}
|
||||||
|
|||||||
Reference in New Issue
Block a user