@rmdes/indiekit-endpoint-microsub 1.0.38 → 1.0.39
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/styles.css +53 -9
- package/lib/controllers/reader.js +91 -2
- package/package.json +1 -1
- package/views/channel.njk +1 -3
- package/views/layouts/reader.njk +1 -0
- package/views/partials/breadcrumbs.njk +16 -0
- package/views/timeline.njk +3 -3
package/assets/styles.css
CHANGED
|
@@ -1015,6 +1015,49 @@
|
|
|
1015
1015
|
color: #7c3aed;
|
|
1016
1016
|
}
|
|
1017
1017
|
|
|
1018
|
+
/* ==========================================================================
|
|
1019
|
+
Breadcrumbs
|
|
1020
|
+
========================================================================== */
|
|
1021
|
+
|
|
1022
|
+
.breadcrumbs {
|
|
1023
|
+
margin-bottom: var(--space-xs);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
.breadcrumbs__list {
|
|
1027
|
+
align-items: center;
|
|
1028
|
+
display: flex;
|
|
1029
|
+
flex-wrap: wrap;
|
|
1030
|
+
font-size: var(--font-size-small);
|
|
1031
|
+
gap: 0;
|
|
1032
|
+
list-style: none;
|
|
1033
|
+
margin: 0;
|
|
1034
|
+
padding: 0;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
.breadcrumbs__item::before {
|
|
1038
|
+
color: var(--color-text-muted);
|
|
1039
|
+
content: "/";
|
|
1040
|
+
margin: 0 var(--space-xs);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
.breadcrumbs__item:first-child::before {
|
|
1044
|
+
content: none;
|
|
1045
|
+
margin: 0;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
.breadcrumbs__link {
|
|
1049
|
+
color: var(--color-primary);
|
|
1050
|
+
text-decoration: none;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
.breadcrumbs__link:hover {
|
|
1054
|
+
text-decoration: underline;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
.breadcrumbs__current {
|
|
1058
|
+
color: var(--color-text-muted);
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1018
1061
|
/* ==========================================================================
|
|
1019
1062
|
View Switcher
|
|
1020
1063
|
========================================================================== */
|
|
@@ -1072,19 +1115,20 @@
|
|
|
1072
1115
|
}
|
|
1073
1116
|
|
|
1074
1117
|
.timeline-view__item {
|
|
1075
|
-
border-radius: var(--border-radius);
|
|
1076
1118
|
position: relative;
|
|
1077
1119
|
}
|
|
1078
1120
|
|
|
1079
|
-
.timeline-
|
|
1080
|
-
border-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
display: block;
|
|
1085
|
-
font-size: 0.75rem;
|
|
1121
|
+
.timeline-view__channel-badge {
|
|
1122
|
+
border-radius: 3px;
|
|
1123
|
+
color: #fff;
|
|
1124
|
+
display: inline-block;
|
|
1125
|
+
font-size: 0.6875rem;
|
|
1086
1126
|
font-weight: 600;
|
|
1087
|
-
|
|
1127
|
+
letter-spacing: 0.02em;
|
|
1128
|
+
line-height: 1;
|
|
1129
|
+
margin-bottom: var(--space-xs);
|
|
1130
|
+
padding: 3px 8px;
|
|
1131
|
+
text-transform: uppercase;
|
|
1088
1132
|
}
|
|
1089
1133
|
|
|
1090
1134
|
.timeline-view__filter {
|
|
@@ -46,9 +46,9 @@ import { getDeckConfig, saveDeckConfig } from "../storage/deck.js";
|
|
|
46
46
|
* @param {object} response - Express response
|
|
47
47
|
*/
|
|
48
48
|
export async function index(request, response) {
|
|
49
|
-
const lastView = request.session?.microsubView || "
|
|
49
|
+
const lastView = request.session?.microsubView || "timeline";
|
|
50
50
|
const validViews = ["channels", "deck", "timeline"];
|
|
51
|
-
const view = validViews.includes(lastView) ? lastView : "
|
|
51
|
+
const view = validViews.includes(lastView) ? lastView : "timeline";
|
|
52
52
|
response.redirect(`${request.baseUrl}/${view}`);
|
|
53
53
|
}
|
|
54
54
|
|
|
@@ -71,6 +71,10 @@ export async function channels(request, response) {
|
|
|
71
71
|
baseUrl: request.baseUrl,
|
|
72
72
|
readerBaseUrl: request.baseUrl,
|
|
73
73
|
activeView: "channels",
|
|
74
|
+
breadcrumbs: [
|
|
75
|
+
{ text: "Reader", href: request.baseUrl },
|
|
76
|
+
{ text: "Channels" },
|
|
77
|
+
],
|
|
74
78
|
});
|
|
75
79
|
}
|
|
76
80
|
|
|
@@ -85,6 +89,11 @@ export async function newChannel(request, response) {
|
|
|
85
89
|
baseUrl: request.baseUrl,
|
|
86
90
|
readerBaseUrl: request.baseUrl,
|
|
87
91
|
activeView: "channels",
|
|
92
|
+
breadcrumbs: [
|
|
93
|
+
{ text: "Reader", href: request.baseUrl },
|
|
94
|
+
{ text: "Channels", href: `${request.baseUrl}/channels` },
|
|
95
|
+
{ text: request.__("microsub.channels.new") },
|
|
96
|
+
],
|
|
88
97
|
});
|
|
89
98
|
}
|
|
90
99
|
|
|
@@ -157,6 +166,11 @@ export async function channel(request, response) {
|
|
|
157
166
|
baseUrl: request.baseUrl,
|
|
158
167
|
readerBaseUrl: request.baseUrl,
|
|
159
168
|
activeView: "channels",
|
|
169
|
+
breadcrumbs: [
|
|
170
|
+
{ text: "Reader", href: request.baseUrl },
|
|
171
|
+
{ text: "Channels", href: `${request.baseUrl}/channels` },
|
|
172
|
+
{ text: channelDocument.name },
|
|
173
|
+
],
|
|
160
174
|
});
|
|
161
175
|
}
|
|
162
176
|
|
|
@@ -184,6 +198,12 @@ export async function settings(request, response) {
|
|
|
184
198
|
baseUrl: request.baseUrl,
|
|
185
199
|
readerBaseUrl: request.baseUrl,
|
|
186
200
|
activeView: "channels",
|
|
201
|
+
breadcrumbs: [
|
|
202
|
+
{ text: "Reader", href: request.baseUrl },
|
|
203
|
+
{ text: "Channels", href: `${request.baseUrl}/channels` },
|
|
204
|
+
{ text: channelDocument.name, href: `${request.baseUrl}/channels/${uid}` },
|
|
205
|
+
{ text: "Settings" },
|
|
206
|
+
],
|
|
187
207
|
});
|
|
188
208
|
}
|
|
189
209
|
|
|
@@ -273,6 +293,12 @@ export async function feeds(request, response) {
|
|
|
273
293
|
baseUrl: request.baseUrl,
|
|
274
294
|
readerBaseUrl: request.baseUrl,
|
|
275
295
|
activeView: "channels",
|
|
296
|
+
breadcrumbs: [
|
|
297
|
+
{ text: "Reader", href: request.baseUrl },
|
|
298
|
+
{ text: "Channels", href: `${request.baseUrl}/channels` },
|
|
299
|
+
{ text: channelDocument.name, href: `${request.baseUrl}/channels/${uid}` },
|
|
300
|
+
{ text: "Feeds" },
|
|
301
|
+
],
|
|
276
302
|
});
|
|
277
303
|
}
|
|
278
304
|
|
|
@@ -354,6 +380,17 @@ export async function item(request, response) {
|
|
|
354
380
|
channel = await channelsCollection.findOne({ _id: itemDocument.channelId });
|
|
355
381
|
}
|
|
356
382
|
|
|
383
|
+
const itemBreadcrumbs = [
|
|
384
|
+
{ text: "Reader", href: request.baseUrl },
|
|
385
|
+
];
|
|
386
|
+
if (channel) {
|
|
387
|
+
itemBreadcrumbs.push(
|
|
388
|
+
{ text: "Channels", href: `${request.baseUrl}/channels` },
|
|
389
|
+
{ text: channel.name, href: `${request.baseUrl}/channels/${channel.uid}` },
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
itemBreadcrumbs.push({ text: itemDocument.name || "Item" });
|
|
393
|
+
|
|
357
394
|
response.render("item", {
|
|
358
395
|
title: itemDocument.name || "Item",
|
|
359
396
|
item: itemDocument,
|
|
@@ -361,6 +398,7 @@ export async function item(request, response) {
|
|
|
361
398
|
baseUrl: request.baseUrl,
|
|
362
399
|
readerBaseUrl: request.baseUrl,
|
|
363
400
|
activeView: "channels",
|
|
401
|
+
breadcrumbs: itemBreadcrumbs,
|
|
364
402
|
});
|
|
365
403
|
}
|
|
366
404
|
|
|
@@ -473,6 +511,10 @@ export async function compose(request, response) {
|
|
|
473
511
|
baseUrl: request.baseUrl,
|
|
474
512
|
readerBaseUrl: request.baseUrl,
|
|
475
513
|
activeView: "channels",
|
|
514
|
+
breadcrumbs: [
|
|
515
|
+
{ text: "Reader", href: request.baseUrl },
|
|
516
|
+
{ text: "Compose" },
|
|
517
|
+
],
|
|
476
518
|
});
|
|
477
519
|
}
|
|
478
520
|
|
|
@@ -648,6 +690,10 @@ export async function searchPage(request, response) {
|
|
|
648
690
|
baseUrl: request.baseUrl,
|
|
649
691
|
readerBaseUrl: request.baseUrl,
|
|
650
692
|
activeView: "channels",
|
|
693
|
+
breadcrumbs: [
|
|
694
|
+
{ text: "Reader", href: request.baseUrl },
|
|
695
|
+
{ text: "Search" },
|
|
696
|
+
],
|
|
651
697
|
});
|
|
652
698
|
}
|
|
653
699
|
|
|
@@ -686,6 +732,10 @@ export async function searchFeeds(request, response) {
|
|
|
686
732
|
baseUrl: request.baseUrl,
|
|
687
733
|
readerBaseUrl: request.baseUrl,
|
|
688
734
|
activeView: "channels",
|
|
735
|
+
breadcrumbs: [
|
|
736
|
+
{ text: "Reader", href: request.baseUrl },
|
|
737
|
+
{ text: "Search" },
|
|
738
|
+
],
|
|
689
739
|
});
|
|
690
740
|
}
|
|
691
741
|
|
|
@@ -719,6 +769,10 @@ export async function subscribe(request, response) {
|
|
|
719
769
|
baseUrl: request.baseUrl,
|
|
720
770
|
readerBaseUrl: request.baseUrl,
|
|
721
771
|
activeView: "channels",
|
|
772
|
+
breadcrumbs: [
|
|
773
|
+
{ text: "Reader", href: request.baseUrl },
|
|
774
|
+
{ text: "Search" },
|
|
775
|
+
],
|
|
722
776
|
});
|
|
723
777
|
}
|
|
724
778
|
|
|
@@ -811,6 +865,13 @@ export async function editFeedForm(request, response) {
|
|
|
811
865
|
baseUrl: request.baseUrl,
|
|
812
866
|
readerBaseUrl: request.baseUrl,
|
|
813
867
|
activeView: "channels",
|
|
868
|
+
breadcrumbs: [
|
|
869
|
+
{ text: "Reader", href: request.baseUrl },
|
|
870
|
+
{ text: "Channels", href: `${request.baseUrl}/channels` },
|
|
871
|
+
{ text: channelDocument.name, href: `${request.baseUrl}/channels/${uid}` },
|
|
872
|
+
{ text: "Feeds", href: `${request.baseUrl}/channels/${uid}/feeds` },
|
|
873
|
+
{ text: "Edit" },
|
|
874
|
+
],
|
|
814
875
|
});
|
|
815
876
|
}
|
|
816
877
|
|
|
@@ -848,6 +909,13 @@ export async function updateFeedUrl(request, response) {
|
|
|
848
909
|
baseUrl: request.baseUrl,
|
|
849
910
|
readerBaseUrl: request.baseUrl,
|
|
850
911
|
activeView: "channels",
|
|
912
|
+
breadcrumbs: [
|
|
913
|
+
{ text: "Reader", href: request.baseUrl },
|
|
914
|
+
{ text: "Channels", href: `${request.baseUrl}/channels` },
|
|
915
|
+
{ text: channelDocument.name, href: `${request.baseUrl}/channels/${uid}` },
|
|
916
|
+
{ text: "Feeds", href: `${request.baseUrl}/channels/${uid}/feeds` },
|
|
917
|
+
{ text: "Edit" },
|
|
918
|
+
],
|
|
851
919
|
});
|
|
852
920
|
}
|
|
853
921
|
|
|
@@ -1029,6 +1097,10 @@ export async function actorProfile(request, response) {
|
|
|
1029
1097
|
baseUrl: request.baseUrl,
|
|
1030
1098
|
readerBaseUrl: request.baseUrl,
|
|
1031
1099
|
activeView: "channels",
|
|
1100
|
+
breadcrumbs: [
|
|
1101
|
+
{ text: "Reader", href: request.baseUrl },
|
|
1102
|
+
{ text: actor.name || "Actor" },
|
|
1103
|
+
],
|
|
1032
1104
|
});
|
|
1033
1105
|
} catch (error) {
|
|
1034
1106
|
console.error(`[Microsub] Actor profile fetch failed: ${error.message}`);
|
|
@@ -1043,6 +1115,10 @@ export async function actorProfile(request, response) {
|
|
|
1043
1115
|
readerBaseUrl: request.baseUrl,
|
|
1044
1116
|
activeView: "channels",
|
|
1045
1117
|
error: "Could not fetch this actor's profile. They may have restricted access.",
|
|
1118
|
+
breadcrumbs: [
|
|
1119
|
+
{ text: "Reader", href: request.baseUrl },
|
|
1120
|
+
{ text: "Actor" },
|
|
1121
|
+
],
|
|
1046
1122
|
});
|
|
1047
1123
|
}
|
|
1048
1124
|
}
|
|
@@ -1163,6 +1239,10 @@ export async function timeline(request, response) {
|
|
|
1163
1239
|
baseUrl: request.baseUrl,
|
|
1164
1240
|
readerBaseUrl: request.baseUrl,
|
|
1165
1241
|
activeView: "timeline",
|
|
1242
|
+
breadcrumbs: [
|
|
1243
|
+
{ text: "Reader", href: request.baseUrl },
|
|
1244
|
+
{ text: "Timeline" },
|
|
1245
|
+
],
|
|
1166
1246
|
});
|
|
1167
1247
|
}
|
|
1168
1248
|
|
|
@@ -1223,6 +1303,10 @@ export async function deck(request, response) {
|
|
|
1223
1303
|
baseUrl: request.baseUrl,
|
|
1224
1304
|
readerBaseUrl: request.baseUrl,
|
|
1225
1305
|
activeView: "deck",
|
|
1306
|
+
breadcrumbs: [
|
|
1307
|
+
{ text: "Reader", href: request.baseUrl },
|
|
1308
|
+
{ text: "Deck" },
|
|
1309
|
+
],
|
|
1226
1310
|
});
|
|
1227
1311
|
}
|
|
1228
1312
|
|
|
@@ -1249,6 +1333,11 @@ export async function deckSettings(request, response) {
|
|
|
1249
1333
|
baseUrl: request.baseUrl,
|
|
1250
1334
|
readerBaseUrl: request.baseUrl,
|
|
1251
1335
|
activeView: "deck",
|
|
1336
|
+
breadcrumbs: [
|
|
1337
|
+
{ text: "Reader", href: request.baseUrl },
|
|
1338
|
+
{ text: "Deck", href: `${request.baseUrl}/deck` },
|
|
1339
|
+
{ text: "Settings" },
|
|
1340
|
+
],
|
|
1252
1341
|
});
|
|
1253
1342
|
}
|
|
1254
1343
|
|
package/package.json
CHANGED
package/views/channel.njk
CHANGED
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
{% block reader %}
|
|
4
4
|
<div class="channel">
|
|
5
5
|
<header class="channel__header">
|
|
6
|
-
<
|
|
7
|
-
{{ icon("previous") }} {{ __("microsub.channels.title") }}
|
|
8
|
-
</a>
|
|
6
|
+
<h1>{{ channel.name }}</h1>
|
|
9
7
|
<div class="channel__actions">
|
|
10
8
|
{% if not showRead and items.length > 0 %}
|
|
11
9
|
<form action="{{ baseUrl }}/api/mark-read" method="POST" style="display: inline;">
|
package/views/layouts/reader.njk
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{# Breadcrumb navigation #}
|
|
2
|
+
{% if breadcrumbs and breadcrumbs.length > 0 %}
|
|
3
|
+
<nav class="breadcrumbs" aria-label="Breadcrumb">
|
|
4
|
+
<ol class="breadcrumbs__list">
|
|
5
|
+
{% for crumb in breadcrumbs %}
|
|
6
|
+
<li class="breadcrumbs__item">
|
|
7
|
+
{% if crumb.href %}
|
|
8
|
+
<a href="{{ crumb.href }}" class="breadcrumbs__link">{{ crumb.text }}</a>
|
|
9
|
+
{% else %}
|
|
10
|
+
<span class="breadcrumbs__current" aria-current="page">{{ crumb.text }}</span>
|
|
11
|
+
{% endif %}
|
|
12
|
+
</li>
|
|
13
|
+
{% endfor %}
|
|
14
|
+
</ol>
|
|
15
|
+
</nav>
|
|
16
|
+
{% endif %}
|
package/views/timeline.njk
CHANGED
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
{% if items.length > 0 %}
|
|
32
32
|
<div class="timeline" id="timeline">
|
|
33
33
|
{% for item in items %}
|
|
34
|
-
<div class="timeline-view__item"
|
|
35
|
-
{% include "partials/item-card.njk" %}
|
|
34
|
+
<div class="timeline-view__item">
|
|
36
35
|
{% if item._channelName %}
|
|
37
|
-
<span class="timeline-view__channel-
|
|
36
|
+
<span class="timeline-view__channel-badge" style="background: {{ item._channelColor or '#888' }}">
|
|
38
37
|
{{ item._channelName }}
|
|
39
38
|
</span>
|
|
40
39
|
{% endif %}
|
|
40
|
+
{% include "partials/item-card.njk" %}
|
|
41
41
|
</div>
|
|
42
42
|
{% endfor %}
|
|
43
43
|
</div>
|