@rmdes/indiekit-endpoint-activitypub 3.8.7 → 3.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/css/base.css +144 -0
- package/assets/css/card.css +377 -0
- package/assets/css/compose.css +169 -0
- package/assets/css/dark-mode.css +94 -0
- package/assets/css/explore.css +530 -0
- package/assets/css/features.css +436 -0
- package/assets/css/federation.css +242 -0
- package/assets/css/interactions.css +236 -0
- package/assets/css/media.css +315 -0
- package/assets/css/messages.css +158 -0
- package/assets/css/moderation.css +119 -0
- package/assets/css/notifications.css +191 -0
- package/assets/css/profile.css +308 -0
- package/assets/css/responsive.css +33 -0
- package/assets/css/skeleton.css +74 -0
- package/assets/reader-interactions.js +115 -0
- package/assets/reader.css +574 -584
- package/index.js +34 -694
- package/lib/batch-broadcast.js +98 -0
- package/lib/controllers/compose.js +5 -7
- package/lib/controllers/interactions-boost.js +8 -13
- package/lib/controllers/interactions-like.js +8 -13
- package/lib/federation-actions.js +70 -0
- package/lib/inbox-queue.js +13 -6
- package/lib/init-indexes.js +251 -0
- package/lib/item-processing.js +22 -2
- package/lib/lookup-cache.js +3 -0
- package/lib/mastodon/backfill-timeline.js +11 -2
- package/lib/mastodon/entities/sanitize.js +19 -88
- package/lib/mastodon/helpers/account-cache.js +3 -0
- package/lib/mastodon/helpers/enrich-accounts.js +42 -55
- package/lib/mastodon/router.js +31 -0
- package/lib/mastodon/routes/accounts.js +16 -49
- package/lib/mastodon/routes/media.js +6 -4
- package/lib/mastodon/routes/notifications.js +6 -24
- package/lib/mastodon/routes/oauth.js +91 -18
- package/lib/mastodon/routes/search.js +3 -1
- package/lib/mastodon/routes/statuses.js +14 -52
- package/lib/mastodon/routes/timelines.js +3 -6
- package/lib/og-unfurl.js +52 -33
- package/lib/storage/moderation.js +11 -2
- package/lib/syndicator.js +239 -0
- package/lib/timeline-store.js +11 -15
- package/package.json +2 -1
- package/views/activitypub-federation-mgmt.njk +2 -2
- package/views/activitypub-moderation.njk +1 -1
- package/views/activitypub-profile.njk +16 -76
- package/views/activitypub-reader.njk +2 -1
- package/views/layouts/ap-reader.njk +2 -0
- package/views/partials/ap-item-card.njk +14 -117
- package/views/partials/ap-item-content.njk +20 -0
- package/views/partials/ap-notification-card.njk +1 -1
|
@@ -26,14 +26,14 @@
|
|
|
26
26
|
{# Boost header if this is a boosted post #}
|
|
27
27
|
{% if item.type == "boost" and item.boostedBy %}
|
|
28
28
|
<div class="ap-card__boost">
|
|
29
|
-
|
|
29
|
+
<span aria-hidden="true">🔁</span><span class="visually-hidden">{{ __("activitypub.reader.boosted") }}</span> {% if item.boostedBy.url %}<a href="{{ mountPath }}/admin/reader/profile?url={{ item.boostedBy.url | urlencode }}">{% if item.boostedBy.nameHtml %}{{ item.boostedBy.nameHtml | safe }}{% else %}{{ item.boostedBy.name or "Someone" }}{% endif %}</a>{% else %}{% if item.boostedBy.nameHtml %}{{ item.boostedBy.nameHtml | safe }}{% else %}{{ item.boostedBy.name or "Someone" }}{% endif %}{% endif %} {{ __("activitypub.reader.boosted") }}
|
|
30
30
|
</div>
|
|
31
31
|
{% endif %}
|
|
32
32
|
|
|
33
33
|
{# Reply context if this is a reply #}
|
|
34
34
|
{% if item.inReplyTo %}
|
|
35
35
|
<div class="ap-card__reply-to">
|
|
36
|
-
|
|
36
|
+
<span aria-hidden="true">↩</span> {{ __("activitypub.reader.replyingTo") }} <a href="{{ mountPath }}/admin/reader/post?url={{ item.inReplyTo | urlencode }}">{{ item.inReplyTo }}</a>
|
|
37
37
|
</div>
|
|
38
38
|
{% endif %}
|
|
39
39
|
|
|
@@ -63,10 +63,10 @@
|
|
|
63
63
|
<time datetime="{{ item.published }}" class="ap-card__timestamp" x-data x-relative-time>
|
|
64
64
|
{{ item.published | date("PPp") }}
|
|
65
65
|
</time>
|
|
66
|
-
{% if item.updated %}<span class="ap-card__edited" title="{{ item.updated | date('PPp') }}">✏️</span>{% endif %}
|
|
66
|
+
{% if item.updated %}<span class="ap-card__edited" title="{{ item.updated | date('PPp') }}" aria-label="Edited"><span aria-hidden="true">✏️</span></span>{% endif %}
|
|
67
67
|
</a>
|
|
68
68
|
{% if item.visibility and item.visibility != "public" %}
|
|
69
|
-
<span class="ap-card__visibility ap-card__visibility--{{ item.visibility }}" title="{% if item.visibility == 'unlisted' %}{{ __('activitypub.reader.compose.visibilityUnlisted') }}{% elif item.visibility == 'private' %}{{ __('activitypub.reader.compose.visibilityFollowers') }}{% elif item.visibility == 'direct' %}DM{% endif %}">{% if item.visibility == "unlisted" %}🔓{% elif item.visibility == "private" %}🔒{% elif item.visibility == "direct" %}✉️{% endif %}</span>
|
|
69
|
+
<span class="ap-card__visibility ap-card__visibility--{{ item.visibility }}" title="{% if item.visibility == 'unlisted' %}{{ __('activitypub.reader.compose.visibilityUnlisted') }}{% elif item.visibility == 'private' %}{{ __('activitypub.reader.compose.visibilityFollowers') }}{% elif item.visibility == 'direct' %}DM{% endif %}" aria-label="{% if item.visibility == 'unlisted' %}{{ __('activitypub.reader.compose.visibilityUnlisted') }}{% elif item.visibility == 'private' %}{{ __('activitypub.reader.compose.visibilityFollowers') }}{% elif item.visibility == 'direct' %}DM{% endif %}"><span aria-hidden="true">{% if item.visibility == "unlisted" %}🔓{% elif item.visibility == "private" %}🔒{% elif item.visibility == "direct" %}✉️{% endif %}</span></span>
|
|
70
70
|
{% endif %}
|
|
71
71
|
{% endif %}
|
|
72
72
|
</header>
|
|
@@ -89,48 +89,11 @@
|
|
|
89
89
|
<span x-show="shown" x-cloak>{{ __("activitypub.reader.hideContent") }}</span>
|
|
90
90
|
</button>
|
|
91
91
|
<div x-show="shown" x-cloak>
|
|
92
|
-
{%
|
|
93
|
-
<div class="ap-card__content">
|
|
94
|
-
{{ item.content.html | safe }}
|
|
95
|
-
</div>
|
|
96
|
-
{% endif %}
|
|
97
|
-
|
|
98
|
-
{# Quoted post embed #}
|
|
99
|
-
{% include "partials/ap-quote-embed.njk" %}
|
|
100
|
-
|
|
101
|
-
{# Link previews #}
|
|
102
|
-
{% include "partials/ap-link-preview.njk" %}
|
|
103
|
-
|
|
104
|
-
{# Media hidden behind CW #}
|
|
105
|
-
{% include "partials/ap-item-media.njk" %}
|
|
106
|
-
|
|
107
|
-
{# Poll options #}
|
|
108
|
-
{% if item.type == "question" or (item.pollOptions and item.pollOptions.length > 0) %}
|
|
109
|
-
{% include "partials/ap-poll-options.njk" %}
|
|
110
|
-
{% endif %}
|
|
92
|
+
{% include "partials/ap-item-content.njk" %}
|
|
111
93
|
</div>
|
|
112
94
|
</div>
|
|
113
95
|
{% else %}
|
|
114
|
-
{
|
|
115
|
-
{% if item.content and item.content.html %}
|
|
116
|
-
<div class="ap-card__content">
|
|
117
|
-
{{ item.content.html | safe }}
|
|
118
|
-
</div>
|
|
119
|
-
{% endif %}
|
|
120
|
-
|
|
121
|
-
{# Quoted post embed #}
|
|
122
|
-
{% include "partials/ap-quote-embed.njk" %}
|
|
123
|
-
|
|
124
|
-
{# Link previews #}
|
|
125
|
-
{% include "partials/ap-link-preview.njk" %}
|
|
126
|
-
|
|
127
|
-
{# Media visible directly #}
|
|
128
|
-
{% include "partials/ap-item-media.njk" %}
|
|
129
|
-
|
|
130
|
-
{# Poll options #}
|
|
131
|
-
{% if item.type == "question" or (item.pollOptions and item.pollOptions.length > 0) %}
|
|
132
|
-
{% include "partials/ap-poll-options.njk" %}
|
|
133
|
-
{% endif %}
|
|
96
|
+
{% include "partials/ap-item-content.njk" %}
|
|
134
97
|
{% endif %}
|
|
135
98
|
|
|
136
99
|
{# Mentions and hashtags #}
|
|
@@ -171,77 +134,11 @@
|
|
|
171
134
|
data-item-url="{{ itemUrl }}"
|
|
172
135
|
data-csrf-token="{{ csrfToken }}"
|
|
173
136
|
data-mount-path="{{ mountPath }}"
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
error: '',
|
|
180
|
-
boostCount: {{ boostCount if boostCount != null else 'null' }},
|
|
181
|
-
likeCount: {{ likeCount if likeCount != null else 'null' }},
|
|
182
|
-
async saveLater() {
|
|
183
|
-
if (this.saved) return;
|
|
184
|
-
const el = this.$root;
|
|
185
|
-
const itemUrl = el.dataset.itemUrl;
|
|
186
|
-
try {
|
|
187
|
-
const res = await fetch('/readlater/save', {
|
|
188
|
-
method: 'POST',
|
|
189
|
-
headers: { 'Content-Type': 'application/json' },
|
|
190
|
-
body: JSON.stringify({
|
|
191
|
-
url: itemUrl,
|
|
192
|
-
title: el.closest('article')?.querySelector('p')?.textContent?.substring(0, 80) || itemUrl,
|
|
193
|
-
source: 'activitypub'
|
|
194
|
-
}),
|
|
195
|
-
credentials: 'same-origin'
|
|
196
|
-
});
|
|
197
|
-
if (res.ok) this.saved = true;
|
|
198
|
-
else this.error = 'Failed to save';
|
|
199
|
-
} catch (e) {
|
|
200
|
-
this.error = e.message;
|
|
201
|
-
}
|
|
202
|
-
if (this.error) setTimeout(() => this.error = '', 3000);
|
|
203
|
-
},
|
|
204
|
-
async interact(action) {
|
|
205
|
-
if (this.loading) return;
|
|
206
|
-
this.loading = true;
|
|
207
|
-
this.error = '';
|
|
208
|
-
const el = this.$root;
|
|
209
|
-
const itemUid = el.dataset.itemUid;
|
|
210
|
-
const csrfToken = el.dataset.csrfToken;
|
|
211
|
-
const basePath = el.dataset.mountPath;
|
|
212
|
-
const prev = { liked: this.liked, boosted: this.boosted, boostCount: this.boostCount, likeCount: this.likeCount };
|
|
213
|
-
if (action === 'like') { this.liked = true; if (this.likeCount !== null) this.likeCount++; }
|
|
214
|
-
else if (action === 'unlike') { this.liked = false; if (this.likeCount !== null && this.likeCount > 0) this.likeCount--; }
|
|
215
|
-
else if (action === 'boost') { this.boosted = true; if (this.boostCount !== null) this.boostCount++; }
|
|
216
|
-
else if (action === 'unboost') { this.boosted = false; if (this.boostCount !== null && this.boostCount > 0) this.boostCount--; }
|
|
217
|
-
try {
|
|
218
|
-
const res = await fetch(basePath + '/admin/reader/' + action, {
|
|
219
|
-
method: 'POST',
|
|
220
|
-
headers: {
|
|
221
|
-
'Content-Type': 'application/json',
|
|
222
|
-
'X-CSRF-Token': csrfToken
|
|
223
|
-
},
|
|
224
|
-
body: JSON.stringify({ url: itemUid })
|
|
225
|
-
});
|
|
226
|
-
const data = await res.json();
|
|
227
|
-
if (!data.success) {
|
|
228
|
-
this.liked = prev.liked;
|
|
229
|
-
this.boosted = prev.boosted;
|
|
230
|
-
this.boostCount = prev.boostCount;
|
|
231
|
-
this.likeCount = prev.likeCount;
|
|
232
|
-
this.error = data.error || 'Failed';
|
|
233
|
-
}
|
|
234
|
-
} catch (e) {
|
|
235
|
-
this.liked = prev.liked;
|
|
236
|
-
this.boosted = prev.boosted;
|
|
237
|
-
this.boostCount = prev.boostCount;
|
|
238
|
-
this.likeCount = prev.likeCount;
|
|
239
|
-
this.error = e.message;
|
|
240
|
-
}
|
|
241
|
-
this.loading = false;
|
|
242
|
-
if (this.error) setTimeout(() => this.error = '', 3000);
|
|
243
|
-
}
|
|
244
|
-
}">
|
|
137
|
+
data-liked="{{ 'true' if isLiked else 'false' }}"
|
|
138
|
+
data-boosted="{{ 'true' if isBoosted else 'false' }}"
|
|
139
|
+
data-like-count="{{ likeCount if likeCount != null else '' }}"
|
|
140
|
+
data-boost-count="{{ boostCount if boostCount != null else '' }}"
|
|
141
|
+
x-data="apCardInteraction()">
|
|
245
142
|
<a href="{{ mountPath }}/admin/reader/compose?replyTo={{ (itemUrl or itemUid) | urlencode }}"
|
|
246
143
|
class="ap-card__action ap-card__action--reply"
|
|
247
144
|
title="{{ __('activitypub.reader.actions.reply') }}">
|
|
@@ -252,7 +149,7 @@
|
|
|
252
149
|
:title="boosted ? '{{ __('activitypub.reader.actions.unboost') }}' : '{{ __('activitypub.reader.actions.boost') }}'"
|
|
253
150
|
:disabled="loading"
|
|
254
151
|
@click="interact(boosted ? 'unboost' : 'boost')">
|
|
255
|
-
|
|
152
|
+
<span aria-hidden="true">🔁</span> <span x-text="boosted ? '{{ __('activitypub.reader.actions.boosted') }}' : '{{ __('activitypub.reader.actions.boost') }}'"></span><template x-if="boostCount !== null"><span class="ap-card__count" x-text="boostCount"></span></template>
|
|
256
153
|
</button>
|
|
257
154
|
<button class="ap-card__action ap-card__action--like"
|
|
258
155
|
:class="{ 'ap-card__action--active': liked }"
|
|
@@ -263,7 +160,7 @@
|
|
|
263
160
|
<span x-text="liked ? '{{ __('activitypub.reader.actions.liked') }}' : '{{ __('activitypub.reader.actions.like') }}'"></span><template x-if="likeCount !== null"><span class="ap-card__count" x-text="likeCount"></span></template>
|
|
264
161
|
</button>
|
|
265
162
|
<a href="{{ itemUrl }}" class="ap-card__action ap-card__action--link" target="_blank" rel="noopener">
|
|
266
|
-
|
|
163
|
+
<span aria-hidden="true">🔗</span> {{ __("activitypub.reader.actions.viewOriginal") }}
|
|
267
164
|
</a>
|
|
268
165
|
{% if application.readlaterEndpoint %}
|
|
269
166
|
<button class="ap-card__action ap-card__action--save"
|
|
@@ -275,7 +172,7 @@
|
|
|
275
172
|
<span x-text="saved ? 'Saved' : 'Save'"></span>
|
|
276
173
|
</button>
|
|
277
174
|
{% endif %}
|
|
278
|
-
<div x-show="error" x-text="error" class="ap-card__action-error" x-transition></div>
|
|
175
|
+
<div x-show="error" x-text="error" class="ap-card__action-error" role="alert" x-transition></div>
|
|
279
176
|
</footer>
|
|
280
177
|
{# Close moderation content warning wrapper #}
|
|
281
178
|
{% if item._moderated %}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{# Shared content rendering — included in both CW and non-CW paths #}
|
|
2
|
+
{% if item.content and item.content.html %}
|
|
3
|
+
<div class="ap-card__content">
|
|
4
|
+
{{ item.content.html | safe }}
|
|
5
|
+
</div>
|
|
6
|
+
{% endif %}
|
|
7
|
+
|
|
8
|
+
{# Quoted post embed #}
|
|
9
|
+
{% include "partials/ap-quote-embed.njk" %}
|
|
10
|
+
|
|
11
|
+
{# Link previews #}
|
|
12
|
+
{% include "partials/ap-link-preview.njk" %}
|
|
13
|
+
|
|
14
|
+
{# Media attachments #}
|
|
15
|
+
{% include "partials/ap-item-media.njk" %}
|
|
16
|
+
|
|
17
|
+
{# Poll options #}
|
|
18
|
+
{% if item.type == "question" or (item.pollOptions and item.pollOptions.length > 0) %}
|
|
19
|
+
{% include "partials/ap-poll-options.njk" %}
|
|
20
|
+
{% endif %}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<img src="{{ item.actorPhoto }}" alt="{{ item.actorName }}" class="ap-notification__avatar" loading="lazy" crossorigin="anonymous">
|
|
15
15
|
{% endif %}
|
|
16
16
|
<span class="ap-notification__avatar ap-notification__avatar--default" aria-hidden="true">{{ item.actorName[0] | upper if item.actorName else "?" }}</span>
|
|
17
|
-
<span class="ap-notification__type-badge">
|
|
17
|
+
<span class="ap-notification__type-badge" aria-hidden="true">
|
|
18
18
|
{% if item.type == "like" %}❤{% elif item.type == "boost" %}🔁{% elif item.type == "follow" or item.type == "follow_request" %}👤{% elif item.type == "reply" %}💬{% elif item.type == "mention" %}@{% elif item.type == "dm" %}✉{% elif item.type == "report" %}⚑{% endif %}
|
|
19
19
|
</span>
|
|
20
20
|
</div>
|