mirror of
https://github.com/svemagie/indiekit-endpoint-activitypub.git
synced 2026-04-02 15:44:58 +02:00
- Replace inline onerror handlers with CSS stacking + event delegation for avatar fallback - Replace inline onclick with event delegation for profile link removal - Replace hardcoded border values with design tokens in reader-links.css - Add data-avatar-fallback pattern: fallback initials always visible, img layered on top Confab-Link: http://localhost:8080/sessions/bb4a6ec4-b711-48cd-b3d7-942ec2a9851d
111 lines
3.9 KiB
Plaintext
111 lines
3.9 KiB
Plaintext
{% extends "layouts/ap-reader.njk" %}
|
|
|
|
{% from "heading/macro.njk" import heading with context %}
|
|
{% from "prose/macro.njk" import prose with context %}
|
|
|
|
{% block readercontent %}
|
|
<div class="ap-profile"
|
|
x-data="{
|
|
following: {{ 'true' if isFollowing else 'false' }},
|
|
muted: {{ 'true' if isMuted else 'false' }},
|
|
blocked: {{ 'true' if isBlocked else 'false' }},
|
|
loading: false,
|
|
async action(endpoint, body) {
|
|
if (this.loading) return;
|
|
this.loading = true;
|
|
try {
|
|
const res = await fetch('{{ mountPath }}/admin/reader/' + endpoint, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRF-Token': '{{ csrfToken }}'
|
|
},
|
|
body: JSON.stringify(body)
|
|
});
|
|
const data = await res.json();
|
|
return data.success;
|
|
} catch { return false; }
|
|
finally { this.loading = false; }
|
|
}
|
|
}">
|
|
|
|
{# Header image #}
|
|
{% if image %}
|
|
<div class="ap-profile__header">
|
|
<img src="{{ image }}" alt="" class="ap-profile__header-img">
|
|
</div>
|
|
{% endif %}
|
|
|
|
{# Profile info #}
|
|
<div class="ap-profile__info">
|
|
<div class="ap-profile__avatar-wrap" data-avatar-fallback>
|
|
{% if icon %}
|
|
<img src="{{ icon }}" alt="{{ name }}" class="ap-profile__avatar">
|
|
{% endif %}
|
|
<div class="ap-profile__avatar ap-profile__avatar--placeholder">{{ name[0] }}</div>
|
|
</div>
|
|
|
|
<div class="ap-profile__details">
|
|
<h2 class="ap-profile__name">{{ name }}</h2>
|
|
{% if actorHandle %}
|
|
<div class="ap-profile__handle">@{{ actorHandle }}@{{ instanceHost }}</div>
|
|
{% endif %}
|
|
{% if bio %}
|
|
<div class="ap-profile__bio">{{ bio | safe }}</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{# Action buttons #}
|
|
<div class="ap-profile__actions">
|
|
<button class="ap-profile__action ap-profile__action--follow"
|
|
:class="{ 'ap-profile__action--active': following }"
|
|
:disabled="loading"
|
|
@click="
|
|
const ok = await action(following ? 'unfollow' : 'follow', { url: '{{ actorUrl }}' });
|
|
if (ok) following = !following;
|
|
">
|
|
<span x-text="following ? '{{ __('activitypub.profile.remote.unfollow') }}' : '{{ __('activitypub.profile.remote.follow') }}'"></span>
|
|
</button>
|
|
|
|
<button class="ap-profile__action"
|
|
:disabled="loading"
|
|
@click="
|
|
const ok = await action(muted ? 'unmute' : 'mute', { url: '{{ actorUrl }}' });
|
|
if (ok) muted = !muted;
|
|
">
|
|
<span x-text="muted ? '{{ __('activitypub.moderation.unmute') }}' : '{{ __('activitypub.moderation.muteActor') }}'"></span>
|
|
</button>
|
|
|
|
<button class="ap-profile__action ap-profile__action--danger"
|
|
:disabled="loading"
|
|
@click="
|
|
const ok = await action(blocked ? 'unblock' : 'block', { url: '{{ actorUrl }}' });
|
|
if (ok) blocked = !blocked;
|
|
">
|
|
<span x-text="blocked ? '{{ __('activitypub.moderation.unblock') }}' : '{{ __('activitypub.moderation.blockActor') }}'"></span>
|
|
</button>
|
|
|
|
<a href="{{ actorUrl }}" class="ap-profile__action" target="_blank" rel="noopener">
|
|
{{ __("activitypub.profile.remote.viewOn") }} {{ instanceHost }}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
{# Posts from this actor #}
|
|
<div class="ap-profile__posts">
|
|
<h3>{{ __("activitypub.profile.remote.postsTitle") }}</h3>
|
|
{% if posts.length > 0 %}
|
|
<div class="ap-timeline">
|
|
{% for item in posts %}
|
|
{% include "partials/ap-item-card.njk" %}
|
|
{% endfor %}
|
|
</div>
|
|
{% elif isFollowing %}
|
|
{{ prose({ text: __("activitypub.profile.remote.noPosts") }) }}
|
|
{% else %}
|
|
{{ prose({ text: __("activitypub.profile.remote.followToSee") }) }}
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|