feat: ActivityPub reader — timeline, notifications, compose, moderation

Add a dedicated fediverse reader view with:
- Timeline view showing posts from followed accounts with threading,
  content warnings, boosts, and media display
- Compose form with dual-path posting (quick AP reply + Micropub blog post)
- Native AP interactions (like, boost, reply, follow/unfollow)
- Notifications view for likes, boosts, follows, mentions, replies
- Moderation tools (mute/block actors, keyword filters)
- Remote actor profile pages with follow state
- Automatic timeline cleanup with configurable retention
- CSRF protection, XSS prevention, input validation throughout

Removes Microsub bridge dependency — AP content now lives in its own
MongoDB collections (ap_timeline, ap_notifications, ap_interactions,
ap_muted, ap_blocked).

Bumps version to 1.1.0.
This commit is contained in:
Ricardo
2026-02-21 12:13:10 +01:00
parent 81a28ef086
commit 4e514235c2
29 changed files with 5402 additions and 230 deletions

View File

@@ -0,0 +1,58 @@
{# Notification card partial #}
<div class="ap-notification{% if not item.read %} ap-notification--unread{% endif %}">
{# Type icon #}
<div class="ap-notification__icon">
{% if item.type == "like" %}
{% elif item.type == "boost" %}
🔁
{% elif item.type == "follow" %}
👤
{% elif item.type == "reply" %}
💬
{% elif item.type == "mention" %}
@
{% endif %}
</div>
{# Notification body #}
<div class="ap-notification__body">
<span class="ap-notification__actor">
<a href="{{ item.actorUrl }}">{{ item.actorName }}</a>
</span>
<span class="ap-notification__action">
{% if item.type == "like" %}
{{ __("activitypub.notifications.liked") }}
{% elif item.type == "boost" %}
{{ __("activitypub.notifications.boostedPost") }}
{% elif item.type == "follow" %}
{{ __("activitypub.notifications.followedYou") }}
{% elif item.type == "reply" %}
{{ __("activitypub.notifications.repliedTo") }}
{% elif item.type == "mention" %}
{{ __("activitypub.notifications.mentionedYou") }}
{% endif %}
</span>
{% if item.targetUrl %}
<a href="{{ item.targetUrl }}" class="ap-notification__target">
{{ item.targetName or item.targetUrl }}
</a>
{% endif %}
{% if item.content and item.content.text %}
<div class="ap-notification__excerpt">
{{ item.content.text | truncate(200) }}
</div>
{% endif %}
</div>
{# Timestamp #}
{% if item.published %}
<time datetime="{{ item.published }}" class="ap-notification__time">
{{ item.published | date("PPp") }}
</time>
{% endif %}
</div>